Files
org-hyperion-cules/fthreads.c
Fish (David B Trout) b7413ae5ec fthreads fix FOR REAL this time
git-svn-id: file:///home/jj/hercules.svn/trunk@865 956126f8-22a0-4046-8f4a-272fa8102e63
2002-04-30 04:41:29 +00:00

870 lines
20 KiB
C

////////////////////////////////////////////////////////////////////////////////////
// fthreads.c Fish's WIN32 version of pthreads
////////////////////////////////////////////////////////////////////////////////////
// (c) Copyright "Fish" (David B. Trout), 2001, 2002. Released under the Q Public License
// (http://www.conmicro.cx/hercules/herclic.html) as modifications to Hercules.
////////////////////////////////////////////////////////////////////////////////////
#if defined(HAVE_CONFIG_H)
#include <config.h> // (needed to set OPTION_FTHREADS flag appropriately)
#endif
#if !defined(OPTION_FTHREADS)
int dummy = 0;
#else // defined(OPTION_FTHREADS)
#define _WIN32_WINNT 0x0403 // (so "InitializeCriticalSectionAndSpinCount" gets defined)
#include <windows.h> // (defines "InitializeCriticalSectionAndSpinCount")
#include <stdio.h>
#include <errno.h>
#include <malloc.h>
#include <sys/time.h>
#include "fthreads.h"
#include "hostinfo.h"
////////////////////////////////////////////////////////////////////////////////////
#if defined(FISH_HANG)
#include "fishhang.h" // (function definitions)
#define MyInitializeCriticalSection(lock) (FishHang_InitializeCriticalSection(pszFile,nLine,(CRITICAL_SECTION*)(lock)))
#define MyEnterCriticalSection(lock) (FishHang_EnterCriticalSection(pszFile,nLine,(CRITICAL_SECTION*)(lock)))
#define MyTryEnterCriticalSection(lock) (FishHang_TryEnterCriticalSection(pszFile,nLine,(CRITICAL_SECTION*)(lock)))
#define MyLeaveCriticalSection(lock) (FishHang_LeaveCriticalSection(pszFile,nLine,(CRITICAL_SECTION*)(lock)))
#define MyDeleteCriticalSection(lock) (FishHang_DeleteCriticalSection(pszFile,nLine,(CRITICAL_SECTION*)(lock)))
#define MyCreateThread(secat,stack,start,parm,flags,tid) (FishHang_CreateThread(pszFile,nLine,(secat),(stack),(start),(parm),(flags),(tid)))
#define MyExitThread(code) (FishHang_ExitThread((code)))
#define MyCreateEvent(sec,man,set,name) (FishHang_CreateEvent(pszFile,nLine,(sec),(man),(set),(name)))
#define MySetEvent(handle) (FishHang_SetEvent(pszFile,nLine,(handle)))
#define MyResetEvent(handle) (FishHang_ResetEvent(pszFile,nLine,(handle)))
#define MyDeleteEvent(handle) (FishHang_CloseHandle(pszFile,nLine,(handle)))
#define MyWaitForSingleObject(handle,millsecs) (FishHang_WaitForSingleObject(pszFile,nLine,(handle),(millsecs)))
#else // !defined(FISH_HANG)
#define MyInitializeCriticalSection(pCS) (InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION*)(pCS),3000))
#define MyEnterCriticalSection(pCS) (EnterCriticalSection((CRITICAL_SECTION*)(pCS)))
#define MyTryEnterCriticalSection(pCS) (TryEnterCriticalSection((CRITICAL_SECTION*)(pCS)))
#define MyLeaveCriticalSection(pCS) (LeaveCriticalSection((CRITICAL_SECTION*)(pCS)))
#define MyDeleteCriticalSection(pCS) (DeleteCriticalSection((CRITICAL_SECTION*)(pCS)))
#define MyCreateThread(secat,stack,start,parm,flags,tid) (CreateThread((secat),(stack),(start),(parm),(flags),(tid)))
#define MyExitThread(code) (ExitThread((code)))
#define MyCreateEvent(sec,man,set,name) (CreateEvent((sec),(man),(set),(name)))
#define MySetEvent(handle) (SetEvent((handle)))
#define MyResetEvent(handle) (ResetEvent((handle)))
#define MyDeleteEvent(handle) (CloseHandle((handle)))
#define MyWaitForSingleObject(handle,millisecs) (WaitForSingleObject((handle),(millisecs)))
#endif // defined(FISH_HANG)
#define IsEventSet(hEventHandle) (WaitForSingleObject(hEventHandle,0) == WAIT_OBJECT_0)
#define _fthreadmsg(fmt...) \
do \
{ \
fprintf(stderr, fmt); \
fflush(stderr); \
} \
while (0)
/////////////////////////////////////////////////////////////////////////////
// Debugging
#if defined(DEBUG) || defined(_DEBUG)
#define TRACE(a...) _fthreadmsg(a)
#define ASSERT(a) \
do \
{ \
if (!(a)) \
{ \
_fthreadmsg("** Assertion Failed: %s(%d)\n",__FILE__,__LINE__); \
} \
} \
while(0)
#define VERIFY(a) ASSERT((a))
#else
#define TRACE(a...)
#define ASSERT(a)
#define VERIFY(a) ((void)(a))
#endif
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
// private internal fthreads CRITICAL_SECTION functions...
void
InitializeFT_MUTEX
(
#ifdef FISH_HANG
char* pszFile,
int nLine,
#endif
fthread_mutex_t* pFT_MUTEX
)
{
MyInitializeCriticalSection(&pFT_MUTEX->MutexLock);
pFT_MUTEX->hUnlockedEvent = MyCreateEvent(NULL,TRUE,TRUE,NULL); // (initially signalled)
pFT_MUTEX->nLockedCount = 0;
pFT_MUTEX->dwLockOwner = 0;
}
////////////////////////////////////////////////////////////////////////////////////
void
DeleteFT_MUTEX
(
#ifdef FISH_HANG
char* pszFile,
int nLine,
#endif
fthread_mutex_t* pFT_MUTEX
)
{
ASSERT(IsEventSet(pFT_MUTEX->hUnlockedEvent) && !pFT_MUTEX->nLockedCount);
pFT_MUTEX->dwLockOwner = 0;
pFT_MUTEX->nLockedCount = 0;
MyDeleteEvent(pFT_MUTEX->hUnlockedEvent);
MyDeleteCriticalSection(&pFT_MUTEX->MutexLock);
}
////////////////////////////////////////////////////////////////////////////////////
void
EnterFT_MUTEX
(
#ifdef FISH_HANG
char* pszFile,
int nLine,
#endif
fthread_mutex_t* pFT_MUTEX
)
{
if (hostinfo.trycritsec_avail)
{
MyEnterCriticalSection(&pFT_MUTEX->MutexLock);
}
else
{
FT_W32_DWORD dwThreadId = GetCurrentThreadId();
for (;;)
{
MyEnterCriticalSection(&pFT_MUTEX->MutexLock);
ASSERT(pFT_MUTEX->nLockedCount >= 0);
if (pFT_MUTEX->nLockedCount <= 0 || pFT_MUTEX->dwLockOwner == dwThreadId) break;
MyLeaveCriticalSection(&pFT_MUTEX->MutexLock);
MyWaitForSingleObject(pFT_MUTEX->hUnlockedEvent,INFINITE);
}
MyResetEvent(pFT_MUTEX->hUnlockedEvent);
pFT_MUTEX->dwLockOwner = dwThreadId;
VERIFY(++pFT_MUTEX->nLockedCount > 0);
MyLeaveCriticalSection(&pFT_MUTEX->MutexLock);
}
}
////////////////////////////////////////////////////////////////////////////////////
void
LeaveFT_MUTEX
(
#ifdef FISH_HANG
char* pszFile,
int nLine,
#endif
fthread_mutex_t* pFT_MUTEX
)
{
if (hostinfo.trycritsec_avail)
{
MyLeaveCriticalSection(&pFT_MUTEX->MutexLock);
}
else
{
MyEnterCriticalSection(&pFT_MUTEX->MutexLock);
ASSERT(pFT_MUTEX->nLockedCount >= 0);
if (--pFT_MUTEX->nLockedCount <= 0)
MySetEvent(pFT_MUTEX->hUnlockedEvent);
MyLeaveCriticalSection(&pFT_MUTEX->MutexLock);
}
}
////////////////////////////////////////////////////////////////////////////////////
FT_W32_BOOL
TryEnterFT_MUTEX
(
#ifdef FISH_HANG
char* pszFile,
int nLine,
#endif
fthread_mutex_t* pFT_MUTEX
)
{
FT_W32_BOOL bSuccess;
if (hostinfo.trycritsec_avail)
{
bSuccess = MyTryEnterCriticalSection(&pFT_MUTEX->MutexLock);
}
else
{
FT_W32_DWORD dwThreadId = GetCurrentThreadId();
MyEnterCriticalSection(&pFT_MUTEX->MutexLock);
ASSERT(pFT_MUTEX->nLockedCount >= 0);
bSuccess = (pFT_MUTEX->nLockedCount <= 0 || pFT_MUTEX->dwLockOwner == dwThreadId);
if (bSuccess)
{
VERIFY(++pFT_MUTEX->nLockedCount > 0);
pFT_MUTEX->dwLockOwner = dwThreadId;
MyResetEvent(pFT_MUTEX->hUnlockedEvent);
}
MyLeaveCriticalSection(&pFT_MUTEX->MutexLock);
}
return bSuccess;
}
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
// (thread signalling not supported...)
void fthread_kill // (nop)
(
int dummy1,
int dummy2
)
{
// (nop)
}
////////////////////////////////////////////////////////////////////////////////////
typedef struct _ftCallThreadParms
{
PFT_THREAD_FUNC pfnTheirThreadFunc;
void* pvTheirThreadArgs;
}
FT_CALL_THREAD_PARMS;
////////////////////////////////////////////////////////////////////////////////////
FT_W32_DWORD
__stdcall
FTWin32ThreadFunc
(
void* pMyArgs
)
{
FT_CALL_THREAD_PARMS* pCallTheirThreadParms;
PFT_THREAD_FUNC pfnTheirThreadFunc;
void* pvTheirThreadArgs;
pCallTheirThreadParms = (FT_CALL_THREAD_PARMS*) pMyArgs;
pfnTheirThreadFunc = pCallTheirThreadParms->pfnTheirThreadFunc;
pvTheirThreadArgs = pCallTheirThreadParms->pvTheirThreadArgs;
free(pCallTheirThreadParms);
(pfnTheirThreadFunc)(pvTheirThreadArgs);
MyExitThread(0);
return 0; // (make compiler happy)
}
////////////////////////////////////////////////////////////////////////////////////
// create a new thread...
int
fthread_create
(
#ifdef FISH_HANG
char* pszFile,
int nLine,
#endif
fthread_t* pdwThreadID,
fthread_attr_t* dummy1,
PFT_THREAD_FUNC pfnThreadFunc,
void* pvThreadArgs,
int nThreadPriority
)
{
FT_CALL_THREAD_PARMS* pCallTheirThreadParms;
FT_W32_HANDLE hWin32ThreadFunc;
pCallTheirThreadParms =
(FT_CALL_THREAD_PARMS*) malloc(sizeof(FT_CALL_THREAD_PARMS));
if (!pCallTheirThreadParms)
{
#ifdef FISH_HANG
_fthreadmsg("fthread_create: malloc(FT_CALL_THREAD_PARMS) failed; %s(%d)\n",pszFile,nLine);
#else
_fthreadmsg("fthread_create: malloc(FT_CALL_THREAD_PARMS) failed\n");
#endif
errno = ENOMEM;
return -1;
}
pCallTheirThreadParms->pfnTheirThreadFunc = pfnThreadFunc;
pCallTheirThreadParms->pvTheirThreadArgs = pvThreadArgs;
hWin32ThreadFunc =
MyCreateThread(NULL,0,FTWin32ThreadFunc,pCallTheirThreadParms,0,(FT_W32_DWORD*)pdwThreadID);
if (!hWin32ThreadFunc)
{
#ifdef FISH_HANG
_fthreadmsg("fthread_create: MyCreateThread failed; %s(%d)\n",pszFile,nLine);
#else
_fthreadmsg("fthread_create: MyCreateThread failed\n");
#endif
free (pCallTheirThreadParms);
errno = EAGAIN;
return -1;
}
if (nThreadPriority != THREAD_PRIORITY_NORMAL)
{
if (!SetThreadPriority(hWin32ThreadFunc,nThreadPriority))
{
#ifdef FISH_HANG
_fthreadmsg("fthread_create: SetThreadPriority failed; %s(%d)\n",pszFile,nLine);
#else
_fthreadmsg("fthread_create: SetThreadPriority failed\n");
#endif
}
}
CloseHandle(hWin32ThreadFunc);
return 0;
}
////////////////////////////////////////////////////////////////////////////////////
// return thread-id...
FT_W32_DWORD
fthread_self
(
)
{
return GetCurrentThreadId();
}
////////////////////////////////////////////////////////////////////////////////////
// exit from a thread...
void
fthread_exit
(
FT_W32_DWORD* pdwExitCode
)
{
MyExitThread(pdwExitCode ? *pdwExitCode : 0);
}
////////////////////////////////////////////////////////////////////////////////////
// initialize a lock...
int
fthread_mutex_init
(
#ifdef FISH_HANG
char* pszFile,
int nLine,
#endif
fthread_mutex_t* pFT_MUTEX
)
{
InitializeFT_MUTEX
(
#ifdef FISH_HANG
pszFile,
nLine,
#endif
pFT_MUTEX
);
return 0;
}
////////////////////////////////////////////////////////////////////////////////////
// lock a "mutex"...
int
fthread_mutex_lock
(
#ifdef FISH_HANG
char* pszFile,
int nLine,
#endif
fthread_mutex_t* pFT_MUTEX
)
{
EnterFT_MUTEX
(
#ifdef FISH_HANG
pszFile,
nLine,
#endif
pFT_MUTEX
);
return 0;
}
////////////////////////////////////////////////////////////////////////////////////
// try to lock a "mutex"...
int
fthread_mutex_trylock
(
#ifdef FISH_HANG
char* pszFile,
int nLine,
#endif
fthread_mutex_t* pFT_MUTEX
)
{
// Note: POSIX defines success as 0, failure as !0
return !TryEnterFT_MUTEX
(
#ifdef FISH_HANG
pszFile,
nLine,
#endif
pFT_MUTEX
);
}
////////////////////////////////////////////////////////////////////////////////////
// unlock a "mutex"...
int
fthread_mutex_unlock
(
#ifdef FISH_HANG
char* pszFile,
int nLine,
#endif
fthread_mutex_t* pFT_MUTEX
)
{
LeaveFT_MUTEX
(
#ifdef FISH_HANG
pszFile,
nLine,
#endif
pFT_MUTEX
);
return 0;
}
////////////////////////////////////////////////////////////////////////////////////
// initialize a "condition"...
int
fthread_cond_init
(
#ifdef FISH_HANG
char* pszFile,
int nLine,
#endif
fthread_cond_t* pFT_COND_VAR
)
{
if ((pFT_COND_VAR->hSigXmitEvent = MyCreateEvent(NULL,TRUE,FALSE,NULL)))
{
if ((pFT_COND_VAR->hSigRecvdEvent = MyCreateEvent(NULL,TRUE,TRUE,NULL)))
{
MyInitializeCriticalSection(&pFT_COND_VAR->CondVarLock);
pFT_COND_VAR->bBroadcastSig = FALSE;
pFT_COND_VAR->nNumWaiting = 0;
return 0;
}
MyDeleteEvent(pFT_COND_VAR->hSigXmitEvent);
}
#ifdef FISH_HANG
_fthreadmsg("fthread_cond_init failure; %s(%d)\n",pszFile,nLine);
#else
_fthreadmsg("fthread_cond_init failure\n");
#endif
errno = EAGAIN;
return -1;
}
////////////////////////////////////////////////////////////////////////////////////
// 'signal' a "condition"... (releases ONE waiting thread)
int
fthread_cond_signal
(
#ifdef FISH_HANG
char* pszFile,
int nLine,
#endif
fthread_cond_t* pFT_COND_VAR
)
{
if (!pFT_COND_VAR) { errno = EINVAL; return -1; }
// Wait for everyone to finish receiving prior signal..
for (;;)
{
MyEnterCriticalSection(&pFT_COND_VAR->CondVarLock);
if (IsEventSet(pFT_COND_VAR->hSigRecvdEvent)) break;
MyLeaveCriticalSection(&pFT_COND_VAR->CondVarLock);
MyWaitForSingleObject(pFT_COND_VAR->hSigRecvdEvent,INFINITE);
}
// Begin transmitting our new signal...
pFT_COND_VAR->bBroadcastSig = FALSE;
MySetEvent(pFT_COND_VAR->hSigXmitEvent);
if (pFT_COND_VAR->nNumWaiting)
{
// Serialize signal reception...
MyResetEvent(pFT_COND_VAR->hSigRecvdEvent);
}
MyLeaveCriticalSection(&pFT_COND_VAR->CondVarLock);
return 0;
}
////////////////////////////////////////////////////////////////////////////////////
// 'broadcast' a "condition"... (releases ALL waiting threads)
int
fthread_cond_broadcast
(
#ifdef FISH_HANG
char* pszFile,
int nLine,
#endif
fthread_cond_t* pFT_COND_VAR
)
{
if (!pFT_COND_VAR) { errno = EINVAL; return -1; }
// Wait for everyone to finish receiving prior signal..
for (;;)
{
MyEnterCriticalSection(&pFT_COND_VAR->CondVarLock);
if (IsEventSet(pFT_COND_VAR->hSigRecvdEvent)) break;
MyLeaveCriticalSection(&pFT_COND_VAR->CondVarLock);
MyWaitForSingleObject(pFT_COND_VAR->hSigRecvdEvent,INFINITE);
}
// Begin transmitting our new signal...
pFT_COND_VAR->bBroadcastSig = TRUE;
MySetEvent(pFT_COND_VAR->hSigXmitEvent);
if (pFT_COND_VAR->nNumWaiting)
{
// Serialize signal reception...
MyResetEvent(pFT_COND_VAR->hSigRecvdEvent);
}
MyLeaveCriticalSection(&pFT_COND_VAR->CondVarLock);
return 0;
}
////////////////////////////////////////////////////////////////////////////////////
// wait for a "condition" to occur...
int
fthread_cond_wait
(
#ifdef FISH_HANG
char* pszFile,
int nLine,
#endif
fthread_cond_t* pFT_COND_VAR,
fthread_mutex_t* pFT_MUTEX
)
{
if (!pFT_COND_VAR || !pFT_MUTEX) { errno = EINVAL; return -1; }
// Release lock (and thus any potential signalers)...
LeaveFT_MUTEX
(
#ifdef FISH_HANG
pszFile,
nLine,
#endif
pFT_MUTEX
);
// Wait for everyone to finish receiving prior signal (if any)..
for (;;)
{
MyEnterCriticalSection(&pFT_COND_VAR->CondVarLock);
if (IsEventSet(pFT_COND_VAR->hSigRecvdEvent)) break;
MyLeaveCriticalSection(&pFT_COND_VAR->CondVarLock);
MyWaitForSingleObject(pFT_COND_VAR->hSigRecvdEvent,INFINITE);
}
// Indicate new signal reception desired...
pFT_COND_VAR->nNumWaiting++;
// Wait for condition variable to be signalled...
for (;;)
{
// Allow signal to be transmitted...
MyLeaveCriticalSection(&pFT_COND_VAR->CondVarLock);
// Wait for signal transmission...
MyWaitForSingleObject(pFT_COND_VAR->hSigXmitEvent,INFINITE);
// Our condition was signalled...
MyEnterCriticalSection(&pFT_COND_VAR->CondVarLock);
// Make sure signal still being transmitted...
if (IsEventSet(pFT_COND_VAR->hSigXmitEvent)) break;
// If signal no longer being transmitted, then
// some other waiter received it; keep waiting
// for another signal...
}
// Indicate we received the signal...
pFT_COND_VAR->nNumWaiting--;
// If we were the only one that was supposed to
// receive it, or if no one remains to receive it,
// then stop transmitting the signal.
if (!pFT_COND_VAR->bBroadcastSig || pFT_COND_VAR->nNumWaiting == 0)
{
MyResetEvent(pFT_COND_VAR->hSigXmitEvent);
MySetEvent(pFT_COND_VAR->hSigRecvdEvent);
}
// Unlock condition variable...
MyLeaveCriticalSection(&pFT_COND_VAR->CondVarLock);
// Re-acquire the original lock before returning...
EnterFT_MUTEX
(
#ifdef FISH_HANG
pszFile,
nLine,
#endif
pFT_MUTEX
);
return 0;
}
////////////////////////////////////////////////////////////////////////////////////
// wait (but not forever) for a "condition" to occur...
int
fthread_cond_timedwait
(
#ifdef FISH_HANG
char* pszFile,
int nLine,
#endif
fthread_cond_t* pFT_COND_VAR,
fthread_mutex_t* pFT_MUTEX,
struct timespec* pTimeTimeout
)
{
struct timeval TimeNow;
FT_W32_DWORD dwWaitRetCode, dwWaitMilliSecs;
if (!pFT_COND_VAR || !pFT_MUTEX) { errno = EINVAL; return -1; }
// Release lock (and thus any potential signalers)...
LeaveFT_MUTEX
(
#ifdef FISH_HANG
pszFile,
nLine,
#endif
pFT_MUTEX
);
// Wait for everyone to finish receiving prior signal..
for (;;)
{
MyEnterCriticalSection(&pFT_COND_VAR->CondVarLock);
if (IsEventSet(pFT_COND_VAR->hSigRecvdEvent)) break;
MyLeaveCriticalSection(&pFT_COND_VAR->CondVarLock);
MyWaitForSingleObject(pFT_COND_VAR->hSigRecvdEvent,INFINITE);
}
// Indicate new signal reception desired...
pFT_COND_VAR->nNumWaiting++;
// Wait for condition variable to be signalled...
for (;;)
{
// Allow signal to be transmitted...
MyLeaveCriticalSection(&pFT_COND_VAR->CondVarLock);
// Wait for signal transmission...
gettimeofday(&TimeNow, NULL);
if (TimeNow.tv_sec > pTimeTimeout->tv_sec ||
(TimeNow.tv_sec == pTimeTimeout->tv_sec &&
(TimeNow.tv_usec * 1000) > pTimeTimeout->tv_nsec))
{
dwWaitMilliSecs = 0;
}
else
{
dwWaitMilliSecs =
((pTimeTimeout->tv_sec - TimeNow.tv_sec) * 1000) +
((pTimeTimeout->tv_nsec - (TimeNow.tv_usec * 1000)) / 1000000);
}
dwWaitRetCode =
MyWaitForSingleObject(pFT_COND_VAR->hSigXmitEvent,dwWaitMilliSecs);
// Our condition was signalled...
// Or we got tired of waiting for it...
MyEnterCriticalSection(&pFT_COND_VAR->CondVarLock);
// Make sure signal still being transmitted...
if (IsEventSet(pFT_COND_VAR->hSigXmitEvent)) break;
// If signal no longer being transmitted, then
// some other waiter received it; keep waiting
// for another signal...
if (WAIT_OBJECT_0 != dwWaitRetCode)
{
// We either got tired of waiting for it,
// or there was an error...
pFT_COND_VAR->nNumWaiting--;
// If we were the only one that was waiting to
// receive it, then indicate signal received
// (even though it really wasn't since we
// timed out) to allow late signal to eventually
// be sent [to a different future waiter].
if (pFT_COND_VAR->nNumWaiting == 0)
{
MySetEvent(pFT_COND_VAR->hSigRecvdEvent);
}
// Unlock condition variable...
MyLeaveCriticalSection(&pFT_COND_VAR->CondVarLock);
// Re-acquire the original lock before returning...
EnterFT_MUTEX
(
#ifdef FISH_HANG
pszFile,
nLine,
#endif
pFT_MUTEX
);
if (WAIT_TIMEOUT == dwWaitRetCode)
{
errno = EAGAIN; // (timeout)
return -1;
}
#ifdef FISH_HANG
_fthreadmsg("fthread_cond_timedwait: Invalid handle; %s(%d)\n",pszFile,nLine);
#else
_fthreadmsg("fthread_cond_timedwait: Invalid handle\n");
#endif
errno = EINVAL;
return -1;
}
}
// Indicate we received the signal...
pFT_COND_VAR->nNumWaiting--;
// If we were the only one that was supposed to
// receive it, or if no one remains to receive it,
// then stop transmitting the signal.
if (!pFT_COND_VAR->bBroadcastSig || pFT_COND_VAR->nNumWaiting == 0)
{
MyResetEvent(pFT_COND_VAR->hSigXmitEvent);
MySetEvent(pFT_COND_VAR->hSigRecvdEvent);
}
// Unlock condition variable...
MyLeaveCriticalSection(&pFT_COND_VAR->CondVarLock);
// Re-acquire the original lock before returning...
EnterFT_MUTEX
(
#ifdef FISH_HANG
pszFile,
nLine,
#endif
pFT_MUTEX
);
return 0;
}
////////////////////////////////////////////////////////////////////////////////////
#undef IsEventSet
#endif // !defined(OPTION_FTHREADS)