Why can taskA release the mutex semaphore successfully that has already been acquired by taskB?

Firstly: task B: create a mutex semaphore (called MS below) by calling xSemaphoreCreateMutex() and take it by xSemaphoreTake() successfully.
Note that task B never release MS anytime and anywhere.
Secondly: task A: release MS by xSemaphoreGive() and the API’s return value is pdTRUE. It means that MS is given successfully.
Thirdly: Task A: try to acquire MS by xSemaphoreTake() and it returns pdTRUE, too! That means MS was released successfully previously in the second stage, therefore it can be acquired without any problem.

I don’t understand why the xSemaphoreGive() API is designed like this. In my mind, the mutex semaphore should only be released by its ownership task(task B), shouldn’t it?
The code is like this:

// TaskB
SemaphoreHandle_t  MS = xSemaphoreCreateMutex();
 void TaskB_proc( void * pvParameters )
 {
    if( MS != NULL )
    {
        if( xSemaphoreTake( xSemaphore ) == pdTRUE )
        {
            // always loop
            while(1) {
              // Do something-1  // run
            }
        }
        // Do something-2  // NOT run
    }
 }
// TaskA
extern SemaphoreHandle_t MS;
// Note: TaskA_proc would wait so long that MS can be created and taken by taskB and then to run. 
 void TaskA_proc( void * pvParameters )
 {
    if( MS != NULL )
    {
        if( xSemaphoreGive( MS ) == pdTRUE )
        {
            // Do something-3 // run

}
	if( xSemaphoreTake( MS ) == pdTRUE )
        {
            // Do something-4  // run
        }
    }
 }

In the end, in the code the priority of task A is higher than task B.

Please post your code. The behavior you describe would naturally be dead wrong, but muteces have been proven correct a perceived bazillion times.

1 Like

Do you have configASSERT() defined?

1 Like

It is the wrong use of the API. configASSERT should trigger - do you have it defined as @jefftenney asked?

1 Like

Code is showed in the message. Thanks!

I think the issue is that the requirement for only the holding task to give the Mutex is a operational requirement on the PROGRAM, and might not be actually enforced by the code, as that would add inefficiency.

If your program breaks the rules, then it will suffer the possible consequences. This is very much in the spirit of the C language that FreeRTOS is written in.

2 Likes

But not a good look if a customer has safety or security certification requirements?

I tried the posted code and hit this assert.

1 Like

your code is incomplete. What is the complete parameter set to your take functions? Do you use a non-infinite-timeout? If so, task A should never get a true return from xSemaphoreTake on a mutex that B owns.

Not defined!
With the help of all of you(especially richard-damon), after checking the source code of xSemaphoreGive() once again and I mentioned the code like below:

Hmm I am not quite sure about this one, since there should be some kind of enforcement.

As far as I remember I had an example somewhere to show the difference between a mutex and a binary semaphore and once a task took a mutex only that task was able to release it.

With respect to the binary semaphore: As soon as a task has access to the semaphore handle it can release it.

Actually, from my understanding it MUST be enforced by the OS because othertwise priority inheritance management would not work. Whether failure to release by the holder needs to be propagated by the caller is a different question, but I do not think that efficiency would be an issue as the test for valid context must be performed by the release code anyways.

My memory of the code is that when configASSERT isn’t defined, the code just goes ahead and does what it does. If the releasing task doesn’t have inhereted priority, it may just work “fine”, but some of the defined preconditions might get violated.

The cost to check might be low, but it isn’t zero, and it may currently happen at points (when configASSERT is defined) where a clean blackout can’t happen. In this case, I seem to remember the check happens AFTER the mutex has been released, and possibly taken again by a higher priority task, so it couldn’t get undone.