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 : mutex.cpp sl@0: // Part of : pthread sl@0: // Interface : POSIX, pthread sl@0: // POSIX implementation of mutexes on Symbian sl@0: // Version : sl@0: // sl@0: sl@0: sl@0: sl@0: #include "mutextypes.h" sl@0: sl@0: /* sl@0: This function waits on the aLock semaphore. sl@0: */ sl@0: int _doWait(RSemaphore* aLock, const struct timespec *abstime) sl@0: { sl@0: int retval = 0; sl@0: if(!abstime) sl@0: { sl@0: aLock->Wait(); sl@0: } sl@0: else sl@0: { sl@0: long lSleepTime = _microsleeptime(abstime); sl@0: if(lSleepTime <0) sl@0: { sl@0: if (EINVAL == errno) sl@0: { sl@0: errno = 0; sl@0: return EINVAL; sl@0: } sl@0: else if(ETIMEDOUT == errno) sl@0: { sl@0: errno = 0; sl@0: return ETIMEDOUT; sl@0: } sl@0: sl@0: } sl@0: sl@0: retval = aLock->Wait(lSleepTime); sl@0: if(retval != KErrNone) sl@0: { sl@0: return ETIMEDOUT; sl@0: } sl@0: sl@0: } sl@0: return 0; sl@0: } sl@0: sl@0: /* sl@0: This internal function destroys the mutex object. sl@0: */ sl@0: void _closeMutex(pthread_mutex_t* mutex) sl@0: { sl@0: _pthread_mutex_t* pMutex = mutex->iPtr; sl@0: if(pMutex) sl@0: { sl@0: if(pMutex->iSemaphoreCreated) sl@0: { sl@0: pMutex->iSignalSemaphore.Close(); sl@0: } sl@0: if(pMutex->iDataLockCreated) sl@0: { sl@0: pMutex->iDataLock.Close(); sl@0: } sl@0: mutex->iPtr = NULL; sl@0: delete pMutex; sl@0: } sl@0: return; sl@0: } sl@0: sl@0: int _mutexCreate (pthread_mutex_t * mutex, sl@0: const pthread_mutexattr_t* attr) sl@0: { sl@0: sl@0: if( attr->iSharedType != PTHREAD_PROCESS_PRIVATE) sl@0: { sl@0: return ENOSYS; sl@0: } sl@0: sl@0: mutex->iState = _EInvalid; sl@0: _pthread_mutex_t* pMutex = new _pthread_mutex_t; sl@0: mutex->iPtr = pMutex; sl@0: if(!pMutex) sl@0: { sl@0: return ENOMEM; sl@0: } sl@0: sl@0: pMutex->iSharedType = attr->iSharedType; sl@0: pMutex->iMutexType = attr->iMutexType; sl@0: pMutex->iDataLockCreated = false; sl@0: pMutex->iSemaphoreCreated = false; sl@0: sl@0: if(pMutex->iSignalSemaphore.CreateLocal(1) != KErrNone) sl@0: { sl@0: _closeMutex(mutex); sl@0: return EAGAIN; sl@0: } sl@0: pMutex->iSemaphoreCreated = true; sl@0: sl@0: if(pMutex->iDataLock.CreateLocal() != KErrNone) sl@0: { sl@0: _closeMutex(mutex); sl@0: return EAGAIN; sl@0: } sl@0: pMutex->iDataLockCreated = true; sl@0: sl@0: pMutex->iCount = 0; sl@0: pMutex->iSemaphoreState = SEM_FREE; sl@0: pMutex->iLockingThread = 0; sl@0: mutex->iState = _EInitialized; sl@0: return 0; sl@0: } sl@0: sl@0: sl@0: /* sl@0: This function is an internal harness function used to resolve the race to dynamically initialize a static mutex sl@0: */ sl@0: bool _InitOnce(pthread_mutex_t* mutex) sl@0: { sl@0: sl@0: pthread_mutexattr_t defaultattributes = sl@0: PTHREAD_MUTEX_ATTRIBUTE_DEFAULT_INITIALIZER; sl@0: pthread_mutexattr_t recursiveattributes = sl@0: PTHREAD_MUTEX_ATTRIBUTE_RECURSIVE_INITIALIZER; sl@0: pthread_mutexattr_t errorcheckattributes = sl@0: PTHREAD_MUTEX_ATTRIBUTE_ERRORCHECK_INITIALIZER; sl@0: sl@0: if(mutex->iState == _EInitialized) sl@0: { sl@0: return true; sl@0: } sl@0: sl@0: mutex->iReentry = 0xBABA; sl@0: sl@0: pthread_mutexattr_t* attr; sl@0: switch(mutex->iState) sl@0: { sl@0: case _ENeedsNormalInit: sl@0: { sl@0: attr = &defaultattributes; sl@0: break; sl@0: } sl@0: sl@0: case _ENeedsRecursiveInit: sl@0: { sl@0: attr = &recursiveattributes; sl@0: break; sl@0: } sl@0: sl@0: case _ENeedsErrorCheckInit: sl@0: { sl@0: attr = &errorcheckattributes; sl@0: break; sl@0: } sl@0: sl@0: default: sl@0: return false; sl@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: sl@0: if(!tlsPtr) sl@0: { sl@0: return false; sl@0: } sl@0: #endif sl@0: sl@0: int retval=0; sl@0: #ifndef NOUSE_INTERNALS sl@0: _pthread_atomicMutexLock(tlsPtr); sl@0: #endif sl@0: if(mutex->iState != _EInitialized) sl@0: { sl@0: retval = _mutexCreate(mutex,attr); sl@0: } sl@0: #ifndef NOUSE_INTERNALS sl@0: _pthread_atomicMutexUnlock(tlsPtr); sl@0: #endif sl@0: 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: /* sl@0: This function is an internal function used to provide the POSIX mutex lock sl@0: functionality. sl@0: */ sl@0: int _internalMutexLock(pthread_mutex_t * mutex,const struct timespec *abstime) sl@0: { sl@0: if( !VALID_MUTEX(mutex) ) sl@0: { sl@0: return EINVAL; sl@0: } sl@0: sl@0: _pthread_mutex_t* pMutex = mutex->iPtr; sl@0: sl@0: sl@0: int retval = 0; sl@0: pthread_t self; sl@0: switch(pMutex->iMutexType) sl@0: { sl@0: case PTHREAD_MUTEX_NORMAL: sl@0: { sl@0: self = pthread_self(); sl@0: pMutex->iDataLock.Wait(); sl@0: if(mutex->iState == _EDestroyed) sl@0: { sl@0: pMutex->iDataLock.Signal(); sl@0: return EINVAL; sl@0: } sl@0: pMutex->iSemaphoreState++; sl@0: pMutex->iDataLock.Signal(); sl@0: sl@0: retval = _doWait(&pMutex->iSignalSemaphore,abstime); sl@0: if(retval == 0) sl@0: { sl@0: pMutex->iDataLock.Wait(); sl@0: if(mutex->iState == _EDestroyed) sl@0: { sl@0: pMutex->iDataLock.Signal(); sl@0: return EINVAL; sl@0: } sl@0: pMutex->iLockingThread = self; sl@0: pMutex->iDataLock.Signal(); sl@0: } sl@0: break; sl@0: } sl@0: sl@0: case PTHREAD_MUTEX_RECURSIVE: sl@0: sl@0: { sl@0: self = pthread_self(); sl@0: if(pMutex->iLockingThread == self) sl@0: { sl@0: pMutex->iDataLock.Wait(); sl@0: if(mutex->iState == _EDestroyed) sl@0: { sl@0: pMutex->iDataLock.Signal(); sl@0: return EINVAL; sl@0: } sl@0: pMutex->iCount++; sl@0: pMutex->iDataLock.Signal(); sl@0: } sl@0: else sl@0: { sl@0: pMutex->iDataLock.Wait(); sl@0: if(mutex->iState == _EDestroyed) sl@0: { sl@0: pMutex->iDataLock.Signal(); sl@0: return EINVAL; sl@0: } sl@0: pMutex->iSemaphoreState++; sl@0: pMutex->iDataLock.Signal(); sl@0: sl@0: retval = _doWait(&pMutex->iSignalSemaphore,abstime); sl@0: if(retval == 0) sl@0: { sl@0: pMutex->iDataLock.Wait(); sl@0: if(mutex->iState == _EDestroyed) sl@0: { sl@0: pMutex->iDataLock.Signal(); sl@0: return EINVAL; sl@0: } sl@0: pMutex->iCount = 1; sl@0: pMutex->iLockingThread = self; sl@0: pMutex->iDataLock.Signal(); sl@0: } sl@0: } sl@0: break; sl@0: } sl@0: sl@0: case PTHREAD_MUTEX_ERRORCHECK: sl@0: { sl@0: self = pthread_self(); sl@0: if(pMutex->iLockingThread == self) sl@0: { sl@0: return EDEADLK; sl@0: } sl@0: else sl@0: { sl@0: pMutex->iDataLock.Wait(); sl@0: if(mutex->iState == _EDestroyed) sl@0: { sl@0: pMutex->iDataLock.Signal(); sl@0: return EINVAL; sl@0: } sl@0: pMutex->iSemaphoreState++; sl@0: pMutex->iDataLock.Signal(); sl@0: sl@0: retval = _doWait(&pMutex->iSignalSemaphore,abstime); sl@0: if(retval == 0) sl@0: { sl@0: pMutex->iDataLock.Wait(); sl@0: if(mutex->iState == _EDestroyed) sl@0: { sl@0: pMutex->iDataLock.Signal(); sl@0: return EINVAL; sl@0: } sl@0: pMutex->iLockingThread = self; sl@0: pMutex->iDataLock.Signal(); sl@0: } sl@0: } sl@0: break; sl@0: } sl@0: sl@0: default: sl@0: retval = ENOSYS; sl@0: break; sl@0: sl@0: } sl@0: return retval; sl@0: sl@0: } sl@0: sl@0: //End of File