/* * 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; }