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