M4OSA_Semaphore.c revision 694816d7291f17364502ac5d3319684a0b180860
1/*
2 * Copyright (C) 2004-2011 NXP Software
3 * Copyright (C) 2011 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17/**
18 ************************************************************************
19 * @file         M4OSA_Semaphore.c
20 * @brief        Semaphore for Windows
21 * @note         This file implements functions to manipulate semaphore
22 ************************************************************************
23*/
24
25
26
27#include "M4OSA_Debug.h"
28#include "M4OSA_Types.h"
29#include "M4OSA_Error.h"
30#include "M4OSA_Memory.h"
31#include "M4OSA_Semaphore.h"
32
33#include <semaphore.h>
34#include <string.h>
35#include <stdlib.h>
36#include <stdio.h>
37#include <errno.h>
38#include <time.h>
39
40
41/* Context for the semaphore */
42typedef struct {
43   M4OSA_UInt32   coreID;     /* semaphore context identifiant */
44   sem_t          semaphore;  /* semaphore */
45} M4OSA_SemaphoreContext;
46
47
48
49
50/**
51 ************************************************************************
52 * @brief      This method creates a new semaphore with the "initialCounter"
53 *             value.
54 * @note       This function creates and allocates a unique context. It's the
55 *             OSAL real time responsibility for managing its context. It must
56 *             be freed by the M4OSA_semaphoreClose function. The context
57 *             parameter will be sent back to any OSAL core semaphore functions
58 *             to allow retrieving data associated to the opened semaphore.
59 * @param      context:(OUT) Context of the created semaphore
60 * @param      initial_count:(IN) Initial counter of the semaphore
61 * @return     M4NO_ERROR: there is no error
62 * @return     M4ERR_PARAMETER: provided context is NULL
63 * @return     M4ERR_ALLOC: there is no more available memory
64 * @return     M4ERR_CONTEXT_FAILED: the context creation failed
65 ************************************************************************
66*/
67M4OSA_ERR M4OSA_semaphoreOpen(M4OSA_Context* context,
68                              M4OSA_UInt32 initial_count)
69{
70   M4OSA_SemaphoreContext* semaphoreContext = M4OSA_NULL;
71
72   M4OSA_TRACE1_2("M4OSA_semaphoreOpen\t\tM4OSA_Context* 0x%x\tM4OSA_UInt32 "
73                  "%d", context, initial_count);
74
75   M4OSA_DEBUG_IF2(context == M4OSA_NULL,
76                   M4ERR_PARAMETER, "M4OSA_semaphoreOpen");
77
78   *context = M4OSA_NULL;
79
80   semaphoreContext = (M4OSA_SemaphoreContext*) M4OSA_32bitAlignedMalloc(
81                      sizeof(M4OSA_SemaphoreContext), M4OSA_SEMAPHORE,
82                      (M4OSA_Char*)"M4OSA_semaphoreOpen: semaphore context");
83
84   if(semaphoreContext == M4OSA_NULL)
85   {
86      M4OSA_DEBUG(M4ERR_ALLOC, "M4OSA_semaphoreOpen");
87
88      return M4ERR_ALLOC;
89   }
90
91   if (0 != sem_init(&semaphoreContext->semaphore, 0, initial_count))
92   {
93      free(semaphoreContext);
94
95      M4OSA_DEBUG(M4ERR_CONTEXT_FAILED,
96         "M4OSA_semaphoreOpen: OS semaphore creation failed");
97
98      return M4ERR_CONTEXT_FAILED;
99   }
100
101   semaphoreContext->coreID = M4OSA_SEMAPHORE ;
102   *context = (M4OSA_Context)semaphoreContext;
103
104   return M4NO_ERROR;
105}
106
107
108
109
110/**
111 ************************************************************************
112 * @brief      This method decrements (one by one) the semaphore counter. The
113 *             semaphore is identified by its context This call is not blocking
114 *             if the semaphore counter is positive or zero (after
115 *             decrementation). This call is blocking if the semaphore counter
116 *             is less than zero (after decrementation), until the semaphore is
117 *             upper than zero (see M4OSA_semaphorePost) or time_out is
118 *             reached.
119 * @note       If "timeout" value is M4OSA_WAIT_FOREVER, the calling thread
120 *             will block indefinitely until the semaphore  is unlocked.
121 * @param      context:(IN/OUT) Context of the semaphore
122 * @param      timeout:(IN) Time out in milliseconds
123 * @return     M4NO_ERROR: there is no error
124 * @return     M4ERR_PARAMETER: at least one parameter is NULL
125 * @return     M4WAR_TIME_OUT: time out is elapsed before semaphore has been
126 *             available.
127 * @return     M4ERR_BAD_CONTEXT: provided context is not a valid one
128 ************************************************************************
129*/
130M4OSA_ERR M4OSA_semaphoreWait(M4OSA_Context context, M4OSA_Int32 timeout)
131{
132   M4OSA_SemaphoreContext* semaphoreContext = (M4OSA_SemaphoreContext*)context;
133   struct timespec         ts;
134   struct timespec         left;
135   int                     result;
136
137   M4OSA_TRACE1_2("M4OSA_semaphoreWait\t\tM4OSA_Context 0x%x\tM4OSA_UInt32 %d",
138                  context, timeout);
139
140   M4OSA_DEBUG_IF2(context == M4OSA_NULL,
141                   M4ERR_PARAMETER, "M4OSA_semaphoreWait");
142
143   M4OSA_DEBUG_IF2(semaphoreContext->coreID != M4OSA_SEMAPHORE,
144                   M4ERR_BAD_CONTEXT, "M4OSA_semaphoreWait");
145
146   if ( (M4OSA_Int32)M4OSA_WAIT_FOREVER == timeout)
147   {
148       if ( 0 != sem_wait(&semaphoreContext->semaphore) )
149       {
150           M4OSA_DEBUG(M4ERR_BAD_CONTEXT,
151                  "M4OSA_semaphoreWait: OS semaphore wait failed");
152
153           return M4ERR_BAD_CONTEXT ;
154       }
155   }
156   else
157   {
158       result = sem_trywait(&semaphoreContext->semaphore);
159       while ( ((EBUSY == result) || (EAGAIN == result)) && ( 0 < timeout ) )
160       {
161           ts.tv_sec  = 0;
162           if (1 <= timeout)
163           {
164               ts.tv_nsec = 1000000;
165               timeout -= 1;
166           }
167           else
168           {
169               ts.tv_nsec = timeout * 1000000;
170               timeout = 0;
171           }
172           nanosleep(&ts, &left);
173           result = sem_trywait(&semaphoreContext->semaphore);
174       }
175       if (0 != result)
176       {
177           if ((EBUSY == result) || (EAGAIN == result))
178           {
179               return M4WAR_TIME_OUT;
180           }
181           else
182           {
183               M4OSA_DEBUG(M4ERR_BAD_CONTEXT, "M4OSA_semaphoreWait: OS semaphore wait failed");
184               return M4ERR_BAD_CONTEXT;
185           }
186       }
187   }
188
189   return M4NO_ERROR;
190}
191
192
193
194
195
196/**
197 ************************************************************************
198 * @brief      This method increments the semaphore counter. The semaphore is
199 *             identified by its context
200 * @note       If the semaphore counter is upper than zero (after addition),
201 *             the M4OSA_semaphoreWait call of the thread with the highest
202 *             priority is unblocked and made ready to run.
203 * @note       No hypotheses can be made on which thread will be unblocked
204 *             between threads with the same priority.
205 * @param      context:(IN/OUT) Context of the semaphore
206 * @return     M4NO_ERROR: there is no error
207 * @return     M4ERR_PARAMETER: at least one parameter is NULL
208 * @return     M4ERR_BAD_CONTEXT: provided context is not a valid one
209************************************************************************
210*/
211M4OSA_ERR M4OSA_semaphorePost(M4OSA_Context context)
212{
213   M4OSA_SemaphoreContext* semaphoreContext = (M4OSA_SemaphoreContext*)context;
214
215   M4OSA_TRACE1_1("M4OSA_semaphorePost\t\tM4OSA_Context 0x%x", context);
216
217   M4OSA_DEBUG_IF2(context == M4OSA_NULL,
218                   M4ERR_PARAMETER, "M4OSA_semaphorePost");
219
220   M4OSA_DEBUG_IF2(semaphoreContext->coreID != M4OSA_SEMAPHORE,
221                   M4ERR_BAD_CONTEXT, "M4OSA_semaphorePost");
222
223   sem_post(&semaphoreContext->semaphore);
224
225   return M4NO_ERROR;
226}
227
228
229
230
231
232/**
233 ************************************************************************
234 * @brief      This method deletes a semaphore (identify by its context).
235 *             After this call the semaphore and its context is no more
236 *             useable. This function frees all the memory related to this
237 *             semaphore.
238 * @note       It is an application issue to warrant no more threads are locked
239 *             on the deleted semaphore.
240 * @param      context:(IN/OUT) Context of the semaphore
241 * @return     M4NO_ERROR: there is no error
242 * @return     M4ERR_PARAMETER: at least one parameter is NULL
243 * @return     M4ERR_BAD_CONTEXT: provided context is not a valid one.
244************************************************************************
245*/
246M4OSA_ERR M4OSA_semaphoreClose(M4OSA_Context context)
247{
248   M4OSA_SemaphoreContext* semaphoreContext = (M4OSA_SemaphoreContext*)context;
249
250   M4OSA_TRACE1_1("M4OSA_semaphoreClose\t\tM4OSA_Context 0x%x", context);
251
252   M4OSA_DEBUG_IF2(context == M4OSA_NULL,
253                   M4ERR_PARAMETER, "M4OSA_semaphoreClose");
254
255   M4OSA_DEBUG_IF2(semaphoreContext->coreID != M4OSA_SEMAPHORE,
256                   M4ERR_BAD_CONTEXT, "M4OSA_semaphoreClose");
257
258   sem_destroy(&semaphoreContext->semaphore);
259
260   free(semaphoreContext);
261
262   return M4NO_ERROR;
263}
264
265