genericopenlibs/openenvcore/libpthread/src/semaphore.cpp
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     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        : semaphore.cpp
       
    15 // Part of     : semaphore 
       
    16 // POSIX implementation of semaphores on Symbian
       
    17 // Version     :
       
    18 //
       
    19 
       
    20 
       
    21 
       
    22 #include <stddef.h>
       
    23 #include <limits.h>
       
    24 #include <e32def.h>
       
    25 #include <e32std.h>
       
    26 #include <errno.h>
       
    27 #include <time.h>
       
    28 #include <sys/time.h>
       
    29 #include <stdlib.h>
       
    30 
       
    31 #include "pthread.h"
       
    32 #include "semaphore.h"
       
    33 #include "semaphoretypes.h"
       
    34 
       
    35 
       
    36 /*
       
    37 This is an internal API used to wait on the semaphore
       
    38 The thread suspended on the semaphore can be cancelled at any time unless the 
       
    39 calling thread's canceltype is PTHREAD_CANCEL_DISABLE
       
    40 */
       
    41 int _cancelable_mutex_wait(_sem_t* asem)
       
    42 {
       
    43     //cancellation point; 
       
    44   pthread_testcancel(); 
       
    45   asem->iMutex.Wait(); 
       
    46   if(asem->iState != _sem_t::EInitialized) 
       
    47   { 
       
    48     errno = EINVAL; 
       
    49     return -1; 
       
    50   } 
       
    51   pthread_testcancel(); 
       
    52   return 0;
       
    53 }
       
    54 
       
    55 /*
       
    56 This is an internal API used to convert the absolute time out time specified 
       
    57 by the timespec struct into an equivalent number of microseconds to wait.
       
    58 */
       
    59 long _microsleeptime_raw(const struct timespec* abstime, 
       
    60                          const struct timeval* now)
       
    61 {
       
    62     if(!abstime)
       
    63     {
       
    64         errno = EINVAL;
       
    65         return -1;
       
    66     }
       
    67     
       
    68     long secs = abstime->tv_sec - now->tv_sec;
       
    69     
       
    70     long usecs = (abstime->tv_nsec - now->tv_usec * 1000)/1000;
       
    71     
       
    72     if (abs(usecs /(1000 * 1000)) > 1)
       
    73     {
       
    74         errno = EINVAL;
       
    75         return -1;
       
    76     }
       
    77     if(secs < 0 ||(secs ==0 && usecs <= 0)) 
       
    78     {
       
    79         errno = ETIMEDOUT;
       
    80         return -1;
       
    81     }
       
    82     return (secs* 1000 * 1000) + usecs;
       
    83 }
       
    84 
       
    85 
       
    86 /*
       
    87 This is an internal API used to convert the absolute time out time specified 
       
    88 by the timespec struct into an equivalent number of microseconds to wait. 
       
    89 Takes care of overflow check.
       
    90 */
       
    91 long _microsleeptime(const struct timespec* abstime)
       
    92 {
       
    93     struct timeval  now;
       
    94     gettimeofday( &now, NULL);
       
    95     
       
    96     if((abstime->tv_nsec >= 1 * 1000 * 1000 * 1000) || (abstime->tv_nsec < 0))
       
    97     {
       
    98         errno = EINVAL;
       
    99         return -1;
       
   100     }
       
   101     
       
   102     //hard-coded overflow check
       
   103     long secs = (abstime->tv_sec - now.tv_sec);
       
   104     if(secs < 0 )
       
   105     {
       
   106         errno = ETIMEDOUT;
       
   107         return -1;
       
   108     }
       
   109     if(secs > KMaxSecsForWait)
       
   110     {
       
   111         errno = EINVAL;
       
   112         return -1;
       
   113     }
       
   114     return _microsleeptime_raw(abstime,&now);
       
   115 }
       
   116 
       
   117 // Adding semaphore into List 
       
   118 void _insertIntoSemList(void *tlsPtr, _sem_node_t *newNode)
       
   119 {
       
   120     _pthread_node_t *currNode;
       
   121     _global_data_t *glbPtr;
       
   122          
       
   123     currNode = (_pthread_node_t *) tlsPtr;
       
   124     glbPtr = currNode->glbDataPtr;
       
   125     
       
   126     glbPtr->lockSemTable.Wait(); // Acquire the global linked-list lock
       
   127     
       
   128     // Append the new node at the beginning
       
   129     newNode->next = glbPtr->semStart;
       
   130     glbPtr->semStart = newNode;
       
   131     
       
   132     glbPtr->lockSemTable.Signal();// Release the global linked-list lock
       
   133 }
       
   134 
       
   135 int _addToSemList(_sem_t *newSem)
       
   136 {
       
   137     _sem_node_t * newNodePtr;
       
   138     _pthread_node_t *selfNodePtr;
       
   139     
       
   140     //Get the TLS value (self node pointer)
       
   141     selfNodePtr = (_pthread_node_t*) _pthread_getTls();
       
   142     if (NULL == selfNodePtr)
       
   143     {
       
   144         THR_PRINTF("[pthread] FATAL :TLS is not initialized \n");
       
   145         return EAGAIN;
       
   146     }
       
   147     
       
   148     newNodePtr = new _sem_node_t;
       
   149     if (NULL == newNodePtr)
       
   150     {
       
   151         return EAGAIN;
       
   152     }
       
   153     //Initialize the new node
       
   154     newNodePtr->next = NULL;
       
   155     newNodePtr->sem  = newSem;
       
   156     
       
   157     _insertIntoSemList((void*)selfNodePtr,newNodePtr);
       
   158     
       
   159     return 0;
       
   160 }
       
   161 // Deleting semaphore from List 
       
   162 int _freeSemFromList(void *tlsPtr, _sem_t *delSem)
       
   163 {
       
   164     _pthread_node_t *currNode;
       
   165     _global_data_t *glbPtr;
       
   166     _sem_node_t *temp;
       
   167     _sem_node_t *prev;
       
   168          
       
   169     currNode = (_pthread_node_t *) tlsPtr;
       
   170     glbPtr = currNode->glbDataPtr;
       
   171     
       
   172     glbPtr->lockSemTable.Wait(); // Acquire the global linked-list lock
       
   173     
       
   174     prev = NULL;
       
   175     for (temp = glbPtr->semStart; temp != NULL; temp = temp->next)
       
   176     {
       
   177         if(temp->sem == delSem) // Found the sem
       
   178         {
       
   179             //First Node
       
   180             if (temp == glbPtr->semStart)
       
   181             {
       
   182                 glbPtr->semStart = temp->next;
       
   183                 delete temp;
       
   184                 glbPtr->lockSemTable.Signal();//Release global linked-list lock
       
   185                 return _SEM_FOUND_IN_LIST;
       
   186             }
       
   187             else
       
   188             {
       
   189                 prev->next = temp->next;
       
   190                 delete temp;
       
   191                 glbPtr->lockSemTable.Signal();//Release global linked-list lock
       
   192                 return _SEM_FOUND_IN_LIST;                
       
   193             }
       
   194         }
       
   195         prev = temp;
       
   196     }
       
   197     
       
   198     // Not found
       
   199     glbPtr->lockSemTable.Signal();// Release the global linked-list lock
       
   200     return _SEM_NOT_FOUND_IN_LIST;
       
   201 }
       
   202 
       
   203 int _findAndFreeSem(_sem_t *delSem)
       
   204 {
       
   205     _pthread_node_t *selfNodePtr;
       
   206     
       
   207     //Get the TLS value (self node pointer)
       
   208     selfNodePtr = (_pthread_node_t*) _pthread_getTls();
       
   209     if (NULL == selfNodePtr)
       
   210     {
       
   211         THR_PRINTF("[pthread] FATAL :TLS is not initialized \n");
       
   212         return _SEM_NOT_FOUND_IN_LIST;
       
   213     }
       
   214 
       
   215     return (_freeSemFromList ((void*)selfNodePtr,delSem));
       
   216 }
       
   217 
       
   218 
       
   219 // End of File