/************************************************************************/ /* SISCO SOFTWARE MODULE HEADER *****************************************/ /************************************************************************/ /* (c) Copyright Systems Integration Specialists Company, Inc., */ /* 1997-2008, All Rights Reserved */ /* */ /* MODULE NAME : glbsem_unix.c */ /* PRODUCT(S) : */ /* */ /* MODULE DESCRIPTION : Multi-thread support for UNIX-like systems ONLY.*/ /* */ /* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ /* */ /* MODIFICATION LOG : */ /* Date Who Rev Comments */ /* -------- --- ------ ------------------------------------------- */ /* 01/29/08 EJV 11 Use S_FMT_* macros to log pointers & handles.*/ /* 12/12/05 JRB 10 Disable gs_wait_mult_event_sem with #if 0 to */ /* catch problems at compile time, not run time.*/ /* 06/06/05 EJV 09 Added S_MT_SUPPORT to avoid Linux errors. */ /* 11/04/03 JRB 08 Del gs_sleep (use sMsSleep). */ /* 10/09/03 JRB 07 Use thisThreadId only if DEBUG_SISCO. */ /* Use clock_gettime for default system. */ /* gs_start_thread: don't init threadHandle=NULL*/ /* 08/25/03 JRB 06 gs_sleep: use rqtp.tv_sec if ms >= 1000. */ /* 06/20/03 EJV 05 Renamed gs_mutex_get to gs_mutex_get_tm. */ /* Del param from gs_mutex_get calls. */ /* 06/12/03 EJV 04 Redesigned mutex sems implementation. */ /* 06/11/03 EJV 03 Added empty functions: gs_named_mutex_xxx */ /* and gs_get_named_event_sem */ /* Added thisFileName, del unmatched #if */ /* 06/06/03 JRB 02 Del logging in gs_mutex_get, gs_mutex_free. */ /* 06/06/03 JRB 01 NEW. Code taken out of glbsem.c */ /************************************************************************/ #include "glbtypes.h" #include "sysincs.h" #include "mem_chk.h" #include "slog.h" #include "glbsem.h" #if defined(S_MT_SUPPORT_RXB) /************************************************************************/ /* For debug version, use a static pointer to avoid duplication of */ /* __FILE__ strings. */ #ifdef DEBUG_SISCO SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; #endif static ST_RET _gs_sig_event_sem (ST_EVENT_SEM es, ST_INT predicate); /*======================================================================*/ /* UNIX FUNCTIONS complying with POSIX 1003.1c */ /*======================================================================*/ /*---*---*---*---*---*---*---*---*---*---*---*---*---*--*/ /* */ /* MUTEX SEMAPHORE FUNCTIONS for */ /* _AIX, __alpha */ /* */ /*---*---*---*---*---*---*---*---*---*---*---*---*---*--*/ /************************************************************************/ /* gs_mutex_create */ /*----------------------------------------------------------------------*/ /* Creates and initializes MUTEX seamphore. */ /* Parameters: */ /* ms pointer to mutex sem struct */ /* Return values: */ /* SD_SUCCESS function successful */ /* SD_FAILURE error occurred */ /************************************************************************/ ST_RET gs_mutex_create (pthread_mutex_t *ms) { ST_RET ret; ST_INT result; pthread_mutexattr_t mutexattr; #if defined(DEBUG_SISCO) ST_THREAD_ID thisThreadId = GET_THREAD_ID(); #endif ret = SD_FAILURE; /* Initialize the mutex attributes variable (needed only for mutex init) */ result = pthread_mutexattr_init (&mutexattr); if ( result != 0 ) { GLBSEM_LOG_ERR3 ("GLBSEM gs_mutex_create error: Thread " S_FMT_PTR " failed to initialize" " mutex semaphore ms=" S_FMT_PTR " attributes (error=%d).", thisThreadId, ms, result); return (ret); } /* Set the mutex attributes (mutex type to PTHREAD_MUTEX_RECURSIVE). */ /* The semaphore type could not be PTHREAD_MUTEX_ERRORCHECK because */ /* in the DEC UNIX manual there is a warning that "DECthreads does not*/ /* currently detect deadlock conditions involving more then one mutex,*/ /* but may in the future." Because of this restriction and the fact */ /* that ICCP Toolkit is implementing an independent mutex semaphore */ /* (currently PTHREAD_MUTEX_NORMAL may be changed to ERRORCHECK) or */ /* possibility that user application may want to use the ERRORCHECK */ /* semaphore we decided to use the PTHREAD_MUTEX_RECURSIVE. */ /* If the semaphore type is PTHREAD_MUTEX_ERRORCHECK then it will */ /* return an error if the current owner of the semaphore tries */ /* to lock the mutex again (or thread tries to unlock mutex that it */ /* does not own). */ result = pthread_mutexattr_settype (&mutexattr, PTHREAD_MUTEX_RECURSIVE); if ( result != 0 ) { GLBSEM_LOG_ERR3 ("GLBSEM gs_mutex_create error: thread " S_FMT_PTR " failed to set mutex" " semaphore ms=" S_FMT_PTR " attributes (error=%d).", thisThreadId, ms, result); switch ( result ) { case EINVAL: GLBSEM_LOG_CERR0 ("error=EINVAL (invalid mutex attribute or type)."); break; case ESRCH: GLBSEM_LOG_CERR0 ("error=ESRCH (non existing mutex attributes object)."); break; } pthread_mutexattr_destroy (&mutexattr); return (ret); } /* Initialize the mutex with specific attributes. The mutex will be */ /* in the unlocked state. */ result = pthread_mutex_init (ms, &mutexattr); if ( result != 0 ) { GLBSEM_LOG_ERR3 ("GLBSEM gs_mutex_create error: thread " S_FMT_PTR " failed to initialize" " mutex semaphore ms=" S_FMT_PTR " (error=%d).", thisThreadId, ms, result); switch ( result ) { case EAGAIN: GLBSEM_LOG_CERR0 ("error=EAGAIN (system resouces not available)."); break; case ENOMEM: GLBSEM_LOG_CERR0 ("error=ENOMEM (insufficient memory for mutex" " initialization)."); break; case EBUSY: GLBSEM_LOG_CERR0 ("error=EBUSY (programs requested mutex" " reinitialization)."); break; case EINVAL: GLBSEM_LOG_CERR0 ("error=EINVAL (invalid mutex argument)."); break; case EPERM: GLBSEM_LOG_CERR0 ("error=EPERM (insufficient privileges)."); break; } pthread_mutexattr_destroy (&mutexattr); return (ret); } /* release the mutex attributes object - not needed anymore */ pthread_mutexattr_destroy (&mutexattr); GLBSEM_LOG_FLOW2 ("GLBSEM gs_mutex_create: thread " S_FMT_PTR " initialized " " mutex semaphore ms=" S_FMT_PTR ".", thisThreadId, ms); /* initialized the mutex successfully */ ret = SD_SUCCESS; return (ret); } /************************************************************************/ /* gs_named_mutex_create */ /*----------------------------------------------------------------------*/ /* Create/Open NAMED mutex. */ /* For each call to this function the gs_named_mutex_destroy must be */ /* called. */ /* Parameters: */ /* ms pointer to mutex object */ /* name pointer to mutex name. */ /* Return values: */ /* SD_SUCCESS function successful */ /* SD_FAILURE error occurred */ /************************************************************************/ #if 0 /* DEBUG: To be implemented later */ ST_RET gs_named_mutex_create (ST_MUTEX_SEM *ms, ST_CHAR *name) { ST_RET ret = SD_FAILURE; /* To be implemented */ return (ret); } #endif /* DEBUG: To be implemented later */ /************************************************************************/ /* gs_mutex_get_tm */ /*----------------------------------------------------------------------*/ /* Lock the MUTEX semaphore ms. */ /* Parameters: */ /* ms pointer to mutex sem struct */ /* timeout this parameter is ignored in UNIX implementation*/ /* Return values: */ /* SD_SUCCESS function successful */ /* SD_FAILURE error occurred */ /* CRITICAL: gs_mutex_get_tm must NOT call any slog, stime, or mem_chk */ /* functions. These functions call ge_mutex_get which would cause */ /* an infinite loop. */ /************************************************************************/ ST_RET gs_mutex_get_tm (ST_MUTEX_SEM *ms, ST_LONG timeout) { ST_INT result; if (!gs_already_inited) /* Make sure gs is initialized. */ gs_init (); /* Because the mutex semaphore type is PTHREAD_MUTEX_RECURSIVE it */ /* will allow to relock the mutex by the thread that owns the mutex */ /* without blocking. The lock count is incremented for each recursive */ /* lock within the thread. */ /* If the mutex is locked by another thread, the calling thread will */ /* wait until the mutex become available. */ result = pthread_mutex_lock (ms); assert (result==0); /* otherwise threads will overwrite each other's data */ if (result == 0) return (SD_SUCCESS); else return (SD_FAILURE); } /************************************************************************/ /* gs_mutex_free */ /*----------------------------------------------------------------------*/ /* Unlock the MUTEX semaphore ms. */ /* Parameters: */ /* ms pointer to mutex sem struct */ /* Return values: */ /* SD_SUCCESS function successful */ /* SD_FAILURE error occurred */ /* CRITICAL: gs_mutex_free must NOT call any slog, stime, or mem_chk */ /* functions. These functions call ge_mutex_free which would cause */ /* an infinite loop. */ /************************************************************************/ ST_RET gs_mutex_free (ST_MUTEX_SEM *ms) { ST_INT result; /* Because the mutex semaphore type is PTHREAD_MUTEX_RECURSIVE */ /* if the calling thread owns the mutex the lock count is decremented.*/ /* the mutex remains owned by the calling thread until the count is 0.*/ /* When the count becomes 0 the mutex is unlocked and can be grabed by*/ /* next waiting thread. */ result = pthread_mutex_unlock (ms); assert (result==0); /* otherwise threads will overwrite each other's data */ if (result == 0) return (SD_SUCCESS); else return (SD_FAILURE); } /************************************************************************/ /* gs_mutex_destroy */ /*----------------------------------------------------------------------*/ /* Free all resources allocated for the MUTEX semaphore ms. */ /* Parameters: */ /* ms pointer to mutex sem struct */ /* Return values: */ /* SD_SUCCESS function successful */ /* SD_FAILURE error occurred */ /************************************************************************/ ST_RET gs_mutex_destroy (pthread_mutex_t *ms) { ST_RET ret; ST_INT result; #if defined(DEBUG_SISCO) ST_THREAD_ID thisThreadId = GET_THREAD_ID(); #endif ret = SD_FAILURE; /* The pthread_mutex_destroy function deinitializes the ms mutex */ /* semaphore. THe function is successful only if the mutex is not */ /* referenced or locked. */ result = pthread_mutex_destroy (ms); if ( result != 0 ) { /* Log a major error here */ GLBSEM_LOG_ERR3 ("GLBSEM gs_mutex_destroy error: thread " S_FMT_PTR " failed to destroy mutex semaphore ms=" S_FMT_PTR " (error=%d)", thisThreadId, ms, result); switch ( result ) { case EBUSY: GLBSEM_LOG_CERR0 ("error=EBUSY (semaphore locked or referenced)"); break; case EINVAL: GLBSEM_LOG_CERR0 ("error=EINVAL (invalid mutex semaphore)"); break; } return (ret); } GLBSEM_LOG_FLOW2 ("GLBSEM gs_mutex_destroy: thread " S_FMT_PTR " destroyed mutex" " semaphore ms=" S_FMT_PTR ".", thisThreadId, ms); /* destroy mutex successful */ ret = SD_SUCCESS; return (ret); } /*---*---*---*---*---*---*---*---*---*---*---*---*---*--*/ /* */ /* USER's EVENT SEMAPHORE FUNCTIONS for */ /* _AIX, __alpha */ /* */ /*---*---*---*---*---*---*---*---*---*---*---*---*---*--*/ /************************************************************************/ /* gs_get_event_sem */ /*----------------------------------------------------------------------*/ /* Creates and initializes an event semaphore. */ /* The event semaphore is implemented using PTHREADs Condition Variable.*/ /* Parameters: */ /* ST_BOOLEAN manualReset Type of event sem */ /* Return values: */ /* ST_EVENT_SEM handle (pointer) to event semaphore */ /* NULL if function failed */ /************************************************************************/ ST_EVENT_SEM gs_get_event_sem (ST_BOOLEAN manualReset) { ST_INT result; ST_EVENT_SEM es = NULL; /* pointer to event sem struct */ #if defined(DEBUG_SISCO) ST_THREAD_ID thisThreadId = GET_THREAD_ID(); /* Let's see just who we are */ #endif /* allocate the memory for the event sem */ es = (ST_EVENT_SEM) chk_calloc (1, sizeof (GS_EVENT_SEM)); if ( es == NULL ) { GLBSEM_LOG_ERR1 ("GLBSEM gs_get_event_sem error: thread " S_FMT_PTR " (allocate memory failed).", thisThreadId); return (NULL); } /* crete mutex for the condition variable */ if ( gs_mutex_create (&es->mutex) != SD_SUCCESS ) { GLBSEM_LOG_ERR1 ("GLBSEM gs_get_event_sem error: thread " S_FMT_PTR " (gs_mutex_create failed).", thisThreadId); chk_free (es); return (NULL); } /* Condition Variable attributes are currently not implemented, use NULL */ result = pthread_cond_init (&es->cond, NULL); if ( result != 0 ) { GLBSEM_LOG_ERR2 ("GLBSEM gs_get_event_sem error: thread " S_FMT_PTR " (pthread_cond_init failed result=%d),", thisThreadId, result); switch ( result ) { case EAGAIN: GLBSEM_LOG_CERR0 ("result=EAGAIN (system resouces not available)."); break; case ENOMEM: GLBSEM_LOG_CERR0 ("result=ENOMEM (insufficient memory for mutex" " initialization)."); break; case EBUSY: GLBSEM_LOG_CERR0 ("result=EBUSY (programs requested condition variable" " reinitialization)."); break; case EINVAL: GLBSEM_LOG_CERR0 ("result=EINVAL (invalid attr argument)."); break; } gs_mutex_destroy (&es->mutex); chk_free (es); return (NULL); } GLBSEM_LOG_FLOW2 ("GLBSEM gs_get_event_sem: thread " S_FMT_PTR " initialized event sem es=" S_FMT_PTR ".", thisThreadId, es); /* successfully initialized the event semaphore */ es->manualReset = manualReset; return (es); } /************************************************************************/ /* gs_get_named_event_sem */ /*----------------------------------------------------------------------*/ /* Create a "manual-reset" or "auto-reset" NAMED event semaphore. */ /* Parameters: */ /* name pointer to semaphore name. */ /* manualReset SD_TRUE or SD_FALSE */ /* Return values: */ /* ST_EVENT_SEM handle to named event semaphore object */ /************************************************************************/ #if 0 /* DEBUG: To be implemented later */ ST_EVENT_SEM gs_get_named_event_sem (ST_CHAR *name, ST_BOOLEAN manualReset) { ST_EVENT_SEM retEventSem = NULL; /* To be implemented */ return (retEventSem); } #endif /* DEBUG: To be implemented later */ /************************************************************************/ /* gs_wait_event_sem */ /*----------------------------------------------------------------------*/ /* Wait for event semaphore es until it becomes signaled or timeout */ /* occurrs. */ /* If compiled with DEBUG_SISCO the gs_track variable need to be set to */ /* value >0 to enable the timing code. This way logging can be used */ /* by an application without degradation of the EVENT sem performance. */ /* Parameters: */ /* es event semaphore object (pointer) */ /* timeout interval in milliseconds to wait for the es to */ /* be signaled, if -1L then the function will be */ /* blocked indefinitely until the event semaphore */ /* is signaled. */ /* Return values: */ /* SD_SUCCESS function successful */ /* SD_FAILURE error occurred */ /* SD_TIMEOUT timeout occurred */ /************************************************************************/ ST_RET gs_wait_event_sem (ST_EVENT_SEM es, ST_LONG timeout) { ST_RET ret; ST_INT result; struct timespec tsDelta; struct timespec tsAbstime; #if defined(DEBUG_SISCO) ST_DOUBLE startTime; ST_DOUBLE endTime; ST_DOUBLE elapsedTime; ST_THREAD_ID thisThreadId = GET_THREAD_ID(); /* Let's see just who we are */ #endif #if defined(linux) struct timeval curtimeval; /* for gettimeofday */ #endif ret = SD_FAILURE; if (!es) { GLBSEM_LOG_ERR1 ("GLBSEM gs_wait_event_sem error: thread " S_FMT_PTR " (invalid es=NULL)", thisThreadId); return (ret); } /* mutex for the specified condition variable must be locked before */ /* going into wait or checking preedicate */ gs_mutex_get (&es->mutex); /* Note: according to the docummentation we may not capture the */ /* signaling of conditional variable if a thread was not waiting*/ /* for it, since the signaling of the condition is not held */ /* (AIX and maybe other UNIX systems). */ /* Let check the predicate for the conditional variable first to*/ /* see if it was set and act accordingly. */ /* To simulate Windows manual-reset semaphore if gs_signal_event_sem */ /* was used then the semaphore remains signaled until it is exlicitly */ /* reset to non-signaled state by calling gs_reset_event_sem. */ /* If it is auto-reset semaphore and ge_signal_event_sem was used but */ /* no thread was waiting then the sem remains signaled until a thread */ /* is released. */ if (es->predicate == 1) { /* conditional variable was signaled before we entered the wait */ if (es->manualReset == SD_FALSE) es->predicate = 0; /* simulate release of a waiting thread */ gs_mutex_free (&es->mutex); GLBSEM_LOG_FLOW2 ("GLBSEM gs_wait_event_sem: thread " S_FMT_PTR " returned from wait for es=" S_FMT_PTR " (on entry p=1)", thisThreadId, es); return (SD_SUCCESS); } /* If gs_pulse_event_sem was used the state of the semaphore should */ /* be always in non-signaled state when this function is entered. */ #if defined(DEBUG_SISCO) if (gs_track) startTime = sGetMsTime (); #endif /* set the absolute wait time */ if ( timeout >= 0 ) { tsDelta.tv_sec = timeout / 1000L; tsDelta.tv_nsec = (timeout % 1000L) * 1000000L; /* nanoseconds */ #if defined(_AIX) || (defined(__alpha) && !defined(__VMS)) /* obtain abosolute time for wakeup */ result = pthread_get_expiration_np (&tsDelta, &tsAbstime); if ( result != 0 ) { GLBSEM_LOG_ERR3 ("GLBSEM gs_wait_event_sem error: thread " S_FMT_PTR ", es=" S_FMT_PTR " (pthread_get_expiration_np failed result=%d)", thisThreadId, es, result); gs_mutex_free (&es->mutex); return (ret); } #else /* all other systems */ /* Get current time & add timeout to it. */ #if defined(linux) /* LINUX linker can't find "clock_gettime" so use "gettimeofday".*/ gettimeofday (&curtimeval,NULL); tsAbstime.tv_sec = curtimeval.tv_sec; /* convert timeval to timespec */ tsAbstime.tv_nsec = curtimeval.tv_usec*1000; #else clock_gettime (CLOCK_REALTIME, &tsAbstime); /* gives timespec, which we want*/ #endif tsAbstime.tv_sec += tsDelta.tv_sec; tsAbstime.tv_nsec += tsDelta.tv_nsec; /* adjust if (nsec) > 1000000000 */ if (tsAbstime.tv_nsec / 1000000000 > 0) { /* in this case, should be EXACTLY = 1 */ tsAbstime.tv_sec++; /* add 1 second */ tsAbstime.tv_nsec = tsAbstime.tv_nsec % 1000000000; } #endif /* all other systems */ } /* wait until condition signaled or timeout */ es->predicate = 0; while ( !es->predicate ) { if ( timeout < 0 ) /* wait indefinitely */ result = pthread_cond_wait (&es->cond, &es->mutex); else /* wait for a period of time, if timeout=0 then fun returns immediatelly */ result = pthread_cond_timedwait (&es->cond, &es->mutex, &tsAbstime); if ( result == 0 ) { if (es->predicate) { /* if gs_signal_event_sem used then state of predicate will */ /* remain set until exlicitly reset by gs_reset_event_sem. */ if (es->manualReset == SD_TRUE && es->predicate == 1) { /* do not reset the predicate */ } else es->predicate = 0; ret = SD_SUCCESS; /* cond var was signaled */ GLBSEM_LOG_FLOW2 ("GLBSEM gs_wait_event_sem: thread " S_FMT_PTR " returning from wait for es=" S_FMT_PTR " (success)", thisThreadId, es); break; /* exit while */ } else { if (es->manualReset == SD_TRUE) { /* On Windows manual-reset semaphore calling PulseEvent allows*/ /* to wake up all waiting threads. We will simulate this */ /* behavior here by ignoring the predicate=0 because other */ /* thread probably did reset it already. */ ret = SD_SUCCESS; /* cond var was signaled */ GLBSEM_LOG_FLOW2 ("GLBSEM gs_wait_event_sem: thread " S_FMT_PTR " returning from wait for es=" S_FMT_PTR ".", thisThreadId, es); break; /* exit while */ } else { /* On Windows the auto-reset semaphore will allow to wake */ /* only one thread, so we have to go back to waiting state */ /* for this thread. */ GLBSEM_LOG_FLOW2 ("GLBSEM gs_wait_event_sem: thread " S_FMT_PTR " spurious wake up for es=" S_FMT_PTR ".", thisThreadId, es); continue; } } } else if (result == ETIMEDOUT) { /* it is possible that the predicate was set shortly before timeout */ if (es->predicate) { ret = SD_SUCCESS; /* cond variable signaled */ GLBSEM_LOG_FLOW2 ("GLBSEM gs_wait_event_sem: thread " S_FMT_PTR " returned from wait for es=" S_FMT_PTR " (timeout but p=1).", thisThreadId, es); } else { ret = SD_TIMEOUT; /* timeout */ GLBSEM_LOG_FLOW3 ("GLBSEM gs_wait_event_sem: thread " S_FMT_PTR ", es=" S_FMT_PTR " (timeout of %d ms)", thisThreadId, es, timeout); } es->predicate = 0; /* clear for next time */ break; /* exit while */ } else { GLBSEM_LOG_ERR3 ("GLBSEM gs_wait_event_sem error: thread " S_FMT_PTR ", es=" S_FMT_PTR " (pthread_cond_(timed)wait failed result=%d)", thisThreadId, es, result); es->predicate = 0; /* clear for next time */ break; /* exit while */ } } /* end while */ /* release the mutex semaphore for the conditional variable */ gs_mutex_free (&es->mutex); #if defined(DEBUG_SISCO) if (gs_track) { endTime = sGetMsTime (); elapsedTime = endTime - startTime; if (elapsedTime > gs_hwEventTime) gs_hwEventTime = elapsedTime; } #endif /* defined(DEBUG_SISCO) */ return (ret); } /************************************************************************/ /* gs_wait_mult_event_sem */ /*----------------------------------------------------------------------*/ /* NOT IMPLEMENTED. */ /* Wait for event semaphore es until it becomes signaled or timeout */ /* occurrs. */ /* Parameters: */ /* numEvents number of event semaphores to wait for */ /* esTable pointer to table of event semaphore objects */ /* activity pointer to table where this function will mark */ /* proper index entry with SD_TRUE for the event */ /* semaphore that have been signaled */ /* timeout interval in milliseconds to wait for the es to */ /* be signaled, if -1L then the function will be */ /* blocked indefinitely until the event semaphore */ /* is signaled. */ /* Return values: */ /* SD_SUCCESS function successful */ /* SD_FAILURE error occurred */ /* SD_TIMEOUT timeout */ /************************************************************************/ #if 0 /* DEBUG: Not implemented on this platform. Is it needed? */ ST_RET gs_wait_mult_event_sem (ST_INT numEvents, ST_EVENT_SEM *esTable, ST_BOOLEAN *activity, ST_LONG timeout) { ST_RET ret = SD_FAILURE; return (ret); } #endif /************************************************************************/ /* _gs_sig_event_sem */ /*----------------------------------------------------------------------*/ /* Signal event semaphore es. */ /* pthread_cond_signal wakes up at least one thread that is currently */ /* blocked on the specified condition. The higher priority thread will */ /* wake up first. This is like Windows auto-reset semaphore. */ /* pthread_cond_broadcast wakes up all waiting threads on specified */ /* condition. This is like Windows manual-reset semaphore. */ /* Parameters: */ /* es event semaphore object (pointer) */ /* predicate value for the predicate to be set to. */ /* Return values: */ /* none */ /************************************************************************/ static ST_RET _gs_sig_event_sem (ST_EVENT_SEM es, ST_INT predicate) { ST_INT result = SD_FAILURE; #if defined(DEBUG_SISCO) ST_THREAD_ID thisThreadId = GET_THREAD_ID(); /* Let's see just who we are */ #endif if (!es) { GLBSEM_LOG_ERR1 ("GLBSEM _gs_sig_event_sem error: thread " S_FMT_PTR " (invalid es=NULL)", thisThreadId); return (result); } /* mutex for the specified condition variable must be locked before */ /* going changing predicate and signaling */ gs_mutex_get (&es->mutex); es->predicate = predicate; if (es->manualReset == SD_TRUE) result = pthread_cond_broadcast (&es->cond); else result = pthread_cond_signal (&es->cond); /* release the mutex semaphore for the conditional variable */ gs_mutex_free (&es->mutex); if (result != 0) { GLBSEM_LOG_ERR3 ("GLBSEM _gs_sig_event_sem error: thread " S_FMT_PTR ", es=" S_FMT_PTR " (pthread_cond_signal(broadcast) failed result=%d)", thisThreadId, es, result); } return (result); } /************************************************************************/ /* gs_signal_event_sem */ /*----------------------------------------------------------------------*/ /* Signal event semaphore es. */ /* This behaviour is similiar to Windows auto-reset event semaphore */ /* when SetEvent is used to signal. */ /* The condition's predicate will be reset by the woken thread, */ /* see gs_wait_event_sem. */ /* If no thread is waiting the predicate remains set but the signaling */ /* is not held. If new thread calls gs_wait_event_sem it will return */ /* without going to wait state because the predicate value is 1. */ /* Parameters: */ /* es event semaphore object (pointer) */ /* Return values: */ /* none */ /************************************************************************/ ST_VOID gs_signal_event_sem (ST_EVENT_SEM es) { ST_INT result; ST_INT predicate = 1; result = _gs_sig_event_sem (es, predicate); if (result == 0) { GLBSEM_LOG_FLOW2 ("GLBSEM gs_signal_event_sem: thread " S_FMT_PTR " signaled es=" S_FMT_PTR ".", GET_THREAD_ID(), es); } } /************************************************************************/ /* gs_pulse_event_sem */ /*----------------------------------------------------------------------*/ /* Signal event semaphore es. */ /* This behaviour is similiar to Windows auto-reset event semaphore */ /* when PulseEvent is used to signal. The condition's predicate will be */ /* reset by the woken thread, see gs_wait_event_sem. */ /* If no thread is waiting the predicate remains set but the signaling */ /* is not held. If a thread calls the gs_wait_event_sem it will go */ /* into wait state because the predicate value is 2. */ /* Parameters: */ /* es event semaphore object (pointer) */ /* Return values: */ /* none */ /************************************************************************/ ST_VOID gs_pulse_event_sem (ST_EVENT_SEM es) { ST_INT result; ST_INT predicate = 2; result = _gs_sig_event_sem (es, predicate); if (result == 0) { GLBSEM_LOG_FLOW2 ("GLBSEM gs_pulse_event_sem: thread " S_FMT_PTR " signaled es=" S_FMT_PTR ".", GET_THREAD_ID(), es); } } /************************************************************************/ /* gs_reset_event_sem */ /*----------------------------------------------------------------------*/ /* Reset event semaphore es. */ /* Parameters: */ /* es event semaphore object (pointer) */ /* Return values: */ /* none */ /************************************************************************/ ST_VOID gs_reset_event_sem (ST_EVENT_SEM es) { /* mutex for the specified condition variable must be locked before */ /* going changing predicate and signaling */ gs_mutex_get (&es->mutex); es->predicate = 0; /* release the mutex semaphore for the conditional variable */ gs_mutex_free (&es->mutex); } /************************************************************************/ /* gs_free_event_sem */ /*----------------------------------------------------------------------*/ /* Release resources taken by event semaphore es. */ /* Parameters: */ /* es event semaphore object (pointer) */ /* Return values: none */ /* none */ /************************************************************************/ ST_VOID gs_free_event_sem (ST_EVENT_SEM es) { ST_RET ret; ST_INT result; #if defined(DEBUG_SISCO) ST_THREAD_ID thisThreadId = GET_THREAD_ID(); /* Let's see just who we are */ #endif if (!es) { GLBSEM_LOG_ERR1 ("GLBSEM gs_free_event_sem error: thread " S_FMT_PTR " (invalid es=NULL)", thisThreadId); return; } /* free mutex */ ret = gs_mutex_destroy (&es->mutex); if ( ret != SD_SUCCESS) return; /* mutex probably busy, a thread is in the gs_wait_event_sem */ /* free the conditional variable */ result = pthread_cond_destroy (&es->cond); if (result != 0) { GLBSEM_LOG_ERR3 ("GLBSEM gs_free_event_sem error: thread " S_FMT_PTR ", es=" S_FMT_PTR " (pthread_cond_destroy failed result=%d)", thisThreadId, es, result); switch ( result ) { case EBUSY: GLBSEM_LOG_CERR0 ("result=EBUSY (program requested to destroy" " referenced condition variable)."); break; case EINVAL: GLBSEM_LOG_CERR0 ("result=EINVAL (invalid cond argument)."); break; } } else { GLBSEM_LOG_FLOW2 ("GLBSEM gs_free_event_sem: thread " S_FMT_PTR " released event sem es=" S_FMT_PTR ".", thisThreadId, es); } /* free this allocated pointer */ chk_free (es); } /*---*---*---*---*---*---*---*---*---*---*---*---*---*--*/ /* */ /* USER's THREAD FUNCTIONS for _AIX, __alpha */ /* */ /*---*---*---*---*---*---*---*---*---*---*---*---*---*--*/ /************************************************************************/ /* gs_start_thread */ /*----------------------------------------------------------------------*/ /* Start a new thread. */ /* Parameters: */ /* threadFunc pointer to thread function to run */ /* threadArg thread function argument */ /* threadHandleOut pointer where to return thread handle */ /* threadIdOut pointer where to return thread ID */ /* Return values: */ /* SD_SUCCESS function successful */ /* SD_FAILURE error occurred */ /************************************************************************/ ST_RET gs_start_thread (ST_THREAD_RET (*threadFunc) (ST_THREAD_ARG), ST_THREAD_ARG threadArg, ST_THREAD_HANDLE *threadHandleOut, ST_THREAD_ID *threadIdOut) { ST_RET ret; ST_INT result; ST_THREAD_HANDLE threadHandle; pthread_attr_t init_attr; /* set the thread parameters just in case the default are not set as */ /* we expecting */ result = pthread_attr_init (&init_attr); if (result != 0 ) { ret = SD_FAILURE; GLBSEM_LOG_ERR1 ("GLBSEM error: gs_start_thread pthread_attr_init failed" " (error=%d)", result); switch ( result ) { case EINVAL: GLBSEM_LOG_CERR0 ("errno=EINVAL (invalid attr argument)"); break; case ENOMEM: GLBSEM_LOG_CERR0 ("errno=ENOMEM (insufficient memory to create thread)"); break; } return (ret); } result = pthread_attr_setdetachstate (&init_attr, PTHREAD_CREATE_JOINABLE); if (result != 0 ) { ret = SD_FAILURE; GLBSEM_LOG_ERR1 ("GLBSEM error: gs_start_thread pthread_attr_setdetachstate failed" " (error=%d)", result); switch ( result ) { case EINVAL: GLBSEM_LOG_CERR0 ("errno=EINVAL (invalid detachstate)"); break; } return (ret); } /* The thread is created with the default attribute PTHREAD_CREATE_JOINABLE */ /* that allows us to wait until the thread terminates in the gs_wait_thread */ /* function. */ result = pthread_create (&threadHandle, /* pointer for thread pointer */ &init_attr, /* if NULL, use default thread attr */ threadFunc, /* thread funct to be executed */ threadArg); /* thread funct argument */ if (result == 0 ) { /* Thread created successfully */ ret = SD_SUCCESS; if (threadHandleOut != NULL) *threadHandleOut = threadHandle; if (threadIdOut != NULL) *threadIdOut = threadHandle; /* use thread handle as id */ GLBSEM_LOG_FLOW1 ("GLBSEM: gs_start_thread created thread threadHandle=" S_FMT_THREAD_HANDLE ".", threadHandle); } else { ret = SD_FAILURE; GLBSEM_LOG_ERR1 ("GLBSEM error: gs_start_thread create thread failed" " (error=%d)", result); switch ( result ) { case EAGAIN: GLBSEM_LOG_CERR0 ("errno=EAGAIN (insufficient resources to create" " thread, limit exceeded)"); break; case EINVAL: GLBSEM_LOG_CERR0 ("errno=EINVAL (invalid attr argument)"); break; case ENOMEM: GLBSEM_LOG_CERR0 ("errno=ENOMEM (insufficient memory to create thread)"); break; case EPERM: GLBSEM_LOG_CERR0 ("errno=EPERM (insufficient permission to create thread)"); break; } } return (ret); } /************************************************************************/ /* gs_wait_thread */ /*----------------------------------------------------------------------*/ /* Wait until thread with threadHandle terminates or timeout occurrs. */ /* On UNIX systems the is no option for timed wait. This function will */ /* wait until the thread is terminated. */ /* Parameters: */ /* threadHandle thread handle returned from gs_start_thread */ /* threadId thread ID returned from gs_start_thread */ /* timeout max time in milliseconds to wait for thread to */ /* terminate. IGNORED. */ /* Return values: */ /* SD_SUCCESS function successful */ /* SD_FAILURE error occurred */ /************************************************************************/ ST_RET gs_wait_thread (ST_THREAD_HANDLE threadHandle, ST_THREAD_ID threadId, ST_LONG timeout) { ST_RET ret; ST_INT result; result = pthread_join (threadHandle, NULL); if ( result == 0 ) { /* thread terminated successfully */ ret = SD_SUCCESS; GLBSEM_LOG_FLOW1 ("GLBSEM: pthread_join SUCCESS for thread threadHandle=" S_FMT_THREAD_HANDLE ".", threadHandle); } else { ret = SD_FAILURE; GLBSEM_LOG_ERR2 ("GLBSEM error: pthread_join failed for thread " S_FMT_THREAD_HANDLE "." " (error=%d)", threadHandle, result); switch ( result ) { case EINVAL: GLBSEM_LOG_CERR0 ("errno=EINVAL (thread is not joinable)"); break; case ESRCH: GLBSEM_LOG_CERR0 ("errno=ESRCH (invalid thread)"); break; case EDEADLK: GLBSEM_LOG_CERR0 ("errno=EDEADLK (deadlock, or thread specifies" " the calling thread)"); break; } } return (ret); } /************************************************************************/ /* gs_close_thread */ /*----------------------------------------------------------------------*/ /* Cleanup after thread terminated. */ /* Parameters: */ /* threadHandle thread handle ret from gs_start_thread()*/ /* Return values: */ /* SD_SUCCESS function successful */ /* SD_FAILURE error occurred */ /************************************************************************/ ST_RET gs_close_thread (ST_THREAD_HANDLE threadHandle) { ST_RET ret = SD_SUCCESS; /* nothing to clean up here */ return (ret); } #endif /* defined(S_MT_SUPPORT) */