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@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 /* ========================================================================== */
TIMM_OSAL_EventCreate(TIMM_OSAL_PTR * pEvents)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 /* ========================================================================== */
TIMM_OSAL_EventDelete(TIMM_OSAL_PTR pEvents)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 /* ========================================================================== */
TIMM_OSAL_EventSet(TIMM_OSAL_PTR pEvents,TIMM_OSAL_U32 uEventFlags,TIMM_OSAL_EVENT_OPERATION eOperation)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 /* ========================================================================== */
TIMM_OSAL_EventRetrieve(TIMM_OSAL_PTR pEvents,TIMM_OSAL_U32 uRequestedEvents,TIMM_OSAL_EVENT_OPERATION eOperation,TIMM_OSAL_U32 * pRetrievedEvents,TIMM_OSAL_U32 uTimeOutMsec)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