os/ossrv/genericopenlibs/openenvcore/libpthread/src/condvar.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // Name        : condvar.cpp
    15 // Part of     : pthread
    16 // Interface   : POSIX, pthread
    17 // POSIX implementation of pthread on Symbian
    18 // Version     :
    19 //
    20 
    21 
    22 
    23 #include "condvartypes.h"
    24 
    25 /*
    26 This internal function initializes the passed queue to be an empty queue
    27 */
    28 bool _QueueInit(_CondQueue* aQueue)
    29 {
    30     if(!aQueue)
    31     {
    32         return false;
    33     }
    34     pthread_mutex_init(&aQueue->iMutex,NULL);
    35     aQueue->iHead = aQueue->iTail = NULL;
    36     return true;
    37 }
    38 
    39 /*
    40 This internal function destroys the passed 
    41 */
    42 int _QueueDestroy(_CondQueue* aQueue)
    43 {
    44     if(!aQueue)
    45     {
    46         return EINVAL;
    47     }
    48     pthread_mutex_lock(&aQueue->iMutex);
    49     _CondNode* head = aQueue->iHead;
    50     pthread_mutex_unlock(&aQueue->iMutex);
    51     if (head) 
    52     {
    53         return EBUSY;   
    54     }
    55     else
    56     {
    57         return pthread_mutex_destroy(&aQueue->iMutex);
    58     }
    59 }
    60 
    61 
    62 /*
    63 This internal function atomically adds a element
    64 to the passed queue
    65 */
    66 bool _QueueAdd(_CondQueue* aQueue, _CondNode* aNode)
    67 {
    68     if( (!aQueue) || (!aNode) )
    69     {
    70         return false;
    71     }
    72     aNode->iNext = NULL;
    73     pthread_mutex_lock(&aQueue->iMutex);
    74     if(!(aQueue->iHead))
    75     {
    76         aQueue->iHead = aQueue->iTail = aNode;
    77     }
    78     else
    79     {
    80         aQueue->iTail->iNext = aNode;
    81         aQueue->iTail = aNode;
    82     }
    83     pthread_mutex_unlock(&aQueue->iMutex);
    84     return true;
    85 }
    86   
    87     
    88 /*
    89 This internal function atomically removes the pased element
    90 from the queue
    91 */
    92 bool _QueueRemove(_CondQueue* aQueue, _CondNode* aNode)
    93 {
    94     if( (!aQueue) || (!aNode) )
    95     {
    96         return false;
    97     }
    98     pthread_mutex_lock(&aQueue->iMutex);
    99         
   100     _CondNode* prev = NULL;
   101     _CondNode* node = aQueue->iHead;
   102     for(; node; node = node->iNext)
   103     {
   104         if(node == aNode)
   105         {
   106             break;
   107         }
   108         prev = node;
   109     }
   110     if(node)
   111     {
   112         if(node == aQueue->iHead)
   113         {
   114             aQueue->iHead = node->iNext;
   115         }
   116         if(node == aQueue->iTail)
   117         {
   118             aQueue->iTail = prev;
   119         }
   120         if(prev)
   121         {
   122             prev->iNext = node->iNext;
   123         }
   124     }// node found
   125     pthread_mutex_unlock(&aQueue->iMutex);
   126     return (node) ? true : false;
   127 }
   128 
   129 /*
   130 This internal function atomically removes the head of the queue, and
   131 returns a pointer to this node
   132 */
   133 _CondNode* _QueueRemoveHead(_CondQueue* aQueue)
   134 {
   135     _CondNode* retNode = NULL;
   136     pthread_mutex_lock(&aQueue->iMutex);
   137     retNode = aQueue->iHead;
   138     if(retNode)
   139     {
   140         aQueue->iHead = retNode->iNext;
   141         if(aQueue->iTail == retNode)
   142         {
   143             aQueue->iTail = aQueue->iHead = NULL;
   144         }
   145     }
   146     pthread_mutex_unlock(&aQueue->iMutex);
   147     return retNode;
   148 }
   149 
   150 
   151 /*
   152 This internal function  removes the head of the queue, and
   153 returns a pointer to this node WITHOUT locking the associated mutex
   154 */
   155 _CondNode* _QueueRemoveHeadNoLock(_CondQueue* aQueue)
   156 {
   157     _CondNode* retNode = NULL;
   158     retNode = aQueue->iHead;
   159     if(retNode)
   160     {
   161         aQueue->iHead = retNode->iNext;
   162         if(aQueue->iTail == retNode)
   163         {
   164             aQueue->iTail = aQueue->iHead = NULL;
   165         }
   166     }
   167     return retNode;
   168 }
   169 
   170 /*
   171 This internal function  locks the queue mutex
   172 */
   173 void  _QueueLock(_CondQueue* aQueue)
   174 {
   175     pthread_mutex_lock(&aQueue->iMutex);
   176 }
   177 
   178 /*
   179 This internal function  unlocks the queue mutex
   180 */
   181 void  _QueueUnlock(_CondQueue* aQueue)
   182 {
   183     pthread_mutex_unlock(&aQueue->iMutex);
   184 }
   185 
   186 /*
   187 This internal function atomically resolves the race to dynamically initialize a static cond var
   188 */
   189 bool _staticCondInit(pthread_cond_t* cond)
   190 {
   191     if(!cond)
   192     {
   193         return false;
   194     }
   195     if(cond->iState == _EInitialized)
   196     {
   197         return true;
   198     }
   199 
   200 
   201     if(cond->iState != _ENeedsNormalInit)
   202     {
   203         return false;
   204     }
   205     int retval=0;
   206 
   207     #ifndef NOUSE_INTERNALS
   208     void* tlsPtr;
   209 
   210     // Get the TLS pointer
   211     tlsPtr = _pthread_getTls();  
   212     if(NULL == tlsPtr)
   213     {
   214         return false;
   215     }
   216     _pthread_atomicMutexLock(tlsPtr);
   217     #endif
   218 
   219     //another thread might win race
   220     if(cond->iState != _EInitialized)
   221     {
   222         retval = pthread_cond_init(cond,NULL);
   223     }
   224 
   225     #ifndef NOUSE_INTERNALS
   226     _pthread_atomicMutexUnlock(tlsPtr);
   227     #endif
   228     if(retval == 0)
   229     {
   230         return true;
   231     }
   232     else
   233     {
   234         return false;
   235     }
   236 }
   237 
   238 /*
   239 This internal function provides the functionality to wait on a condition variable,
   240 */
   241 int _internalCondWait(pthread_cond_t *cond, pthread_mutex_t *mutex,const struct timespec *abstime)
   242 {
   243     if(!_staticCondInit(cond))
   244     {
   245         return EINVAL;
   246     }
   247     
   248     _CondNode* newNode = new _CondNode;  
   249     if(!newNode)
   250     {
   251         return ENOMEM;
   252     }
   253     sem_init(&newNode->iSemaphore,0,0);
   254       
   255     _QueueAdd(&cond->iQueue,newNode);
   256 
   257     int retval=0;
   258     
   259     //unlock passed mutex
   260     retval = pthread_mutex_unlock(mutex);
   261     if(retval != 0)
   262     {
   263         _QueueRemove(&cond->iQueue,newNode);
   264         sem_destroy(&newNode->iSemaphore);
   265         delete newNode; 
   266         errno = 0; // Condition variables should not set errno
   267         return retval;
   268     }    
   269 
   270     //node removed from queue by pthread_cond_signal or pthread_cond_broadcast
   271     //by timeout below
   272     if(abstime)
   273     {
   274         retval = sem_timedwait(&newNode->iSemaphore,abstime);   
   275         if(retval != 0)
   276         {
   277             _QueueRemove(&cond->iQueue,newNode);
   278         }//timed_wait timedout
   279     }
   280     else
   281     {
   282         retval = sem_wait(&newNode->iSemaphore);    
   283     }
   284     if(retval != 0)
   285     {
   286         retval = errno;
   287     }
   288     sem_destroy(&newNode->iSemaphore);
   289     delete newNode; 
   290     /* This is a cancellation point */
   291     //test for cancel
   292     pthread_testcancel();
   293 
   294     //lock the passed mutex
   295     pthread_mutex_lock(mutex);
   296 
   297     errno = 0; // Condition variables should not set errno
   298     return retval;
   299 }
   300 
   301 //End of File