Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (c) 2010, Texas Instruments Incorporated
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * *  Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  *
     12  * *  Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * *  Neither the name of Texas Instruments Incorporated nor the names of
     17  *    its contributors may be used to endorse or promote products derived
     18  *    from this software without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 /*
     34 *   @file  timm_osal_events.c
     35 *   This file contains methods that provides the functionality
     36 *   for creating/using events.
     37 *
     38 *  @path \
     39 *
     40 */
     41 /* -------------------------------------------------------------------------- */
     42 /* =========================================================================
     43  *!
     44  *! Revision History
     45  *! ===================================
     46  *! 06-Nov-2008 Maiya ShreeHarsha: Linux specific changes
     47  *! 0.1: Created the first draft version, ksrini (at) ti.com
     48  * ========================================================================= */
     49 
     50 /******************************************************************************
     51 * Includes
     52 ******************************************************************************/
     53 #include <stdio.h>
     54 #include <pthread.h>		/*for POSIX calls */
     55 #include <sys/time.h>
     56 #include <errno.h>
     57 
     58 #include "timm_osal_types.h"
     59 #include "timm_osal_trace.h"
     60 #include "timm_osal_error.h"
     61 #include "timm_osal_memory.h"
     62 #include "timm_osal_events.h"
     63 
     64 
     65 typedef struct
     66 {
     67 	TIMM_OSAL_BOOL bSignaled;
     68 	TIMM_OSAL_U32 eFlags;
     69 	pthread_mutex_t mutex;
     70 	pthread_cond_t condition;
     71 } TIMM_OSAL_THREAD_EVENT;
     72 
     73 
     74 /* ========================================================================== */
     75 /**
     76 * @fn TIMM_OSAL_EventCreate function
     77 *
     78 *
     79 */
     80 /* ========================================================================== */
     81 TIMM_OSAL_ERRORTYPE TIMM_OSAL_EventCreate(TIMM_OSAL_PTR * pEvents)
     82 {
     83 	TIMM_OSAL_ERRORTYPE bReturnStatus = TIMM_OSAL_ERR_UNKNOWN;
     84 	TIMM_OSAL_THREAD_EVENT *plEvent = NULL;
     85 
     86 	plEvent =
     87 	    (TIMM_OSAL_THREAD_EVENT *)
     88 	    TIMM_OSAL_Malloc(sizeof(TIMM_OSAL_THREAD_EVENT), 0, 0, 0);
     89 
     90 	if (TIMM_OSAL_NULL == plEvent)
     91 	{
     92 		bReturnStatus = TIMM_OSAL_ERR_ALLOC;
     93 		goto EXIT;
     94 	}
     95 	plEvent->bSignaled = TIMM_OSAL_FALSE;
     96 	plEvent->eFlags = 0;
     97 
     98 	if (SUCCESS != pthread_mutex_init(&(plEvent->mutex), NULL))
     99 	{
    100 		TIMM_OSAL_Error("Event Create:Mutex Init failed !");
    101 		goto EXIT;	/*bReturnStatus = TIMM_OSAL_ERR_UNKNOWN */
    102 	}
    103 
    104 	if (SUCCESS != pthread_cond_init(&(plEvent->condition), NULL))
    105 	{
    106 		TIMM_OSAL_Error
    107 		    ("Event Create:Conditional Variable  Init failed !");
    108 		pthread_mutex_destroy(&(plEvent->mutex));
    109 		/*TIMM_OSAL_Free(plEvent); */
    110 	} else
    111 	{
    112 		*pEvents = (TIMM_OSAL_PTR) plEvent;
    113 		bReturnStatus = TIMM_OSAL_ERR_NONE;
    114 	}
    115       EXIT:
    116 	if ((TIMM_OSAL_ERR_NONE != bReturnStatus) &&
    117 	    (TIMM_OSAL_NULL != plEvent))
    118 	{
    119 		TIMM_OSAL_Free(plEvent);
    120 	}
    121 	return bReturnStatus;
    122 }
    123 
    124 /* ========================================================================== */
    125 /**
    126 * @fn TIMM_OSAL_EventDelete function
    127 *
    128 *
    129 */
    130 /* ========================================================================== */
    131 TIMM_OSAL_ERRORTYPE TIMM_OSAL_EventDelete(TIMM_OSAL_PTR pEvents)
    132 {
    133 	TIMM_OSAL_ERRORTYPE bReturnStatus = TIMM_OSAL_ERR_NONE;
    134 	TIMM_OSAL_THREAD_EVENT *plEvent = (TIMM_OSAL_THREAD_EVENT *) pEvents;
    135 
    136 	if (TIMM_OSAL_NULL == plEvent)
    137 	{
    138 		bReturnStatus = TIMM_OSAL_ERR_PARAMETER;
    139 		goto EXIT;
    140 	}
    141 
    142 	if (SUCCESS != pthread_mutex_lock(&(plEvent->mutex)))
    143 	{
    144 		TIMM_OSAL_Error("Event Delete: Mutex Lock failed !");
    145 		bReturnStatus = TIMM_OSAL_ERR_UNKNOWN;
    146 	}
    147 	if (SUCCESS != pthread_cond_destroy(&(plEvent->condition)))
    148 	{
    149 		TIMM_OSAL_Error
    150 		    ("Event Delete: Conditional Variable Destroy failed !");
    151 		bReturnStatus = TIMM_OSAL_ERR_UNKNOWN;
    152 	}
    153 
    154 	if (SUCCESS != pthread_mutex_unlock(&(plEvent->mutex)))
    155 	{
    156 		TIMM_OSAL_Error("Event Delete: Mutex Unlock failed !");
    157 		bReturnStatus = TIMM_OSAL_ERR_UNKNOWN;
    158 	}
    159 
    160 	if (SUCCESS != pthread_mutex_destroy(&(plEvent->mutex)))
    161 	{
    162 		TIMM_OSAL_Error("Event Delete: Mutex Destory failed !");
    163 		bReturnStatus = TIMM_OSAL_ERR_UNKNOWN;
    164 	}
    165 
    166 	TIMM_OSAL_Free(plEvent);
    167       EXIT:
    168 	return bReturnStatus;
    169 }
    170 
    171 
    172 /* ========================================================================== */
    173 /**
    174 * @fn TIMM_OSAL_EventSet function
    175 *
    176 *
    177 */
    178 /* ========================================================================== */
    179 TIMM_OSAL_ERRORTYPE TIMM_OSAL_EventSet(TIMM_OSAL_PTR pEvents,
    180     TIMM_OSAL_U32 uEventFlags, TIMM_OSAL_EVENT_OPERATION eOperation)
    181 {
    182 
    183 	TIMM_OSAL_ERRORTYPE bReturnStatus = TIMM_OSAL_ERR_UNKNOWN;
    184 	TIMM_OSAL_THREAD_EVENT *plEvent = (TIMM_OSAL_THREAD_EVENT *) pEvents;
    185 
    186 	if (TIMM_OSAL_NULL == plEvent)
    187 	{
    188 		bReturnStatus = TIMM_OSAL_ERR_PARAMETER;
    189 		goto EXIT;
    190 	}
    191 
    192 	if (SUCCESS != pthread_mutex_lock(&(plEvent->mutex)))
    193 	{
    194 		TIMM_OSAL_Error("Event Set: Mutex Lock failed !");
    195 		bReturnStatus = TIMM_OSAL_ERR_UNKNOWN;
    196 		goto EXIT;
    197 	}
    198 
    199 	switch (eOperation)
    200 	{
    201 	case TIMM_OSAL_EVENT_AND:
    202 		plEvent->eFlags = plEvent->eFlags & uEventFlags;
    203 		break;
    204 	case TIMM_OSAL_EVENT_OR:
    205 		plEvent->eFlags = plEvent->eFlags | uEventFlags;
    206 		break;
    207 	default:
    208 		TIMM_OSAL_Error("Event Set: Bad eOperation !");
    209 		bReturnStatus = TIMM_OSAL_ERR_PARAMETER;
    210 		pthread_mutex_unlock(&plEvent->mutex);
    211 		goto EXIT;
    212 	}
    213 
    214 	plEvent->bSignaled = TIMM_OSAL_TRUE;
    215 
    216 	if (SUCCESS != pthread_cond_signal(&plEvent->condition))
    217 	{
    218 		TIMM_OSAL_Error
    219 		    ("Event Set: Condition Variable Signal failed !");
    220 		bReturnStatus = TIMM_OSAL_ERR_UNKNOWN;
    221 		pthread_mutex_unlock(&plEvent->mutex);
    222 		goto EXIT;
    223 	}
    224 
    225 	if (SUCCESS != pthread_mutex_unlock(&plEvent->mutex))
    226 	{
    227 		TIMM_OSAL_Error("Event Set: Mutex Unlock failed !");
    228 		bReturnStatus = TIMM_OSAL_ERR_UNKNOWN;
    229 	} else
    230 		bReturnStatus = TIMM_OSAL_ERR_NONE;
    231 
    232       EXIT:
    233 	return bReturnStatus;
    234 
    235 
    236 }
    237 
    238 /* ========================================================================== */
    239 /**
    240 * @fn TIMM_OSAL_EventRetrieve function
    241 *
    242 *Spurious  wakeups  from  the  pthread_cond_timedwait() or pthread_cond_wait() functions  may  occur.
    243 *
    244 *A representative sequence for using condition variables is shown below
    245 *
    246 *Thread A (Retrieve Events)							|Thread B (Set Events)
    247 *------------------------------------------------------------------------------------------------------------
    248 *1) Do work up to the point where a certain condition 	|1)Do work
    249 *  must occur (such as "count" must reach a specified 	|2)Lock associated mutex
    250 *  value)											|3)Change the value of the global variable
    251 *2) Lock associated mutex and check value of a global 	|  that Thread-A is waiting upon.
    252 *  variable										|4)Check value of the global Thread-A wait
    253 *3) Call pthread_cond_wait() to perform a blocking wait 	|  variable. If it fulfills the desired
    254 *  for signal from Thread-B. Note that a call to 			|  condition, signal Thread-A.
    255 *  pthread_cond_wait() automatically and atomically 		|5)Unlock mutex.
    256 *  unlocks the associated mutex variable so that it can 	|6)Continue
    257 *  be used by Thread-B.							|
    258 *4) When signalled, wake up. Mutex is automatically and 	|
    259 *  atomically locked.								|
    260 *5) Explicitly unlock mutex							|
    261 *6) Continue										|
    262 *
    263 */
    264 /* ========================================================================== */
    265 TIMM_OSAL_ERRORTYPE TIMM_OSAL_EventRetrieve(TIMM_OSAL_PTR pEvents,
    266     TIMM_OSAL_U32 uRequestedEvents,
    267     TIMM_OSAL_EVENT_OPERATION eOperation,
    268     TIMM_OSAL_U32 * pRetrievedEvents, TIMM_OSAL_U32 uTimeOutMsec)
    269 {
    270 	TIMM_OSAL_ERRORTYPE bReturnStatus = TIMM_OSAL_ERR_UNKNOWN;
    271 	struct timespec timeout;
    272 	struct timeval now;
    273 	TIMM_OSAL_U32 timeout_us;
    274 	TIMM_OSAL_U32 isolatedFlags;
    275 	int status = -1;
    276 	int and_operation;
    277 	TIMM_OSAL_THREAD_EVENT *plEvent = (TIMM_OSAL_THREAD_EVENT *) pEvents;
    278 
    279 	if (TIMM_OSAL_NULL == plEvent)
    280 	{
    281 		bReturnStatus = TIMM_OSAL_ERR_PARAMETER;
    282 		goto EXIT;
    283 	}
    284 
    285 	/* Lock the mutex for access to the eFlags global variable */
    286 	if (SUCCESS != pthread_mutex_lock(&(plEvent->mutex)))
    287 	{
    288 		TIMM_OSAL_Error("Event Retrieve: Mutex Lock failed !");
    289 		bReturnStatus = TIMM_OSAL_ERR_UNKNOWN;
    290 		goto EXIT;
    291 	}
    292 
    293 	/*Check the eOperation and put it in a variable */
    294 	and_operation = ((TIMM_OSAL_EVENT_AND == eOperation) ||
    295 	    (TIMM_OSAL_EVENT_AND_CONSUME == eOperation));
    296 
    297 	/* Isolate the flags. The & operation is suffice for an TIMM_OSAL_EVENT_OR eOperation */
    298 	isolatedFlags = plEvent->eFlags & uRequestedEvents;
    299 
    300 	/*Check if it is the AND operation. If yes then, all the flags must match */
    301 	if (and_operation)
    302 	{
    303 		isolatedFlags = (isolatedFlags == uRequestedEvents);
    304 	}
    305 
    306 
    307 	if (isolatedFlags)
    308 	{
    309 
    310 		/*We have got required combination of the eFlags bits and will return it back */
    311 		*pRetrievedEvents = plEvent->eFlags;
    312 		bReturnStatus = TIMM_OSAL_ERR_NONE;
    313 	} else
    314 	{
    315 
    316 		/*Required combination of bits is not yet available */
    317 		if (TIMM_OSAL_NO_SUSPEND == uTimeOutMsec)
    318 		{
    319 			*pRetrievedEvents = 0;
    320 			bReturnStatus = TIMM_OSAL_ERR_NONE;
    321 		}
    322 
    323 		else if (TIMM_OSAL_SUSPEND == uTimeOutMsec)
    324 		{
    325 
    326 			/*Wait till we get the required combination of bits. We we get the required
    327 			 *bits then we go out of the while loop
    328 			 */
    329 			while (!isolatedFlags)
    330 			{
    331 
    332 				/*Wait on the conditional variable for another thread to set the eFlags and signal */
    333 				pthread_cond_wait(&(plEvent->condition),
    334 				    &(plEvent->mutex));
    335 
    336 				/* eFlags set by some thread. Now, isolate the flags.
    337 				 * The & operation is suffice for an TIMM_OSAL_EVENT_OR eOperation
    338 				 */
    339 				isolatedFlags =
    340 				    plEvent->eFlags & uRequestedEvents;
    341 
    342 				/*Check if it is the AND operation. If yes then, all the flags must match */
    343 				if (and_operation)
    344 				{
    345 					isolatedFlags =
    346 					    (isolatedFlags ==
    347 					    uRequestedEvents);
    348 				}
    349 			}
    350 
    351 			/* Obtained the requested combination of bits on eFlags */
    352 			*pRetrievedEvents = plEvent->eFlags;
    353 			bReturnStatus = TIMM_OSAL_ERR_NONE;
    354 
    355 		} else
    356 		{
    357 
    358 			/* Calculate uTimeOutMsec in terms of the absolute time. uTimeOutMsec is in milliseconds */
    359 			gettimeofday(&now, NULL);
    360 			timeout_us = now.tv_usec + 1000 * uTimeOutMsec;
    361 			timeout.tv_sec = now.tv_sec + timeout_us / 1000000;
    362 			timeout.tv_nsec = (timeout_us % 1000000) * 1000;
    363 
    364 			while (!isolatedFlags)
    365 			{
    366 
    367 				/* Wait till uTimeOutMsec for a thread to signal on the conditional variable */
    368 				status =
    369 				    pthread_cond_timedwait(&(plEvent->
    370 					condition), &(plEvent->mutex),
    371 				    &timeout);
    372 
    373 				/*Timedout or error and returned without being signalled */
    374 				if (SUCCESS != status)
    375 				{
    376 					if (ETIMEDOUT == status)
    377 						bReturnStatus =
    378 						    TIMM_OSAL_ERR_NONE;
    379 					*pRetrievedEvents = 0;
    380 					break;
    381 				}
    382 
    383 				/* eFlags set by some thread. Now, isolate the flags.
    384 				 * The & operation is suffice for an TIMM_OSAL_EVENT_OR eOperation
    385 				 */
    386 				isolatedFlags =
    387 				    plEvent->eFlags & uRequestedEvents;
    388 
    389 				/*Check if it is the AND operation. If yes then, all the flags must match */
    390 				if (and_operation)
    391 				{
    392 					isolatedFlags =
    393 					    (isolatedFlags ==
    394 					    uRequestedEvents);
    395 				}
    396 
    397 			}
    398 		}
    399 	}
    400 
    401 	/*If we have got the required combination of bits, we will have to reset the eFlags if CONSUME is mentioned
    402 	 *in the eOperations
    403 	 */
    404 	if (isolatedFlags && ((eOperation == TIMM_OSAL_EVENT_AND_CONSUME) ||
    405 		(eOperation == TIMM_OSAL_EVENT_OR_CONSUME)))
    406 	{
    407 		plEvent->eFlags = 0;
    408 	}
    409 
    410 	/*Manually unlock the mutex */
    411 	if (SUCCESS != pthread_mutex_unlock(&(plEvent->mutex)))
    412 	{
    413 		TIMM_OSAL_Error("Event Retrieve: Mutex Unlock failed !");
    414 		bReturnStatus = TIMM_OSAL_ERR_UNKNOWN;
    415 	}
    416 
    417       EXIT:
    418 	return bReturnStatus;
    419 
    420 }
    421