Skip to content

Commit

Permalink
#1876 Unifies reentrant lock between tuners and frequency controller. (
Browse files Browse the repository at this point in the history
…#1901)

Co-authored-by: sheirerd <[email protected]>
  • Loading branch information
DSheirer and sheirerd authored May 4, 2024
1 parent aa8d449 commit cbe451a
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1417,8 +1417,6 @@ public void stop()

mAvailablePhase1TrafficChannelQueue.clear();
mAvailablePhase2TrafficChannelQueue.clear();
//TODO: debug
mLog.info("TCM - Stopping and clearing channel grant event maps");
mTS1ChannelGrantEventMap.clear();
mTS2ChannelGrantEventMap.clear();
}
Expand Down
78 changes: 45 additions & 33 deletions src/main/java/io/github/dsheirer/source/tuner/TunerController.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,18 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Base tuner controller implementation.
*/
public abstract class TunerController implements Tunable, ISourceEventProcessor, ISourceEventListener,
INativeBufferProvider, Listener<INativeBuffer>, ITunerErrorListener
{
private final static Logger mLog = LoggerFactory.getLogger(TunerController.class);

//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 FrequencyController mFrequencyController;
private int mMiddleUnusableHalfBandwidth;
private int mMeasuredFrequencyError;
Expand All @@ -74,6 +77,26 @@ public TunerController(ITunerErrorListener tunerErrorListener)
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.
* @param minimum frequency Hertz
Expand All @@ -85,17 +108,6 @@ public void setFrequencyExtents(long minimum, long 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.
*/
Expand Down Expand Up @@ -292,12 +304,12 @@ public void setFrequency(long frequency) throws SourceException
{
try
{
getFrequencyControllerLock().lock();
getLock().lock();
mFrequencyController.setFrequency(frequency);
}
finally
{
getFrequencyControllerLock().unlock();
getLock().unlock();
}
}

Expand All @@ -318,12 +330,12 @@ public boolean canTune(long frequency)

try
{
getFrequencyControllerLock().lock();
getLock().lock();
canTune = mFrequencyController.canTune(frequency);
}
finally
{
getFrequencyControllerLock().unlock();
getLock().unlock();
}

return canTune;
Expand All @@ -341,12 +353,12 @@ public double getFrequencyCorrection()

try
{
getFrequencyControllerLock().lock();
getLock().lock();
correction = mFrequencyController.getFrequencyCorrection();
}
finally
{
getFrequencyControllerLock().unlock();
getLock().unlock();
}

return correction;
Expand All @@ -356,12 +368,12 @@ public void setFrequencyCorrection(double correction) throws SourceException
{
try
{
getFrequencyControllerLock().lock();
getLock().lock();
mFrequencyController.setFrequencyCorrection(correction);
}
finally
{
getFrequencyControllerLock().unlock();
getLock().unlock();
}
}

Expand All @@ -375,12 +387,12 @@ public long getMinimumFrequency()

try
{
getFrequencyControllerLock().lock();
getLock().lock();
minimum = mFrequencyController.getMinimumFrequency();
}
finally
{
getFrequencyControllerLock().unlock();
getLock().unlock();
}

return minimum;
Expand All @@ -394,12 +406,12 @@ public void setMinimumFrequency(long minimum)
{
try
{
getFrequencyControllerLock().lock();
getLock().lock();
mFrequencyController.setMinimumFrequency(minimum);
}
finally
{
getFrequencyControllerLock().unlock();
getLock().unlock();
}
}

Expand All @@ -413,12 +425,12 @@ public long getMaximumFrequency()

try
{
getFrequencyControllerLock().lock();
getLock().lock();
maximum = mFrequencyController.getMaximumFrequency();
}
finally
{
getFrequencyControllerLock().unlock();
getLock().unlock();
}

return maximum;
Expand All @@ -432,12 +444,12 @@ public void setMaximumFrequency(long maximum)
{
try
{
getFrequencyControllerLock().lock();
getLock().lock();
mFrequencyController.setMaximumFrequency(maximum);
}
finally
{
getFrequencyControllerLock().unlock();
getLock().unlock();
}
}

Expand All @@ -447,12 +459,12 @@ public long getMinTunedFrequency() throws SourceException

try
{
getFrequencyControllerLock().lock();
getLock().lock();
minTuned = mFrequencyController.getFrequency() - (getUsableBandwidth() / 2);
}
finally
{
getFrequencyControllerLock().unlock();
getLock().unlock();
}

return minTuned;
Expand All @@ -464,12 +476,12 @@ public long getMaxTunedFrequency() throws SourceException

try
{
getFrequencyControllerLock().lock();
getLock().lock();
maxTuned = mFrequencyController.getFrequency() + (getUsableBandwidth() / 2);
}
finally
{
getFrequencyControllerLock().unlock();
getLock().unlock();
}

return maxTuned;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ public abstract class FCDTunerController extends TunerController

private FCDConfiguration mConfiguration = new FCDConfiguration();
protected ComplexMixer mComplexMixer;
private ReentrantLock mListenerLock = new ReentrantLock();

/**
* Generic FCD tuner controller - contains functionality common across both
Expand Down Expand Up @@ -126,7 +125,7 @@ else if(getTunerType() == TunerType.FUNCUBE_DONGLE_PRO_PLUS)
@Override
public void addBufferListener(Listener<INativeBuffer> listener)
{
mListenerLock.lock();
getLock().lock();

try
{
Expand All @@ -139,7 +138,7 @@ public void addBufferListener(Listener<INativeBuffer> listener)
}
finally
{
mListenerLock.unlock();
getLock().unlock();
}
}

Expand All @@ -150,7 +149,7 @@ public void addBufferListener(Listener<INativeBuffer> listener)
@Override
public void removeBufferListener(Listener<INativeBuffer> listener)
{
mListenerLock.lock();
getLock().lock();

try
{
Expand All @@ -167,7 +166,7 @@ public void removeBufferListener(Listener<INativeBuffer> listener)
}
finally
{
mListenerLock.unlock();
getLock().unlock();
}
}

Expand Down Expand Up @@ -460,7 +459,7 @@ public void setFCDMode(Mode mode) throws UsbException, UsbClaimException
*/
public void setTunedFrequency(long frequency) throws SourceException
{
mListenerLock.lock();
getLock().lock();

try
{
Expand All @@ -473,7 +472,7 @@ public void setTunedFrequency(long frequency) throws SourceException
}
finally
{
mListenerLock.unlock();
getLock().unlock();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@
import io.github.dsheirer.source.InvalidFrequencyException;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FrequencyController
{
Expand All @@ -42,11 +43,6 @@ public class FrequencyController
private boolean mSampleRateLocked = false;
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
* @param tunable that can be controlled by this frequency controller.
Expand All @@ -56,15 +52,6 @@ public FrequencyController(Tunable 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.
*/
Expand Down Expand Up @@ -294,7 +281,7 @@ public void setFrequencyCorrection(double correction) throws SourceException
*/
public void addSourceEventProcessor(ISourceEventProcessor processor)
{
mLock.lock();
mTunable.getLock().lock();

try
{
Expand All @@ -305,7 +292,7 @@ public void addSourceEventProcessor(ISourceEventProcessor processor)
}
finally
{
mLock.unlock();
mTunable.getLock().unlock();
}
}

Expand All @@ -314,15 +301,15 @@ public void addSourceEventProcessor(ISourceEventProcessor processor)
*/
public void removeSourceEventProcessor(ISourceEventProcessor processor)
{
mLock.lock();
mTunable.getLock().lock();

try
{
mProcessors.remove(processor);
}
finally
{
mLock.unlock();
mTunable.getLock().unlock();
}
}

Expand Down Expand Up @@ -354,7 +341,7 @@ protected void broadcastSampleRateChange() throws SourceException

public void broadcast(SourceEvent event) throws SourceException
{
mLock.lock();
mTunable.getLock().lock();

try
{
Expand All @@ -365,13 +352,18 @@ public void broadcast(SourceEvent event) throws SourceException
}
finally
{
mLock.unlock();
mTunable.getLock().unlock();
}
}


public interface Tunable
{
/**
* Reentrant lock to synchronize threaded access to tuner controls.
*/
ReentrantLock getLock();

/**
* Gets the tuned frequency of the device
*/
Expand Down
Loading

0 comments on commit cbe451a

Please sign in to comment.