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