1065 lines
38 KiB
C
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) */
|