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 */ 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 */ 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 */ 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 */ 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