#1876 Unifies reentrant lock between tuners and frequency controller. (#1901)

Co-authored-by: sheirerd <sheirerd@ainfosec.com>
This commit is contained in:
Denny Sheirer
2024-05-04 05:29:54 -04:00
committed by GitHub
parent aa8d449140
commit cbe451a793
10 changed files with 79 additions and 101 deletions

View File

@@ -1417,8 +1417,6 @@ public class P25TrafficChannelManager extends TrafficChannelManager implements I
mAvailablePhase1TrafficChannelQueue.clear(); mAvailablePhase1TrafficChannelQueue.clear();
mAvailablePhase2TrafficChannelQueue.clear(); mAvailablePhase2TrafficChannelQueue.clear();
//TODO: debug
mLog.info("TCM - Stopping and clearing channel grant event maps");
mTS1ChannelGrantEventMap.clear(); mTS1ChannelGrantEventMap.clear();
mTS2ChannelGrantEventMap.clear(); mTS2ChannelGrantEventMap.clear();
} }

View File

@@ -42,15 +42,18 @@ import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/**
* Base tuner controller implementation.
*/
public abstract class TunerController implements Tunable, ISourceEventProcessor, ISourceEventListener, public abstract class TunerController implements Tunable, ISourceEventProcessor, ISourceEventListener,
INativeBufferProvider, Listener<INativeBuffer>, ITunerErrorListener INativeBufferProvider, Listener<INativeBuffer>, ITunerErrorListener
{ {
private final static Logger mLog = LoggerFactory.getLogger(TunerController.class); private final static Logger mLog = LoggerFactory.getLogger(TunerController.class);
//Protects access to the native buffer broadcaster for adding, removing or checking for listener count. //Protects access to the native buffer broadcaster for adding, removing or checking for listener count.
protected ReentrantLock mBufferListenerLock = new ReentrantLock(); private ReentrantLock mBufferListenerLock = new ReentrantLock();
private ReentrantLock mLock = new ReentrantLock();
protected Broadcaster<INativeBuffer> mNativeBufferBroadcaster = new Broadcaster(); protected Broadcaster<INativeBuffer> mNativeBufferBroadcaster = new Broadcaster();
protected FrequencyController mFrequencyController; protected FrequencyController mFrequencyController;
private int mMiddleUnusableHalfBandwidth; private int mMiddleUnusableHalfBandwidth;
private int mMeasuredFrequencyError; private int mMeasuredFrequencyError;
@@ -74,6 +77,26 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
mFrequencyErrorCorrectionManager = new FrequencyErrorCorrectionManager(this); mFrequencyErrorCorrectionManager = new FrequencyErrorCorrectionManager(this);
} }
/**
* Lock for controlling configuration access to this tuner controller and any embedded tuner to ensure that
* configuration changes happen atomically. There are at least two threads that can touch this controller:
*
* A: channel processing that changes the center tuned frequency and frequency correction.
* b: user ui thread that can touch any of the frequency correction and gain controls.
*
* Generally, we'll lock on each of the primary configuration change points - getter and setter for:
* Frequency
* Frequency Correction
* Sample Rate
* Gain Controls
*
* @return lock for controlling access to tuner controller and em
*/
public ReentrantLock getLock()
{
return mLock;
}
/** /**
* Updates the frequency controller with the new minimum and maximum values. * Updates the frequency controller with the new minimum and maximum values.
* @param minimum frequency Hertz * @param minimum frequency Hertz
@@ -85,17 +108,6 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
mFrequencyController.setMaximumFrequency(maximum); mFrequencyController.setMaximumFrequency(maximum);
} }
/**
* Lock for the frequency controller. This should only be used by the channel source manager to lock access to the
* frequency controller while creating a channel source, to block multi-threaded access to the frequency controller
* which might put the center tuned frequency value in an indeterminant state.
* @return frequency controller lock
*/
public ReentrantLock getFrequencyControllerLock()
{
return mFrequencyController.getFrequencyControllerLock();
}
/** /**
* Frequency correction manager for this tuner controller. * Frequency correction manager for this tuner controller.
*/ */
@@ -292,12 +304,12 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
{ {
try try
{ {
getFrequencyControllerLock().lock(); getLock().lock();
mFrequencyController.setFrequency(frequency); mFrequencyController.setFrequency(frequency);
} }
finally finally
{ {
getFrequencyControllerLock().unlock(); getLock().unlock();
} }
} }
@@ -318,12 +330,12 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
try try
{ {
getFrequencyControllerLock().lock(); getLock().lock();
canTune = mFrequencyController.canTune(frequency); canTune = mFrequencyController.canTune(frequency);
} }
finally finally
{ {
getFrequencyControllerLock().unlock(); getLock().unlock();
} }
return canTune; return canTune;
@@ -341,12 +353,12 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
try try
{ {
getFrequencyControllerLock().lock(); getLock().lock();
correction = mFrequencyController.getFrequencyCorrection(); correction = mFrequencyController.getFrequencyCorrection();
} }
finally finally
{ {
getFrequencyControllerLock().unlock(); getLock().unlock();
} }
return correction; return correction;
@@ -356,12 +368,12 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
{ {
try try
{ {
getFrequencyControllerLock().lock(); getLock().lock();
mFrequencyController.setFrequencyCorrection(correction); mFrequencyController.setFrequencyCorrection(correction);
} }
finally finally
{ {
getFrequencyControllerLock().unlock(); getLock().unlock();
} }
} }
@@ -375,12 +387,12 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
try try
{ {
getFrequencyControllerLock().lock(); getLock().lock();
minimum = mFrequencyController.getMinimumFrequency(); minimum = mFrequencyController.getMinimumFrequency();
} }
finally finally
{ {
getFrequencyControllerLock().unlock(); getLock().unlock();
} }
return minimum; return minimum;
@@ -394,12 +406,12 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
{ {
try try
{ {
getFrequencyControllerLock().lock(); getLock().lock();
mFrequencyController.setMinimumFrequency(minimum); mFrequencyController.setMinimumFrequency(minimum);
} }
finally finally
{ {
getFrequencyControllerLock().unlock(); getLock().unlock();
} }
} }
@@ -413,12 +425,12 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
try try
{ {
getFrequencyControllerLock().lock(); getLock().lock();
maximum = mFrequencyController.getMaximumFrequency(); maximum = mFrequencyController.getMaximumFrequency();
} }
finally finally
{ {
getFrequencyControllerLock().unlock(); getLock().unlock();
} }
return maximum; return maximum;
@@ -432,12 +444,12 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
{ {
try try
{ {
getFrequencyControllerLock().lock(); getLock().lock();
mFrequencyController.setMaximumFrequency(maximum); mFrequencyController.setMaximumFrequency(maximum);
} }
finally finally
{ {
getFrequencyControllerLock().unlock(); getLock().unlock();
} }
} }
@@ -447,12 +459,12 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
try try
{ {
getFrequencyControllerLock().lock(); getLock().lock();
minTuned = mFrequencyController.getFrequency() - (getUsableBandwidth() / 2); minTuned = mFrequencyController.getFrequency() - (getUsableBandwidth() / 2);
} }
finally finally
{ {
getFrequencyControllerLock().unlock(); getLock().unlock();
} }
return minTuned; return minTuned;
@@ -464,12 +476,12 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
try try
{ {
getFrequencyControllerLock().lock(); getLock().lock();
maxTuned = mFrequencyController.getFrequency() + (getUsableBandwidth() / 2); maxTuned = mFrequencyController.getFrequency() + (getUsableBandwidth() / 2);
} }
finally finally
{ {
getFrequencyControllerLock().unlock(); getLock().unlock();
} }
return maxTuned; return maxTuned;

