• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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