This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Recursive locking mechanism with timeout

Other Parts Discussed in Thread: SYSBIOS, CC2650

Hi,

I am using SYSBIOS 6.41.02.41 (it came with the TI-MAC stack and TI-RTOS 2.11.01.09)
The device is CC2650 (4X4)

I have asked a similar question previously, but this time, it's a little bit more complicated.
Here's a link to my previous post

My goal is to be able to restrict access to a peripheral (I used UART with TI-RTOS drivers in this case). When a task requests and obtains access to the peripheral, I want only that task to be allowed to use the peripheral. Other tasks can request access to the peripheral and can block with a specified timeout.

The code that I am using was previously developed using FreeRTOS Binary Recursive Sempahores (big word for mutex which can be called by the same task again).

So far, I was able to accomplish everything that I wanted with GateMutexPri, however, this doesn't allow the use of a timeout to allow other tasks to poll the peripheral in case it is busy.

Does anybody know a clean way to accomplish this? Either through TI-RTOS drivers or SYSBIOS.

Thanks in advance

Michel

  • So I figured this one out on my own. I found this forum which helped me clear some explanations that were misleading about binary semaphores.

    Here's the general idea behind my solution:

    • I use a global variable that stores the task handle of the "current" owner
    • I use a GateMutex to access (read & write) the current owner variable
    • I use a semaphore with pend (this allows me to use a timeout)
    • The semaphore is a binary semaphore in PRIORITY mode (the highest priority task will be given ownership first

    Here is the sample code (Note: this has not been thoroughly tested, but should give an idea on how it's done).

    // Function to take ownership
    bool OwnershipTake(uint32 timeoutTicks)
    {
       Task_Handle currentOwner;
       Task_Handle selfHandle = Task_self();
       
       // Copy protected variable
       IArg key = GateMutexPri_enter(someGateMutex);
       {
          currentOwner = mCurrentOwner;
       }
       GateMutexPri_leave(someGateMutex, key);
       
       // Check who is the owner
       if (currentOwner == selfHandle)
       {
          // We are already the owner
          return TRUE;
       }
       else
       {      
          // Pend on semaphore for ownership
          if (Semaphore_pend(ownerSemaphore, timeoutTicks))
          {
             // Take ownership
             key = GateMutexPri_enter(someGateMutex);
             {
                mCurrentOwner = selfHandle;
             }
             GateMutexPri_leave(someGateMutex, key);
             return TRUE;
          }
          else
          {
             // We timed out.
             return FALSE;
          }
       }
    }
    
    // Function to release ownership
    bool OwnershipRelease(void)
    {
       Task_Handle currentOwner;
       Task_Handle selfHandle = Task_self();
       
       // Copy protected variable
       IArg key = GateMutexPri_enter(someGateMutex);
       {
          currentOwner = mCurrentOwner;
       }
       GateMutexPri_leave(someGateMutex, key);
       
       // Check who is the owner
       if (currentOwner != selfHandle)
       {
          // Could already be released or another task has the ownership
          return FALSE;
       }
       else
       {
          // Release ownership
          IArg key = GateMutexPri_enter(someGateMutex);
          {
             mCurrentOwner = NULL;
             Semaphore_post(ownerSemaphore);
          }
          GateMutexPri_leave(someGateMutex, key);
          return TRUE;
       }
    }
    
    //Pseudo-code when accessing the protected resource
     Task_Handle currentOwner;
     Task_Handle selfHandle = Task_self();  
      
     // Copy protected variable
     IArg key = GateMutexPri_enter(someGateMutex);
     {
       currentOwner = mCurrentOwner;
     }
     GateMutexPri_leave(someGateMutex, key);
       
     // Check who is the owner
     if (currentOwner != selfHandle)
     {
       // Task is not current owner. Wait on semaphore
       if (Semaphore_pend(ownerSemaphore, timeoutTicks))
       {
    
         //
         // Access the protected resource here
         //
    
         // Semaphore was taken so we need to post back to it
         Semaphore_post(ownerSemaphore);
       }
       return;
     }
     else
     {
       // Current task is the owner. We write directly to resource (pending on semaphore would result in deadlock)
    
       //
       // Access the protected resource here
       //
    
    }

    Hope this helps others

    If there is a Module that can already do that, it would be great.

    Michel

  • Hi Michel,

    The basic flow looks ok. We debated when we created the Gate modules on whether to have a timeout or not. The main reason we decided to not have a timeout was cost of error handling. The code gets ugly and costly if you require the caller to check the return from a Gate enter or leave. We understood potential of locked systems though. So we documented that there should not be blocking calls (e.g. Task_sleep, etc.) inside a gate enter/leave pair. Basically do only what is necessary and do it as quickly as possible.

    Todd
  • Hi Todd,
    Thanks for the feedback.
    I completely understand the dilemmas when making design decisions. The reason that I run into these weird cases is because I am porting code from FreeRTOS to TI-RTOS and the modules are not always the same. I'm just glad I found a way to work around it.
    Michel