/* * Copyright (c) 2010, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * @file timm_osal_events.c * This file contains methods that provides the functionality * for creating/using events. * * @path \ * */ /* -------------------------------------------------------------------------- */ /* ========================================================================= *! *! Revision History *! =================================== *! 06-Nov-2008 Maiya ShreeHarsha: Linux specific changes *! 0.1: Created the first draft version, ksrini@ti.com * ========================================================================= */ /****************************************************************************** * Includes ******************************************************************************/ #include <stdio.h> #include <pthread.h> /*for POSIX calls */ #include <sys/time.h> #include <errno.h> #include "timm_osal_types.h" #include "timm_osal_trace.h" #include "timm_osal_error.h" #include "timm_osal_memory.h" #include "timm_osal_events.h" typedef struct { TIMM_OSAL_BOOL bSignaled; TIMM_OSAL_U32 eFlags; pthread_mutex_t mutex; pthread_cond_t condition; } TIMM_OSAL_THREAD_EVENT; /* ========================================================================== */ /** * @fn TIMM_OSAL_EventCreate function * * */ /* ========================================================================== */ TIMM_OSAL_ERRORTYPE TIMM_OSAL_EventCreate(TIMM_OSAL_PTR * pEvents) { TIMM_OSAL_ERRORTYPE bReturnStatus = TIMM_OSAL_ERR_UNKNOWN; TIMM_OSAL_THREAD_EVENT *plEvent = NULL; plEvent = (TIMM_OSAL_THREAD_EVENT *) TIMM_OSAL_Malloc(sizeof(TIMM_OSAL_THREAD_EVENT), 0, 0, 0); if (TIMM_OSAL_NULL == plEvent) { bReturnStatus = TIMM_OSAL_ERR_ALLOC; goto EXIT; } plEvent->bSignaled = TIMM_OSAL_FALSE; plEvent->eFlags = 0; if (SUCCESS != pthread_mutex_init(&(plEvent->mutex), NULL)) { TIMM_OSAL_Error("Event Create:Mutex Init failed !"); goto EXIT; /*bReturnStatus = TIMM_OSAL_ERR_UNKNOWN */ } if (SUCCESS != pthread_cond_init(&(plEvent->condition), NULL)) { TIMM_OSAL_Error ("Event Create:Conditional Variable Init failed !"); pthread_mutex_destroy(&(plEvent->mutex)); /*TIMM_OSAL_Free(plEvent); */ } else { *pEvents = (TIMM_OSAL_PTR) plEvent; bReturnStatus = TIMM_OSAL_ERR_NONE; } EXIT: if ((TIMM_OSAL_ERR_NONE != bReturnStatus) && (TIMM_OSAL_NULL != plEvent)) { TIMM_OSAL_Free(plEvent); } return bReturnStatus; } /* ========================================================================== */ /** * @fn TIMM_OSAL_EventDelete function * * */ /* ========================================================================== */ TIMM_OSAL_ERRORTYPE TIMM_OSAL_EventDelete(TIMM_OSAL_PTR pEvents) { TIMM_OSAL_ERRORTYPE bReturnStatus = TIMM_OSAL_ERR_NONE; TIMM_OSAL_THREAD_EVENT *plEvent = (TIMM_OSAL_THREAD_EVENT *) pEvents; if (TIMM_OSAL_NULL == plEvent) { bReturnStatus = TIMM_OSAL_ERR_PARAMETER; goto EXIT; } if (SUCCESS != pthread_mutex_lock(&(plEvent->mutex))) { TIMM_OSAL_Error("Event Delete: Mutex Lock failed !"); bReturnStatus = TIMM_OSAL_ERR_UNKNOWN; } if (SUCCESS != pthread_cond_destroy(&(plEvent->condition))) { TIMM_OSAL_Error ("Event Delete: Conditional Variable Destroy failed !"); bReturnStatus = TIMM_OSAL_ERR_UNKNOWN; } if (SUCCESS != pthread_mutex_unlock(&(plEvent->mutex))) { TIMM_OSAL_Error("Event Delete: Mutex Unlock failed !"); bReturnStatus = TIMM_OSAL_ERR_UNKNOWN; } if (SUCCESS != pthread_mutex_destroy(&(plEvent->mutex))) { TIMM_OSAL_Error("Event Delete: Mutex Destory failed !"); bReturnStatus = TIMM_OSAL_ERR_UNKNOWN; } TIMM_OSAL_Free(plEvent); EXIT: return bReturnStatus; } /* ========================================================================== */ /** * @fn TIMM_OSAL_EventSet function * * */ /* ========================================================================== */ TIMM_OSAL_ERRORTYPE TIMM_OSAL_EventSet(TIMM_OSAL_PTR pEvents, TIMM_OSAL_U32 uEventFlags, TIMM_OSAL_EVENT_OPERATION eOperation) { TIMM_OSAL_ERRORTYPE bReturnStatus = TIMM_OSAL_ERR_UNKNOWN; TIMM_OSAL_THREAD_EVENT *plEvent = (TIMM_OSAL_THREAD_EVENT *) pEvents; if (TIMM_OSAL_NULL == plEvent) { bReturnStatus = TIMM_OSAL_ERR_PARAMETER; goto EXIT; } if (SUCCESS != pthread_mutex_lock(&(plEvent->mutex))) { TIMM_OSAL_Error("Event Set: Mutex Lock failed !"); bReturnStatus = TIMM_OSAL_ERR_UNKNOWN; goto EXIT; } switch (eOperation) { case TIMM_OSAL_EVENT_AND: plEvent->eFlags = plEvent->eFlags & uEventFlags; break; case TIMM_OSAL_EVENT_OR: plEvent->eFlags = plEvent->eFlags | uEventFlags; break; default: TIMM_OSAL_Error("Event Set: Bad eOperation !"); bReturnStatus = TIMM_OSAL_ERR_PARAMETER; pthread_mutex_unlock(&plEvent->mutex); goto EXIT; } plEvent->bSignaled = TIMM_OSAL_TRUE; if (SUCCESS != pthread_cond_signal(&plEvent->condition)) { TIMM_OSAL_Error ("Event Set: Condition Variable Signal failed !"); bReturnStatus = TIMM_OSAL_ERR_UNKNOWN; pthread_mutex_unlock(&plEvent->mutex); goto EXIT; } if (SUCCESS != pthread_mutex_unlock(&plEvent->mutex)) { TIMM_OSAL_Error("Event Set: Mutex Unlock failed !"); bReturnStatus = TIMM_OSAL_ERR_UNKNOWN; } else bReturnStatus = TIMM_OSAL_ERR_NONE; EXIT: return bReturnStatus; } /* ========================================================================== */ /** * @fn TIMM_OSAL_EventRetrieve function * *Spurious wakeups from the pthread_cond_timedwait() or pthread_cond_wait() functions may occur. * *A representative sequence for using condition variables is shown below * *Thread A (Retrieve Events) |Thread B (Set Events) *------------------------------------------------------------------------------------------------------------ *1) Do work up to the point where a certain condition |1)Do work * must occur (such as "count" must reach a specified |2)Lock associated mutex * value) |3)Change the value of the global variable *2) Lock associated mutex and check value of a global | that Thread-A is waiting upon. * variable |4)Check value of the global Thread-A wait *3) Call pthread_cond_wait() to perform a blocking wait | variable. If it fulfills the desired * for signal from Thread-B. Note that a call to | condition, signal Thread-A. * pthread_cond_wait() automatically and atomically |5)Unlock mutex. * unlocks the associated mutex variable so that it can |6)Continue * be used by Thread-B. | *4) When signalled, wake up. Mutex is automatically and | * atomically locked. | *5) Explicitly unlock mutex | *6) Continue | * */ /* ========================================================================== */ TIMM_OSAL_ERRORTYPE TIMM_OSAL_EventRetrieve(TIMM_OSAL_PTR pEvents, TIMM_OSAL_U32 uRequestedEvents, TIMM_OSAL_EVENT_OPERATION eOperation, TIMM_OSAL_U32 * pRetrievedEvents, TIMM_OSAL_U32 uTimeOutMsec) { TIMM_OSAL_ERRORTYPE bReturnStatus = TIMM_OSAL_ERR_UNKNOWN; struct timespec timeout; struct timeval now; TIMM_OSAL_U32 timeout_us; TIMM_OSAL_U32 isolatedFlags; int status = -1; int and_operation; TIMM_OSAL_THREAD_EVENT *plEvent = (TIMM_OSAL_THREAD_EVENT *) pEvents; if (TIMM_OSAL_NULL == plEvent) { bReturnStatus = TIMM_OSAL_ERR_PARAMETER; goto EXIT; } /* Lock the mutex for access to the eFlags global variable */ if (SUCCESS != pthread_mutex_lock(&(plEvent->mutex))) { TIMM_OSAL_Error("Event Retrieve: Mutex Lock failed !"); bReturnStatus = TIMM_OSAL_ERR_UNKNOWN; goto EXIT; } /*Check the eOperation and put it in a variable */ and_operation = ((TIMM_OSAL_EVENT_AND == eOperation) || (TIMM_OSAL_EVENT_AND_CONSUME == eOperation)); /* Isolate the flags. The & operation is suffice for an TIMM_OSAL_EVENT_OR eOperation */ isolatedFlags = plEvent->eFlags & uRequestedEvents; /*Check if it is the AND operation. If yes then, all the flags must match */ if (and_operation) { isolatedFlags = (isolatedFlags == uRequestedEvents); } if (isolatedFlags) { /*We have got required combination of the eFlags bits and will return it back */ *pRetrievedEvents = plEvent->eFlags; bReturnStatus = TIMM_OSAL_ERR_NONE; } else { /*Required combination of bits is not yet available */ if (TIMM_OSAL_NO_SUSPEND == uTimeOutMsec) { *pRetrievedEvents = 0; bReturnStatus = TIMM_OSAL_ERR_NONE; } else if (TIMM_OSAL_SUSPEND == uTimeOutMsec) { /*Wait till we get the required combination of bits. We we get the required *bits then we go out of the while loop */ while (!isolatedFlags) { /*Wait on the conditional variable for another thread to set the eFlags and signal */ pthread_cond_wait(&(plEvent->condition), &(plEvent->mutex)); /* eFlags set by some thread. Now, isolate the flags. * The & operation is suffice for an TIMM_OSAL_EVENT_OR eOperation */ isolatedFlags = plEvent->eFlags & uRequestedEvents; /*Check if it is the AND operation. If yes then, all the flags must match */ if (and_operation) { isolatedFlags = (isolatedFlags == uRequestedEvents); } } /* Obtained the requested combination of bits on eFlags */ *pRetrievedEvents = plEvent->eFlags; bReturnStatus = TIMM_OSAL_ERR_NONE; } else { /* Calculate uTimeOutMsec in terms of the absolute time. uTimeOutMsec is in milliseconds */ gettimeofday(&now, NULL); timeout_us = now.tv_usec + 1000 * uTimeOutMsec; timeout.tv_sec = now.tv_sec + timeout_us / 1000000; timeout.tv_nsec = (timeout_us % 1000000) * 1000; while (!isolatedFlags) { /* Wait till uTimeOutMsec for a thread to signal on the conditional variable */ status = pthread_cond_timedwait(&(plEvent-> condition), &(plEvent->mutex), &timeout); /*Timedout or error and returned without being signalled */ if (SUCCESS != status) { if (ETIMEDOUT == status) bReturnStatus = TIMM_OSAL_ERR_NONE; *pRetrievedEvents = 0; break; } /* eFlags set by some thread. Now, isolate the flags. * The & operation is suffice for an TIMM_OSAL_EVENT_OR eOperation */ isolatedFlags = plEvent->eFlags & uRequestedEvents; /*Check if it is the AND operation. If yes then, all the flags must match */ if (and_operation) { isolatedFlags = (isolatedFlags == uRequestedEvents); } } } } /*If we have got the required combination of bits, we will have to reset the eFlags if CONSUME is mentioned *in the eOperations */ if (isolatedFlags && ((eOperation == TIMM_OSAL_EVENT_AND_CONSUME) || (eOperation == TIMM_OSAL_EVENT_OR_CONSUME))) { plEvent->eFlags = 0; } /*Manually unlock the mutex */ if (SUCCESS != pthread_mutex_unlock(&(plEvent->mutex))) { TIMM_OSAL_Error("Event Retrieve: Mutex Unlock failed !"); bReturnStatus = TIMM_OSAL_ERR_UNKNOWN; } EXIT: return bReturnStatus; }