sl@0: // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // Name : condvar.cpp sl@0: // Part of : pthread sl@0: // Interface : POSIX, pthread sl@0: // POSIX implementation of pthread on Symbian sl@0: // Version : sl@0: // sl@0: sl@0: sl@0: sl@0: #include "condvartypes.h" sl@0: sl@0: /* sl@0: This internal function initializes the passed queue to be an empty queue sl@0: */ sl@0: bool _QueueInit(_CondQueue* aQueue) sl@0: { sl@0: if(!aQueue) sl@0: { sl@0: return false; sl@0: } sl@0: pthread_mutex_init(&aQueue->iMutex,NULL); sl@0: aQueue->iHead = aQueue->iTail = NULL; sl@0: return true; sl@0: } sl@0: sl@0: /* sl@0: This internal function destroys the passed sl@0: */ sl@0: int _QueueDestroy(_CondQueue* aQueue) sl@0: { sl@0: if(!aQueue) sl@0: { sl@0: return EINVAL; sl@0: } sl@0: pthread_mutex_lock(&aQueue->iMutex); sl@0: _CondNode* head = aQueue->iHead; sl@0: pthread_mutex_unlock(&aQueue->iMutex); sl@0: if (head) sl@0: { sl@0: return EBUSY; sl@0: } sl@0: else sl@0: { sl@0: return pthread_mutex_destroy(&aQueue->iMutex); sl@0: } sl@0: } sl@0: sl@0: sl@0: /* sl@0: This internal function atomically adds a element sl@0: to the passed queue sl@0: */ sl@0: bool _QueueAdd(_CondQueue* aQueue, _CondNode* aNode) sl@0: { sl@0: if( (!aQueue) || (!aNode) ) sl@0: { sl@0: return false; sl@0: } sl@0: aNode->iNext = NULL; sl@0: pthread_mutex_lock(&aQueue->iMutex); sl@0: if(!(aQueue->iHead)) sl@0: { sl@0: aQueue->iHead = aQueue->iTail = aNode; sl@0: } sl@0: else sl@0: { sl@0: aQueue->iTail->iNext = aNode; sl@0: aQueue->iTail = aNode; sl@0: } sl@0: pthread_mutex_unlock(&aQueue->iMutex); sl@0: return true; sl@0: } sl@0: sl@0: sl@0: /* sl@0: This internal function atomically removes the pased element sl@0: from the queue sl@0: */ sl@0: bool _QueueRemove(_CondQueue* aQueue, _CondNode* aNode) sl@0: { sl@0: if( (!aQueue) || (!aNode) ) sl@0: { sl@0: return false; sl@0: } sl@0: pthread_mutex_lock(&aQueue->iMutex); sl@0: sl@0: _CondNode* prev = NULL; sl@0: _CondNode* node = aQueue->iHead; sl@0: for(; node; node = node->iNext) sl@0: { sl@0: if(node == aNode) sl@0: { sl@0: break; sl@0: } sl@0: prev = node; sl@0: } sl@0: if(node) sl@0: { sl@0: if(node == aQueue->iHead) sl@0: { sl@0: aQueue->iHead = node->iNext; sl@0: } sl@0: if(node == aQueue->iTail) sl@0: { sl@0: aQueue->iTail = prev; sl@0: } sl@0: if(prev) sl@0: { sl@0: prev->iNext = node->iNext; sl@0: } sl@0: }// node found sl@0: pthread_mutex_unlock(&aQueue->iMutex); sl@0: return (node) ? true : false; sl@0: } sl@0: sl@0: /* sl@0: This internal function atomically removes the head of the queue, and sl@0: returns a pointer to this node sl@0: */ sl@0: _CondNode* _QueueRemoveHead(_CondQueue* aQueue) sl@0: { sl@0: _CondNode* retNode = NULL; sl@0: pthread_mutex_lock(&aQueue->iMutex); sl@0: retNode = aQueue->iHead; sl@0: if(retNode) sl@0: { sl@0: aQueue->iHead = retNode->iNext; sl@0: if(aQueue->iTail == retNode) sl@0: { sl@0: aQueue->iTail = aQueue->iHead = NULL; sl@0: } sl@0: } sl@0: pthread_mutex_unlock(&aQueue->iMutex); sl@0: return retNode; sl@0: } sl@0: sl@0: sl@0: /* sl@0: This internal function removes the head of the queue, and sl@0: returns a pointer to this node WITHOUT locking the associated mutex sl@0: */ sl@0: _CondNode* _QueueRemoveHeadNoLock(_CondQueue* aQueue) sl@0: { sl@0: _CondNode* retNode = NULL; sl@0: retNode = aQueue->iHead; sl@0: if(retNode) sl@0: { sl@0: aQueue->iHead = retNode->iNext; sl@0: if(aQueue->iTail == retNode) sl@0: { sl@0: aQueue->iTail = aQueue->iHead = NULL; sl@0: } sl@0: } sl@0: return retNode; sl@0: } sl@0: sl@0: /* sl@0: This internal function locks the queue mutex sl@0: */ sl@0: void _QueueLock(_CondQueue* aQueue) sl@0: { sl@0: pthread_mutex_lock(&aQueue->iMutex); sl@0: } sl@0: sl@0: /* sl@0: This internal function unlocks the queue mutex sl@0: */ sl@0: void _QueueUnlock(_CondQueue* aQueue) sl@0: { sl@0: pthread_mutex_unlock(&aQueue->iMutex); sl@0: } sl@0: sl@0: /* sl@0: This internal function atomically resolves the race to dynamically initialize a static cond var sl@0: */ sl@0: bool _staticCondInit(pthread_cond_t* cond) sl@0: { sl@0: if(!cond) sl@0: { sl@0: return false; sl@0: } sl@0: if(cond->iState == _EInitialized) sl@0: { sl@0: return true; sl@0: } sl@0: sl@0: sl@0: if(cond->iState != _ENeedsNormalInit) sl@0: { sl@0: return false; sl@0: } sl@0: int retval=0; sl@0: sl@0: #ifndef NOUSE_INTERNALS sl@0: void* tlsPtr; sl@0: sl@0: // Get the TLS pointer sl@0: tlsPtr = _pthread_getTls(); sl@0: if(NULL == tlsPtr) sl@0: { sl@0: return false; sl@0: } sl@0: _pthread_atomicMutexLock(tlsPtr); sl@0: #endif sl@0: sl@0: //another thread might win race sl@0: if(cond->iState != _EInitialized) sl@0: { sl@0: retval = pthread_cond_init(cond,NULL); sl@0: } sl@0: sl@0: #ifndef NOUSE_INTERNALS sl@0: _pthread_atomicMutexUnlock(tlsPtr); sl@0: #endif sl@0: if(retval == 0) sl@0: { sl@0: return true; sl@0: } sl@0: else sl@0: { sl@0: return false; sl@0: } sl@0: } sl@0: sl@0: /* sl@0: This internal function provides the functionality to wait on a condition variable, sl@0: */ sl@0: int _internalCondWait(pthread_cond_t *cond, pthread_mutex_t *mutex,const struct timespec *abstime) sl@0: { sl@0: if(!_staticCondInit(cond)) sl@0: { sl@0: return EINVAL; sl@0: } sl@0: sl@0: _CondNode* newNode = new _CondNode; sl@0: if(!newNode) sl@0: { sl@0: return ENOMEM; sl@0: } sl@0: sem_init(&newNode->iSemaphore,0,0); sl@0: sl@0: _QueueAdd(&cond->iQueue,newNode); sl@0: sl@0: int retval=0; sl@0: sl@0: //unlock passed mutex sl@0: retval = pthread_mutex_unlock(mutex); sl@0: if(retval != 0) sl@0: { sl@0: _QueueRemove(&cond->iQueue,newNode); sl@0: sem_destroy(&newNode->iSemaphore); sl@0: delete newNode; sl@0: errno = 0; // Condition variables should not set errno sl@0: return retval; sl@0: } sl@0: sl@0: //node removed from queue by pthread_cond_signal or pthread_cond_broadcast sl@0: //by timeout below sl@0: if(abstime) sl@0: { sl@0: retval = sem_timedwait(&newNode->iSemaphore,abstime); sl@0: if(retval != 0) sl@0: { sl@0: _QueueRemove(&cond->iQueue,newNode); sl@0: }//timed_wait timedout sl@0: } sl@0: else sl@0: { sl@0: retval = sem_wait(&newNode->iSemaphore); sl@0: } sl@0: if(retval != 0) sl@0: { sl@0: retval = errno; sl@0: } sl@0: sem_destroy(&newNode->iSemaphore); sl@0: delete newNode; sl@0: /* This is a cancellation point */ sl@0: //test for cancel sl@0: pthread_testcancel(); sl@0: sl@0: //lock the passed mutex sl@0: pthread_mutex_lock(mutex); sl@0: sl@0: errno = 0; // Condition variables should not set errno sl@0: return retval; sl@0: } sl@0: sl@0: //End of File