View File

@@ -65,7 +65,6 @@ public abstract class FCDTunerController extends TunerController
private FCDConfiguration mConfiguration = new FCDConfiguration(); private FCDConfiguration mConfiguration = new FCDConfiguration();
protected ComplexMixer mComplexMixer; protected ComplexMixer mComplexMixer;
private ReentrantLock mListenerLock = new ReentrantLock();
/** /**
* Generic FCD tuner controller - contains functionality common across both * Generic FCD tuner controller - contains functionality common across both
@@ -126,7 +125,7 @@ public abstract class FCDTunerController extends TunerController
@Override @Override
public void addBufferListener(Listener<INativeBuffer> listener) public void addBufferListener(Listener<INativeBuffer> listener)
{ {
mListenerLock.lock(); getLock().lock();
try try
{ {
@@ -139,7 +138,7 @@ public abstract class FCDTunerController extends TunerController
} }
finally finally
{ {
mListenerLock.unlock(); getLock().unlock();
} }
} }
@@ -150,7 +149,7 @@ public abstract class FCDTunerController extends TunerController
@Override @Override
public void removeBufferListener(Listener<INativeBuffer> listener) public void removeBufferListener(Listener<INativeBuffer> listener)
{ {
mListenerLock.lock(); getLock().lock();
try try
{ {
@@ -167,7 +166,7 @@ public abstract class FCDTunerController extends TunerController
} }
finally finally
{ {
mListenerLock.unlock(); getLock().unlock();
} }
} }
@@ -460,7 +459,7 @@ public abstract class FCDTunerController extends TunerController
*/ */
public void setTunedFrequency(long frequency) throws SourceException public void setTunedFrequency(long frequency) throws SourceException
{ {
mListenerLock.lock(); getLock().lock();
try try
{ {
@@ -473,7 +472,7 @@ public abstract class FCDTunerController extends TunerController
} }
finally finally
{ {
mListenerLock.unlock(); getLock().unlock();
} }
} }

