Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dabProcessor::reset sometimes terminates the app #97

Open
nlitsme opened this issue Oct 5, 2023 · 5 comments
Open

dabProcessor::reset sometimes terminates the app #97

nlitsme opened this issue Oct 5, 2023 · 5 comments

Comments

@nlitsme
Copy link

nlitsme commented Oct 5, 2023

I noticed in sdrangel, which uses a fork of dab-cmdline.
that occasionally, when switching channel, the app crashes.

looking into this, this is in the thread-assignment operator, which checks if
the current thread is still joinable ( -> it is still running ) and then terminates the app.

Two threads are terminated simultaneously:

  • dabProcessor::start() -> terminate
  • dabProcessor::run() -> mscHandler::start() -> terminate

other threads running:

  • dabProcessor::run() -> sampleReader::getSample(int)
  • mscHandler::run() -> cond_timedwait
  • mscHandler::run() -> cond_timedwait

I don't have a debug build, so I can't tell if these are all for the same object.

Looking at dabProcessor, the stop() method seems suspect. I think the sleep(1) call looks like an attempt to work around a synchronisation problem. Which may be the root cause.

willem

@JvanKatwijk
Copy link
Owner

JvanKatwijk commented Oct 5, 2023 via email

@srcejon
Copy link
Contributor

srcejon commented Nov 12, 2023

The problem will occur if dabReset() is called twice quickly. Perhaps adding this to one of the examples will show it.

You can see there is a potential problem just by looking at the code for start(), stop() and run() though:

stop() uses 'running' to determine whether to join:

if (running. load ()) {
   running. store (false);
   myReader. setRunning (false);
   sleep (1);
   threadHandle. join ();

}

However, the running variable is only set some lines of code in to run()

void dabProcessor::run (void) {
std::complex FreqCorr;
timeSyncer myTimeSyncer (&myReader);
int32_t i;
float fineOffset = 0;
float coarseOffset = 0;
bool correctionNeeded = true;
std::vector<complex> ofdmBuffer (T_null);
int dip_attempts = 0;
int index_attempts = 0;
int startIndex = -1;

  isSynced	= false;
  snr		= 0;
  running. store (true);  //// Set here <----

If reset() is called twice quickly, it's possible that running isn't yet set from the first invocation when stop is called for the second invocation. This means join doesn't get called - and so when the thread destructor is called, terminate() is called as the thread is still joinable.

Unfortunately, just setting running to true in start() isn't enough. That ensures join is called - but the thread sometimes doesn't end.

@JvanKatwijk
Copy link
Owner

JvanKatwijk commented Nov 14, 2023 via email

@srcejon
Copy link
Contributor

srcejon commented Nov 14, 2023

That is because the DAB library was designed for just running a single service in a single channel.

I believe that is all that we are doing. What I think happens is the following:

  • When the user changes the frequency, dabReset() is called.
  • stop() in the dab library has a 1 second delay.
  • This is long enough, that the user could change the frequency again, while it is waiting, resulting in a second call to dabReset() getting queued, so it is called immediately after the first returns.

I guess I could add some code to prevent that - but calling dabReset() twice in succession didn't seem unreasonable.

@JvanKatwijk
Copy link
Owner

JvanKatwijk commented Nov 15, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants