Home | History | Annotate | Download | only in src
      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