/* FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry. This file is part of the FreeRTOS.org distribution. FreeRTOS.org is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. FreeRTOS.org is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with FreeRTOS.org; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA A special exception to the GPL can be applied should you wish to distribute a combined work that includes FreeRTOS.org, without being obliged to provide the source code for any proprietary components. See the licensing section of http://www.FreeRTOS.org for full details of how and when the exception can be applied. *************************************************************************** See http://www.FreeRTOS.org for documentation, latest information, license and contact details. Please ensure to read the configuration and relevant port sections of the online documentation. Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along with commercial development and support options. *************************************************************************** */ #include "queue.h" #ifndef SEMAPHORE_H #define SEMAPHORE_H typedef xQueueHandle xSemaphoreHandle; #define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( unsigned portCHAR ) 1 ) #define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( unsigned portCHAR ) 0 ) #define semGIVE_BLOCK_TIME ( ( portTickType ) 0 ) /** * semphr. h *
vSemaphoreCreateBinary( xSemaphoreHandle xSemaphore )* * Macro that implements a semaphore by using the existing queue mechanism. * The queue length is 1 as this is a binary semaphore. The data size is 0 * as we don't want to actually store any data - we just want to know if the * queue is empty or full. * * @param xSemaphore Handle to the created semaphore. Should be of type xSemaphoreHandle. * * Example usage:
xSemaphoreHandle xSemaphore; void vATask( void * pvParameters ) { // Semaphore cannot be used before a call to vSemaphoreCreateBinary (). // This is a macro so pass the variable in directly. vSemaphoreCreateBinary( xSemaphore ); if( xSemaphore != NULL ) { // The semaphore was created successfully. // The semaphore can now be used. } }* \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary * \ingroup Semaphores */ #define vSemaphoreCreateBinary( xSemaphore ) { \ xSemaphore = xQueueCreate( ( unsigned portCHAR ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH ); \ if( xSemaphore != NULL ) \ { \ xSemaphoreGive( xSemaphore ); \ } \ } /** * semphr. h * xSemaphoreTake( * xSemaphoreHandle xSemaphore, * portTickType xBlockTime * ) * * Macro to obtain a semaphore. The semaphore must of been created using * vSemaphoreCreateBinary (). * * @param xSemaphore A handle to the semaphore being obtained. This is the * handle returned by vSemaphoreCreateBinary (); * * @param xBlockTime The time in ticks to wait for the semaphore to become * available. The macro portTICK_RATE_MS can be used to convert this to a * real time. A block time of zero can be used to poll the semaphore. * * @return pdTRUE if the semaphore was obtained. pdFALSE if xBlockTime * expired without the semaphore becoming available. * * Example usage:
xSemaphoreHandle xSemaphore = NULL; // A task that creates a semaphore. void vATask( void * pvParameters ) { // Create the semaphore to guard a shared resource. vSemaphoreCreateBinary( xSemaphore ); } // A task that uses the semaphore. void vAnotherTask( void * pvParameters ) { // ... Do other things. if( xSemaphore != NULL ) { // See if we can obtain the semaphore. If the semaphore is not available // wait 10 ticks to see if it becomes free. if( xSemaphoreTake( xSemaphore, ( portTickType ) 10 ) == pdTRUE ) { // We were able to obtain the semaphore and can now access the // shared resource. // ... // We have finished accessing the shared resource. Release the // semaphore. xSemaphoreGive( xSemaphore ); } else { // We could not obtain the semaphore and can therefore not access // the shared resource safely. } } }* \defgroup xSemaphoreTake xSemaphoreTake * \ingroup Semaphores */ #define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueReceive( ( xQueueHandle ) xSemaphore, NULL, xBlockTime ) /** * semphr. h *
xSemaphoreGive( xSemaphoreHandle xSemaphore )* * Macro to release a semaphore. The semaphore must of been created using * vSemaphoreCreateBinary (), and obtained using sSemaphoreTake (). * * This must not be used from an ISR. See xSemaphoreGiveFromISR () for * an alternative which can be used from an ISR. * * @param xSemaphore A handle to the semaphore being released. This is the * handle returned by vSemaphoreCreateBinary (); * * @return pdTRUE if the semaphore was released. pdFALSE if an error occurred. * Semaphores are implemented using queues. An error can occur if there is * no space on the queue to post a message - indicating that the * semaphore was not first obtained correctly. * * Example usage:
xSemaphoreHandle xSemaphore = NULL; void vATask( void * pvParameters ) { // Create the semaphore to guard a shared resource. vSemaphoreCreateBinary( xSemaphore ); if( xSemaphore != NULL ) { if( xSemaphoreGive( xSemaphore ) != pdTRUE ) { // We would expect this call to fail because we cannot give // a semaphore without first "taking" it! } // Obtain the semaphore - don't block if the semaphore is not // immediately available. if( xSemaphoreTake( xSemaphore, ( portTickType ) 0 ) ) { // We now have the semaphore and can access the shared resource. // ... // We have finished accessing the shared resource so can free the // semaphore. if( xSemaphoreGive( xSemaphore ) != pdTRUE ) { // We would not expect this call to fail because we must have // obtained the semaphore to get here. } } } }* \defgroup xSemaphoreGive xSemaphoreGive * \ingroup Semaphores */ #define xSemaphoreGive( xSemaphore ) xQueueSend( ( xQueueHandle ) xSemaphore, NULL, semGIVE_BLOCK_TIME ) /** * semphr. h *
xSemaphoreGiveFromISR( xSemaphoreHandle xSemaphore, portSHORT sTaskPreviouslyWoken )* * Macro to release a semaphore. The semaphore must of been created using * vSemaphoreCreateBinary (), and obtained using xSemaphoreTake (). * * This macro can be used from an ISR. * * @param xSemaphore A handle to the semaphore being released. This is the * handle returned by vSemaphoreCreateBinary (); * * @param sTaskPreviouslyWoken This is included so an ISR can make multiple calls * to xSemaphoreGiveFromISR () from a single interrupt. The first call * should always pass in pdFALSE. Subsequent calls should pass in * the value returned from the previous call. See the file serial .c in the * PC port for a good example of using xSemaphoreGiveFromISR (). * * @return pdTRUE if a task was woken by releasing the semaphore. This is * used by the ISR to determine if a context switch may be required following * the ISR. * * Example usage:
#define LONG_TIME 0xffff #define TICKS_TO_WAIT 10 xSemaphoreHandle xSemaphore = NULL; // Repetitive task. void vATask( void * pvParameters ) { for( ;; ) { // We want this task to run every 10 ticks or a timer. The semaphore // was created before this task was started // Block waiting for the semaphore to become available. if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE ) { // It is time to execute. // ... // We have finished our task. Return to the top of the loop where // we will block on the semaphore until it is time to execute // again. } } } // Timer ISR void vTimerISR( void * pvParameters ) { static unsigned portCHAR ucLocalTickCount = 0; // A timer tick has occurred. // ... Do other time functions. // Is it time for vATask () to run? ucLocalTickCount++; if( ucLocalTickCount >= TICKS_TO_WAIT ) { // Unblock the task by releasing the semaphore. xSemaphoreGive( xSemaphore ); // Reset the count so we release the semaphore again in 10 ticks time. ucLocalTickCount = 0; } }* \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR * \ingroup Semaphores */ #define xSemaphoreGiveFromISR( xSemaphore, xTaskPreviouslyWoken ) xQueueSendFromISR( ( xQueueHandle ) xSemaphore, NULL, xTaskPreviouslyWoken ) #endif