Files
microser/mmslib/util/glbsem_unix.c
2026-06-15 15:48:16 +08:00

1065 lines
38 KiB
C

/************************************************************************/
/* 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) */