A simple but efficient mutex implementation for FreeRTOS

by Isaac Marino Bavaresco

This is file "mutex.c".

NEW: Fixed the declaration of "pxOwner".

//==============================================================================
// Copyright (c) 2007-2009, Isaac Marino Bavaresco
// All rights reserved
// isaacbavaresco@yahoo.com.br
//==============================================================================
#include "FreeRTOS.h"
#include "list.h"
#include "task.h"
//==============================================================================
typedef struct
{
	xList			xTasksWaitingToTake;
	xTaskHandle		pxOwner;
	size_t			uxCount;
} xMUTEX;
//==============================================================================
typedef xMUTEX *xMutexHandle;
//==============================================================================
xMutexHandle xMutexCreate( void )
{
xMUTEX *pxNewMutex;
	
	pxNewMutex = pvPortMalloc( sizeof( xMUTEX ));
	if( pxNewMutex != NULL )
	{
		pxNewMutex->pxOwner	= NULL;
		pxNewMutex->uxCount	= 0;
		vListInitialise( &( pxNewMutex->xTasksWaitingToTake ) );
	}

	return pxNewMutex;
}
//==============================================================================
signed portBASE_TYPE xMutexTake( xMutexHandle pxMutex, portTickType xTicksToWait )
	{
	portENTER_CRITICAL();
	if( pxMutex->pxOwner == xTaskGetCurrentTaskHandle() )
		{
		pxMutex->uxCount++;
		portEXIT_CRITICAL();
		return pdTRUE;
		}

	if(( xTicksToWait > ( portTickType ) 0 ) && ( pxMutex->pxOwner != NULL ))
		{
		vTaskPlaceOnEventList( &( pxMutex->xTasksWaitingToTake ), xTicksToWait );
		taskYIELD();

		if( pxMutex->pxOwner == xTaskGetCurrentTaskHandle() )
			{
			pxMutex->uxCount = 1;
			portEXIT_CRITICAL();
			return pdTRUE;
			}
		else
			{
			portEXIT_CRITICAL();
			return pdFALSE;
			}
		}

	if( pxMutex->pxOwner == NULL )
		{
		pxMutex->pxOwner = xTaskGetCurrentTaskHandle();
		pxMutex->uxCount = 1;
		portEXIT_CRITICAL();
		return pdTRUE;
		}

	portEXIT_CRITICAL();
	return pdFALSE;
	}
//==============================================================================
signed portBASE_TYPE xMutexGive( xMutexHandle pxMutex, portBASE_TYPE Release )
	{
	portENTER_CRITICAL();
	if( pxMutex->pxOwner != xTaskGetCurrentTaskHandle() )
		{
		portEXIT_CRITICAL();
		return pdFALSE;
		}

	if( Release )
		pxMutex->uxCount = 0;
	else
		{
		if( --pxMutex->uxCount != 0 )
			{
			portEXIT_CRITICAL();
			return pdFALSE;
			}
		}
	

	if( !listLIST_IS_EMPTY( &pxMutex->xTasksWaitingToTake ))
		{
		pxMutex->pxOwner = (xTaskHandle)listGET_OWNER_OF_HEAD_ENTRY( (&pxMutex->xTasksWaitingToTake) );
		pxMutex->uxCount = 1;

		if( xTaskRemoveFromEventList( &pxMutex->xTasksWaitingToTake ) == pdTRUE )
			taskYIELD();
		}
	else
		pxMutex->pxOwner = NULL;

	portEXIT_CRITICAL();
	return pdTRUE;
	}
//==============================================================================
signed portBASE_TYPE xDoIOwnTheMutex( xMutexHandle pxMutex )
	{
	portBASE_TYPE c;

	portENTER_CRITICAL();
	c = pxMutex->pxOwner == xTaskGetCurrentTaskHandle();
	portEXIT_CRITICAL();

	return c;
	}
//==============================================================================