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

If an `AuxiliaryTask` is started from a higher-priority thread and immediately scheduled, it does not start #486

Open
giuliomoro opened this issue Sep 8, 2018 · 1 comment

Comments

@giuliomoro
Copy link
Contributor

@giuliomoro giuliomoro commented Sep 8, 2018

say that you have:

... render()
{
  if(context->audioFramesElapsed == 0)
  {
    AuxiliaryTask task = Bela_createAuxiliaryTask(...);
    Bela_scheduleAuxiliaryTask(task);
  }
}

then the AuxiliaryTaskLoop() for that task in core/AuxiliaryTask.cpp never runs.

The underlying problem is as following:

Bela_createAuxiliaryTask() calls, under the hood:
pthread_create()

Bela_scheduleAuxiliaryTask() calls, under the hood:

if(pthread_mutex_trylock(&taskToSchedule->mutex))
{
// if this fails to lock, it means the task has not finished the user callback yet, in which case we don't care.
} else {
// otherwise , we lock successfully, so we signal the condition that `AuxiliaryTaskLoop()` is waiting on
  ret = pthread_cond_signal(&taskToSchedule->cond);
  pthread_mutex_unlock(&taskToSchedule->mutex); // and leave them the lock
}

while auxiliaryTaskLoop() does:

auxiliaryTaskLoop()
{
   // sleep immediately as the thread starts and wait to be signalled, trying to recreate
   // the semantics of Xenomai's rt_task_create() + rt_task_start(), where the thread would not 
   // start at creation.
   pthread_mutex_lock(&task->mutex);
   pthread_cond_wait(&task->cond, &task->mutex);
   pthread_mutex_unlock(&task->mutex);
...
   while(!gShouldStop)
   {
        auxiliary_argfunction(task->args); // the user-defined callback
        pthread_mutex_lock(&task->mutex);
        pthread_cond_wait(&task->cond, &task->mutex);
        pthread_mutex_unlock(&task->mutex);
   }
}

Now, if the priority of the invoking thread (the one runningrender() in this case) is higher than that given to the AuxiliaryTask, then auxiliaryTaskLoop() will not have a chance to run between Bela_createAuxiliaryTask() and Bela_scheduleAuxiliaryTask. Therefore pthread_cond_signal() will signal a condition that no one is waiting on, and when auxiliaryTaskLoop() does indeed get a chance to run, it will just sleep on the first pthread_cond_wait() outside the loop and wait there forever, without ever running auxiliary_argfunction().

@giuliomoro

This comment has been minimized.

Copy link
Contributor Author

@giuliomoro giuliomoro commented Sep 8, 2018

The solution proposed in 6b05171 temporarily elevates the priority of auxiliaryTaskLoop() so that it does actually run once.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
1 participant
You can’t perform that action at this time.