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