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