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

1140 lines
36 KiB
C

/************************************************************************/
/* SISCO SOFTWARE MODULE HEADER *****************************************/
/************************************************************************/
/* (c) Copyright Systems Integration Specialists Company, Inc., */
/* 1997-2008, All Rights Reserved */
/* */
/* MODULE NAME : glbsem_w32.c */
/* PRODUCT(S) : */
/* */
/* MODULE DESCRIPTION : Multi-thread support for Windows ONLY. */
/* */
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */
/* */
/* MODIFICATION LOG : */
/* Date Who Rev Comments */
/* -------- --- ------ ------------------------------------------- */
/* 06/10/08 EJV 21 Ported to Windows Vista. */
/* 03/27/08 EJV 20 Use S_MAX_PATH instead of MAX_PATH. */
/* 01/29/08 EJV 19 Use S_FMT_* macros to log pointers & handles.*/
/* 05/23/07 DSF 18 Added dependency on advapi32.dll */
/* 06/29/06 MDE,EJV 17 Added UNICODE support (gs_translate_name). */
/* Del <process.h>, see sysincs.h. */
/* 04/12/05 DSF 16 Added refCount member to GS_MUTEX (Windows) */
/* 01/06/05 DSF 15 Added owner member to GS_MUTEX (Windows) */
/* 01/14/05 EJV 14 Reversed change. */
/* 07/21/04 DWL 13 Added ifdef so non debug configs would build.*/
/* 07/02/04 DSF 12 Always link in winmm.lib */
/* 05/21/04 DSF 11 Timeout log is now FLOW instead of NERR */
/* 04/19/04 DSF 10 gs_wait_thread () now returns SD_TIMEOUT on */
/* timeouts */
/* 12/29/03 ASK 09 enable logLastError, pass gle to logLastError*/
/* 12/03/03 EJV 08 gs_is_win_ver(): chg return ST_RET to ST_INT;*/
/* Add SD_WIN_VER_2003_AND_LATER, replaced */
/* SD_WIN_VER_NET with SD_WIN_VER_2003; */
/* 12/01/03 EJV 07 gs_is_win_ver: chk for corr ret 1, 0, -1. */
/* Named mutex, event: for 2000S w/terminal serv*/
/* chg from XP to SD_WIN_VER_2K_AND_LATER. */
/* 11/24/03 DSF 06 Spelling */
/* 11/04/03 JRB 05 Del gs_sleep (use sMsSleep). */
/* 06/20/03 EJV 04 Renamed gs_mutex_get to gs_mutex_get_tm. */
/* 06/12/03 EJV 03 Redesigned mutex sems implementation. */
/* 06/10/03 EJV 02 Added gs_named_mutex_xxx functions. */
/* 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"
#ifdef WIN32
#pragma comment(linker, "/defaultlib:winmm.lib")
#pragma comment(linker, "/defaultlib:advapi32.lib")
/************************************************************************/
/* 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_VOID logLastError (DWORD errCode);
/*---*---*---*---*---*---*---*---*---*---*---*---*---*--*/
/* */
/* MUTEX SEMAPHORE FUNCTIONS for _WIN32 */
/* */
/*---*---*---*---*---*---*---*---*---*---*---*---*---*--*/
/************************************************************************/
/* gs_mutex_create */
/*----------------------------------------------------------------------*/
/* Initialize the mutex semaphore ms. */
/* CRITICAL_SECTION is used for mutex semaphore for faster operation. */
/* Parameters: */
/* ms pointer to mutex object */
/* Return values: */
/* SD_SUCCESS function successful */
/* SD_FAILURE error occurred */
/************************************************************************/
ST_RET gs_mutex_create (ST_MUTEX_SEM *ms)
{
ms->mutexType = GS_MUTEX_UNNAMED;
ms->owner = 0;
ms->refCount = 0;
InitializeCriticalSection (&ms->u.cs);
return (SD_SUCCESS);
}
/************************************************************************/
/* gs_translate_name */
/*----------------------------------------------------------------------*/
/* This function, if necessary, will prepend "Global\\" to the name and */
/* convert the name to Unicode. */
/* name ptr to name str (named mutex or sem). */
/* newName, wideName ptr to output buffer. */
/* bufSize output buffer size. */
/* */
/* !NOTE: The UNICODE was not tested. */
/************************************************************************/
#if defined (UNICODE)
ST_RET gs_translate_name (ST_CHAR *name, WCHAR *wideName, ST_UINT bufSize)
#else
ST_RET gs_translate_name (ST_CHAR *name, ST_CHAR *newName, ST_UINT bufSize)
#endif
{
#if defined (UNICODE)
ST_CHAR tmpName[S_MAX_PATH]; /* max size that a mutex/sem name can have */
#endif
ST_UINT maxLen;
ST_BOOLEAN bPrepend = SD_FALSE;
/* NOTE: do not put any logging to this function. It is used in DLLs. */
/* compute the max name size that can be handled & set bPrepend flag */
#if defined (UNICODE)
maxLen = sizeof(tmpName) - 1;
#else
maxLen = bufSize - 1;
#endif
if (gs_is_win_ver (SD_WIN_VER_2K_AND_LATER) == 1)
if (memcmp (name, "Global\\", strlen ("Global\\")) != 0)
{
/* need to prepend "Global\\" */
maxLen = maxLen - strlen ("Global\\");
bPrepend = SD_TRUE;
}
/* make sure we got buffer big enough for the resulting prepended name */
if (strlen(name) > maxLen)
return (SD_FAILURE);
#if defined (UNICODE)
{
/* copy the name to temporary buffer and prepend "Global\\" if necessary */
if (bPrepend)
sprintf (tmpName, "Global\\%s", name);
else
strcpy (tmpName, name);
/* Convert ANSI name to Unicode (error will be set if bufSize is too small) */
if (MultiByteToWideChar (CP_ACP, 0, tmpName, strlen (tmpName)+1, wideName, bufSize) == 0)
return (SD_FAILURE);
}
#else /* !defined (UNICODE) */
if (bPrepend)
sprintf (newName, "Global\\%s", name);
else
strcpy (newName, name);
#endif /* !defined (UNICODE) */
return (SD_SUCCESS);
}
/************************************************************************/
/* gs_named_mutex_create */
/*----------------------------------------------------------------------*/
/* Create/Open NAMED mutex. */
/* On Windows XP this function prepends 'Global\\' to the mutex name */
/* and sets the security descriptor in the way that the mutex can */
/* be accessed by processes in different user spaces (in Windows XP Fast*/
/* User Switching). */
/* For each call to this function the gs_named_mutex_destroy must be */
/* called. */
/* Parameters: */
/* ms pointer where to return handle to named mutex */
/* name pointer to mutex name. */
/* Return values: */
/* SD_SUCCESS function successful */
/* SD_FAILURE error occurred */
/************************************************************************/
ST_RET gs_named_mutex_create (ST_MUTEX_SEM *ms, ST_CHAR *name)
{
ST_RET ret = SD_SUCCESS;
HANDLE hMutex = NULL;
#if defined (UNICODE)
WCHAR mutexName[S_MAX_PATH];
#else
ST_CHAR mutexName[S_MAX_PATH];
#endif
if (ms == NULL || name == NULL)
{
#if defined(DEBUG_SISCO)
GLBSEM_LOG_ERR0 ("GLBSEM error: gs_named_mutex_create() failed ms=NULL or name=NULL");
#endif
return (SD_FAILURE);
}
ret = gs_translate_name (name, mutexName, (ST_UINT) (sizeof(mutexName)/sizeof(mutexName[0])));
if (ret != SD_SUCCESS)
{
#if defined(DEBUG_SISCO)
GLBSEM_LOG_ERR1 ("GLBSEM error: gs_translate_name () failed, name='%s'.", name);
#endif
return (ret);
}
/* set the mutex type */
ms->mutexType = GS_MUTEX_NAMED;
ms->owner = 0;
ms->refCount = 0;
if (gs_is_win_ver (SD_WIN_VER_2K_AND_LATER) == 1)
{
PSECURITY_DESCRIPTOR psd;
SECURITY_ATTRIBUTES sa;
/* This code allows the mutex to be accessed from different */
/* applications in different users (Windows XP Fast User Switching). */
psd = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (psd == NULL)
return (SD_FAILURE);
if (!InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION))
{
LocalFree (psd);
return (SD_FAILURE);
}
if (!SetSecurityDescriptorDacl(psd, TRUE, (PACL) NULL, FALSE))
{
LocalFree (psd);
return (SD_FAILURE);
}
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = psd;
sa.bInheritHandle = TRUE;
hMutex = CreateMutex (&sa, /* security attributes */
SD_FALSE, /* FALSE is initially not owned */
mutexName); /* object name */
if (hMutex == NULL)
{
#if defined(DEBUG_SISCO)
DWORD gle = GetLastError ();
GLBSEM_LOG_ERR2 ("GLBSEM error: CreateMutex failed GLE=%d for %s",
(unsigned int) gle, mutexName);
#endif
ret = SD_FAILURE;
}
LocalFree (psd);
}
else
{
/* this is Win 98, NT or 2000 */
hMutex = CreateMutex (NULL, /* no security attributes */
SD_FALSE, /* FALSE is initially not owned */
mutexName); /* object name */
if (hMutex == NULL)
{
#if defined(DEBUG_SISCO)
DWORD gle = GetLastError ();
GLBSEM_LOG_ERR2 ("GLBSEM error: CreateMutex failed GLE=%d for %s",
(unsigned int) gle, mutexName);
#endif
ret = SD_FAILURE;
}
}
ms->u.hMutex = hMutex; /* return the handle to user */
return (ret);
}
/************************************************************************/
/* gs_mutex_get_tm */
/*----------------------------------------------------------------------*/
/* Lock the mutex semaphore ms. */
/* This function uses the gs_wait_event_sem to wait for ownership of */
/* the named mutex. The named mutex object can be also passed to the */
/* gs_wait_mult_event_sem function when waiting for multiple objects is */
/* required. */
/* */
/* Parameters: */
/* ms pointer to mutex object */
/* timeout Interval in milliseconds to wait for the named */
/* mutex to be owned, if -1L then the function will*/
/* be blocked indefinitely until the named mutex */
/* is owned. */
/* The timeout parameter is ignored for unnamed */
/* mutex. The function will wait indefinetely until*/
/* the mutex is owned. */
/* Return values: */
/* none */
/* SD_SUCCESS function successful */
/* SD_FAILURE error occurred */
/* SD_TIMEOUT timeout */
/* */
/* CRITICAL: gs_mutex_get_tm must NOT call any slog, stime, or mem_chk */
/* functions. These functions call gs_mutex_get_tm causing */
/* an infinite loop. Logging in the named mutex code is OK. */
/************************************************************************/
ST_RET gs_mutex_get_tm (ST_MUTEX_SEM *ms, ST_LONG timeout)
{
ST_RET ret = SD_SUCCESS;
if (!gs_already_inited) /* Make sure gs is initialized. */
gs_init ();
if (ms->mutexType == GS_MUTEX_UNNAMED)
/* ! do not put logging here to avoid infinite loop */
EnterCriticalSection (&ms->u.cs);
else
/* named mutex */
ret = gs_wait_event_sem ((ST_EVENT_SEM) ms->u.hMutex, timeout);
if (ret == SD_SUCCESS)
{
ms->owner = GET_THREAD_ID ();
++ms->refCount;
}
return (ret);
}
/************************************************************************/
/* gs_mutex_free */
/*----------------------------------------------------------------------*/
/* Unlock the mutex semaphore ms. */
/* Parameters: */
/* ms pointer to mutex object */
/* 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. Logging in the named mutex code is OK. */
/************************************************************************/
ST_RET gs_mutex_free (ST_MUTEX_SEM *ms)
{
ST_RET ret = SD_SUCCESS;
--ms->refCount;
if (ms->refCount == 0)
ms->owner = 0;
if (ms->mutexType == GS_MUTEX_UNNAMED)
/* ! do not put logging here to avoid infinite loop */
LeaveCriticalSection (&ms->u.cs);
else
{
/* named mutex */
if (ReleaseMutex (ms->u.hMutex) == SD_FALSE)
{
#if defined(DEBUG_SISCO)
DWORD gle = GetLastError ();
GLBSEM_LOG_ERR2 ("GLBSEM error: ReleaseMutex failed for hMutex=" S_FMT_HANDLE " (GLE=%d)",
ms->u.hMutex, (unsigned int) gle);
#endif
ret = SD_FAILURE;
}
}
return (ret);
}
/************************************************************************/
/* gs_mutex_destroy */
/*----------------------------------------------------------------------*/
/* Free all resources allocated for the MUTEX semaphore ms. */
/* Parameters: */
/* ms pointer to mutex object */
/* Return values: */
/* SD_SUCCESS function successful */
/* SD_FAILURE error occurred */
/************************************************************************/
ST_RET gs_mutex_destroy (ST_MUTEX_SEM *ms)
{
ST_RET ret = SD_SUCCESS;
if (ms->mutexType == GS_MUTEX_UNNAMED)
DeleteCriticalSection (&ms->u.cs);
else
{
/* named mutex */
if (CloseHandle (ms->u.hMutex) == SD_FALSE)
{
#if defined(DEBUG_SISCO)
DWORD gle = GetLastError ();
GLBSEM_LOG_ERR2 ("GLBSEM error: CloseHandle failed for hMutex=" S_FMT_HANDLE " (GLE=%d)",
ms->u.hMutex, (unsigned int) gle);
#endif
ret = SD_FAILURE;
}
}
return (ret);
}
/*---*---*---*---*---*---*---*---*---*---*---*---*---*--*/
/* */
/* USER's EVENT SEMAPHORE FUNCTIONS for _WIN32 */
/* */
/*---*---*---*---*---*---*---*---*---*---*---*---*---*--*/
/************************************************************************/
/* gs_get_event_sem */
/*----------------------------------------------------------------------*/
/* Create a "manual-reset" or "auto-reset" event semaphore. */
/* Parameters: */
/* manualReset SD_TRUE or SD_FALSE */
/* Return values: */
/* ST_EVENT_SEM handle to event semaphore object */
/************************************************************************/
ST_EVENT_SEM gs_get_event_sem (ST_BOOLEAN manualReset)
{
ST_EVENT_SEM retEventSem;
retEventSem = CreateEvent(NULL, // no security attributes
manualReset, // manual-reset event
FALSE, // initial state is signaled
NULL // object name
);
if (retEventSem == NULL)
GLBSEM_LOG_ERR1 ("GLBSEM error: CreateEvent failed for event semaphore, rc = %d", GetLastError ());
return (retEventSem);
}
/************************************************************************/
/* gs_get_named_event_sem */
/*----------------------------------------------------------------------*/
/* Create a "manual-reset" or "auto-reset" NAMED event semaphore. */
/* On Windows XP this function prepends 'Global\\' to the semaphore name*/
/* and sets the security descriptor in the way that the semaphore can */
/* be accessed by processes in different user spaces (in Windows XP Fast*/
/* User Switching). */
/* Parameters: */
/* name pointer to semaphore name. */
/* manualReset SD_TRUE or SD_FALSE */
/* Return values: */
/* ST_EVENT_SEM handle to named event semaphore object */
/************************************************************************/
ST_EVENT_SEM gs_get_named_event_sem (ST_CHAR *name, ST_BOOLEAN manualReset)
{
ST_EVENT_SEM retEventSem = NULL;
#if defined (UNICODE)
WCHAR semName[S_MAX_PATH];
#else
ST_CHAR semName[S_MAX_PATH];
#endif
/* NOTE: do not put any logging to this function. It is used in DLLs. */
if (gs_translate_name (name, semName, (ST_UINT) (sizeof(semName)/sizeof(semName[0])))
!= SD_SUCCESS)
return (NULL);
if (gs_is_win_ver (SD_WIN_VER_2K_AND_LATER) == 1)
{
PSECURITY_DESCRIPTOR psd;
SECURITY_ATTRIBUTES sa;
/* This code allows the event semaphore to be accessed from different */
/* applications in different users (Windows XP Fast User Switching). */
psd = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (psd == NULL)
return (NULL);
if (!InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION))
{
LocalFree (psd);
return (NULL);
}
if (!SetSecurityDescriptorDacl(psd, TRUE, (PACL) NULL, FALSE))
{
LocalFree (psd);
return (NULL);
}
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = psd;
sa.bInheritHandle = TRUE;
retEventSem = CreateEvent(&sa, /* security attributes */
manualReset, /* manual-reset event */
SD_FALSE, /* initial state is non-signaled */
semName); /* object name */
LocalFree (psd);
}
else
{
/* this is Win 98, NT or 2000 */
retEventSem = CreateEvent (NULL, manualReset, SD_FALSE, semName);
}
return (retEventSem);
}
/************************************************************************/
/* 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 */
/* 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 */
/************************************************************************/
ST_RET gs_wait_event_sem (ST_EVENT_SEM es, ST_LONG timeout)
{
ST_RET ret;
DWORD rc;
#if defined(DEBUG_SISCO)
DWORD gle;
ST_DOUBLE startTime;
ST_DOUBLE endTime;
ST_DOUBLE elapsedTime;
#endif
ST_THREAD_ID thisThreadId;
/* Let's see just who we are */
thisThreadId = GET_THREAD_ID();
#if defined(DEBUG_SISCO)
if (gs_track)
startTime = sGetMsTime ();
#endif
rc = WaitForSingleObject (es, timeout);
#if defined(DEBUG_SISCO)
if (gs_track)
{
endTime = sGetMsTime ();
elapsedTime = endTime - startTime;
if (elapsedTime > gs_hwEventTime)
gs_hwEventTime = elapsedTime;
}
#endif
if (rc == WAIT_FAILED)
{
#if defined(DEBUG_SISCO)
gle = GetLastError ();
GLBSEM_LOG_ERR3 ("GLBSEM error: WaitEvent rc=0x%04x, GLE=0x%04x, ThreadId=0x%08x",
(unsigned int) rc, (unsigned int)gle, thisThreadId);
logLastError (gle);
#endif
ret = SD_FAILURE;
}
else if (rc == WAIT_TIMEOUT)
ret = SD_TIMEOUT;
else
ret = SD_SUCCESS;
return (ret);
}
/************************************************************************/
/* gs_wait_mult_event_sem */
/*----------------------------------------------------------------------*/
/* Wait for event semaphores in table esTable until one of them 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: */
/* 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 */
/************************************************************************/
ST_RET gs_wait_mult_event_sem (ST_INT numEvents, ST_EVENT_SEM *esTable,
ST_BOOLEAN *activity, ST_LONG timeout)
{
ST_RET ret;
DWORD rc;
ST_INT i;
#if defined(DEBUG_SISCO)
DWORD gle;
ST_DOUBLE startTime;
ST_DOUBLE endTime;
ST_DOUBLE elapsedTime;
#endif
ST_THREAD_ID thisThreadId;
/* Let's see just who we are */
thisThreadId = GET_THREAD_ID();
#if defined(DEBUG_SISCO)
if (gs_track)
startTime = sGetMsTime ();
#endif
rc = WaitForMultipleObjects (numEvents, esTable, FALSE, timeout);
#if defined(DEBUG_SISCO)
if (gs_track)
{
endTime = sGetMsTime ();
elapsedTime = endTime - startTime;
if (elapsedTime > gs_hwEventTime)
gs_hwEventTime = elapsedTime;
}
#endif
/* make sure activity array is zero'd out */
memset (activity, '\x0', sizeof (ST_BOOLEAN) * numEvents);
i = rc - WAIT_OBJECT_0;
if ((i >= 0) && (i < numEvents))
{
activity[i] = SD_TRUE;
ret = SD_SUCCESS;
}
else if (rc == WAIT_FAILED)
{
#if defined(DEBUG_SISCO)
gle = GetLastError ();
GLBSEM_LOG_ERR3 ("GLBSEM error: WaitEvent rc=0x%04x, GLE=0x%04x, ThreadId=0x%08x",
(unsigned int) rc, (unsigned int)gle, thisThreadId);
logLastError (gle);
#endif
ret = SD_FAILURE;
}
else if (rc == WAIT_TIMEOUT)
ret = SD_TIMEOUT;
else
ret = SD_SUCCESS;
return (ret);
}
/************************************************************************/
/* gs_signal_event_sem */
/*----------------------------------------------------------------------*/
/* Signal event semaphore es. */
/* Manual-Reset: all waiting threads are released, es remains signaled */
/* until reset explicitly by call to ResetEvent. */
/* Auto-Reset: first waiting thread is released and es will be reset */
/* to non-signaled state. If no thread is waiting the es */
/* remains in signaled state unless ResetEvent is called. */
/* Parameters: */
/* es event semaphore object */
/* Return values: */
/* none */
/************************************************************************/
ST_VOID gs_signal_event_sem (ST_EVENT_SEM es)
{
BOOL rc;
#if defined(DEBUG_SISCO)
DWORD gle;
#endif
rc = SetEvent(es);
#if defined(DEBUG_SISCO)
if (rc == FALSE)
{
gle = GetLastError ();
GLBSEM_LOG_ERR1 ("GLBSEM error: SetEvent GLE=0x%04x", (unsigned int) gle);
logLastError (gle);
}
#endif
}
/************************************************************************/
/* gs_pulse_event_sem */
/*----------------------------------------------------------------------*/
/* Uses PulseEvent to signal the event semaphore es. */
/* Manual-Reset: all waiting threads are released, es state changes to */
/* non-signaled. */
/* Auto-Reset: first waiting thread is released and es will be reset */
/* to non-signaled state even if no thread is waiting. */
/* Parameters: */
/* es event semaphore object */
/* Return values: */
/* none */
/************************************************************************/
ST_VOID gs_pulse_event_sem (ST_EVENT_SEM es)
{
BOOL rc;
#if defined(DEBUG_SISCO)
DWORD gle;
#endif
rc = PulseEvent(es);
#if defined(DEBUG_SISCO)
if (rc == FALSE)
{
gle = GetLastError ();
GLBSEM_LOG_ERR1 ("GLBSEM error: PulseEvent GLE=0x%04x", (unsigned int) gle);
logLastError (gle);
}
#endif
}
/************************************************************************/
/* gs_reset_event_sem */
/*----------------------------------------------------------------------*/
/* Reset event semaphore es. */
/* This function should be called after function gs_wait_event_sem or */
/* gs_wait_mult_event_sem return SD_SUCCESS and the signaled event */
/* semaphore is a "manual-reset" semaphore. */
/* Parameters: */
/* es event semaphore object */
/* Return values: */
/* none */
/************************************************************************/
ST_VOID gs_reset_event_sem (ST_EVENT_SEM es)
{
BOOL rc;
#if defined(DEBUG_SISCO)
DWORD gle;
#endif
rc = ResetEvent (es);
#if defined(DEBUG_SISCO)
if (rc == FALSE)
{
gle = GetLastError ();
GLBSEM_LOG_ERR1 ("GLBSEM error: ResetEvent gle=0x%04x", (unsigned int)gle);
logLastError (gle);
}
#endif
}
/************************************************************************/
/* gs_free_event_sem */
/*----------------------------------------------------------------------*/
/* Release resources taken be event semaphore es. */
/* Parameters: */
/* es event semaphore object */
/* Return values: */
/* none */
/************************************************************************/
ST_VOID gs_free_event_sem (ST_EVENT_SEM es)
{
BOOL rc;
#if defined(DEBUG_SISCO)
DWORD gle;
#endif
rc = CloseHandle (es);
#if defined(DEBUG_SISCO)
if (rc == FALSE)
{
gle = GetLastError ();
GLBSEM_LOG_ERR1 ("GLBSEM error: CloseHandle GLE=0x%04x", (unsigned int)gle);
logLastError (gle);
}
#endif
}
/*---*---*---*---*---*---*---*---*---*---*---*---*---*--*/
/* */
/* USER's THREAD FUNCTIONS for _WIN32 */
/* */
/*---*---*---*---*---*---*---*---*---*---*---*---*---*--*/
/************************************************************************/
/* gs_start_thread */
/*----------------------------------------------------------------------*/
/* Start a new thread. The thread handle should be closed after the */
/* thread terminates by calling the gs_close_thread(). The function */
/* gs_wait_thread can be used to wait until a thread terminates. */
/* Parameters: */
/* threadFunc pointer to thread function to run */
/* threadArg thread function argument list */
/* 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 (ST_THREAD_CALL_CONV *threadFunc) (ST_THREAD_ARG),
ST_THREAD_ARG threadArg,
ST_THREAD_HANDLE *threadHandleOut,
ST_THREAD_ID *threadIdOut)
{
ST_RET ret;
ST_THREAD_HANDLE threadHandle;
ST_THREAD_ID threadId;
threadHandle = _beginthreadex (NULL, /* No security */
0, /* Use def stack size */
threadFunc,
threadArg, /* Argument for thread */
0, /* Creation flags, 0 for running initial state */
&threadId); /* Thread identifier */
if (threadHandle == 0)
{
GLBSEM_LOG_ERR1 ("GLBSEM error: gs_start_thread _beginthreadex failed errno=%d",
errno);
ret = SD_FAILURE;
}
else
{
ret = SD_SUCCESS;
if (threadHandleOut != NULL)
*threadHandleOut = threadHandle;
if (threadIdOut != NULL)
*threadIdOut = threadId;
GLBSEM_LOG_FLOW2 ("GLBSEM: gs_start_thread created thread threadHandle=" S_FMT_THREAD_HANDLE
" threadId=0x%08x", threadHandle, threadId);
}
return (ret);
}
/************************************************************************/
/* gs_wait_thread */
/*----------------------------------------------------------------------*/
/* Wait until thread with threadHandle terminates or timeout occurrs. */
/* 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. */
/* 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;
DWORD rc;
#if defined(DEBUG_SISCO)
DWORD gle;
#endif
rc = WaitForSingleObject ((HANDLE)threadHandle, timeout);
if (rc != WAIT_OBJECT_0)
{
#if defined(DEBUG_SISCO)
gle = GetLastError ();
#endif
if (rc == WAIT_TIMEOUT)
{
ret = SD_TIMEOUT;
/* WAIT_FAILED or WAIT_TIMEOUT */
#if defined(DEBUG_SISCO)
GLBSEM_LOG_FLOW3 ("GLBSEM: Timeout=%d ms in Wait Thread threadHandle=" S_FMT_THREAD_HANDLE ", "
"threadId=0x%08x", timeout, threadHandle, threadId);
#endif
}
else
{
#if defined(DEBUG_SISCO)
GLBSEM_LOG_ERR3 ("GLBSEM error: Wait Thread threadHandle=" S_FMT_THREAD_HANDLE ", rc=0x%04x, GLE=0x%04x",
threadHandle, (unsigned int)rc, (unsigned int)gle);
logLastError (gle);
#endif
ret = SD_FAILURE;
}
}
else
ret = SD_SUCCESS;
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;
#if defined(DEBUG_SISCO)
DWORD gle;
#endif
if (threadHandle)
{
if (CloseHandle ((HANDLE)threadHandle) == 0)
{
#if defined(DEBUG_SISCO)
gle = GetLastError ();
GLBSEM_LOG_ERR1 ("GLBSEM error: Close Thread GLE=0x%04x", (unsigned int)gle);
#endif
ret = SD_FAILURE;
}
}
else
{
GLBSEM_LOG_ERR1 ("GLBSEM error: Close Thread invalid threadHandle=" S_FMT_THREAD_HANDLE ".",
threadHandle);
ret = SD_FAILURE;
}
return (ret);
}
/************************************************************************/
/* gs_set_thread_name */
/*----------------------------------------------------------------------*/
/* Start a new thread. */
/* Parameters: */
/* threadId ID of Thread whose name is to be set */
/* -1 if name is to be set for calling */
/* thread */
/* pThreadName Name to set */
/************************************************************************/
#define THREADNAME_EXCEPT_ID 0x406D1388
#define THREADNAME_INFO_TYPE 0x1000
typedef struct tagTHREADNAME_INFO
{
ST_LONG type;
ST_CHAR *pName;
ST_THREAD_ID threadId;
LONG flags;
} THREADNAME_INFO;
ST_VOID gs_set_thread_name (ST_THREAD_ID threadId, ST_CHAR *pThreadName)
{
THREADNAME_INFO info;
info.type = THREADNAME_INFO_TYPE;
info.pName = pThreadName;
info.threadId = threadId;
info.flags = 0;
__try
{
#if (_MSC_VER >= 1300)
RaiseException (THREADNAME_EXCEPT_ID, 0,
sizeof (info) / sizeof (ST_LONG), (ULONG_PTR *) &info);
#else
RaiseException (THREADNAME_EXCEPT_ID, 0,
sizeof (info) / sizeof (ST_LONG), (DWORD *) &info);
#endif
}
__except (EXCEPTION_CONTINUE_EXECUTION)
{
}
}
/*---*---*---*---*---*---*---*---*---*---*---*---*---*--*/
/* */
/* Misc. FUNCTIONS for _WIN32 */
/* */
/*---*---*---*---*---*---*---*---*---*---*---*---*---*--*/
/************************************************************************/
/* gs_is_win_ver */
/*----------------------------------------------------------------------*/
/* Accesses the OS version of the running system and checks if the */
/* version is ver. */
/* This function is compatible with Windows 95 and above. */
/* Parameters: */
/* ST_UINT ver see SD_WIN_* choices in glbsem.h */
/* Return: */
/* 1 If OS version is ver */
/* 0 If OS version is not ver */
/* -1 If could not access OS version info or ver invalid */
/************************************************************************/
ST_INT gs_is_win_ver (ST_UINT ver)
{
ST_INT ret = 0;
OSVERSIONINFO OsVerInfo; /* supported on Win 95 and up */
/* NOTE: do not put any logging to this function. It is used in DLLs. */
OsVerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
if (GetVersionEx (&OsVerInfo) == 0)
return (-1);
switch (ver)
{
case SD_WIN_VER_95_98_Me: /* 95, 98, Me */
if (OsVerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
ret = 1;
break;
case SD_WIN_VER_NT_AND_LATER: /* NT 3.51, NT 4.0 and above */
if (OsVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
ret = 1;
break;
case SD_WIN_VER_2K_AND_LATER: /* 2000 and above */
if (OsVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
((OsVerInfo.dwMajorVersion == 5 && OsVerInfo.dwMinorVersion >= 0) ||
OsVerInfo.dwMajorVersion > 5))
ret = 1;
break;
case SD_WIN_VER_XP_AND_LATER: /* XP and above */
if (OsVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
((OsVerInfo.dwMajorVersion == 5 && OsVerInfo.dwMinorVersion >= 1) ||
OsVerInfo.dwMajorVersion > 5))
ret = 1;
break;
case SD_WIN_VER_2003_AND_LATER: /* 2003 and above */
if (OsVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
((OsVerInfo.dwMajorVersion == 5 && OsVerInfo.dwMinorVersion >= 2) ||
OsVerInfo.dwMajorVersion > 5))
ret = 1;
break;
case SD_WIN_VER_VISTA_AND_LATER: /* Vista and above */
if (OsVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
((OsVerInfo.dwMajorVersion == 6 && OsVerInfo.dwMinorVersion >= 0) ||
OsVerInfo.dwMajorVersion > 6))
ret = 1;
break;
case SD_WIN_VER_95:
if (OsVerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
OsVerInfo.dwMajorVersion == 4 && OsVerInfo.dwMinorVersion == 0)
ret = 1;
break;
case SD_WIN_VER_98:
if (OsVerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
OsVerInfo.dwMajorVersion == 4 && OsVerInfo.dwMinorVersion == 10)
ret = 1;
break;
case SD_WIN_VER_Me:
if (OsVerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
OsVerInfo.dwMajorVersion == 4 && OsVerInfo.dwMinorVersion == 90)
ret = 1;
break;
case SD_WIN_VER_NT_351:
if (OsVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
OsVerInfo.dwMajorVersion == 3 && OsVerInfo.dwMinorVersion == 51)
ret = 1;
break;
case SD_WIN_VER_NT_40:
if (OsVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
OsVerInfo.dwMajorVersion == 4 && OsVerInfo.dwMinorVersion == 0)
ret = 1;
break;
case SD_WIN_VER_2000:
if (OsVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
OsVerInfo.dwMajorVersion == 5 && OsVerInfo.dwMinorVersion == 0)
ret = 1;
break;
case SD_WIN_VER_XP:
if (OsVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
OsVerInfo.dwMajorVersion == 5 && OsVerInfo.dwMinorVersion == 1)
ret = 1;
break;
case SD_WIN_VER_2003:
if (OsVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
OsVerInfo.dwMajorVersion == 5 && OsVerInfo.dwMinorVersion == 2)
ret = 1;
break;
case SD_WIN_VER_VISTA: /* Vista workstation or Longhorn server */
if (OsVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
OsVerInfo.dwMajorVersion == 6 && OsVerInfo.dwMinorVersion == 0)
ret = 1;
break;
default:
ret = -1; /* invalid ver */
}
return (ret);
}
/************************************************************************/
/* logLastError */
/*----------------------------------------------------------------------*/
/* Parameters: */
/* Return values: */
/************************************************************************/
static ST_VOID logLastError (DWORD errCode)
{
LPVOID lpMsgBuf;
DWORD len;
len = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
errCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL);
if(len == 0) /* FormatMessage failed... */
return;
GLBSEM_LOG_CERR1 (" -> %s", lpMsgBuf);
// Free the buffer.
LocalFree( lpMsgBuf );
}
#endif