View File

@@ -22,11 +22,12 @@ import io.github.dsheirer.source.ISourceEventProcessor;
import io.github.dsheirer.source.InvalidFrequencyException; import io.github.dsheirer.source.InvalidFrequencyException;
import io.github.dsheirer.source.SourceEvent; import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceException; import io.github.dsheirer.source.SourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FrequencyController public class FrequencyController
{ {
@@ -42,11 +43,6 @@ public class FrequencyController
private boolean mSampleRateLocked = false; private boolean mSampleRateLocked = false;
private List<ISourceEventProcessor> mProcessors = new ArrayList<>(); private List<ISourceEventProcessor> mProcessors = new ArrayList<>();
/**
* Lock protecting access to frequency control plane, source event processor subscriptions and event broadcasting
*/
private ReentrantLock mLock = new ReentrantLock();
/** /**
* Constructs an instance * Constructs an instance
* @param tunable that can be controlled by this frequency controller. * @param tunable that can be controlled by this frequency controller.
@@ -56,15 +52,6 @@ public class FrequencyController
mTunable = tunable; mTunable = tunable;
} }
/**
* Lock for controlling access to frequency control plane, event processor subscriptions and source event broadcasts.
*/
public ReentrantLock getFrequencyControllerLock()
{
return mLock;
}
/** /**
* Prepare for disposal of this instance. * Prepare for disposal of this instance.
*/ */
@@ -294,7 +281,7 @@ public class FrequencyController
*/ */
public void addSourceEventProcessor(ISourceEventProcessor processor) public void addSourceEventProcessor(ISourceEventProcessor processor)
{ {
mLock.lock(); mTunable.getLock().lock();
try try
{ {
@@ -305,7 +292,7 @@ public class FrequencyController
} }
finally finally
{ {
mLock.unlock(); mTunable.getLock().unlock();
} }
} }
@@ -314,7 +301,7 @@ public class FrequencyController
*/ */
public void removeSourceEventProcessor(ISourceEventProcessor processor) public void removeSourceEventProcessor(ISourceEventProcessor processor)
{ {
mLock.lock(); mTunable.getLock().lock();
try try
{ {
@@ -322,7 +309,7 @@ public class FrequencyController
} }
finally finally
{ {
mLock.unlock(); mTunable.getLock().unlock();
} }
} }
@@ -354,7 +341,7 @@ public class FrequencyController
public void broadcast(SourceEvent event) throws SourceException public void broadcast(SourceEvent event) throws SourceException
{ {
mLock.lock(); mTunable.getLock().lock();
try try
{ {
@@ -365,13 +352,18 @@ public class FrequencyController
} }
finally finally
{ {
mLock.unlock(); mTunable.getLock().unlock();
} }
} }
public interface Tunable public interface Tunable
{ {
/**
* Reentrant lock to synchronize threaded access to tuner controls.
*/
ReentrantLock getLock();
/** /**
* Gets the tuned frequency of the device * Gets the tuned frequency of the device
*/ */

View File

@@ -116,7 +116,7 @@ public class HeterodyneChannelSourceManager extends ChannelSourceManager
try try
{ {
mTunerController.getFrequencyControllerLock().lock(); mTunerController.getLock().lock();
if(CenterFrequencyCalculator.canTune(tunerChannel, mTunerController, mTunerChannels)) if(CenterFrequencyCalculator.canTune(tunerChannel, mTunerController, mTunerChannels))
{ {
try try
@@ -150,7 +150,7 @@ public class HeterodyneChannelSourceManager extends ChannelSourceManager
} }
finally finally
{ {
mTunerController.getFrequencyControllerLock().unlock(); mTunerController.getLock().unlock();
} }
return source; return source;

View File

@@ -106,7 +106,7 @@ public class PassThroughSourceManager extends ChannelSourceManager
try try
{ {
mTunerController.getFrequencyControllerLock().lock(); mTunerController.getLock().lock();
PassThroughChannelSource channelSource = new PassThroughChannelSource(new SourceEventProxy(), PassThroughChannelSource channelSource = new PassThroughChannelSource(new SourceEventProxy(),
mTunerController, tunerChannel, threadName); mTunerController, tunerChannel, threadName);
@@ -116,7 +116,7 @@ public class PassThroughSourceManager extends ChannelSourceManager
} }
finally finally
{ {
mTunerController.getFrequencyControllerLock().unlock(); mTunerController.getLock().unlock();
} }
return source; return source;

View File

@@ -431,7 +431,7 @@ public class PolyphaseChannelSourceManager extends ChannelSourceManager
try try
{ {
mTunerController.getFrequencyControllerLock().lock(); mTunerController.getLock().lock();
if(isTunable(tunerChannel)) if(isTunable(tunerChannel))
{ {
//Get a new set of currently tuned channels //Get a new set of currently tuned channels
@@ -478,7 +478,7 @@ public class PolyphaseChannelSourceManager extends ChannelSourceManager
} }
finally finally
{ {
mTunerController.getFrequencyControllerLock().unlock(); mTunerController.getLock().unlock();
} }
return tunerChannelSource; return tunerChannelSource;

View File

@@ -67,7 +67,6 @@ public class RTL2832TunerController extends USBTunerController
private EmbeddedTuner mEmbeddedTuner; private EmbeddedTuner mEmbeddedTuner;
private long mTunedFrequency = 0; private long mTunedFrequency = 0;
private boolean mBiasTEnabled = false; private boolean mBiasTEnabled = false;
private ReentrantLock mLock = new ReentrantLock();
/** /**
* Abstract tuner controller device. Use the static gettype() method * Abstract tuner controller device. Use the static gettype() method
@@ -79,28 +78,6 @@ public class RTL2832TunerController extends USBTunerController
super(bus, portAddress, tunerErrorListener); super(bus, portAddress, tunerErrorListener);
} }
/**
* Lock for controlling configuration access to this tuner controller and the embedded tuner to ensure that
* configuration changes involving multiple USB control messages can happen atomically. There are at least two
* threads that can touch this controller:
*
* A: channel processing that changes the center tuned frequency and frequency correction.
* b: user ui thread that can touch any of the frequency correction and gain controls.
*
* Generally, we'll lock on each of the primary configuration change points - getter and setter for:
* Frequency
* Frequency Correction
* Sample Rate
* Gain Controls
*
* @return lock for controlling access to tuner controller and em
*/
private ReentrantLock getLock()
{
return mLock;
}
@Override @Override
protected INativeBufferFactory getNativeBufferFactory() protected INativeBufferFactory getNativeBufferFactory()
{ {

View File

@@ -185,7 +185,7 @@ public abstract class RspTunerController<I extends IControlRsp> extends TunerCon
@Override @Override
public void addBufferListener(Listener<INativeBuffer> listener) public void addBufferListener(Listener<INativeBuffer> listener)
{ {
mBufferListenerLock.lock(); getLock().lock();
try try
{ {
@@ -198,7 +198,7 @@ public abstract class RspTunerController<I extends IControlRsp> extends TunerCon
} }
finally finally
{ {
mBufferListenerLock.unlock(); getLock().unlock();
} }
} }
@@ -209,7 +209,7 @@ public abstract class RspTunerController<I extends IControlRsp> extends TunerCon
@Override @Override
public void removeBufferListener(Listener<INativeBuffer> listener) public void removeBufferListener(Listener<INativeBuffer> listener)
{ {
mBufferListenerLock.lock(); getLock().lock();
try try
{ {
@@ -222,7 +222,7 @@ public abstract class RspTunerController<I extends IControlRsp> extends TunerCon
} }
finally finally
{ {
mBufferListenerLock.unlock(); getLock().unlock();
} }
} }

View File

@@ -477,7 +477,7 @@ public abstract class USBTunerController extends TunerController
{ {
if(isRunning()) if(isRunning())
{ {
mBufferListenerLock.lock(); getLock().lock();
try try
{ {
@@ -492,7 +492,7 @@ public abstract class USBTunerController extends TunerController
} }
finally finally
{ {
mBufferListenerLock.unlock(); getLock().unlock();
} }
} }
} }
@@ -503,7 +503,7 @@ public abstract class USBTunerController extends TunerController
@Override @Override
public void removeBufferListener(Listener<INativeBuffer> listener) public void removeBufferListener(Listener<INativeBuffer> listener)
{ {
mBufferListenerLock.lock(); getLock().lock();
try try
{ {
@@ -516,7 +516,7 @@ public abstract class USBTunerController extends TunerController
} }
finally finally
{ {
mBufferListenerLock.unlock(); getLock().unlock();
} }
} }