| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /** |
| ************************************************************************ |
| * @file M4OSA_Semaphore.c |
| * @brief Semaphore for Windows |
| * @note This file implements functions to manipulate semaphore |
| ************************************************************************ |
| */ |
| |
| |
| |
| #include "M4OSA_Debug.h" |
| #include "M4OSA_Types.h" |
| #include "M4OSA_Error.h" |
| #include "M4OSA_Memory.h" |
| #include "M4OSA_Semaphore.h" |
| |
| #include <semaphore.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <errno.h> |
| #include <time.h> |
| |
| |
| /* Context for the semaphore */ |
| typedef struct { |
| M4OSA_UInt32 coreID; /* semaphore context identifiant */ |
| sem_t semaphore; /* semaphore */ |
| } M4OSA_SemaphoreContext; |
| |
| |
| |
| |
| /** |
| ************************************************************************ |
| * @brief This method creates a new semaphore with the "initialCounter" |
| * value. |
| * @note This function creates and allocates a unique context. It's the |
| * OSAL real time responsibility for managing its context. It must |
| * be freed by the M4OSA_semaphoreClose function. The context |
| * parameter will be sent back to any OSAL core semaphore functions |
| * to allow retrieving data associated to the opened semaphore. |
| * @param context:(OUT) Context of the created semaphore |
| * @param initial_count:(IN) Initial counter of the semaphore |
| * @return M4NO_ERROR: there is no error |
| * @return M4ERR_PARAMETER: provided context is NULL |
| * @return M4ERR_ALLOC: there is no more available memory |
| * @return M4ERR_CONTEXT_FAILED: the context creation failed |
| ************************************************************************ |
| */ |
| M4OSA_ERR M4OSA_semaphoreOpen(M4OSA_Context* context, |
| M4OSA_UInt32 initial_count) |
| { |
| M4OSA_SemaphoreContext* semaphoreContext = M4OSA_NULL; |
| |
| M4OSA_TRACE1_2("M4OSA_semaphoreOpen\t\tM4OSA_Context* 0x%x\tM4OSA_UInt32 " |
| "%d", context, initial_count); |
| |
| M4OSA_DEBUG_IF2(context == M4OSA_NULL, |
| M4ERR_PARAMETER, "M4OSA_semaphoreOpen"); |
| |
| *context = M4OSA_NULL; |
| |
| semaphoreContext = (M4OSA_SemaphoreContext*) M4OSA_32bitAlignedMalloc( |
| sizeof(M4OSA_SemaphoreContext), M4OSA_SEMAPHORE, |
| (M4OSA_Char*)"M4OSA_semaphoreOpen: semaphore context"); |
| |
| if(semaphoreContext == M4OSA_NULL) |
| { |
| M4OSA_DEBUG(M4ERR_ALLOC, "M4OSA_semaphoreOpen"); |
| |
| return M4ERR_ALLOC; |
| } |
| |
| if (0 != sem_init(&semaphoreContext->semaphore, 0, initial_count)) |
| { |
| free(semaphoreContext); |
| |
| M4OSA_DEBUG(M4ERR_CONTEXT_FAILED, |
| "M4OSA_semaphoreOpen: OS semaphore creation failed"); |
| |
| return M4ERR_CONTEXT_FAILED; |
| } |
| |
| semaphoreContext->coreID = M4OSA_SEMAPHORE ; |
| *context = (M4OSA_Context)semaphoreContext; |
| |
| return M4NO_ERROR; |
| } |
| |
| |
| |
| |
| /** |
| ************************************************************************ |
| * @brief This method decrements (one by one) the semaphore counter. The |
| * semaphore is identified by its context This call is not blocking |
| * if the semaphore counter is positive or zero (after |
| * decrementation). This call is blocking if the semaphore counter |
| * is less than zero (after decrementation), until the semaphore is |
| * upper than zero (see M4OSA_semaphorePost) or time_out is |
| * reached. |
| * @note If "timeout" value is M4OSA_WAIT_FOREVER, the calling thread |
| * will block indefinitely until the semaphore is unlocked. |
| * @param context:(IN/OUT) Context of the semaphore |
| * @param timeout:(IN) Time out in milliseconds |
| * @return M4NO_ERROR: there is no error |
| * @return M4ERR_PARAMETER: at least one parameter is NULL |
| * @return M4WAR_TIME_OUT: time out is elapsed before semaphore has been |
| * available. |
| * @return M4ERR_BAD_CONTEXT: provided context is not a valid one |
| ************************************************************************ |
| */ |
| M4OSA_ERR M4OSA_semaphoreWait(M4OSA_Context context, M4OSA_Int32 timeout) |
| { |
| M4OSA_SemaphoreContext* semaphoreContext = (M4OSA_SemaphoreContext*)context; |
| struct timespec ts; |
| struct timespec left; |
| int result; |
| |
| M4OSA_TRACE1_2("M4OSA_semaphoreWait\t\tM4OSA_Context 0x%x\tM4OSA_UInt32 %d", |
| context, timeout); |
| |
| M4OSA_DEBUG_IF2(context == M4OSA_NULL, |
| M4ERR_PARAMETER, "M4OSA_semaphoreWait"); |
| |
| M4OSA_DEBUG_IF2(semaphoreContext->coreID != M4OSA_SEMAPHORE, |
| M4ERR_BAD_CONTEXT, "M4OSA_semaphoreWait"); |
| |
| if ( (M4OSA_Int32)M4OSA_WAIT_FOREVER == timeout) |
| { |
| if ( 0 != sem_wait(&semaphoreContext->semaphore) ) |
| { |
| M4OSA_DEBUG(M4ERR_BAD_CONTEXT, |
| "M4OSA_semaphoreWait: OS semaphore wait failed"); |
| |
| return M4ERR_BAD_CONTEXT ; |
| } |
| } |
| else |
| { |
| result = sem_trywait(&semaphoreContext->semaphore); |
| while ( ((EBUSY == result) || (EAGAIN == result)) && ( 0 < timeout ) ) |
| { |
| ts.tv_sec = 0; |
| if (1 <= timeout) |
| { |
| ts.tv_nsec = 1000000; |
| timeout -= 1; |
| } |
| else |
| { |
| ts.tv_nsec = timeout * 1000000; |
| timeout = 0; |
| } |
| nanosleep(&ts, &left); |
| result = sem_trywait(&semaphoreContext->semaphore); |
| } |
| if (0 != result) |
| { |
| if ((EBUSY == result) || (EAGAIN == result)) |
| { |
| return M4WAR_TIME_OUT; |
| } |
| else |
| { |
| M4OSA_DEBUG(M4ERR_BAD_CONTEXT, "M4OSA_semaphoreWait: OS semaphore wait failed"); |
| return M4ERR_BAD_CONTEXT; |
| } |
| } |
| } |
| |
| return M4NO_ERROR; |
| } |
| |
| |
| |
| |
| |
| /** |
| ************************************************************************ |
| * @brief This method increments the semaphore counter. The semaphore is |
| * identified by its context |
| * @note If the semaphore counter is upper than zero (after addition), |
| * the M4OSA_semaphoreWait call of the thread with the highest |
| * priority is unblocked and made ready to run. |
| * @note No hypotheses can be made on which thread will be unblocked |
| * between threads with the same priority. |
| * @param context:(IN/OUT) Context of the semaphore |
| * @return M4NO_ERROR: there is no error |
| * @return M4ERR_PARAMETER: at least one parameter is NULL |
| * @return M4ERR_BAD_CONTEXT: provided context is not a valid one |
| ************************************************************************ |
| */ |
| M4OSA_ERR M4OSA_semaphorePost(M4OSA_Context context) |
| { |
| M4OSA_SemaphoreContext* semaphoreContext = (M4OSA_SemaphoreContext*)context; |
| |
| M4OSA_TRACE1_1("M4OSA_semaphorePost\t\tM4OSA_Context 0x%x", context); |
| |
| M4OSA_DEBUG_IF2(context == M4OSA_NULL, |
| M4ERR_PARAMETER, "M4OSA_semaphorePost"); |
| |
| M4OSA_DEBUG_IF2(semaphoreContext->coreID != M4OSA_SEMAPHORE, |
| M4ERR_BAD_CONTEXT, "M4OSA_semaphorePost"); |
| |
| sem_post(&semaphoreContext->semaphore); |
| |
| return M4NO_ERROR; |
| } |
| |
| |
| |
| |
| |
| /** |
| ************************************************************************ |
| * @brief This method deletes a semaphore (identify by its context). |
| * After this call the semaphore and its context is no more |
| * useable. This function frees all the memory related to this |
| * semaphore. |
| * @note It is an application issue to warrant no more threads are locked |
| * on the deleted semaphore. |
| * @param context:(IN/OUT) Context of the semaphore |
| * @return M4NO_ERROR: there is no error |
| * @return M4ERR_PARAMETER: at least one parameter is NULL |
| * @return M4ERR_BAD_CONTEXT: provided context is not a valid one. |
| ************************************************************************ |
| */ |
| M4OSA_ERR M4OSA_semaphoreClose(M4OSA_Context context) |
| { |
| M4OSA_SemaphoreContext* semaphoreContext = (M4OSA_SemaphoreContext*)context; |
| |
| M4OSA_TRACE1_1("M4OSA_semaphoreClose\t\tM4OSA_Context 0x%x", context); |
| |
| M4OSA_DEBUG_IF2(context == M4OSA_NULL, |
| M4ERR_PARAMETER, "M4OSA_semaphoreClose"); |
| |
| M4OSA_DEBUG_IF2(semaphoreContext->coreID != M4OSA_SEMAPHORE, |
| M4ERR_BAD_CONTEXT, "M4OSA_semaphoreClose"); |
| |
| sem_destroy(&semaphoreContext->semaphore); |
| |
| free(semaphoreContext); |
| |
| return M4NO_ERROR; |
| } |
| |