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