280 lines
6.8 KiB
C
280 lines
6.8 KiB
C
#include "progwrp.h"
|
|
#include "export.h"
|
|
#include "implementations.h"
|
|
|
|
#define SEMAPHORE_BIT (1 << 31)
|
|
|
|
typedef struct
|
|
{
|
|
PULONG CondVarBitMasks;
|
|
ULONG NumberBitMasks;
|
|
}COND_VAR_BASE, * PCOND_VAR_BASE;
|
|
|
|
|
|
NTSYSAPI PVOID RtlAllocateHeap(
|
|
PVOID HeapHandle,
|
|
ULONG Flags,
|
|
SIZE_T Size
|
|
);
|
|
|
|
NTSYSAPI VOID RtlFreeHeap(
|
|
PVOID HeapHandle,
|
|
ULONG Flags,
|
|
PVOID BaseAddress
|
|
);
|
|
|
|
#define RtlMoveMemory RtlMoveMemory
|
|
|
|
VOID NTAPI RtlMoveMemory(
|
|
PVOID Destination,
|
|
PVOID Source,
|
|
SIZE_T Length
|
|
);
|
|
|
|
/*
|
|
A condition variable is a synchronization object which allows many
|
|
threads to synchronize on one variable, in a pseudo-queue.
|
|
|
|
I determined that the condition variable could consist of an expandable array of bit masks.
|
|
One bit mask has two bits per thread; one to indicate that the section of the bit mask is in use
|
|
and another to indicate that the bit mask has been signalled.
|
|
*/
|
|
|
|
typedef struct {
|
|
HANDLE SingleWakeEvent;
|
|
HANDLE AllWakeEvent;
|
|
HANDLE AccessSemaphore;
|
|
ULONG WaiterCount;
|
|
}CONDITION_VARIABLE_INT, * PCONDITION_VARIABLE_INT;
|
|
|
|
BOOL WINAPI Implementation_SleepConditionVariableSRW(
|
|
PCONDITION_VARIABLE ConditionVariable,
|
|
PSRWLOCK SRWLock,
|
|
DWORD dwMilliseconds,
|
|
ULONG Flags
|
|
)
|
|
{
|
|
int i;
|
|
DWORD dwWaitStatus;
|
|
DWORD dwCondVarIdx;
|
|
PTEB_CUSTOM Teb;
|
|
PCONDITION_VARIABLE_INT pCondVar;
|
|
|
|
if (!(!SRWLock && Flags == 2)) {
|
|
|
|
if (!ConditionVariable || !SRWLock || Flags & ~(CONDITION_VARIABLE_LOCKMODE_SHARED))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
Teb = (PTEB_CUSTOM)NtCurrentTeb();
|
|
|
|
if (!ConditionVariable->Ptr)
|
|
{
|
|
pCondVar = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CONDITION_VARIABLE_INT));
|
|
if (!pCondVar)
|
|
return FALSE;
|
|
#ifdef _M_X64
|
|
if (InterlockedCompareExchange64(ConditionVariable, pCondVar, 0))
|
|
#else
|
|
if (InterlockedCompareExchange(ConditionVariable, pCondVar, 0))
|
|
#endif
|
|
HeapFree(GetProcessHeap(), 0, pCondVar);
|
|
else
|
|
{
|
|
pCondVar->WaiterCount = 0;
|
|
pCondVar->AccessSemaphore = CreateSemaphoreA(NULL, 1, 1, NULL);
|
|
pCondVar->AllWakeEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
|
|
pCondVar->SingleWakeEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
}
|
|
}
|
|
|
|
pCondVar = ConditionVariable->Ptr;
|
|
|
|
WaitForSingleObject(pCondVar->AccessSemaphore, INFINITE);
|
|
|
|
InterlockedIncrement(&pCondVar->WaiterCount);
|
|
|
|
ReleaseSemaphore(pCondVar->AccessSemaphore, 1, NULL);
|
|
|
|
if (Flags & CONDITION_VARIABLE_LOCKMODE_SHARED)
|
|
Implementation_ReleaseSRWLockShared(SRWLock);
|
|
else
|
|
Implementation_ReleaseSRWLockExclusive(SRWLock);
|
|
|
|
|
|
HANDLE MultipleHandles[2] = { pCondVar->AllWakeEvent, pCondVar->SingleWakeEvent };
|
|
dwWaitStatus = WaitForMultipleObjects(2, MultipleHandles, FALSE, dwMilliseconds);
|
|
|
|
if (!InterlockedDecrement(&pCondVar->WaiterCount)) {
|
|
ResetEvent(pCondVar->AllWakeEvent);
|
|
ResetEvent(pCondVar->SingleWakeEvent);
|
|
ReleaseSemaphore(pCondVar->AccessSemaphore, 1, NULL);
|
|
}
|
|
else if (dwWaitStatus == WAIT_OBJECT_0 + 1)
|
|
{
|
|
ReleaseSemaphore(pCondVar->AccessSemaphore, 1, NULL);
|
|
}
|
|
|
|
|
|
if (Flags & CONDITION_VARIABLE_LOCKMODE_SHARED)
|
|
Implementation_AcquireSRWLockShared(SRWLock);
|
|
else
|
|
Implementation_AcquireSRWLockExclusive(SRWLock);
|
|
|
|
if (dwWaitStatus != WAIT_OBJECT_0 &&
|
|
dwWaitStatus != WAIT_OBJECT_0 + 1)
|
|
{
|
|
SetLastError(ERROR_TIMEOUT);
|
|
return FALSE;
|
|
}
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL WINAPI Implementation_SleepConditionVariableCS(
|
|
PCONDITION_VARIABLE ConditionVariable,
|
|
PCRITICAL_SECTION CriticalSection,
|
|
DWORD dwMilliseconds
|
|
)
|
|
{
|
|
int i;
|
|
DWORD dwWaitStatus;
|
|
DWORD dwCondVarIdx;
|
|
PTEB_CUSTOM Teb;
|
|
PCONDITION_VARIABLE_INT pCondVar;
|
|
|
|
if (!ConditionVariable || !CriticalSection)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (!ConditionVariable->Ptr)
|
|
{
|
|
pCondVar = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CONDITION_VARIABLE_INT));
|
|
|
|
#ifdef _M_X64
|
|
if (InterlockedCompareExchange64(ConditionVariable, pCondVar, 0))
|
|
#else
|
|
if (InterlockedCompareExchange(ConditionVariable, pCondVar, 0))
|
|
#endif
|
|
HeapFree(GetProcessHeap(), 0, pCondVar);
|
|
else
|
|
{
|
|
pCondVar->WaiterCount = 0;
|
|
pCondVar->AccessSemaphore = CreateSemaphoreA(NULL, 1, 1, NULL);
|
|
pCondVar->AllWakeEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
|
|
pCondVar->SingleWakeEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
}
|
|
}
|
|
|
|
pCondVar = ConditionVariable->Ptr;
|
|
|
|
WaitForSingleObject(pCondVar->AccessSemaphore, INFINITE);
|
|
|
|
InterlockedIncrement(&pCondVar->WaiterCount);
|
|
|
|
ReleaseSemaphore(pCondVar->AccessSemaphore, 1, NULL);
|
|
|
|
LeaveCriticalSection(CriticalSection);
|
|
HANDLE MultipleHandles[2] = { pCondVar->AllWakeEvent, pCondVar->SingleWakeEvent };
|
|
dwWaitStatus = WaitForMultipleObjects(2, MultipleHandles, FALSE, dwMilliseconds);
|
|
|
|
if (!InterlockedDecrement(&pCondVar->WaiterCount)) {
|
|
ResetEvent(pCondVar->AllWakeEvent);
|
|
ResetEvent(pCondVar->SingleWakeEvent);
|
|
ReleaseSemaphore(pCondVar->AccessSemaphore, 1, NULL);
|
|
}
|
|
else if (dwWaitStatus == WAIT_OBJECT_0 + 1)
|
|
{
|
|
ReleaseSemaphore(pCondVar->AccessSemaphore, 1, NULL);
|
|
}
|
|
|
|
EnterCriticalSection(CriticalSection);
|
|
SetLastError(dwWaitStatus);
|
|
if (dwWaitStatus != WAIT_OBJECT_0 &&
|
|
dwWaitStatus != WAIT_OBJECT_0 + 1)
|
|
{
|
|
SetLastError(ERROR_TIMEOUT);
|
|
return FALSE;
|
|
}
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
void WINAPI Implementation_InitializeConditionVariable(
|
|
PCONDITION_VARIABLE ConditionVariable
|
|
)
|
|
{
|
|
ConditionVariable->Ptr = 0;
|
|
}
|
|
|
|
typedef struct _THREAD_BASIC_INFORMATION {
|
|
NTSTATUS ExitStatus;
|
|
PVOID TebBaseAddress;
|
|
CLIENT_ID ClientId;
|
|
KAFFINITY AffinityMask;
|
|
KPRIORITY Priority;
|
|
KPRIORITY BasePriority;
|
|
} THREAD_BASIC_INFORMATION, * PTHREAD_BASIC_INFORMATION;
|
|
|
|
typedef struct _OBJECT_BASIC_INFORMATION {
|
|
ULONG Attributes;
|
|
ACCESS_MASK GrantedAccess;
|
|
ULONG HandleCount;
|
|
ULONG PointerCount;
|
|
ULONG PagedPoolCharge;
|
|
ULONG NonPagedPoolCharge;
|
|
ULONG Reserved[3];
|
|
ULONG NameInfoSize;
|
|
ULONG TypeInfoSize;
|
|
ULONG SecurityDescriptorSize;
|
|
LARGE_INTEGER CreationTime;
|
|
} OBJECT_BASIC_INFORMATION, * POBJECT_BASIC_INFORMATION;
|
|
|
|
|
|
void WINAPI Implementation_WakeConditionVariable(
|
|
PCONDITION_VARIABLE ConditionVariable
|
|
)
|
|
{
|
|
if (ConditionVariable)
|
|
{
|
|
PCONDITION_VARIABLE_INT pCondVar = ConditionVariable->Ptr;
|
|
if (ConditionVariable->Ptr) {
|
|
WaitForSingleObject(pCondVar->AccessSemaphore, INFINITE);
|
|
if (!pCondVar->WaiterCount) {
|
|
ReleaseSemaphore(pCondVar->AccessSemaphore, 1, NULL);
|
|
}
|
|
else {
|
|
SetEvent(pCondVar->SingleWakeEvent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void WINAPI Implementation_WakeAllConditionVariable(
|
|
PCONDITION_VARIABLE ConditionVariable
|
|
)
|
|
{
|
|
if (ConditionVariable)
|
|
{
|
|
PCONDITION_VARIABLE_INT pCondVar = ConditionVariable->Ptr;
|
|
if (ConditionVariable->Ptr) {
|
|
WaitForSingleObject(pCondVar->AccessSemaphore, INFINITE);
|
|
if (!pCondVar->WaiterCount) {
|
|
ReleaseSemaphore(pCondVar->AccessSemaphore, 1, NULL);
|
|
}
|
|
else {
|
|
SetEvent(pCondVar->AllWakeEvent);
|
|
}
|
|
}
|
|
}
|
|
|
|
} |