fixed potential race during init

This commit is contained in:
Jeff Hill
2003-09-03 22:52:48 +00:00
parent e7d51c5e30
commit 0dd7efb4a2

View File

@@ -37,28 +37,27 @@
#include "epicsAssert.h"
#include "ellLib.h"
typedef struct win32ThreadGlobal {
CRITICAL_SECTION mutex;
ELLLIST threadList;
DWORD tlsIndexThreadLibraryEPICS;
} win32ThreadGlobal;
typedef struct win32ThreadParam {
ELLNODE node;
HANDLE handle;
EPICSTHREADFUNC funptr;
void *parm;
char *pName;
void * parm;
char * pName;
DWORD id;
unsigned epicsPriority;
char isSuspended;
} win32ThreadParam;
static ELLLIST threadList;
static DWORD tlsIndexThreadLibraryEPICS = 0xFFFFFFFF;
typedef struct epicsThreadPrivateOSD {
DWORD key;
} epicsThreadPrivateOSD;
static HANDLE win32ThreadGlobalMutex = 0;
static int win32ThreadInitOK = 0;
#define osdOrdinaryPriorityStateCount 5u
static const int osdOrdinaryPriorityList [osdOrdinaryPriorityStateCount] =
{
@@ -88,27 +87,94 @@ static const int osdRealtimePriorityList [osdRealtimePriorityStateCount] =
6 // allowed on >= W2k, but no #define supplied
};
/*
* fetchWin32ThreadGlobal ()
* Search for "Synchronization and Multiprocessor Issues" in ms doc
* to understand why this is necessary and why this works on smp systems.
*/
static win32ThreadGlobal * fetchWin32ThreadGlobal ( void )
{
void threadCleanupWIN32 ( void );
static win32ThreadGlobal * pWin32ThreadGlobal = 0;
static LONG initStarted = 0;
static LONG initCompleted = 0;
int crtlStatus;
LONG started;
LONG done;
done = InterlockedCompareExchange ( & initCompleted, 0, 0 );
if ( done ) {
return pWin32ThreadGlobal;
}
started = InterlockedCompareExchange ( & initStarted, 0, 1 );
if ( started ) {
unsigned tries = 0u;
while ( ! InterlockedCompareExchange ( & initCompleted, 0, 0 ) ) {
/*
* I am not fond of busy loops, but since this will
* collide very infrequently and this is the lowest
* level init then perhaps this is ok
*/
Sleep ( 1 );
if ( tries++ > 1000 ) {
return 0;
}
}
return pWin32ThreadGlobal;
}
pWin32ThreadGlobal = ( win32ThreadGlobal * )
calloc ( 1, sizeof ( * pWin32ThreadGlobal ) );
if ( ! pWin32ThreadGlobal ) {
InterlockedExchange ( & initStarted, 0 );
return 0;
}
InitializeCriticalSection ( & pWin32ThreadGlobal->mutex );
ellInit ( & pWin32ThreadGlobal->threadList );
pWin32ThreadGlobal->tlsIndexThreadLibraryEPICS = TlsAlloc();
if ( pWin32ThreadGlobal->tlsIndexThreadLibraryEPICS == 0xFFFFFFFF ) {
DeleteCriticalSection ( & pWin32ThreadGlobal->mutex );
free ( pWin32ThreadGlobal );
pWin32ThreadGlobal = 0;
return 0;
}
crtlStatus = atexit ( threadCleanupWIN32 );
if ( crtlStatus ) {
TlsFree ( pWin32ThreadGlobal->tlsIndexThreadLibraryEPICS );
DeleteCriticalSection ( & pWin32ThreadGlobal->mutex );
free ( pWin32ThreadGlobal );
pWin32ThreadGlobal = 0;
return 0;
}
InterlockedExchange ( & initCompleted, 1 );
return pWin32ThreadGlobal;
}
static void epicsParmCleanupWIN32 ( win32ThreadParam * pParm )
{
BOOL success;
DWORD stat;
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
if ( ! pGbl ) {
fprintf ( stderr, "epicsParmCleanupWIN32: unable to find ctx\n" );
return;
}
if ( pParm ) {
//fprintf ( stderr, "thread %s is exiting\n", pParm->pName );
stat = WaitForSingleObject ( win32ThreadGlobalMutex, INFINITE );
assert ( stat == WAIT_OBJECT_0 );
ellDelete ( & threadList, & pParm->node );
success = ReleaseMutex ( win32ThreadGlobalMutex );
assert ( success );
EnterCriticalSection ( & pGbl->mutex );
ellDelete ( & pGbl->threadList, & pParm->node );
LeaveCriticalSection ( & pGbl->mutex );
// close the handle if its an implicit thread id
if ( ! pParm->funptr ) {
CloseHandle ( pParm->handle );
}
free ( pParm );
TlsSetValue ( tlsIndexThreadLibraryEPICS, 0 );
TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, 0 );
}
}
@@ -117,25 +183,21 @@ static void epicsParmCleanupWIN32 ( win32ThreadParam * pParm )
*/
static void threadCleanupWIN32 ( void )
{
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
win32ThreadParam * pParm;
WaitForSingleObject ( win32ThreadGlobalMutex, INFINITE );
if ( ! pGbl ) {
fprintf ( stderr, "threadCleanupWIN32: unable to find ctx\n" );
return;
}
while ( pParm = ( win32ThreadParam * ) ellFirst ( & threadList ) ) {
while ( pParm = ( win32ThreadParam * ) ellFirst ( & pGbl->threadList ) ) {
epicsParmCleanupWIN32 ( pParm );
}
if ( tlsIndexThreadLibraryEPICS != 0xFFFFFFFF ) {
TlsFree ( tlsIndexThreadLibraryEPICS );
tlsIndexThreadLibraryEPICS = 0xFFFFFFFF;
}
TlsFree ( pGbl->tlsIndexThreadLibraryEPICS );
ReleaseMutex ( win32ThreadGlobalMutex );
if ( win32ThreadGlobalMutex ) {
CloseHandle ( win32ThreadGlobalMutex );
win32ThreadGlobalMutex = NULL;
}
DeleteCriticalSection ( & pGbl->mutex );
}
/*
@@ -326,8 +388,16 @@ epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize ( epicsThreadS
void epicsThreadCleanupWIN32 ()
{
win32ThreadParam * pParm = (win32ThreadParam *)
TlsGetValue ( tlsIndexThreadLibraryEPICS );
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
win32ThreadParam * pParm;
if ( ! pGbl ) {
fprintf ( stderr, "epicsThreadCleanupWIN32: unable to find ctx\n" );
return;
}
pParm = ( win32ThreadParam * )
TlsGetValue ( pGbl->tlsIndexThreadLibraryEPICS );
epicsParmCleanupWIN32 ( pParm );
}
@@ -366,12 +436,18 @@ void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName )
*/
static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter )
{
win32ThreadParam *pParm = (win32ThreadParam *) lpParameter;
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
win32ThreadParam * pParm = ( win32ThreadParam * ) lpParameter;
BOOL success;
if ( ! pGbl ) {
fprintf ( stderr, "epicsWin32ThreadEntry: unable to find ctx\n" );
return 0;
}
SetThreadName ( pParm->id, pParm->pName );
success = TlsSetValue ( tlsIndexThreadLibraryEPICS, pParm );
success = TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, pParm );
if ( success ) {
/* printf ( "starting thread %d\n", pParm->id ); */
( *pParm->funptr ) ( pParm->parm );
@@ -386,79 +462,6 @@ static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter )
return ( ( unsigned ) success ); /* this indirectly closes the thread handle */
}
/*
* epicsThreadInit ()
*/
static void epicsThreadInit ( void )
{
HANDLE win32ThreadGlobalMutexTmp;
DWORD status;
BOOL success;
int crtlStatus;
if ( win32ThreadGlobalMutex ) {
/* wait for init to complete */
status = WaitForSingleObject ( win32ThreadGlobalMutex, INFINITE );
assert ( status == WAIT_OBJECT_0 );
success = ReleaseMutex ( win32ThreadGlobalMutex );
assert ( success );
return;
}
else {
win32ThreadGlobalMutexTmp = CreateMutex ( NULL, TRUE, NULL );
if ( win32ThreadGlobalMutexTmp == 0 ) {
return;
}
/*
* InterlockedCompareExchangePointer is not supported on W95 but is
* supported by all other versions of windows and by Borland 551.
* Since it will be convienent to build on NT and then run on W95
* then we use the new function only if its a build for 64 bit
* windows. On 32 bit windows the conversion from pointer to type
* LONG should always work correctly.
*/
# if _WIN64
if ( InterlockedCompareExchangePointer ( & win32ThreadGlobalMutex,
win32ThreadGlobalMutexTmp, 0 ) != 0) {
# else
if ( InterlockedCompareExchange ( (LPLONG) & win32ThreadGlobalMutex,
(LONG) win32ThreadGlobalMutexTmp, 0 ) != 0 ) {
# endif
CloseHandle (win32ThreadGlobalMutexTmp);
/* wait for init to complete */
status = WaitForSingleObject ( win32ThreadGlobalMutex, INFINITE );
assert ( status == WAIT_OBJECT_0 );
success = ReleaseMutex ( win32ThreadGlobalMutex );
assert ( success );
return;
}
}
if ( tlsIndexThreadLibraryEPICS == 0xFFFFFFFF ) {
tlsIndexThreadLibraryEPICS = TlsAlloc();
if ( tlsIndexThreadLibraryEPICS == 0xFFFFFFFF ) {
success = ReleaseMutex (win32ThreadGlobalMutex);
assert (success);
return;
}
}
crtlStatus = atexit ( threadCleanupWIN32 );
if (crtlStatus) {
success = ReleaseMutex ( win32ThreadGlobalMutex );
assert ( success );
return;
}
ellInit ( & threadList );
win32ThreadInitOK = TRUE;
success = ReleaseMutex ( win32ThreadGlobalMutex );
assert ( success );
}
static win32ThreadParam * epicsThreadParmCreate ( const char *pName )
{
win32ThreadParam *pParmWIN32;
@@ -479,19 +482,18 @@ static win32ThreadParam * epicsThreadParmCreate ( const char *pName )
static win32ThreadParam * epicsThreadImplicitCreate ( void )
{
win32ThreadParam *pParm;
char name[64];
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
DWORD id = GetCurrentThreadId ();
win32ThreadParam * pParm;
char name[64];
HANDLE handle;
DWORD stat;
BOOL success;
if ( ! win32ThreadInitOK ) {
epicsThreadInit ();
if ( ! win32ThreadInitOK ) {
return NULL;
}
if ( ! pGbl ) {
fprintf ( stderr, "epicsThreadImplicitCreate: unable to find ctx\n" );
return 0;
}
success = DuplicateHandle ( GetCurrentProcess (), GetCurrentThread (),
GetCurrentProcess (), & handle, 0, FALSE, DUPLICATE_SAME_ACCESS );
if ( ! success ) {
@@ -507,19 +509,15 @@ static win32ThreadParam * epicsThreadImplicitCreate ( void )
win32ThreadPriority = GetThreadPriority ( pParm->handle );
assert ( win32ThreadPriority != THREAD_PRIORITY_ERROR_RETURN );
pParm->epicsPriority = epicsThreadGetOsiPriorityValue ( win32ThreadPriority );
success = TlsSetValue ( tlsIndexThreadLibraryEPICS, pParm );
success = TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, pParm );
if ( ! success ) {
epicsParmCleanupWIN32 ( pParm );
pParm = 0;
}
else {
stat = WaitForSingleObject ( win32ThreadGlobalMutex, INFINITE );
assert ( stat == WAIT_OBJECT_0 );
ellAdd ( & threadList, & pParm->node );
success = ReleaseMutex ( win32ThreadGlobalMutex );
assert ( success );
EnterCriticalSection ( & pGbl->mutex );
ellAdd ( & pGbl->threadList, & pParm->node );
LeaveCriticalSection ( & pGbl->mutex );
}
}
return pParm;
@@ -531,18 +529,15 @@ static win32ThreadParam * epicsThreadImplicitCreate ( void )
epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate (const char *pName,
unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC pFunc,void *pParm)
{
win32ThreadParam *pParmWIN32;
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
win32ThreadParam * pParmWIN32;
int osdPriority;
DWORD wstat;
BOOL bstat;
if ( ! win32ThreadInitOK ) {
epicsThreadInit ();
if ( ! win32ThreadInitOK ) {
return NULL;
}
if ( ! pGbl ) {
return NULL;
}
pParmWIN32 = epicsThreadParmCreate ( pName );
if ( pParmWIN32 == 0 ) {
return ( epicsThreadId ) pParmWIN32;
@@ -551,7 +546,8 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate (const char *pName,
pParmWIN32->parm = pParm;
pParmWIN32->epicsPriority = priority;
pParmWIN32->handle = (HANDLE) _beginthreadex ( 0, stackSize, epicsWin32ThreadEntry,
pParmWIN32->handle = (HANDLE) _beginthreadex ( 0,
stackSize, epicsWin32ThreadEntry,
pParmWIN32, CREATE_SUSPENDED, &pParmWIN32->id );
if ( pParmWIN32->handle == 0 ) {
free ( pParmWIN32 );
@@ -573,13 +569,9 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate (const char *pName,
return NULL;
}
wstat = WaitForSingleObject ( win32ThreadGlobalMutex, INFINITE );
assert ( wstat == WAIT_OBJECT_0 );
ellAdd ( & threadList, & pParmWIN32->node );
bstat = ReleaseMutex ( win32ThreadGlobalMutex );
assert ( bstat );
EnterCriticalSection ( & pGbl->mutex );
ellAdd ( & pGbl->threadList, & pParmWIN32->node );
LeaveCriticalSection ( & pGbl->mutex );
return ( epicsThreadId ) pParmWIN32;
}
@@ -589,10 +581,14 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate (const char *pName,
*/
epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf ()
{
win32ThreadParam *pParm = (win32ThreadParam *) TlsGetValue (tlsIndexThreadLibraryEPICS);
BOOL success;
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
win32ThreadParam * pParm;
DWORD stat;
assert ( pGbl );
pParm = ( win32ThreadParam * )
TlsGetValue ( pGbl->tlsIndexThreadLibraryEPICS );
if ( ! pParm ) {
pParm = epicsThreadImplicitCreate ();
if ( ! pParm ) {
@@ -602,16 +598,14 @@ epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf ()
}
}
stat = WaitForSingleObject (win32ThreadGlobalMutex, INFINITE);
assert ( stat == WAIT_OBJECT_0 );
EnterCriticalSection ( & pGbl->mutex );
stat = SuspendThread ( pParm->handle );
pParm->isSuspended = 1;
success = ReleaseMutex (win32ThreadGlobalMutex);
assert (success);
LeaveCriticalSection ( & pGbl->mutex );
assert (stat!=0xFFFFFFFF);
assert ( stat != 0xFFFFFFFF );
}
/*
@@ -619,20 +613,20 @@ epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf ()
*/
epicsShareFunc void epicsShareAPI epicsThreadResume ( epicsThreadId id )
{
win32ThreadParam *pParm = (win32ThreadParam *) id;
BOOL success;
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
win32ThreadParam * pParm = ( win32ThreadParam * ) id;
DWORD stat;
stat = WaitForSingleObject (win32ThreadGlobalMutex, INFINITE);
assert ( stat == WAIT_OBJECT_0 );
assert ( pGbl );
EnterCriticalSection ( & pGbl->mutex );
stat = ResumeThread ( pParm->handle );
pParm->isSuspended = 0;
success = ReleaseMutex (win32ThreadGlobalMutex);
assert (success);
LeaveCriticalSection ( & pGbl->mutex );
assert (stat!=0xFFFFFFFF);
assert ( stat != 0xFFFFFFFF );
}
/*
@@ -640,7 +634,7 @@ epicsShareFunc void epicsShareAPI epicsThreadResume ( epicsThreadId id )
*/
epicsShareFunc unsigned epicsShareAPI epicsThreadGetPriority (epicsThreadId id)
{
win32ThreadParam *pParm = (win32ThreadParam *) id;
win32ThreadParam * pParm = ( win32ThreadParam * ) id;
return pParm->epicsPriority;
}
@@ -649,8 +643,13 @@ epicsShareFunc unsigned epicsShareAPI epicsThreadGetPriority (epicsThreadId id)
*/
epicsShareFunc unsigned epicsShareAPI epicsThreadGetPrioritySelf ()
{
win32ThreadParam *pParm = (win32ThreadParam *)
TlsGetValue ( tlsIndexThreadLibraryEPICS );
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
win32ThreadParam * pParm;
assert ( pGbl );
pParm = ( win32ThreadParam * )
TlsGetValue ( pGbl->tlsIndexThreadLibraryEPICS );
if ( ! pParm ) {
pParm = epicsThreadImplicitCreate ();
}
@@ -670,7 +669,7 @@ epicsShareFunc unsigned epicsShareAPI epicsThreadGetPrioritySelf ()
*/
epicsShareFunc void epicsShareAPI epicsThreadSetPriority ( epicsThreadId id, unsigned priority )
{
win32ThreadParam *pParm = (win32ThreadParam *) id;
win32ThreadParam * pParm = ( win32ThreadParam * ) id;
BOOL stat = SetThreadPriority ( pParm->handle, epicsThreadGetOsdPriorityValue (priority) );
assert (stat);
}
@@ -680,8 +679,8 @@ epicsShareFunc void epicsShareAPI epicsThreadSetPriority ( epicsThreadId id, uns
*/
epicsShareFunc int epicsShareAPI epicsThreadIsEqual ( epicsThreadId id1, epicsThreadId id2 )
{
win32ThreadParam *pParm1 = (win32ThreadParam *) id1;
win32ThreadParam *pParm2 = (win32ThreadParam *) id2;
win32ThreadParam * pParm1 = ( win32ThreadParam * ) id1;
win32ThreadParam * pParm2 = ( win32ThreadParam * ) id2;
return ( id1 == id2 && pParm1->id == pParm2->id );
}
@@ -690,11 +689,11 @@ epicsShareFunc int epicsShareAPI epicsThreadIsEqual ( epicsThreadId id1, epicsTh
*/
epicsShareFunc int epicsShareAPI epicsThreadIsSuspended ( epicsThreadId id )
{
win32ThreadParam *pParm = (win32ThreadParam *) id;
win32ThreadParam *pParm = ( win32ThreadParam * ) id;
DWORD exitCode;
BOOL stat;
stat = GetExitCodeThread ( pParm->handle, &exitCode );
stat = GetExitCodeThread ( pParm->handle, & exitCode );
if ( stat ) {
if ( exitCode != STILL_ACTIVE ) {
return 1;
@@ -757,7 +756,13 @@ double epicsShareAPI epicsThreadSleepQuantum ()
*/
epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetIdSelf (void)
{
win32ThreadParam *pParm = (win32ThreadParam *) TlsGetValue (tlsIndexThreadLibraryEPICS);
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
win32ThreadParam * pParm;
assert ( pGbl );
pParm = ( win32ThreadParam * ) TlsGetValue (
pGbl->tlsIndexThreadLibraryEPICS );
if ( ! pParm ) {
pParm = epicsThreadImplicitCreate ();
assert ( pParm ); /* very dangerous to allow non-unique thread id into use */
@@ -765,16 +770,18 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetIdSelf (void)
return ( epicsThreadId ) pParm;
}
epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetId ( const char *pName )
epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetId ( const char * pName )
{
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
win32ThreadParam * pParm;
DWORD stat;
BOOL success;
stat = WaitForSingleObject ( win32ThreadGlobalMutex, INFINITE );
assert ( stat == WAIT_OBJECT_0 );
for ( pParm = ( win32ThreadParam * ) ellFirst ( & threadList );
if ( ! pGbl ) {
return 0;
}
EnterCriticalSection ( & pGbl->mutex );
for ( pParm = ( win32ThreadParam * ) ellFirst ( & pGbl->threadList );
pParm; pParm = ( win32ThreadParam * ) ellNext ( & pParm->node ) ) {
if ( pParm->pName ) {
if ( strcmp ( pParm->pName, pName ) == 0 ) {
@@ -783,8 +790,7 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetId ( const char *pName
}
}
success = ReleaseMutex ( win32ThreadGlobalMutex );
assert ( success );
LeaveCriticalSection ( & pGbl->mutex );
// !!!! warning - the thread parm could vanish at any time !!!!
@@ -797,7 +803,15 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetId ( const char *pName
*/
epicsShareFunc const char * epicsShareAPI epicsThreadGetNameSelf (void)
{
win32ThreadParam *pParm = (win32ThreadParam *) TlsGetValue (tlsIndexThreadLibraryEPICS);
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
win32ThreadParam * pParm;
if ( ! pGbl ) {
return "thread library not initialized";
}
pParm = ( win32ThreadParam * )
TlsGetValue ( pGbl->tlsIndexThreadLibraryEPICS );
if ( ! pParm ) {
pParm = epicsThreadImplicitCreate ();
}
@@ -813,13 +827,14 @@ epicsShareFunc const char * epicsShareAPI epicsThreadGetNameSelf (void)
/*
* epicsThreadGetName ()
*/
epicsShareFunc void epicsShareAPI epicsThreadGetName ( epicsThreadId id, char *pName, size_t size )
epicsShareFunc void epicsShareAPI epicsThreadGetName (
epicsThreadId id, char * pName, size_t size )
{
win32ThreadParam *pParm = (win32ThreadParam *) id;
win32ThreadParam * pParm = ( win32ThreadParam * ) id;
if ( size ) {
size_t sizeMinusOne = size-1;
strncpy (pName, pParm->pName, sizeMinusOne);
strncpy ( pName, pParm->pName, sizeMinusOne );
pName [sizeMinusOne] = '\0';
}
}
@@ -861,7 +876,7 @@ static const char * epics_GetThreadPriorityAsString ( HANDLE thr )
*/
static void epicsThreadShowPrivate ( epicsThreadId id, unsigned level )
{
win32ThreadParam *pParm = (win32ThreadParam *) id;
win32ThreadParam * pParm = ( win32ThreadParam * ) id;
if ( pParm ) {
printf ( "%-15s %-8p %-8x %-9u %-9s %-7s", pParm->pName,
@@ -889,21 +904,22 @@ static void epicsThreadShowPrivate ( epicsThreadId id, unsigned level )
*/
epicsShareFunc void epicsShareAPI epicsThreadShowAll ( unsigned level )
{
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
win32ThreadParam * pParm;
DWORD stat;
BOOL success;
stat = WaitForSingleObject ( win32ThreadGlobalMutex, INFINITE );
assert ( stat == WAIT_OBJECT_0 );
if ( ! pGbl ) {
return;
}
EnterCriticalSection ( & pGbl->mutex );
epicsThreadShowPrivate ( 0, level );
for ( pParm = ( win32ThreadParam * ) ellFirst ( & threadList );
for ( pParm = ( win32ThreadParam * ) ellFirst ( & pGbl->threadList );
pParm; pParm = ( win32ThreadParam * ) ellNext ( & pParm->node ) ) {
epicsThreadShowPrivate ( ( epicsThreadId ) pParm, level );
}
success = ReleaseMutex ( win32ThreadGlobalMutex );
assert ( success );
LeaveCriticalSection ( & pGbl->mutex );
}
/*
@@ -921,24 +937,18 @@ epicsShareFunc void epicsShareAPI epicsThreadShow ( epicsThreadId id, unsigned l
epicsShareFunc void epicsShareAPI epicsThreadOnceOsd (
epicsThreadOnceId *id, void (*func)(void *), void *arg )
{
BOOL success;
DWORD stat;
if ( ! win32ThreadInitOK ) {
epicsThreadInit ();
assert ( win32ThreadInitOK );
}
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
stat = WaitForSingleObject ( win32ThreadGlobalMutex, INFINITE );
assert ( stat == WAIT_OBJECT_0 );
assert ( pGbl );
EnterCriticalSection ( & pGbl->mutex );
if ( ! *id ) {
( *func ) ( arg );
*id = 1;
}
success = ReleaseMutex ( win32ThreadGlobalMutex );
assert ( success );
LeaveCriticalSection ( & pGbl->mutex );
}
/*