uC-OS2 icon indicating copy to clipboard operation
uC-OS2 copied to clipboard

'OS_FLAG_CONSUME' implementation cause race condition

Open Qetu107 opened this issue 2 years ago • 2 comments

#define FLAG_UNLOCKED ((OS_FLAGS)0x0001)

OS_FLAG_GRP *flag_group;

void WorkWithSharedResource()
{
    INT8U err;

    // 1: Start of critical section
    OSFlagPend(flag_group, FLAG_UNLOCKED, (OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME), 0, &err);

    // 2: start long-running operation, wait semaphore (signaled in interrupt)
    OSSemPend(...)

    // 3: end of critical section
    OSFlagPost(flag_group, FLAG_UNLOCKED, OS_FLAG_SET, &err)
}

// high priority task
void TaskA(void *p_arg)
{
   while (true)
   {
       WorkWithSharedResource();
   }
}

// low priority task
void TaskB(void *p_arg)
{
   while (true)
   {
       WorkWithSharedResource();
   }
}

Conditions: flag_grp->flags contains FLAG_UNLOCKED (i.e. bit is set)

Steps:

  1. 1A - high priority task acquire flag (because flag is set)
  2. 2A - high priority task start pend on semaphore
  3. context switch to TaskB
  4. 1B - low priority task start pend (flag is not set, TaskA consumed it in step 1)
  5. semaphore signaled by interrupt, TaskA become ready, context switch to TaskA
  6. 3A - high priority task set flag (in that step TaskB become ready through pgrp->OSFlagWaitList traversal)
  7. 1A - TaskA continues execution, it's priority is higher than TaskB. So 'FLAG_UNLOCKED' will be acquired again.
  8. 2A - TaskA pend on semaphore
  9. context switch to TaskB
  10. OSFlagPend continues execution in believing that flag group contains 'FLAG_UNLOCKED' flag (because of OSTCBCur->OSTCBFlagsRdy), but it's not. So, TaskA and TaskB in critical section, race condition...

Qetu107 avatar Oct 28 '21 13:10 Qetu107

#18 - Fix 'OS_FLAG_CONSUME' option behavior.

Qetu107 avatar Oct 29 '21 07:10 Qetu107

P.S. In this example code 'flag_group' should act as a binary semaphore with FIFO strategy.

Qetu107 avatar Oct 29 '21 11:10 Qetu107

Flags don't function in the same way as semaphores and should not be used for Critical Sections. If multiple tasks are pending on a flag with the consume option, the loop inside FlagPost will ready all of them. Flags were designed to operate primarily as a notification mechanism. For resource protection, you should use semaphores or mutexes.

forg0ne avatar Jan 12 '23 22:01 forg0ne