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