mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4340 lines
133 KiB
4340 lines
133 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dllsem16.c
|
|
|
|
Abstract:
|
|
|
|
This module implements 32 equivalents of OS/2 V1.21 Semaphore
|
|
API Calls. These are called from 16->32 thunks (i386\doscalls.asm).
|
|
|
|
NOTE: there is a semantic problem with os2 1.x Semaphores since
|
|
they are used in both a mutex manner (Request/Clear) and an event
|
|
manner (Wait/Clear). The manuals don't tell apps writers what will
|
|
happen if they use the same semaphore both ways.
|
|
|
|
The current implementation is: A semaphore is associated with
|
|
an Nt Semaphore object AND a Cruiser event. If Wait is called,
|
|
it blocks on the event. If a request is called, it blocks on the
|
|
Semaphore. A clear can be both a Release and a Post, depends on the
|
|
Wait/Request called.
|
|
|
|
Author:
|
|
|
|
Yaron Shamir (YaronS) 12-Apr-1991 (stubs)
|
|
|
|
Yaron Shamir (YaronS) 28-May-1991 (implementation as described above)
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#define INCL_OS2V20_SEMAPHORES
|
|
#define INCL_OS2V20_MEMORY
|
|
#define INCL_OS2V20_TASKING
|
|
#define INCL_OS2V20_ERRORS
|
|
#include "os2dll.h"
|
|
#include "os2dll16.h"
|
|
#include "os2win.h"
|
|
#include "stdlib.h"
|
|
|
|
#if DBG
|
|
// Set the values as appropriate (with NTSD or at compile-time) to see all
|
|
// semaphore operations relating to any of these 4 semaphores.
|
|
// To disable this feature, leave the variables at 0.
|
|
// WARNING: remember to use the flat address, not the 16-bit seg:off
|
|
PVOID Os2DebugSem = (HSEM)0x0;
|
|
PVOID Os2DebugSem1 = (HSEM)0x0;
|
|
PVOID Os2DebugSem2 = (HSEM)0x0;
|
|
PVOID Os2DebugSem3 = (HSEM)0x0;
|
|
// Undef the 2 lines below to see print-out of failures to open this NT event
|
|
//#define DBG_SEM_EVENT_STR "\\SEM\\HACKNT3C"
|
|
//#define DBG_SEM_INDEX 0x3c
|
|
#endif // DBG
|
|
|
|
//
|
|
// Owner Thread values:
|
|
//
|
|
// SEM_AT_INIT - semaphore initialized, used both for mutex and for event semanitcs
|
|
// SEM_MUTEX_NO_OWNER - mutex semaphore, not owned
|
|
// SEM_EVENT - event semaphore (sem/wait/clear)
|
|
// Other - mutex semaphore, owned
|
|
//
|
|
#define SEM_DUAL -3
|
|
#define SEM_AT_INIT -2
|
|
#define SEM_MUTEX_NOT_OWNED -1
|
|
#define SEM_EVENT 0
|
|
|
|
#define OD2SEMTHRESHOLD 800
|
|
ULONG Od2NumSemCreated = 0;
|
|
//
|
|
// The following support the hacky pm print driver usage of FS ram semaphore
|
|
// with cb == 12 instead of 14 as documented
|
|
//
|
|
#define NUMOFPRINTDRIVERSEM 500
|
|
PULONG pHackPrinterDriverSem;
|
|
|
|
//
|
|
// The following is used to sync RAM shared semaphores
|
|
//
|
|
HANDLE Od2SyncSem;
|
|
|
|
//
|
|
// The following is used to sync when garbage collector is at work
|
|
//
|
|
HANDLE Od2GarbageCollectSem;
|
|
//
|
|
// The following flag is used to optimized allocation
|
|
// of semaphores until no more space/reources, then we lock
|
|
// it all, clean and unlock
|
|
//
|
|
BOOLEAN LockFlag = FALSE;
|
|
|
|
//
|
|
// The hint for the next index for shared RAM semaphore
|
|
//
|
|
USHORT Od2SemIndexHint;
|
|
|
|
//
|
|
// Special Heap for tiled structrures - need to be in the 512M tiled area
|
|
//
|
|
extern PVOID Od2TiledHeap;
|
|
|
|
APIRET
|
|
DosGetShrSeg(
|
|
IN PSZ pszSegName,
|
|
OUT PSEL pSel
|
|
);
|
|
|
|
APIRET
|
|
DosAllocShrSeg(
|
|
IN USHORT cbSize,
|
|
IN PSZ pszSegName,
|
|
OUT PSEL pSel
|
|
);
|
|
|
|
APIRET
|
|
DosHoldSignal(
|
|
ULONG fDisable,
|
|
ULONG pstack
|
|
);
|
|
|
|
APIRET
|
|
DosCloseSemNoRemove(
|
|
IN POS21X_SEM pRealSem,
|
|
IN BOOL FreeMem
|
|
);
|
|
|
|
APIRET
|
|
DosSemWait(
|
|
IN HSEM hsem,
|
|
IN LONG lTimeOut
|
|
);
|
|
|
|
APIRET
|
|
Od2CloseSem(
|
|
IN BOOL SyncFlag,
|
|
IN HSEM hsem
|
|
);
|
|
|
|
// Alertable wait for single object. By enabling alert allow context change to be
|
|
// done by server. But in the case that it wasn't done, continue to wait for the
|
|
// object.
|
|
|
|
NTSTATUS
|
|
Od2AlertableWaitForSingleObject(
|
|
IN HANDLE handle
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
while (((Status =
|
|
NtWaitForSingleObject(
|
|
handle,
|
|
TRUE, // alertable
|
|
NULL)) == STATUS_ALERTED) || (Status == STATUS_USER_APC)) {
|
|
#if DBG
|
|
if (Status == STATUS_USER_APC) {
|
|
DbgPrint("WARNING !!! Od2AlertableWaitForSingleObject was broken by APC\n");
|
|
}
|
|
#endif
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Od2AcquireMutant(
|
|
IN HANDLE handle
|
|
)
|
|
{
|
|
if (Od2CurrentThreadId() == 1) {
|
|
DosHoldSignal(HLDSIG_DISABLE, 0);
|
|
}
|
|
return Od2AlertableWaitForSingleObject(handle);
|
|
}
|
|
|
|
NTSTATUS
|
|
Od2ReleaseMutant(
|
|
IN HANDLE handle
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Status = NtReleaseMutant(handle, NULL);
|
|
if (Od2CurrentThreadId() == 1) {
|
|
DosHoldSignal(HLDSIG_ENABLE, 0);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
// Acquire Sync Sem. Write the thread Id of the thread that started critical
|
|
// semaphore processing. This will be used by server to allow to the thread
|
|
// owner Sync to finish semaphores processing before termination.
|
|
|
|
NTSTATUS
|
|
Od2AcquireSync(VOID)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Status = Od2AcquireMutant(Od2SyncSem);
|
|
if (NT_SUCCESS(Status)) {
|
|
Od2Process->Pib.SyncOwner = Od2CurrentThreadId();
|
|
}
|
|
else
|
|
{
|
|
#if DBG
|
|
DbgPrint("Od2AcquireSync: Wait for Sync, Status=%x\n", Status);
|
|
ASSERT(FALSE);
|
|
#endif // DBG
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
// Release Sync Sem. Before actual release, sign that the semaphore processing is
|
|
// over.
|
|
|
|
NTSTATUS
|
|
Od2ReleaseSync(VOID)
|
|
{
|
|
NTSTATUS Status;
|
|
Od2Process->Pib.SyncOwner = 0;
|
|
Status = Od2ReleaseMutant(Od2SyncSem);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("Od2AcquireSync: Relsease Sync, Status=%x\n", Status);
|
|
ASSERT(FALSE);
|
|
}
|
|
#endif // DBG
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS Od2InitSem()
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING SemString_U;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
|
|
RtlInitUnicodeString( &SemString_U, OS2_SS_SYNCHRONIZATION_SEM);
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
&SemString_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
//
|
|
// Open the global subsystem synchronization Nt mutant
|
|
//
|
|
Status = NtOpenMutant(&Od2SyncSem,
|
|
MUTANT_ALL_ACCESS,
|
|
&Obja);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("Od2InitSem: error at NtopenSemaphore, Status %x\n", Status);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Create an Nt mutant that has one free unit, for garbage collect
|
|
// syncronization
|
|
//
|
|
Status = NtCreateMutant(
|
|
&Od2GarbageCollectSem,
|
|
MUTANT_ALL_ACCESS,
|
|
NULL,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("Od2InitSem: error at NtCreateSemaphore, Status %x\n", Status);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Initialize index hint for shared RAM semaphores. We assume that there will
|
|
// be no more than 256 processes permanently. We assume also that there are
|
|
// no more than 256 shared RAM semaphores will be initialized by each
|
|
// process. If this assumptions are TRUE, the hint will be always the index of
|
|
// the empty slot for each process.
|
|
// Just in the case that there is the process that has been created more then
|
|
// 256 shared RAM semaphores, the hint will point to the semaphores of the next
|
|
// process. But there is a good chance that the next process doesn't use
|
|
// shared RAM semaphores at all or uses semaphores of the processes that
|
|
// were started before, or uses a little number of semaphores.
|
|
|
|
Od2SemIndexHint = (((USHORT)Od2Process->Pib.ProcessId) << 8);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
POS21X_SEM
|
|
Od2LookupSem (
|
|
HSEM hsem
|
|
)
|
|
{
|
|
POS21X_SEM pSem;
|
|
BOOLEAN TookTaskLock = FALSE;
|
|
NTSTATUS Status;
|
|
|
|
pSem = (POS21X_SEM)(*(PULONG)hsem & 0xFFFFFFFC);
|
|
if (((ULONG)pSem < (ULONG)Od2TiledHeap + OD2TILEDHEAP_SIZE) && ((ULONG)pSem >= (ULONG)Od2TiledHeap)) {
|
|
//
|
|
// No need for special support (RAM sem in shared memory hook)
|
|
// - the 4 bytes in user area contains
|
|
// bit: 31 1
|
|
// | pointer to prealsem in od2heap | 2bits for set/clear
|
|
//
|
|
if (pSem->pMyself == (PVOID)hsem) {
|
|
return pSem;
|
|
}
|
|
#if DBG
|
|
else {
|
|
DbgPrint("[%d,%d]Od2LookupSem: Private RAM sem signature corrupted hsem=%x, *hsem=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
pSem
|
|
);
|
|
}
|
|
#endif // DBG
|
|
}
|
|
|
|
if (LockFlag) {
|
|
TookTaskLock = TRUE;
|
|
Status = Od2AcquireMutant(Od2GarbageCollectSem);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status) && Status != STATUS_SEMAPHORE_LIMIT_EXCEEDED) {
|
|
KdPrint(("Od2LookupSem: failed to NtWaitForSingleObject on garbage sem, Status=%x\n",
|
|
Status));
|
|
}
|
|
else if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("[%d,%d] Od2LookupSem: WARNING !!! Wait on GarbageCollectSem, status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
}
|
|
//
|
|
// Special support for RAM semaphores in shared memory - we look
|
|
// them up in the linked list
|
|
//
|
|
lookagain:
|
|
pSem = (POS21X_SEM)Od2Sem16ListHead;
|
|
|
|
try {
|
|
while (pSem != NULL) {
|
|
|
|
//
|
|
// Check if pMyself is equal to hsem
|
|
//
|
|
if (pSem->pMyself == (PVOID)hsem) {
|
|
|
|
//
|
|
// Special support for lousy apps like SQL1.11,
|
|
// that look for RAM sem being zero after clear
|
|
//
|
|
if (((*(PULONG)hsem & 0xFFFFFFFC) == 0) && (pSem->u.SharedRamSignature == 0)){
|
|
*(PULONG)hsem = (ULONG)pSem | (*(PULONG)hsem & 0x3);
|
|
}
|
|
|
|
if (TookTaskLock) {
|
|
Status = Od2ReleaseMutant(Od2GarbageCollectSem);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("Od2LookupSem: failed to NtReleaseSemaphore on sync sem, Status=%x\n",
|
|
Status));
|
|
}
|
|
#endif
|
|
}
|
|
return pSem;
|
|
}
|
|
pSem = (POS21X_SEM)(pSem->Next);
|
|
}
|
|
if (TookTaskLock) {
|
|
Status = Od2ReleaseMutant(Od2GarbageCollectSem);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("Od2LookupSem: failed to NtReleaseSemaphore on sync sem, Status=%x\n",
|
|
Status));
|
|
}
|
|
#endif
|
|
}
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
#if DBG
|
|
DbgPrint("Od2LookupSem: A Pointer became invalid while searching\n");
|
|
#endif
|
|
Sleep(100);
|
|
goto lookagain;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
APIRET
|
|
Od2GetSemNtEvent(
|
|
IN HSEM hsem,
|
|
OUT PHANDLE pNtEventHandle
|
|
)
|
|
{
|
|
APIRET rc = NO_ERROR;
|
|
POS21X_SEM pRealSem;
|
|
POR2_HANDLE_TABLE SemaphoreTable;
|
|
POD2_SEMAPHORE Semaphore;
|
|
BOOLEAN SharedSem;
|
|
ULONG HandleIndex;
|
|
|
|
pRealSem = Od2LookupSem (hsem);
|
|
|
|
if (pRealSem == NULL)
|
|
return ERROR_INVALID_HANDLE;
|
|
|
|
//
|
|
// Validate the passed OS/2 2.0 semaphore handle and extract the
|
|
// shared/private flag and the index field. Return an error if
|
|
// not a valid handle.
|
|
//
|
|
|
|
rc = Od2ValidateSemaphoreHandle( pRealSem->Event,
|
|
&SharedSem,
|
|
&HandleIndex
|
|
);
|
|
if (rc != NO_ERROR) {
|
|
return( rc );
|
|
}
|
|
|
|
//
|
|
// Get the pointer to either the shared or private semaphore table.
|
|
// Table must exist. Return an error if it does not.
|
|
//
|
|
|
|
SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
|
|
if (!SemaphoreTable) {
|
|
return( ERROR_INVALID_HANDLE );
|
|
}
|
|
|
|
//
|
|
// Map the semaphore handle into a pointer to the semaphore structure
|
|
// contained in the table. Return an error if the handle is outside
|
|
// the current limits of the table. If the mapping is successful then
|
|
// the semaphore table is left locked while we use the pointer.
|
|
//
|
|
|
|
Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
|
|
HandleIndex,
|
|
FALSE
|
|
);
|
|
if (Semaphore == NULL) {
|
|
return( ERROR_INVALID_HANDLE );
|
|
}
|
|
|
|
|
|
//
|
|
// Entry in semaphore table is for an Event semaphore, so extract the
|
|
// NT Event handle from the record and release the lock, so we are
|
|
// not holding the lock while we are doing the query.
|
|
//
|
|
|
|
*pNtEventHandle = Semaphore->u.EventHandle;
|
|
ReleaseHandleTableLock( SemaphoreTable );
|
|
}
|
|
|
|
POS21X_SEM
|
|
SemWasCreatedByThisProcess(
|
|
IN PCHAR name)
|
|
{
|
|
POS21X_SEM pSem;
|
|
|
|
for (pSem = (POS21X_SEM)Od2Sem16ListHead;
|
|
pSem != NULL;
|
|
pSem = (POS21X_SEM)(pSem->Next)) { // search list for a
|
|
|
|
if (pSem->pMyself == (PVOID)(&(pSem->pMyself)) && // System Semaphore
|
|
!strcmp(pSem->u.SysSemName,name)) { // with same name
|
|
return(pSem);
|
|
}
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
APIRET
|
|
Od2OpenSem(
|
|
IN HSEM UserSem,
|
|
OUT POS21X_SEM *ppRealSem,
|
|
IN PSZ pszSemName,
|
|
IN BOOL Insert
|
|
)
|
|
{
|
|
APIRET rc = NO_ERROR;
|
|
NTSTATUS Status;
|
|
ULONG CreateAttributes = 0;
|
|
POS21X_SEM pRealSem;
|
|
PSZ eventname = NULL;
|
|
PSZ pszSrc, pszDst;
|
|
STRING CanonicalSemString, CanonicalEventString;
|
|
UNICODE_STRING CanonicalSemString_U;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
BOOL KeepName=FALSE;
|
|
|
|
if (pszSemName == NULL)
|
|
return ERROR_INVALID_NAME;
|
|
|
|
//
|
|
// We support \sem\XXX by creating a named event \sem32\XXX
|
|
// and a NtSemaphore named \sem32\XXXNt16Sem
|
|
//
|
|
|
|
eventname = RtlAllocateHeap (Od2Heap, 0, CCHMAXPATH);
|
|
if (eventname == NULL)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
//
|
|
// first chars must be \sem\. We leave the rest for Od2Canonicalize
|
|
//
|
|
|
|
try {
|
|
if ( ((pszSemName[0] != '\\') && (pszSemName[0] != '/')) ||
|
|
((pszSemName[1] != 's') && (pszSemName[1] != 'S')) ||
|
|
((pszSemName[2] != 'e') && (pszSemName[2] != 'E')) ||
|
|
((pszSemName[3] != 'm') && (pszSemName[3] != 'M')) ||
|
|
((pszSemName[4] != '\\') && (pszSemName[4] != '/'))) {
|
|
return ERROR_INVALID_NAME;
|
|
}
|
|
else {
|
|
eventname[0] = '\\';
|
|
eventname[1] = 's';
|
|
eventname[2] = 'e';
|
|
eventname[3] = 'm';
|
|
eventname[4] = '3';
|
|
eventname[5] = '2';
|
|
eventname[6] = '\\';
|
|
//
|
|
// Copy rest of string
|
|
//
|
|
pszSrc = pszSemName + 5;
|
|
pszDst = eventname + 7;
|
|
while (*pszSrc) {
|
|
*pszDst++ = *pszSrc++;
|
|
if ((pszSrc - pszSemName) >= CCHMAXPATH) {
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
return ERROR_INVALID_NAME;
|
|
}
|
|
}
|
|
*pszDst = '\0';
|
|
}
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP ();
|
|
}
|
|
//
|
|
// Prepare the Nt Semaphore name, by
|
|
// Canonicalizing and appendint nt16sem
|
|
//
|
|
rc = Od2Canonicalize( eventname,
|
|
CANONICALIZE_SEMAPHORE,
|
|
&CanonicalEventString,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (rc) {
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
return(rc);
|
|
}
|
|
|
|
if (UserSem == NULL && Insert) {
|
|
if (pRealSem = SemWasCreatedByThisProcess(CanonicalEventString.Buffer)) {
|
|
|
|
//
|
|
// We tried to open a system semaphore which has already
|
|
// been created or opened by this process
|
|
// we just have to inc. the counter and return the same handle
|
|
//
|
|
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
RtlFreeHeap(Od2Heap, 0,CanonicalEventString.Buffer);
|
|
|
|
if (pRealSem->SysSemCount == 0xff) {
|
|
KdPrint(("Od2OpenSem: SysSemCount overflow\n"));
|
|
}
|
|
else {
|
|
pRealSem->SysSemCount++;
|
|
}
|
|
*ppRealSem = pRealSem;
|
|
return (NO_ERROR);
|
|
}
|
|
KeepName = TRUE;
|
|
}
|
|
|
|
|
|
CanonicalSemString.Buffer = RtlAllocateHeap (
|
|
Od2Heap, 0,
|
|
CanonicalEventString.Length+8 // 8 for Ntsem16
|
|
);
|
|
|
|
if (CanonicalSemString.Buffer == NULL) {
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
RtlFreeHeap(Od2Heap, 0,CanonicalEventString.Buffer);
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
strncpy( CanonicalSemString.Buffer,
|
|
CanonicalEventString.Buffer,
|
|
CanonicalEventString.Length
|
|
);
|
|
CanonicalSemString.Buffer[CanonicalEventString.Length] = '\0';
|
|
strcpy(&(CanonicalSemString.Buffer[CanonicalEventString.Length]),
|
|
"Nt16sem");
|
|
CanonicalSemString.Buffer[CanonicalEventString.Length + 7] = '\0';
|
|
|
|
if (! KeepName) {
|
|
RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
|
|
}
|
|
|
|
//
|
|
// Convert Nt Semaphore string to Unicode
|
|
//
|
|
|
|
Od2InitMBString(&CanonicalSemString, CanonicalSemString.Buffer);
|
|
|
|
//
|
|
// UNICODE conversion -
|
|
//
|
|
rc = Od2MBStringToUnicodeString(
|
|
&CanonicalSemString_U,
|
|
&CanonicalSemString,
|
|
TRUE);
|
|
|
|
RtlFreeHeap(Od2Heap, 0,CanonicalSemString.Buffer);
|
|
|
|
if (rc) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("Od2OpenSem: no memory for Unicode Conversion\n");
|
|
}
|
|
#endif
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
if (KeepName) {
|
|
RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
&CanonicalSemString_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
|
|
pRealSem = (HSYSSEM)RtlAllocateHeap (Od2TiledHeap, 0, sizeof (OS21X_SEM));
|
|
if (pRealSem == NULL) {
|
|
#if DBG
|
|
DbgPrint("Od2OpenSem: out of space on Od2TiledHeap\n");
|
|
ASSERT(FALSE);
|
|
#endif
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
RtlFreeUnicodeString (&CanonicalSemString_U);
|
|
if (KeepName) {
|
|
RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
|
|
}
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
if (((ULONG)(pRealSem) > (ULONG)Od2TiledHeap + OD2TILEDHEAP_SIZE) && ((ULONG)(pRealSem) < (ULONG)Od2TiledHeap)) {
|
|
//
|
|
// Got out of the initial Heap, return error
|
|
//
|
|
#if DBG
|
|
DbgPrint("Od2OpenSem: out of space on Od2TiledHeap\n");
|
|
ASSERT(FALSE);
|
|
#endif
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
RtlFreeHeap (Od2TiledHeap, 0, pRealSem);
|
|
RtlFreeUnicodeString (&CanonicalSemString_U);
|
|
if (KeepName) {
|
|
RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
|
|
}
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
RtlZeroMemory(pRealSem, sizeof (OS21X_SEM));
|
|
|
|
//
|
|
// Open an Nt semaphore
|
|
//
|
|
Status = NtOpenSemaphore(&(pRealSem->Mutex),
|
|
SEMAPHORE_ALL_ACCESS,
|
|
&Obja);
|
|
|
|
RtlFreeUnicodeString (&CanonicalSemString_U);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
|
|
DbgPrint("Od2OpenSem: error at NtopenSemaphore, Status %x\n", Status);
|
|
}
|
|
#endif
|
|
#if DBG
|
|
if (((Os2DebugSem != 0) && (UserSem == Os2DebugSem)) ||
|
|
((Os2DebugSem3 != 0) && (UserSem == Os2DebugSem3)) ||
|
|
((Os2DebugSem2 != 0) && (UserSem == Os2DebugSem2)) ||
|
|
((Os2DebugSem1 != 0) && (UserSem == Os2DebugSem1)))
|
|
{
|
|
KdPrint(("[%d,%d] Od2OpenSem(%x,*=%x): failed to NtOpenSemaphore, eventname=%s, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
UserSem,
|
|
*(PULONG)UserSem,
|
|
eventname,
|
|
Status));
|
|
}
|
|
#endif // DBG
|
|
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
RtlFreeHeap (Od2TiledHeap, 0, pRealSem);
|
|
if (KeepName) {
|
|
RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
|
|
}
|
|
return ERROR_SEM_NOT_FOUND;
|
|
}
|
|
|
|
rc = DosOpenEventSem(eventname,
|
|
&(pRealSem->Event));
|
|
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("Od2OpenSem: error at DosOpenEventSem, Status %d\n", rc);
|
|
}
|
|
#endif
|
|
#if DBG
|
|
if (((Os2DebugSem != 0) && (UserSem == Os2DebugSem)) ||
|
|
((Os2DebugSem2 != 0) && (UserSem == Os2DebugSem2)) ||
|
|
((Os2DebugSem3 != 0) && (UserSem == Os2DebugSem3)) ||
|
|
((Os2DebugSem1 != 0) && (UserSem == Os2DebugSem1)))
|
|
{
|
|
KdPrint(("[%d,%d] Od2OpenSem(%x,*=%x): failed to DosOpenEventSem, rc=%d\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
UserSem,
|
|
*(PULONG)UserSem,
|
|
rc));
|
|
}
|
|
#endif // DBG
|
|
|
|
NtClose(pRealSem->Mutex);
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
RtlFreeHeap (Od2TiledHeap, 0, pRealSem);
|
|
if (KeepName) {
|
|
RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
pRealSem->OwnerThread = (TID)SEM_AT_INIT;
|
|
|
|
//
|
|
// UserSem:
|
|
// if NULL - indicates sys semaphore
|
|
// if non NULL - this is the pointer to a RAM sem
|
|
// that resides in a shared mem
|
|
// the reason we open it is to get real handles between processes
|
|
//
|
|
if (UserSem == NULL) {
|
|
pRealSem->pMyself = (PVOID)(&(pRealSem->pMyself));
|
|
if (Insert) {
|
|
pRealSem->u.SysSemName = CanonicalEventString.Buffer;
|
|
pRealSem->SysSemCount = 1;
|
|
}
|
|
}
|
|
else {
|
|
pRealSem->pMyself = (PVOID)UserSem;
|
|
}
|
|
|
|
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
|
|
if (Insert) {
|
|
//
|
|
// Link the new semaphore on the per-process semaphore
|
|
// list
|
|
//
|
|
|
|
Status = Od2AcquireMutant(Od2GarbageCollectSem);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("Od2OpenSem: failed to NtWaitForSingleObject on garbage sem, Status=%x\n",
|
|
Status));
|
|
}
|
|
else if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("[%d,%d] Od2OpenSem: WARNING !!! Wait on GarbageCollectSem, status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
pRealSem->Next = Od2Sem16ListHead;
|
|
Od2Sem16ListHead = (struct OS21X_SEM *)pRealSem;
|
|
Status = Od2ReleaseMutant(Od2GarbageCollectSem);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("Od2OpenSem: failed to NtReleaseSemaphore on sync sem, Status=%x\n",
|
|
Status));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Now set the output pointer to the sem structure
|
|
//
|
|
*ppRealSem = pRealSem;
|
|
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
APIRET
|
|
Od2CreateSem(
|
|
IN HSEM UserSem,
|
|
IN USHORT fExclusive,
|
|
OUT POS21X_SEM *ppRealSem,
|
|
IN PSZ pszSemName
|
|
)
|
|
{
|
|
APIRET rc = NO_ERROR;
|
|
NTSTATUS Status;
|
|
ULONG CreateAttributes = 0;
|
|
POS21X_SEM pRealSem;
|
|
PSZ eventname = NULL;
|
|
PSZ pszSrc, pszDst;
|
|
STRING CanonicalSemString, CanonicalEventString;
|
|
UNICODE_STRING CanonicalSemString_U;
|
|
OBJECT_ATTRIBUTES Obja, *pObja;
|
|
CHAR localSecurityDescriptor[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
|
|
|
// If the least significant byte of the RAM semaphore isn't 0, it must
|
|
// be created as busy semaphore. That means that after setting the least
|
|
// significant byte of the RAM semaphore to non-zero and calling for
|
|
// DosSemRequest or DosSemWait, thread will wait until any other thread
|
|
// will clear this semaphore.
|
|
|
|
BOOLEAN MakeBusy = (UserSem != NULL) && (((*(PULONG)UserSem) & 0xff) != 0);
|
|
|
|
BOOLEAN MakeSys = FALSE, KeepName=FALSE;
|
|
ULONG RegionSize = 0x10000;
|
|
ULONG SharedFlag;
|
|
HSEM tmpsem;
|
|
char *pchtmp;
|
|
|
|
pObja = NULL;
|
|
|
|
|
|
//
|
|
// UserSem:
|
|
// if NULL - indicates we create a sys semaphore
|
|
// by calling DosCreateSem
|
|
// if non NULL - this is the pointer to a RAM sem
|
|
// given by the app.
|
|
//
|
|
|
|
if (UserSem == NULL) {
|
|
|
|
MakeSys = TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Due to (somewhat awkward) 1.21 semantics, a RAM semaphore
|
|
// can be magically used by two processes, if happend to reside
|
|
// in a memory shared between them
|
|
//
|
|
rc = DosQueryMem(
|
|
(PVOID) UserSem,
|
|
&RegionSize,
|
|
&SharedFlag);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("Can't query shared mem %d\n", rc);
|
|
}
|
|
#endif
|
|
}
|
|
if (SharedFlag & PAG_SHARED) {
|
|
|
|
MakeSys = TRUE;
|
|
//
|
|
// makeup a name from the air, to be used later.
|
|
//
|
|
pszSemName = "\\SEM\\HACKNT00000";
|
|
//
|
|
// try in a loop to open it, increment number until
|
|
// we succeed.
|
|
// Start from the hint, that possibly will be the index of
|
|
// the empty slot.
|
|
//
|
|
do
|
|
{
|
|
Od2SemIndexHint++;
|
|
// We don't use index 0
|
|
if (Od2SemIndexHint == 0) {
|
|
Od2SemIndexHint++;
|
|
}
|
|
//
|
|
// construct last 4 characters as the digits of i
|
|
//
|
|
pchtmp = _itoa (Od2SemIndexHint, &pszSemName[11], 16);
|
|
rc = Od2OpenSem(NULL, &(POS21X_SEM)tmpsem, pszSemName,TRUE);
|
|
if (rc != NO_ERROR) {
|
|
|
|
//
|
|
// does not exist - go for it
|
|
//
|
|
// HSEM is:
|
|
//
|
|
// bit: 31 19 17 1
|
|
// |magic number|iswait| 16b index | 2bits for set/clear
|
|
|
|
*(PULONG)UserSem = ((ULONG)Od2SemIndexHint << 2) | 0xCCC00000;
|
|
|
|
#if DBG
|
|
#ifdef DBG_SEM_INDEX
|
|
if (Od2SemIndexHint == DBG_SEM_INDEX) {
|
|
DbgPrint("[%d,%d] Od2LookUpOrCreateSem: looping for open, got rc=%x for index %x for hsem=%x, *=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
rc,
|
|
DBG_SEM_INDEX
|
|
UserSem,
|
|
*(PULONG)UserSem
|
|
);
|
|
}
|
|
#endif // DBG_SEM_INDEX
|
|
#endif // DBG
|
|
break;
|
|
}
|
|
Od2CloseSem(FALSE,tmpsem);
|
|
} while (TRUE);
|
|
}
|
|
}
|
|
|
|
if ((MakeSys) && (pszSemName != NULL)) {
|
|
|
|
pObja = &Obja;
|
|
|
|
//
|
|
// We support \sem\XXX by creating a named event \sem32\XXX
|
|
// and a NtSemaphore named \sem32\XXXNt16Sem
|
|
//
|
|
|
|
eventname = RtlAllocateHeap (Od2Heap, 0, CCHMAXPATH);
|
|
if (eventname == NULL)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
//
|
|
// first chars must be \sem\. We leave the rest for Od2Canonicalize
|
|
//
|
|
|
|
try {
|
|
if ( ((pszSemName[0] != '\\') && (pszSemName[0] != '/')) ||
|
|
((pszSemName[1] != 's') && (pszSemName[1] != 'S')) ||
|
|
((pszSemName[2] != 'e') && (pszSemName[2] != 'E')) ||
|
|
((pszSemName[3] != 'm') && (pszSemName[3] != 'M')) ||
|
|
((pszSemName[4] != '\\') && (pszSemName[4] != '/'))) {
|
|
return ERROR_INVALID_NAME;
|
|
}
|
|
else {
|
|
eventname[0] = '\\';
|
|
eventname[1] = 's';
|
|
eventname[2] = 'e';
|
|
eventname[3] = 'm';
|
|
eventname[4] = '3';
|
|
eventname[5] = '2';
|
|
eventname[6] = '\\';
|
|
//
|
|
// Copy rest of string
|
|
//
|
|
pszSrc = pszSemName + 5;
|
|
pszDst = eventname + 7;
|
|
while (*pszSrc) {
|
|
*pszDst++ = *pszSrc++;
|
|
if ((pszSrc - pszSemName) >= CCHMAXPATH) {
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
return ERROR_INVALID_NAME;
|
|
}
|
|
}
|
|
// Null terminate string
|
|
*pszDst = '\0';
|
|
}
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP ();
|
|
}
|
|
//
|
|
// Prepare the Nt Semaphore name, by
|
|
// Canonicalizing and appendint nt16sem
|
|
//
|
|
rc = Od2Canonicalize( eventname,
|
|
CANONICALIZE_SEMAPHORE,
|
|
&CanonicalEventString,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (rc) {
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
if (rc == ERROR_FILE_NOT_FOUND ||
|
|
rc == ERROR_PATH_NOT_FOUND ||
|
|
rc == ERROR_FILENAME_EXCED_RANGE) {
|
|
return(ERROR_INVALID_NAME);
|
|
}
|
|
return(rc);
|
|
}
|
|
|
|
KeepName = (UserSem == NULL);
|
|
|
|
CanonicalSemString.Buffer =
|
|
RtlAllocateHeap (Od2Heap, 0,
|
|
CanonicalEventString.Length+8 // 8 for Ntsem16
|
|
);
|
|
|
|
if (CanonicalSemString.Buffer == NULL) {
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
RtlFreeHeap(Od2Heap, 0,CanonicalEventString.Buffer);
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
strncpy( CanonicalSemString.Buffer,
|
|
CanonicalEventString.Buffer,
|
|
CanonicalEventString.Length
|
|
);
|
|
CanonicalSemString.Buffer[CanonicalEventString.Length] = '\0';
|
|
strcpy (&(CanonicalSemString.Buffer[strlen(CanonicalSemString.Buffer)]),
|
|
"Nt16sem");
|
|
CanonicalSemString.Buffer[CanonicalEventString.Length+7] = '\0';
|
|
|
|
if (!KeepName) {
|
|
RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
|
|
}
|
|
|
|
//
|
|
// Convert Nt Semaphore string to Unicode
|
|
//
|
|
|
|
Od2InitMBString(&CanonicalSemString, CanonicalSemString.Buffer);
|
|
|
|
//
|
|
// UNICODE conversion -
|
|
//
|
|
|
|
rc = Od2MBStringToUnicodeString(
|
|
&CanonicalSemString_U,
|
|
&CanonicalSemString,
|
|
TRUE);
|
|
|
|
RtlFreeHeap(Od2Heap, 0,CanonicalSemString.Buffer);
|
|
|
|
if (rc) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("Od2CreateSem: no memory for Unicode Conversion\n");
|
|
}
|
|
#endif
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
if (KeepName) {
|
|
RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
// PatrickQ: create and attach a security descriptor. This was missing
|
|
// till August 10, 1994 and caused a bug when one instance of OS2.EXE
|
|
// creates an event, then in another user context (e.g. when using AT)
|
|
// OS2.EXE attempts to open the existing event => gets access denied.
|
|
// Prevented PMSHELL from running as a service.
|
|
|
|
Status = RtlCreateSecurityDescriptor( (PSECURITY_DESCRIPTOR)
|
|
&localSecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION );
|
|
if (!NT_SUCCESS( Status ))
|
|
{
|
|
#if DBG
|
|
DbgPrint("OS2: Od2CreateSem, failed at RtlCreateSecurityDescriptor %x\n",
|
|
Status);
|
|
#endif
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
if (KeepName)
|
|
{
|
|
RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
|
|
}
|
|
return ERROR_ACCESS_DENIED;
|
|
}
|
|
|
|
Status = RtlSetDaclSecurityDescriptor( (PSECURITY_DESCRIPTOR)
|
|
&localSecurityDescriptor,
|
|
(BOOLEAN)TRUE,
|
|
(PACL) NULL,
|
|
(BOOLEAN)FALSE );
|
|
|
|
if (!NT_SUCCESS( Status ))
|
|
{
|
|
#if DBG
|
|
DbgPrint("OS2: Od2CreateSem, failed at RtlSetDaclSecurityDescriptor %x\n",
|
|
Status);
|
|
#endif
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
if (KeepName)
|
|
{
|
|
RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
|
|
}
|
|
return ERROR_ACCESS_DENIED;
|
|
}
|
|
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
&CanonicalSemString_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
(PSECURITY_DESCRIPTOR) &localSecurityDescriptor);
|
|
|
|
}
|
|
|
|
pRealSem = (HSYSSEM)RtlAllocateHeap (Od2TiledHeap, 0, sizeof (OS21X_SEM));
|
|
if (pRealSem == NULL) {
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
if (eventname != NULL) {
|
|
RtlFreeUnicodeString (&CanonicalSemString_U);
|
|
}
|
|
if (KeepName) {
|
|
RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
|
|
}
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
if (((ULONG)(pRealSem) > (ULONG)Od2TiledHeap + OD2TILEDHEAP_SIZE) && ((ULONG)(pRealSem) < (ULONG)Od2TiledHeap)) {
|
|
//
|
|
// Got out of the initial Heap, return error
|
|
//
|
|
#if DBG
|
|
DbgPrint("Od2CreateSem: out of space on Od2TiledHeap\n");
|
|
ASSERT(FALSE);
|
|
#endif
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
RtlFreeHeap (Od2TiledHeap, 0, pRealSem);
|
|
RtlFreeUnicodeString (&CanonicalSemString_U);
|
|
if (KeepName) {
|
|
RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
|
|
}
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
RtlZeroMemory(pRealSem, sizeof (OS21X_SEM));
|
|
|
|
if (UserSem == NULL) {
|
|
if (fExclusive == CSEM_PUBLIC) {
|
|
CreateAttributes |= DC_SEM_SHARED;
|
|
pRealSem->FlagsByte |= SYSSEM_PUBLIC;
|
|
}
|
|
else {
|
|
pRealSem->FlagsByte |= SYSSEM_PRIVATE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create an Nt semaphore that has one free unit
|
|
//
|
|
Status = NtCreateSemaphore(&(pRealSem->Mutex),
|
|
SEMAPHORE_ALL_ACCESS,
|
|
pObja,
|
|
1,
|
|
1);
|
|
|
|
if (eventname != NULL) {
|
|
//
|
|
// free the unicode allocated string
|
|
//
|
|
RtlFreeUnicodeString (&CanonicalSemString_U);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("Od2CreateSem: error at NtCreateSemaphore, Status %x\n", Status);
|
|
#endif
|
|
if (eventname != NULL) {
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
}
|
|
RtlFreeHeap (Od2TiledHeap, 0, pRealSem);
|
|
if (KeepName) {
|
|
RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
|
|
}
|
|
switch (Status) {
|
|
case STATUS_OBJECT_NAME_COLLISION:
|
|
return ERROR_ALREADY_EXISTS;
|
|
default:
|
|
return (Or2MapNtStatusToOs2Error(Status, ERROR_TOO_MANY_SEMAPHORES));
|
|
}
|
|
}
|
|
|
|
pRealSem->OwnerThread = (TID)SEM_AT_INIT;
|
|
|
|
if (MakeBusy) {
|
|
|
|
// Busy semaphore will be created. It is created as a result of using
|
|
// DosSemRequest for the 1st time for the RAM semaphore that it's
|
|
// least significant byte wasn't zero.
|
|
|
|
NTSTATUS Status;
|
|
TIME Time = {0L, 0L};
|
|
|
|
// NT semaphore is free after creation. Take the semaphore
|
|
// (with timeout 0).
|
|
|
|
Status = NtWaitForSingleObject(
|
|
pRealSem->Mutex,
|
|
TRUE,
|
|
&Time);
|
|
|
|
// We must always get SUCCESS. The semaphore was just created and
|
|
// no one can get it, because this code is protected by Od2Sync.
|
|
// Just in the case ... print appropriate message.
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
#if DBG
|
|
DbgPrint("[%d,%d] ERROR !!! Od2CreateSem %x : *=%x NtWaitForSingleObject fail with %x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(), UserSem, *(PULONG)UserSem, Status);
|
|
#endif // DBG
|
|
}
|
|
else
|
|
{
|
|
// Print this message always. We will be prompted if apps
|
|
// use busy semaphores. Lotus Notes 3.0 is the only known app that
|
|
// do it.
|
|
#if DBG
|
|
DbgPrint("[%d,%d] Od2CreateSem %x : *=%x make busy semaphore\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(), UserSem, *(PULONG)UserSem);
|
|
#endif // DBG
|
|
}
|
|
}
|
|
|
|
// Make the event initially not signaled if the semaphore must be maked
|
|
// busy.
|
|
|
|
rc = DosCreateEventSem(eventname,
|
|
&(pRealSem->Event),
|
|
CreateAttributes,
|
|
!MakeBusy);
|
|
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("Od2CreateSem: error at DosCreateEventSem, Status %d\n", rc);
|
|
}
|
|
#endif
|
|
NtClose(pRealSem->Mutex);
|
|
if (eventname != NULL)
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
RtlFreeHeap (Od2TiledHeap, 0, pRealSem);
|
|
if (KeepName) {
|
|
RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// if a system semaphore:
|
|
// Make pRealSem->pMyself to point at itself
|
|
// Keep its name
|
|
//
|
|
// if a RAM semaphore:
|
|
// Make pRealSem->pMyself the initial pointer
|
|
// provided by the program
|
|
//
|
|
|
|
if (UserSem == NULL) {
|
|
pRealSem->pMyself = (PVOID)(&(pRealSem->pMyself));
|
|
if (pszSemName != NULL) {
|
|
pRealSem->u.SysSemName = CanonicalEventString.Buffer;
|
|
pRealSem->SysSemCount = 1;
|
|
}
|
|
}
|
|
else {
|
|
pRealSem->pMyself = (PVOID)UserSem;
|
|
}
|
|
//
|
|
// Link the new semaphore on the per-process semaphore
|
|
// list
|
|
//
|
|
|
|
Status = Od2AcquireMutant(Od2GarbageCollectSem);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("Od2CreateSem: failed to NtWaitForSingleObject on garbage sem, Status=%x\n",
|
|
Status));
|
|
}
|
|
else if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("[%d,%d] Od2CreateSem: WARNING !!! Wait on GarbageCollectSem, status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
|
|
pRealSem->Next = Od2Sem16ListHead;
|
|
Od2Sem16ListHead = (struct OS21X_SEM *)pRealSem;
|
|
Status = Od2ReleaseMutant(Od2GarbageCollectSem);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status) && Status != STATUS_SEMAPHORE_LIMIT_EXCEEDED) {
|
|
KdPrint(("Od2CreateSem: failed to NtReleaseSemaphore on sync sem, Status=%x\n",
|
|
Status));
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Now set the output pointer to the sem structure
|
|
//
|
|
*ppRealSem = pRealSem;
|
|
|
|
if (eventname != NULL)
|
|
RtlFreeHeap (Od2Heap, 0, eventname);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
BOOLEAN GarbageCollect(VOID)
|
|
{
|
|
|
|
//
|
|
// This routine is called when Od2CreateSem is unable to create a new
|
|
// RAM semaphore. This can be caused by the fact that in OS/2 a RAM semaphore
|
|
// requires almost 0 resources, while in NT it is a OS21X_SEM strcuture, plus
|
|
// two objects - event and semaphore
|
|
//
|
|
// The algorithm is:
|
|
// raise the lockflag so subsequent calls to Od2LookupSem lock,
|
|
// lock the task lock
|
|
// go thru the list of RAM semaphores, find private RAM semaphores
|
|
// which are cleared, close them and free heap.
|
|
// release the task lock. Subsequent calls to the deleted semaphores will
|
|
// recreate them
|
|
// clear the lock flag
|
|
//
|
|
|
|
POS21X_SEM pPrevSem, pRealSem;
|
|
HSEM hsem;
|
|
NTSTATUS Status;
|
|
APIRET rc;
|
|
BOOLEAN DeletedSomeStuff = FALSE;
|
|
ULONG hsem_value;
|
|
#if DBG
|
|
ULONG NumSem = 0, NumFreed = 0;
|
|
#endif //DBG
|
|
|
|
LockFlag = TRUE;
|
|
Status = Od2AcquireMutant(Od2GarbageCollectSem);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("Od2GarbageCollect: failed to NtWaitForSingleObject on garbage sem, Status=%x\n",
|
|
Status));
|
|
}
|
|
else if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("[%d,%d] GarbageCollect: WARNING !!! Wait on GarbageCollectSem, status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
//
|
|
// Allow all threads in this process, which may got thru Od2LookupSem,
|
|
// and did not finish an API, to do so, before we gargage collect
|
|
// 1. Those that were waiting on a cleared semaphore, will get it
|
|
// 2. Those that were clearing a semaphore will clear it and free
|
|
// the threads in category 1.
|
|
// 3. Those waiting on a non-cleared semaphore, will keep waiting, however
|
|
// the garbage collector does not free these semaphores.
|
|
//
|
|
Sleep(2000);
|
|
for (pRealSem = pPrevSem = (POS21X_SEM)Od2Sem16ListHead;
|
|
pPrevSem->Next != NULL;) {
|
|
|
|
#if DBG
|
|
NumSem++;
|
|
#endif //DBG
|
|
//
|
|
// check if a private RAM sem
|
|
//
|
|
hsem = (HSEM)(pRealSem->pMyself);
|
|
|
|
// Validate validity of each semaphore in the list
|
|
try
|
|
{
|
|
hsem_value = *(PULONG)hsem;
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
#if DBG
|
|
DbgPrint("[%d,%d] GarbageCollect: WARNING !!! can't access RAM semaphore %x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem);
|
|
#endif
|
|
//
|
|
// Can't access this semaphore - maybe memory was released !
|
|
// Remove this semaphore from the list and go to next by
|
|
// setting value to 0
|
|
hsem_value = 0;
|
|
}
|
|
|
|
if ((hsem_value != (ULONG)hsem) &&
|
|
((hsem_value & 0xFFF00000) != 0xCCC00000)) {
|
|
//
|
|
// Private RAM Semaphore:
|
|
//
|
|
if (hsem_value == 0) {
|
|
|
|
LONG PreviousCount;
|
|
|
|
// defend against:DosSemClear already zeroed hsem but haven't
|
|
// released it yet
|
|
|
|
NtReleaseSemaphore (
|
|
pRealSem->Mutex,
|
|
1,
|
|
&PreviousCount);
|
|
|
|
//
|
|
// It is cleared - delete it
|
|
//
|
|
|
|
Status = NtClose (pRealSem->Mutex);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("DosCloseSem: error at NtClose, Status %x\n", Status);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
DeletedSomeStuff = TRUE;
|
|
}
|
|
|
|
// defend against:DosSemClear already zeroed hsem but haven't
|
|
// released it yet
|
|
|
|
DosPostEventSem (pRealSem->Event);
|
|
|
|
//
|
|
// delete it
|
|
//
|
|
rc = DosCloseEventSem (pRealSem->Event);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("DosCloseSem: error at DosCloseEventSem, Status %d\n", rc);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
DeletedSomeStuff = TRUE;
|
|
}
|
|
|
|
#if DBG
|
|
NumFreed++;
|
|
#endif
|
|
//
|
|
// unlink it
|
|
//
|
|
if (pRealSem == (POS21X_SEM)Od2Sem16ListHead) {
|
|
//
|
|
// chop the head of the list, start from scratch
|
|
//
|
|
Od2Sem16ListHead = pRealSem->Next;
|
|
//
|
|
// Free sem structure from heap;
|
|
RtlFreeHeap(Od2TiledHeap, 0, pRealSem);
|
|
pRealSem = pPrevSem = (POS21X_SEM)Od2Sem16ListHead;
|
|
}
|
|
else {
|
|
pPrevSem->Next = pRealSem->Next;
|
|
//
|
|
// Free sem structure from heap;
|
|
RtlFreeHeap(Od2TiledHeap, 0, pRealSem);
|
|
pRealSem = (POS21X_SEM)(pPrevSem->Next);
|
|
}
|
|
Od2NumSemCreated = 0;
|
|
}
|
|
else {
|
|
//
|
|
// Semaphore is not clear - skip
|
|
//
|
|
pPrevSem = pRealSem;
|
|
pRealSem = (POS21X_SEM)(pPrevSem->Next);
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// Not A private RAM semaphore - skip
|
|
pPrevSem = pRealSem;
|
|
pRealSem = (POS21X_SEM)(pPrevSem->Next);
|
|
}
|
|
}
|
|
Status = Od2ReleaseMutant(Od2GarbageCollectSem);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("Os2 - GarbageCollect: failed to NtReleaseSemaphore on sync sem, Status=%x\n",
|
|
Status));
|
|
}
|
|
KdPrint(("Os2 - GarbageCollect: found %d semaphores, deleted %d\n",
|
|
NumSem,NumFreed));
|
|
#endif
|
|
LockFlag = FALSE;
|
|
return(DeletedSomeStuff);
|
|
}
|
|
|
|
//
|
|
// The parameter CheckInitializationOfSem must be TRUE only if Od2LookupOrCreateSem was
|
|
// called from DosSemRequest or DosSemWait. In this case busy semaphore might be created (only
|
|
// if there is RAM semaphore that used for the 1st time). Busy semaphore, while
|
|
// created cause until other thread will clear the semaphore by DosSemClear.
|
|
//
|
|
|
|
POS21X_SEM
|
|
Od2LookupOrCreateSem (
|
|
HSEM hsem,
|
|
PBOOLEAN firsttime,
|
|
ULONG source
|
|
)
|
|
{
|
|
APIRET rc = NO_ERROR;
|
|
POS21X_SEM pRealSem, pPrevSem;
|
|
ULONG tmp;
|
|
NTSTATUS Status;
|
|
BOOLEAN FlushSharedRamSem = FALSE;
|
|
|
|
PSZ pszSemName;
|
|
char *pchtmp;
|
|
|
|
pRealSem = Od2LookupSem(hsem);
|
|
|
|
if (pRealSem != NULL) {
|
|
if (pRealSem->u.SharedRamSignature &&
|
|
pRealSem->pMyself != (PVOID)(&(pRealSem->pMyself))) {
|
|
|
|
//
|
|
// if a RAM semaphore in shared memory, check that the
|
|
// actual signature in the pRealSem structure (per process)
|
|
// is identical to the signature in shared memory. If it
|
|
// is not, it means that this is a re-use of old sem, in
|
|
// which case we cleanup and use this structure for the new
|
|
// semaphore
|
|
//
|
|
|
|
if ((*(PULONG)hsem & 0x3FFFC) != (pRealSem->u.SharedRamSignature & 0x3FFFC)) {
|
|
#if PMNT
|
|
#if DBG
|
|
DbgPrint("[%d,%d] Od2LookupOrCreateSem: signature mismatch, hsem=%x, *=%x, signature=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem,
|
|
pRealSem->u.SharedRamSignature);
|
|
#endif // DBG
|
|
#endif // PMNT
|
|
FlushSharedRamSem = TRUE;
|
|
goto SyncLabel;
|
|
}
|
|
}
|
|
|
|
*firsttime = FALSE;
|
|
return(pRealSem);
|
|
}
|
|
|
|
SyncLabel:
|
|
Status = Od2AcquireSync();
|
|
#if DBG
|
|
if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("[%d,%d] Od2LookupOrCreateSem: FAILED to NtWaitForSingleObject on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
|
|
pRealSem = Od2LookupSem(hsem);
|
|
|
|
if (FlushSharedRamSem) {
|
|
//
|
|
// see if another thread in this process did not fix it yet
|
|
//
|
|
if ((*(PULONG)hsem & 0x3FFFC) != (pRealSem->u.SharedRamSignature & 0x3FFFC)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("FlushSharedRamSem: Flushing reference of *hsem %x, pRealSem at %x\n",
|
|
*(PULONG)hsem, pRealSem);
|
|
}
|
|
#endif
|
|
if ((source & SEM_FROM_CLEAR) && ((*(PULONG)hsem & 0xFFF00000) != 0xCCC00000)) {
|
|
Status = Od2ReleaseSync();
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] Od2LookupOrCreateSem (flashing skipped): failed to NtReleaseMutant on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
*firsttime = FALSE;
|
|
//
|
|
// *(PULONG)hsem &= 0xffffff00;
|
|
//
|
|
__asm
|
|
{
|
|
mov eax, hsem
|
|
lock and dword ptr [eax], 0xffffff00
|
|
}
|
|
return(pRealSem);
|
|
}
|
|
|
|
#if PMNT
|
|
#if DBG
|
|
DbgPrint("[%d,%d] FlushSharedRamSem: Flushing reference of hsem=%x, *=%x, signature=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem,
|
|
pRealSem->u.SharedRamSignature);
|
|
#endif // DBG
|
|
#endif // PMNT
|
|
//
|
|
// Need to flush and recreate the process copy of the
|
|
// shared RAM sem
|
|
//
|
|
// 1. close handles
|
|
// 2. unlink structure and free memory
|
|
// 3. let the algorithm below take care of it as a new
|
|
// shared RAM semaphore
|
|
//
|
|
Status = NtClose (pRealSem->Mutex);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("FlushShareRamSem: error at NtClose, Status %x\n", Status);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
rc = DosCloseEventSem (pRealSem->Event);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("FlushShareRamSem: error at DosCloseEventSem, Status %d\n", rc);
|
|
}
|
|
#endif
|
|
}
|
|
//
|
|
// Now unlink it from the per-process semaphore list
|
|
// and free heap space allocated
|
|
//
|
|
|
|
Status = Od2AcquireMutant(Od2GarbageCollectSem);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("FlushSharedRamSem: FAILED to NtWaitForSingleObject on garbage sem, Status=%x\n",
|
|
Status));
|
|
}
|
|
else if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("[%d,%d] Od2LookupOrCreateSem: WARNING !!! Wait on GarbageCollectSem, status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
if (pRealSem == (POS21X_SEM)Od2Sem16ListHead) {
|
|
//
|
|
// Get rid of first on the list
|
|
//
|
|
|
|
Od2Sem16ListHead = pRealSem->Next;
|
|
RtlFreeHeap(Od2TiledHeap, 0, pRealSem);
|
|
}
|
|
else {
|
|
for (pPrevSem = (POS21X_SEM)Od2Sem16ListHead;
|
|
pPrevSem->Next != NULL;
|
|
pPrevSem = (POS21X_SEM)(pPrevSem->Next)) {
|
|
|
|
if ((POS21X_SEM)(pPrevSem->Next) == pRealSem) {
|
|
|
|
//
|
|
// Found our semaphore on the list
|
|
//
|
|
|
|
pPrevSem->Next = pRealSem->Next;
|
|
RtlFreeHeap(Od2TiledHeap, 0, pRealSem);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Shared RAM semaphore was closed.
|
|
//
|
|
Od2NumSemCreated--;
|
|
|
|
Status = Od2ReleaseMutant(Od2GarbageCollectSem);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("FlushSharedRamSem: failed to NtReleaseSemaphore on sync sem, Status=%x\n",
|
|
Status));
|
|
}
|
|
#endif
|
|
pRealSem = NULL;
|
|
}
|
|
else {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("FlushShareRamSem: Another thread in this process Flushed reference of *hsem %x, pRealSem at %x\n",
|
|
*(PULONG)hsem, pRealSem);
|
|
}
|
|
#endif
|
|
#if PMNT
|
|
#if DBG
|
|
DbgPrint("[%d,%d] FlushShareRamSem: Another thread in this process flushed reference of hsem=%x, *=%x, signature=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem,
|
|
pRealSem->u.SharedRamSignature);
|
|
#endif // DBG
|
|
#endif // PMNT
|
|
}
|
|
}
|
|
|
|
if (pRealSem != NULL) {
|
|
*firsttime = FALSE;
|
|
Status = Od2ReleaseSync();
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] Od2LookupOrCreateSem (semaphore was found): failed to NtReleaseMutant on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
|
|
return(pRealSem);
|
|
}
|
|
|
|
//
|
|
// A RAM Semaphore first call in this process.
|
|
// Initialize an OS21X_SEM by a call to
|
|
// Od2CreateSem or Od2OpenSem
|
|
//
|
|
//
|
|
// check for a magic number that mark RAM semaphores
|
|
// that reside in shared memory
|
|
//
|
|
|
|
tmp = *(PULONG)hsem;
|
|
if ((tmp & 0xFFF00000) == 0xCCC00000) {
|
|
*firsttime = FALSE;
|
|
|
|
//
|
|
// makeup a name from the air, to be used later.
|
|
//
|
|
pszSemName = "\\SEM\\HACKNT00000";
|
|
//
|
|
// HSEM is:
|
|
//
|
|
// bit: 31 17 1
|
|
// |magic number | 16b index | 2bits for set/clear|
|
|
//
|
|
// extract the sem index out of sem handle
|
|
//
|
|
tmp = (tmp >> 2) & 0xFFFF;
|
|
//
|
|
// construct last 4 characters as the digits of i
|
|
//
|
|
pchtmp = _itoa (tmp, &pszSemName[11], 16);
|
|
|
|
//
|
|
// open the semaphore (RAM sem created previously in shared mem
|
|
//
|
|
rc = Od2OpenSem(
|
|
hsem,
|
|
&pRealSem,
|
|
pszSemName,
|
|
TRUE);
|
|
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
|
|
((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
|
|
((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
|
|
((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1)))
|
|
{
|
|
KdPrint(("[%d,%d] Od2LookupOrCreateSem(%x,*=%x): failed to Od2OpenSem on %s, rc=%d\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem,
|
|
pszSemName,
|
|
rc));
|
|
}
|
|
#endif // DBG
|
|
|
|
// Create semaphore.
|
|
//
|
|
|
|
if (!(source & SEM_FROM_REQUESTWAIT)) {
|
|
|
|
// Erase the least significat byte of the semaphore,
|
|
// so semaphore will not be created in busy state.
|
|
|
|
//
|
|
// *(PULONG)hsem &= 0xffffff00;
|
|
//
|
|
__asm
|
|
{
|
|
mov eax, hsem
|
|
lock and dword ptr [eax], 0xffffff00
|
|
}
|
|
}
|
|
|
|
*firsttime = TRUE;
|
|
//
|
|
// We failed to open - there was garbage in the user memory
|
|
// Create the semaphore
|
|
//
|
|
rc = Od2CreateSem(
|
|
hsem,
|
|
CSEM_PRIVATE,
|
|
&pRealSem,
|
|
NULL);
|
|
#if DBG
|
|
#ifdef DBG_SEM_INDEX
|
|
if ((*(PULONG)hsem & 0x3FFFC) == (DBG_SEM_INDEX << 2)) {
|
|
KdPrint(("[%d,%d] Od2LookupOrCreateSem: created (due to garbage) %x for hsem=%x, *=%x, rc=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
DBG_SEM_INDEX,
|
|
hsem,
|
|
*(PULONG)hsem,
|
|
rc
|
|
));
|
|
}
|
|
#endif // DBG_SEM_INDEX
|
|
#endif // DBG
|
|
}
|
|
#if DBG
|
|
#ifdef DBG_SEM_INDEX
|
|
else {
|
|
//
|
|
// success opening
|
|
//
|
|
if (tmp == (DBG_SEM_INDEX << 2)) {
|
|
KdPrint(("[%d,%d] Od2LookupOrCreateSem: opened %x for hsem=%x, *=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
DBG_SEM_INDEX,
|
|
hsem,
|
|
*(PULONG)hsem
|
|
));
|
|
}
|
|
}
|
|
#endif // DBG_SEM_INDEX
|
|
#endif // DBG
|
|
//
|
|
// record the signature of the ram sem for later checks
|
|
//
|
|
if (rc == NO_ERROR) {
|
|
pRealSem->u.SharedRamSignature = *(PULONG)hsem;
|
|
}
|
|
}
|
|
else {
|
|
|
|
if (!(source & SEM_FROM_REQUESTWAIT)) {
|
|
|
|
// Erase the least significat byte of the semaphore,
|
|
// so semaphore will not be created in busy state.
|
|
|
|
//
|
|
// *(PULONG)hsem &= 0xffffff00;
|
|
//
|
|
__asm
|
|
{
|
|
mov eax, hsem
|
|
lock and dword ptr [eax], 0xffffff00
|
|
}
|
|
}
|
|
|
|
*firsttime = TRUE;
|
|
|
|
//
|
|
// Create the semaphore (usual case)
|
|
//
|
|
rc = Od2CreateSem(
|
|
hsem,
|
|
CSEM_PRIVATE,
|
|
&pRealSem,
|
|
NULL);
|
|
|
|
if (rc == NO_ERROR) {
|
|
if ((*(PULONG)hsem & 0xFFF00000) == 0xCCC00000) {
|
|
//
|
|
// record the signature of the ram sem for later checks
|
|
//
|
|
pRealSem->u.SharedRamSignature = *(PULONG)hsem;
|
|
#if DBG
|
|
#if DBG_SEM_INDEX
|
|
if ((*(PULONG)hsem & 0x3FFFC) == (DBG_SEM_INDEX << 2)) {
|
|
KdPrint(("[%d,%d] Od2LookupOrCreateSem: created (new) %x for hsem=%x, *=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
DBG_SEM_INDEX,
|
|
hsem,
|
|
*(PULONG)hsem
|
|
));
|
|
}
|
|
#endif //DBG_SEM_INDEX
|
|
#endif //DBG
|
|
}
|
|
}
|
|
|
|
#ifdef PMNT
|
|
#if DBG
|
|
if (FlushSharedRamSem) {
|
|
DbgPrint("[%d,%d] FlushShareRamSem: created new entry for hsem=%x, *=%x, signature=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem,
|
|
pRealSem->u.SharedRamSignature);
|
|
}
|
|
#endif // DBG
|
|
#endif // PMNT
|
|
}
|
|
|
|
Od2NumSemCreated++;
|
|
Status = Od2ReleaseSync();
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] Od2LookupOrCreateSem (semaphore was created): failed to NtReleaseMutant on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
|
|
if ((rc != NO_ERROR && rc != ERROR_ALREADY_EXISTS && rc != ERROR_DUPLICATE_NAME && rc != ERROR_INVALID_NAME) ||
|
|
(Od2NumSemCreated > OD2SEMTHRESHOLD)) {
|
|
#if DBG
|
|
if (rc != NO_ERROR) {
|
|
DbgPrint ("Od2LookupOrCreate: error initializing a RAM sem %d, call GarbageCollect()\n", rc);
|
|
}
|
|
else {
|
|
DbgPrint ("Od2LookupOrCreate: low on RAM semaphores - call GarbageCollect\n");
|
|
}
|
|
#endif
|
|
if (GarbageCollect()) {
|
|
//
|
|
// Succeeded to gain more resources, try again
|
|
//
|
|
#if DBG
|
|
DbgPrint ("Od2LookupOrCreate: GarbageCollect freed some resource, try create again\n");
|
|
#endif
|
|
// Call Od2LookupOrCreateSem with the same value for parameter "source"
|
|
|
|
return (Od2LookupOrCreateSem (hsem, firsttime, source));
|
|
|
|
}
|
|
//
|
|
// no resources - quit
|
|
//
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
DbgPrint ("OS2: GarbageCollect could not free resources, Exit Application\n");
|
|
#endif
|
|
DosExit(EXIT_PROCESS, 0);
|
|
}
|
|
|
|
#if DBG
|
|
DbgPrint("OS2: GarbageCollect could not free resources, return NULL\n");
|
|
#endif
|
|
return NULL;
|
|
}
|
|
//
|
|
// expected errors - return NULL (the rest were checked above)
|
|
//
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("Od2LookupOrCreate: error initializing a RAM sem, %d\n", rc);
|
|
}
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
return(pRealSem);
|
|
}
|
|
|
|
/*
|
|
This routine is called upon process exit clean-up.
|
|
The idea here is to go through the private list of semaphores and, for
|
|
each shared RAM semaphore, do:
|
|
- close the associated NT events
|
|
- if the signature matches the contents of the RAM semaphore:
|
|
- try to open the NT events
|
|
- if we get an error, this means we were the last to keep a handle to those
|
|
events, so we should clear the RAM semaphore so that the OS/2 ss won't
|
|
think later on (when/if this same RAM location is used as a shared RAM
|
|
semaphore) it is a RAM semaphore with a valid index.
|
|
NOTICE: we do not remove the entries from the Od2Sem16ListHead list. We
|
|
just close the handles stored there. This is based on the assumption
|
|
that nobody will need this list past this point and that the memory
|
|
used for the list will be freed soon when the process exits.
|
|
*/
|
|
VOID
|
|
Od2CloseAllRAMSharedSemaphores( VOID)
|
|
{
|
|
|
|
POS21X_SEM pSem;
|
|
HSEM hsem, tmpsem;
|
|
PSZ pszSemName, pchtmp;
|
|
ULONG index;
|
|
APIRET rc;
|
|
NTSTATUS Status;
|
|
|
|
pSem = (POS21X_SEM)Od2Sem16ListHead;
|
|
|
|
while (pSem != NULL) {
|
|
|
|
if (pSem->u.SharedRamSignature && // Shared
|
|
pSem->pMyself != (PVOID)(&(pSem->pMyself))) { // Ram
|
|
|
|
Status = Od2AcquireSync();
|
|
#if DBG
|
|
if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("[%d,%d] Od2CloseAllRAMSharedSemaphores: FAILED to NtWaitForSingleObject on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
|
|
if (DosCloseSemNoRemove(pSem,FALSE)) {
|
|
Status = Od2ReleaseSync();
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] Od2CloseAllRAMSharedSemaphores (close fail): failed to NtReleaseMutant on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
hsem = pSem->pMyself;
|
|
|
|
try {
|
|
index = (*(PULONG)hsem & 0x3FFFF) >> 2;
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
pSem = (POS21X_SEM)(pSem->Next);
|
|
|
|
Status = Od2ReleaseSync();
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] Od2CloseAllRAMSharedSemaphores (exception handler): failed to NtReleaseMutant on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
if ((pSem->u.SharedRamSignature & 0x3FFFC) == (*(PULONG)hsem & 0x3FFFC)) {
|
|
//
|
|
// compose the name for the semaphore
|
|
//
|
|
pszSemName = "\\SEM\\HACKNT00000";
|
|
//
|
|
// construct last 4 characters as the digits of i
|
|
//
|
|
pchtmp = _itoa (index, &pszSemName[11], 16);
|
|
rc = Od2OpenSem(NULL, &(POS21X_SEM)tmpsem, pszSemName,FALSE);
|
|
|
|
if (rc == ERROR_SEM_NOT_FOUND) {
|
|
//
|
|
// This was the last open handle. The semaphore must flushed by other
|
|
// processes.
|
|
//
|
|
if ((*(PULONG)hsem & 0xFFF00000) == 0xCCC00000) {
|
|
|
|
//
|
|
// *(PULONG)hsem = 0xCCC00000;
|
|
//
|
|
// If the signature is used by app (it isn't 0xCCC?????) like PMSHELL
|
|
// that use the most significant word of the semaphore for managing
|
|
// list of free semaphores for reusing, don't write 0xCCC00000 signature.
|
|
// In this case the semaphore will be flushed as well.
|
|
// Unfortunately there is a small time window that the value that might
|
|
// be used by app was destroyed.
|
|
//
|
|
__asm {
|
|
mov eax, hsem
|
|
mov cx, 0xCCC0
|
|
xchg word ptr [eax+2], cx
|
|
mov dx, cx
|
|
and dx, 0xFFF0
|
|
cmp dx, 0xCCC0
|
|
je Od2CloseRamSemOk
|
|
xchg cx, word ptr [eax+2]
|
|
Od2CloseRamSemOk:
|
|
mov word ptr [eax], 0
|
|
}
|
|
}
|
|
}
|
|
else if (rc == NO_ERROR) {
|
|
DosCloseSemNoRemove(tmpsem,TRUE);
|
|
}
|
|
#if DBG
|
|
else {
|
|
DbgPrint("[%d,%d] Od2CloseAllRAMSharedSemaphores: Fail to open. rc=%d\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
rc);
|
|
}
|
|
#endif // DBG
|
|
}
|
|
|
|
pSem = (POS21X_SEM)(pSem->Next);
|
|
|
|
Status = Od2ReleaseSync();
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] Od2CloseAllRAMSharedSemaphores: failed to NtReleaseMutant on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
pSem = (POS21X_SEM)(pSem->Next);
|
|
}
|
|
}
|
|
|
|
// The process is over and we used Od2Sync for the last time. This is the
|
|
// good opportunity to close it's handle.
|
|
|
|
Status = NtClose(Od2SyncSem);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] Od2CloseAllRAMSharedSemaphores: failed to NtClose sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif // DBG
|
|
|
|
}
|
|
|
|
APIRET
|
|
DosCreateSem(
|
|
IN USHORT fExclusive,
|
|
OUT PHSYSSEM phSem,
|
|
IN PSZ pszSemName
|
|
)
|
|
{
|
|
ULONG Sem;
|
|
APIRET rc = NO_ERROR;
|
|
POS21X_SEM pRealSem;
|
|
NTSTATUS Status;
|
|
|
|
try {
|
|
Od2ProbeForWrite( phSem, sizeof( HSYSSEM ), 1 );
|
|
Od2ProbeForRead( pszSemName, 2, 1 );
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP ();
|
|
}
|
|
|
|
if (fExclusive != CSEM_PRIVATE && fExclusive != CSEM_PUBLIC){
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
Status = Od2AcquireSync();
|
|
#if DBG
|
|
if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("[%d,%d] DosCreateSem: failed to NtWaitForSingleObject on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
|
|
rc = Od2CreateSem(
|
|
NULL,
|
|
fExclusive,
|
|
&pRealSem,
|
|
pszSemName);
|
|
|
|
Status = Od2ReleaseSync();
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] DosCreateSem: failed to NtReleaseMutant on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("DosCreateSem: error calling Od2CreateSem, %d\n", rc);
|
|
}
|
|
#endif
|
|
return rc;
|
|
}
|
|
|
|
Sem = (ULONG) *phSem = (ULONG) pRealSem;
|
|
*phSem = (POS21X_SEM)(FLATTOFARPTR(Sem));
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
APIRET
|
|
Od2CloseSem(
|
|
IN BOOL SyncFlag,
|
|
IN HSEM hsem
|
|
)
|
|
{
|
|
APIRET rc = NO_ERROR;
|
|
NTSTATUS Status;
|
|
POS21X_SEM pRealSem, pPrevSem;
|
|
|
|
try {
|
|
Od2ProbeForWrite( (PVOID)hsem, sizeof( HSYSSEM ), 1 );
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP ();
|
|
}
|
|
|
|
pRealSem = Od2LookupSem(hsem);
|
|
|
|
if (pRealSem == NULL) {
|
|
// not found or ram sem handle
|
|
return ERROR_INVALID_HANDLE;
|
|
}
|
|
|
|
//
|
|
// SyncFlag is true when called from DosCloseSem
|
|
// it is false when called from Od2OpenSem,
|
|
// where we have already issued Od2AcquireSync()
|
|
//
|
|
if (SyncFlag) {
|
|
Status = Od2AcquireSync();
|
|
#if DBG
|
|
if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("[%d,%d] DosCloseSem: failed to NtWaitForSingleObject on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (pRealSem->SysSemCount > 1 ) {
|
|
//
|
|
// System semaphore was created/opened more than once
|
|
// we shouldn't close it yet
|
|
//
|
|
pRealSem->SysSemCount --;
|
|
|
|
if (SyncFlag) {
|
|
Status = Od2ReleaseSync();
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] DosCloseSem: failed to NtReleaseMutant on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
if (SyncFlag) {
|
|
Status = Od2ReleaseSync();
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] DosCloseSem: failed to NtReleaseMutant on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
}
|
|
//
|
|
// On OS/2, a Set System Semaphore can not be closed
|
|
// perform a wait with no blocking, and if no_error
|
|
// close
|
|
//
|
|
if (pRealSem->FlagsByte != 0) {
|
|
|
|
rc = DosSemWait(
|
|
hsem,
|
|
0);
|
|
if (rc != NO_ERROR){
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("DosCloseSem: error at DosSemWait, rc %d, return ERROR_SEM_IS_SET\n", rc);
|
|
}
|
|
DbgPrint("[%d,%d] DosCloseSem(%x): DosSemWait returned rc=%d\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
rc);
|
|
#endif
|
|
return (ERROR_SEM_IS_SET);
|
|
}
|
|
}
|
|
|
|
Status = NtClose (pRealSem->Mutex);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("DosCloseSem: error at NtClose, Status %x\n", Status);
|
|
}
|
|
#endif
|
|
return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE));
|
|
}
|
|
|
|
rc = DosCloseEventSem (pRealSem->Event);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("DosCloseSem: error at DosCloseEventSem, Status %d\n", rc);
|
|
}
|
|
#endif
|
|
return rc;
|
|
}
|
|
//
|
|
// Now unlink it from the per-process semaphore list
|
|
// and free heap space allocated
|
|
//
|
|
|
|
Status = Od2AcquireMutant(Od2GarbageCollectSem);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("DosCloseSem: failed to NtWaitForSingleObject on garbage sem, Status=%x\n",
|
|
Status));
|
|
}
|
|
else if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("[%d,%d] DosCloseSem: WARNING !!! Wait on GarbageCollectSem, status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
|
|
|
|
if (pRealSem->pMyself == (PVOID)(&(pRealSem->pMyself)) && // System Semaphore
|
|
pRealSem->u.SysSemName ){
|
|
RtlFreeHeap(Od2Heap, 0, pRealSem->u.SysSemName);
|
|
}
|
|
|
|
if (pRealSem == (POS21X_SEM)Od2Sem16ListHead) {
|
|
//
|
|
// Get rid of first on the list
|
|
//
|
|
|
|
Od2Sem16ListHead = pRealSem->Next;
|
|
RtlFreeHeap(Od2TiledHeap, 0, pRealSem);
|
|
}
|
|
else {
|
|
for (pPrevSem = (POS21X_SEM)Od2Sem16ListHead;
|
|
pPrevSem->Next != NULL;
|
|
pPrevSem = (POS21X_SEM)(pPrevSem->Next)) {
|
|
|
|
if ((POS21X_SEM)(pPrevSem->Next) == pRealSem) {
|
|
|
|
//
|
|
// Found our semaphore on the list
|
|
//
|
|
|
|
pPrevSem->Next = pRealSem->Next;
|
|
RtlFreeHeap(Od2TiledHeap, 0, pRealSem);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Status = Od2ReleaseMutant(Od2GarbageCollectSem);
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("DosCloseSem: failed to NtReleaseSemaphore on sync sem, Status=%x\n",
|
|
Status));
|
|
}
|
|
#endif
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
APIRET
|
|
DosCloseSem(
|
|
IN HSEM hsem
|
|
)
|
|
{
|
|
return (Od2CloseSem(TRUE, hsem));
|
|
}
|
|
|
|
|
|
|
|
APIRET
|
|
DosCloseSemNoRemove(
|
|
IN POS21X_SEM pRealSem,
|
|
IN BOOL FreeMem
|
|
)
|
|
{
|
|
APIRET rc;
|
|
NTSTATUS Status;
|
|
HSEM tmpMutex, tmpEvent;
|
|
|
|
tmpMutex = pRealSem->Mutex;
|
|
tmpEvent = pRealSem->Event;
|
|
|
|
if (FreeMem)
|
|
RtlFreeHeap(Od2TiledHeap, 0, pRealSem);
|
|
|
|
Status = NtClose (tmpMutex);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("DosCloseSemNoRemove: error at NtClose, Status %x\n", Status);
|
|
}
|
|
#endif
|
|
return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE));
|
|
}
|
|
|
|
rc = DosCloseEventSem (tmpEvent);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("DosCloseSemNoRemove: error at DosCloseEventSem, Status %d\n", rc);
|
|
}
|
|
#endif
|
|
return rc;
|
|
}
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
APIRET
|
|
DosSemClear(
|
|
IN HSEM hsem
|
|
)
|
|
{
|
|
APIRET rc = NO_ERROR;
|
|
NTSTATUS Status;
|
|
POS21X_SEM pRealSem;
|
|
SEMAPHORE_BASIC_INFORMATION SemInfo;
|
|
BOOLEAN firsttime;
|
|
ULONG hsemValue;
|
|
|
|
#if DBG
|
|
if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
|
|
((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
|
|
((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
|
|
((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
|
|
KdPrint(("[%d,%d] DosSemClear(%x, *=%x): entering\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem));
|
|
}
|
|
#endif // DBG
|
|
|
|
try {
|
|
Od2ProbeForWrite( (PVOID)hsem, sizeof( ULONG ), 1 );
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP ();
|
|
}
|
|
|
|
// If the semaphore will be created in will be initially in not busy state.
|
|
|
|
pRealSem = Od2LookupOrCreateSem(hsem, &firsttime, SEM_FROM_CLEAR);
|
|
|
|
if (pRealSem == NULL)
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
if (firsttime) {
|
|
// if ((*(PULONG)hsem & 0xFFF00000) != 0xCCC00000) {
|
|
//
|
|
// private mem RAM sem: set value and return
|
|
//
|
|
// *(PULONG)hsem = (ULONG)pRealSem;
|
|
// }
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosSemClear 1st time succeeded: Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(), hsem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
|
|
if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
|
|
((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
|
|
((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
|
|
((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
|
|
KdPrint(("[%d,%d] DosSemClear(%x, *=%x): first time, exiting OK\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem));
|
|
}
|
|
#endif // DBG
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if (((hsemValue=*(PULONG)hsem) != (ULONG)hsem) &&
|
|
((hsemValue & 0xFFF00000) != 0xCCC00000)) {
|
|
//
|
|
// Private RAM Semaphore:
|
|
// OS/2 1.X Apps (SQLQ 1.11 ) expects the semaphore location
|
|
// to be actually ZERO (undocumented)
|
|
//
|
|
|
|
// BUGBUG Maybe OS/2 clears only low word
|
|
|
|
*(PULONG)hsem = 0;
|
|
}
|
|
|
|
//
|
|
// since hsem=0 garbage colection might free pRealSem
|
|
// we enclose with try-except
|
|
//
|
|
// Note that after we will release the sem,
|
|
// by NtReleseSemaphore or DosPostEventSem
|
|
// we will not be sure that the user
|
|
// memory at *hsem will still be valid - would be freed by a thread
|
|
// waiting for this semaphore.
|
|
// instead of *hsem we will use local variable hsemValue.
|
|
//
|
|
|
|
try {
|
|
|
|
if ((pRealSem->OwnerThread != SEM_EVENT) && // This is not a private WAIT/CLEAR RAM semaphore
|
|
(((hsemValue & 0xFFFC0000) != 0xCCC40000)) ) { // This is not a shared WAIT/CLEAR RAM semaphore
|
|
//
|
|
// free a REQUEST - What we need to do is
|
|
// To NtReleaseSemaphore on the Semaphore
|
|
//
|
|
if (hsemValue != (ULONG)hsem ||
|
|
(pRealSem->FlagsByte & SYSSEM_PUBLIC)) {
|
|
|
|
//
|
|
// RAM sem and public sys sem - simply release
|
|
//
|
|
|
|
LONG PreviousCount;
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosSemClear about to Release Mutex: Sem %x, *Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(), hsem, hsemValue, pRealSem->Mutex,pRealSem->Event);
|
|
}
|
|
#endif
|
|
Status = NtReleaseSemaphore (
|
|
pRealSem->Mutex,
|
|
1,
|
|
&PreviousCount);
|
|
if ( !NT_SUCCESS(Status) && Status != STATUS_SEMAPHORE_LIMIT_EXCEEDED ) {
|
|
#if DBG
|
|
DbgPrint ("DosSemClear: error NtReleaseSempahore , %lx\n", Status);
|
|
#endif
|
|
rc = Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE);
|
|
}
|
|
if (pRealSem->OwnerThread != (TID)SEM_AT_INIT &&
|
|
pRealSem->OwnerThread != (TID)SEM_DUAL &&
|
|
!(pRealSem->FlagsByte & SYSSEM_PUBLIC)) {
|
|
pRealSem->OwnerThread = (TID)SEM_MUTEX_NOT_OWNED;
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// EXCLUSIVE system semaphores - query before release, for ownership
|
|
//
|
|
// BUGBUG - EXCLUSIVE system semaphores need to be rewritten,
|
|
// because ownerthreadid is not shared. Also, tight sync is
|
|
// needed to get the right errors when the owner dies etc.
|
|
// for now - we sync every clear with the rest of the processes
|
|
//
|
|
|
|
Status = Od2AcquireSync();
|
|
#if DBG
|
|
if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("[%d,%d] DosSemClear: FAILED to NtWaitForSingleObject on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
Status = NtQuerySemaphore(
|
|
pRealSem->Mutex,
|
|
SemaphoreBasicInformation,
|
|
(PVOID)(&SemInfo),
|
|
sizeof(SemInfo),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("DosSemClear: error in NtQuerySemaphore, %lx\n", Status);
|
|
}
|
|
#endif
|
|
rc = Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE);
|
|
}
|
|
else {
|
|
if (SemInfo.CurrentCount == 0) {
|
|
|
|
//
|
|
// Sempahore is not signaled i.e. it is not clear
|
|
// so let's release it
|
|
//
|
|
|
|
if (pRealSem->RequestCount) {
|
|
//
|
|
// must be a system semaphore that was prevoiusly
|
|
// requested by the same thread more than once.
|
|
// don't really free the thread, just count
|
|
//
|
|
pRealSem->RequestCount--;
|
|
}
|
|
else if ((ULONG)pRealSem->OwnerThread > 0 &&
|
|
(ULONG)pRealSem->OwnerThread < _64K ){
|
|
//
|
|
// A thread has this semaphore, release it
|
|
//
|
|
Status = NtReleaseSemaphore (
|
|
pRealSem->Mutex,
|
|
1,
|
|
NULL);
|
|
if ( !NT_SUCCESS(Status) && Status != STATUS_SEMAPHORE_LIMIT_EXCEEDED ) {
|
|
#if DBG
|
|
DbgPrint ("DosSemClear: error NtReleaseSempahore , %lx\n", Status);
|
|
#endif
|
|
rc = Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE);
|
|
}
|
|
if (pRealSem->OwnerThread != (TID)SEM_AT_INIT &&
|
|
pRealSem->OwnerThread != (TID)SEM_DUAL) {
|
|
pRealSem->OwnerThread = (TID)SEM_MUTEX_NOT_OWNED;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
Status = Od2ReleaseSync();
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] DosSemClear: failed to NtReleaseMutant on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//
|
|
// Post the Event if it is not a RAM semaphore
|
|
// of type REQUEST/CLEAR
|
|
//
|
|
if ( (pRealSem->OwnerThread == (TID)SEM_EVENT) || // WAIT/CLEAR private RAM SEM
|
|
(pRealSem->OwnerThread == (TID)SEM_AT_INIT) || // Initialized RAM SEM
|
|
(pRealSem->OwnerThread == (TID)SEM_DUAL) || // RAM SEM use for both mutext and event
|
|
(hsemValue == (ULONG)hsem) || // System Semaphore
|
|
( ((hsemValue & 0xFFF00000) == 0xCCC00000) &&
|
|
((hsemValue & 0xFFFC0000) != 0xCCC80000) ) ) { // This is not a shared REQUEST/CLEAR RAM semaphore
|
|
|
|
|
|
//
|
|
// This is a WAIT/CLEAR type semaphore - post the event
|
|
//
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosSemClear about to PostEvent: Sem %x, *Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(), hsem, hsemValue, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
#endif
|
|
rc = DosPostEventSem (pRealSem->Event);
|
|
if (rc != NO_ERROR) {
|
|
if (rc == ERROR_ALREADY_POSTED || rc == ERROR_TOO_MANY_POSTS) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("DosSemClear: Posting the Event, %d\n", rc);
|
|
}
|
|
#endif
|
|
rc = NO_ERROR;
|
|
} else {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("DosSemClear: error Posting the Event, %d\n", rc);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (rc == NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosSemClear succeeded Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(),hsem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER) {
|
|
#if DBG
|
|
DbgPrint ("DosSemClear - user freed Sem %x\n", hsem);
|
|
#endif
|
|
}
|
|
|
|
#if DBG
|
|
if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
|
|
((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
|
|
((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
|
|
((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
|
|
KdPrint(("[%d,%d] DosSemClear(%x, *=%x): exiting, rc=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem,
|
|
rc));
|
|
}
|
|
#endif // DBG
|
|
|
|
return rc;
|
|
}
|
|
|
|
APIRET
|
|
DosSemSet(
|
|
IN HSEM hsem
|
|
)
|
|
{
|
|
APIRET rc = NO_ERROR;
|
|
APIRET rc1 = NO_ERROR;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
POS21X_SEM pRealSem;
|
|
ULONG Dummy;
|
|
LARGE_INTEGER CapturedTimeout;
|
|
PLARGE_INTEGER NtTimeout;
|
|
BOOLEAN firsttime;
|
|
|
|
#if DBG
|
|
if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
|
|
((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
|
|
((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
|
|
((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
|
|
KdPrint(("[%d,%d] DosSemSet(%x, *=%x): entering\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem));
|
|
}
|
|
#endif // DBG
|
|
|
|
try {
|
|
Od2ProbeForWrite( (PVOID)hsem, sizeof( ULONG ), 1 );
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP ();
|
|
}
|
|
|
|
// If the semaphore will be created it will be initially in not busy state.
|
|
|
|
pRealSem = Od2LookupOrCreateSem(hsem, &firsttime, SEM_FROM_SET);
|
|
|
|
if (pRealSem == NULL)
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
if (*(PULONG)hsem != (ULONG)hsem) {
|
|
//
|
|
// RAM semaphore:
|
|
// change state if needed
|
|
//
|
|
if (pRealSem->OwnerThread == (TID)SEM_AT_INIT) {
|
|
pRealSem->OwnerThread = (TID)SEM_EVENT; // mark it as a WAIT/CLEAR semaphore, no owner
|
|
}
|
|
if ((*(PULONG)hsem & 0xFFF00000) != 0xCCC00000) {
|
|
//
|
|
// private mem RAM sem: set value and return
|
|
//
|
|
// *(PULONG)hsem |= 1;
|
|
__asm
|
|
{
|
|
mov eax, hsem
|
|
lock or dword ptr [eax], 1
|
|
}
|
|
}
|
|
else {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosSemSet on shared mem RAM: Sem %x, *Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(),hsem, *(PULONG)hsem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
#endif
|
|
//
|
|
// *(PULONG)hsem |= 0x00040000;
|
|
//
|
|
__asm
|
|
{
|
|
mov eax, hsem
|
|
lock or dword ptr [eax], 0x00040000
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// We Implement a Set by a WaitForSingleObject on the Nt
|
|
// Semaphore (effectively decrement count only if > 0 )
|
|
// and a Reset on the event
|
|
//
|
|
|
|
|
|
// RAM semaphore used for requests as well
|
|
if ( (pRealSem->OwnerThread != (TID)SEM_EVENT && (*(PULONG)hsem != (ULONG)hsem)) ||
|
|
// public system semaphore
|
|
((*(PULONG)hsem == (ULONG)hsem) && (pRealSem->FlagsByte & SYSSEM_PUBLIC)) ){
|
|
|
|
//
|
|
// Capture the timeout value of zero and convert it into an
|
|
// NT timeout value.
|
|
//
|
|
NtTimeout = Od2CaptureTimeout( 0, (PLARGE_INTEGER)&CapturedTimeout );
|
|
|
|
Status = NtWaitForSingleObject(
|
|
pRealSem->Mutex,
|
|
TRUE, // Alertable
|
|
NtTimeout // Immediate return
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint ("[%d,%d]DosSemSet: ERROR at NtWaitForSingleObject, %x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
#endif
|
|
rc1 = Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If it not a mutex, we Reset the event
|
|
//
|
|
|
|
if ((*(PULONG)hsem == (ULONG)hsem) || pRealSem->OwnerThread == (TID)SEM_EVENT || pRealSem->OwnerThread == (TID)SEM_DUAL) {
|
|
|
|
rc = DosResetEventSem (pRealSem->Event, &Dummy);
|
|
|
|
if (rc == ERROR_ALREADY_RESET)
|
|
rc = NO_ERROR;
|
|
}
|
|
|
|
if (rc == NO_ERROR && rc1 == NO_ERROR) {
|
|
|
|
if (*(PULONG)hsem != (ULONG)hsem) {
|
|
//
|
|
// RAM semaphore:
|
|
// OS/2 1.X apps expect sem location last two bits to be 1
|
|
//
|
|
// *(PULONG)hsem |= 1;
|
|
}
|
|
else {
|
|
pRealSem->OwnerThread = (TID)SEM_MUTEX_NOT_OWNED;
|
|
pRealSem->RequestCount = 0;
|
|
}
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
if (firsttime) {
|
|
DbgPrint ("[TID %x]: DosSemSet 1st time succeeded: Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(), hsem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
else {
|
|
DbgPrint ("[TID %x]: DosSemSet succeeded Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(), hsem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if DBG
|
|
if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
|
|
((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
|
|
((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
|
|
((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
|
|
KdPrint(("[%d,%d] DosSemSet(%x, *=%x): exiting OK\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem));
|
|
}
|
|
#endif // DBG
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if (rc != NO_ERROR){
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("DosSemSet: error Resetting the Event, %d\n", rc);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
else {
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("DosSemSet: error Resetting the Mutex, %d\n", rc1);
|
|
}
|
|
#endif
|
|
rc = rc1;
|
|
}
|
|
|
|
#if DBG
|
|
if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
|
|
((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
|
|
((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
|
|
((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
|
|
KdPrint(("[%d,%d] DosSemSet(%x, *=%x): exiting, rc=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem,
|
|
rc));
|
|
}
|
|
#endif // DBG
|
|
return rc;
|
|
}
|
|
|
|
APIRET
|
|
DosSemWait(
|
|
IN HSEM hsem,
|
|
IN LONG lTimeOut
|
|
)
|
|
{
|
|
APIRET rc = NO_ERROR;
|
|
POS21X_SEM pRealSem;
|
|
BOOLEAN firsttime;
|
|
BOOLEAN CheckCurrentOwner = FALSE;
|
|
LARGE_INTEGER CapturedTimeout;
|
|
PLARGE_INTEGER NtTimeout;
|
|
LARGE_INTEGER StartTimeStamp;
|
|
|
|
#if DBG
|
|
if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
|
|
((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
|
|
((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
|
|
((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
|
|
KdPrint(("[%d,%d] DosSemWait(%x, *=%x): entering\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem));
|
|
}
|
|
#endif // DBG
|
|
|
|
//
|
|
// If the least significant byte of RAM semaphore is 0, it is free (OS/2 native
|
|
// conmpartability).
|
|
// This fiture of OS/2 is used by Saros Mezzanine, that reuse memory that contain
|
|
// semaphores that were set. It is enough to zero this memory in OS/2 to free the
|
|
// semaphores.
|
|
//
|
|
|
|
if (((*(PULONG)hsem & 0xff) == 0) && (*(PULONG)hsem != (ULONG)hsem)) {
|
|
return NO_ERROR;
|
|
}
|
|
|
|
try {
|
|
Od2ProbeForWrite( (PVOID)hsem, sizeof( ULONG ), 1 );
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP ();
|
|
}
|
|
|
|
// If the semaphore will be ckeated, will be checked if it must be created
|
|
// in initially busy state.
|
|
|
|
pRealSem = Od2LookupOrCreateSem(hsem, &firsttime, SEM_FROM_REQUESTWAIT);
|
|
|
|
if (pRealSem == NULL)
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
if (*(PULONG)hsem != (ULONG)hsem) {
|
|
//
|
|
// RAM semaphore:
|
|
//
|
|
|
|
if (pRealSem->OwnerThread != (TID)SEM_DUAL && pRealSem->OwnerThread != (TID)SEM_EVENT) {
|
|
if (pRealSem->OwnerThread == (TID)SEM_AT_INIT) {
|
|
pRealSem->OwnerThread = (TID)SEM_EVENT; // mark it as a WAIT/CLEAR semaphore, no owner
|
|
}
|
|
else {
|
|
//
|
|
// This semaphore used to be a Request/Clear only, need to verify
|
|
// that we block if currently owned.
|
|
//
|
|
CheckCurrentOwner = TRUE;
|
|
pRealSem->OwnerThread = (TID)SEM_DUAL;
|
|
}
|
|
}
|
|
|
|
if (firsttime) {
|
|
if ((*(PULONG)hsem & 0xFFF00000) != 0xCCC00000) {
|
|
//
|
|
//
|
|
// private mem RAM sem: set value and return
|
|
//
|
|
*(PULONG)hsem = (ULONG)pRealSem;
|
|
}
|
|
else {
|
|
//
|
|
// *(PULONG)hsem |= 0x00040000;
|
|
//
|
|
__asm
|
|
{
|
|
mov eax, hsem
|
|
lock or dword ptr [eax], 0x00040000
|
|
}
|
|
}
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosSemWait 1st time succeeded: Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(),hsem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
#endif
|
|
// Os2 semaphore can be initialized as busy. In this case we
|
|
// must wait on it.
|
|
// return(NO_ERROR);
|
|
}
|
|
|
|
//
|
|
// We Implement a Wait by a Waiting on the Event part of
|
|
// the OS21X_SEM
|
|
//
|
|
|
|
|
|
//
|
|
// RAM semaphore:
|
|
// OS/2 1.X apps expect sem location last two bits to be 0
|
|
//
|
|
|
|
//
|
|
// *(PULONG) hsem &= 0xfffffffc;
|
|
//
|
|
__asm
|
|
{
|
|
mov eax, hsem
|
|
lock and dword ptr [eax], 0XFFFFFFFC
|
|
}
|
|
|
|
if ((*(PULONG)hsem & 0xFFF00000) == 0xCCC00000) {
|
|
//
|
|
// RAM sem in shared memory.
|
|
// make sure that subsequent sem clear will wake us
|
|
//
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosSemWait on shared mem RAM: Sem %x, *Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(),hsem, *(PULONG)hsem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
#endif
|
|
if ((*(PULONG)hsem & 0xFFFC0000) == 0xCCC80000) {
|
|
CheckCurrentOwner = TRUE;
|
|
}
|
|
// WAIT/CLEAR shared RAM sem
|
|
//
|
|
// *(PULONG) hsem |= 0x00040000;
|
|
//
|
|
__asm
|
|
{
|
|
mov eax, hsem
|
|
lock or dword ptr [eax], 0x00040000
|
|
}
|
|
}
|
|
|
|
if (CheckCurrentOwner) {
|
|
NTSTATUS Status;
|
|
//
|
|
// This semaphore used to be for Request/Clear only,
|
|
// we have to make sure that if someone owns it we block
|
|
// 1. Block on the mutex
|
|
// 2. Free the mutex (a wait does not block others)
|
|
//
|
|
|
|
//
|
|
// Capture the timeout value and convert it into an NT timeout value.
|
|
//
|
|
NtTimeout = Od2CaptureTimeout( lTimeOut, (PLARGE_INTEGER)&CapturedTimeout );
|
|
|
|
do {
|
|
if (NtTimeout) {
|
|
Od2StartTimeout(&StartTimeStamp);
|
|
}
|
|
Status = NtWaitForSingleObject(
|
|
pRealSem->Mutex,
|
|
TRUE, // Alertable
|
|
NtTimeout
|
|
);
|
|
#if DBG
|
|
if (Status == STATUS_USER_APC) {
|
|
DbgPrint("[%d,%d] WARNING !!! DosSemRequest was broken by APC\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId()
|
|
);
|
|
}
|
|
#endif
|
|
} while (Status == STATUS_USER_APC &&
|
|
(Status = Od2ContinueTimeout(&StartTimeStamp, NtTimeout)) == STATUS_SUCCESS
|
|
);
|
|
|
|
//
|
|
// BUGBUG: This code is a little strange. The status can be positive value,
|
|
// for example, STATUS_TIMEOUT. In this case rc will remain NO_ERROR too.
|
|
//
|
|
if (!NT_SUCCESS(Status)) {
|
|
rc = Or2MapNtStatusToOs2Error(Status, ERROR_SEM_TIMEOUT);
|
|
#if DBG
|
|
DbgPrint ("[%d,%d] DosSemWait after Request: error Waiting for Mutex, %x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
#endif
|
|
}
|
|
|
|
Status = NtReleaseSemaphore (
|
|
pRealSem->Mutex,
|
|
1,
|
|
NULL);
|
|
if ( !NT_SUCCESS(Status) && Status != STATUS_SEMAPHORE_LIMIT_EXCEEDED ) {
|
|
#if DBG
|
|
DbgPrint ("DosSemWait: error NtReleaseSempahore , %lx\n", Status);
|
|
#endif
|
|
}
|
|
if (rc != NO_ERROR) {
|
|
goto NoWait;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
rc = DosWaitEventSem (pRealSem->Event, lTimeOut);
|
|
|
|
NoWait:
|
|
if (rc != NO_ERROR) {
|
|
if (rc == ERROR_TIMEOUT || rc == ERROR_SEM_TIMEOUT) {
|
|
rc = ERROR_SEM_TIMEOUT;
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosSemWait, timeout on Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(),hsem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosSemWait, Error %d on Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(),rc, hsem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
#endif
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosSemWait succeeded Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(),hsem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
|
|
((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
|
|
((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
|
|
((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
|
|
KdPrint(("[%d,%d] DosSemWait(%x, *=%x): exiting OK\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem));
|
|
}
|
|
#endif // DBG
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosSemSetWait(
|
|
IN HSEM hsem,
|
|
IN LONG lTimeOut
|
|
)
|
|
{
|
|
APIRET rc;
|
|
|
|
//
|
|
// we simply set and then Wait. Should be atomic
|
|
//
|
|
rc = DosSemSet (hsem);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("DosSemSetWait: error at DosSemSet, Status %d\n", rc);
|
|
}
|
|
#endif
|
|
return rc;
|
|
}
|
|
|
|
rc = DosSemWait(hsem, lTimeOut);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("DosSemSetWait: error at DosSemWait, Status %d\n", rc);
|
|
}
|
|
#endif
|
|
return rc;
|
|
}
|
|
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
APIRET
|
|
DosSemRequest(
|
|
IN HSEM hsem,
|
|
IN LONG lTimeOut
|
|
)
|
|
{
|
|
APIRET rc = NO_ERROR;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
POS21X_SEM pRealSem;
|
|
ULONG Dummy;
|
|
LARGE_INTEGER CapturedTimeout;
|
|
PLARGE_INTEGER NtTimeout;
|
|
LARGE_INTEGER StartTimeStamp;
|
|
BOOLEAN firsttime;
|
|
BOOLEAN CheckIfClear = FALSE;
|
|
|
|
//
|
|
// BUGBUG: In OS/2 native the RAM semaphore that has zero least significant byte is
|
|
// treated free (see comment for DosSemWait).
|
|
//
|
|
|
|
#if DBG
|
|
if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
|
|
((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
|
|
((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
|
|
((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1)))
|
|
{
|
|
KdPrint(("[%d,%d] DosSemRequest(%x, *=%x): entering\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem));
|
|
}
|
|
#endif // DBG
|
|
|
|
try {
|
|
Od2ProbeForWrite( (PVOID)hsem, sizeof( ULONG ), 1 );
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP ();
|
|
}
|
|
|
|
// If the semaphore will be created, will be checked if it will be created
|
|
// initially busy semaphore.
|
|
|
|
pRealSem = Od2LookupOrCreateSem(hsem, &firsttime, SEM_FROM_REQUESTWAIT);
|
|
|
|
if (pRealSem == NULL)
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
if (pRealSem->FlagsByte & SYSSEM_QUEUE) {
|
|
//
|
|
// If this is a system semaphore that was used by DosPeekQueue call to DosSemWait.
|
|
// This is special hack to work around bogus usage of semaphores with queues by
|
|
// ICL applications (see mail conversations with Thierry Tabard).
|
|
// [YosefD Jul-19-1995]
|
|
//
|
|
return DosSemWait(hsem, lTimeOut);
|
|
}
|
|
|
|
if (firsttime) {
|
|
pRealSem->OwnerThread = (TID)SEM_MUTEX_NOT_OWNED; // mark it as a REQUEST/CLEAR semaphore, no owner
|
|
if ((*(PULONG)hsem & 0xFFF00000) != 0xCCC00000) {
|
|
//
|
|
// private mem RAM sem: set value and return
|
|
//
|
|
*(PULONG)hsem = (ULONG)pRealSem | 1;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Capture the timeout value and convert it into an NT timeout value.
|
|
//
|
|
|
|
NtTimeout = Od2CaptureTimeout( lTimeOut, (PLARGE_INTEGER)&CapturedTimeout );
|
|
|
|
|
|
if ((*(PULONG)hsem == (ULONG)hsem) && !(pRealSem->FlagsByte & SYSSEM_PUBLIC)) {
|
|
//
|
|
// take semaphore to examine state
|
|
//
|
|
Status = Od2AcquireSync();
|
|
#if DBG
|
|
if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("[%d,%d] DosSemRequest: failed to NtWaitForSingleObject on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
if (pRealSem->OwnerThread == (TID)Od2CurrentThreadId()){
|
|
//
|
|
// must be a system semaphore that was prevoiusly
|
|
// requested by this thread.
|
|
//
|
|
pRealSem->RequestCount++;
|
|
Status = Od2ReleaseSync();
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] DosSemRequest (nested): failed to NtReleaseMutant on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
Status = STATUS_SUCCESS;
|
|
goto no_wait;
|
|
}
|
|
Status = Od2ReleaseSync();
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] DosSemRequest (not nested): failed to NtReleaseMutant on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Implement a Request by a WaitForSingleObject on the Nt
|
|
// Semaphore
|
|
//
|
|
//
|
|
// first watch for the ill case where someone used DosSemWait
|
|
// on this semaphore before. Set it to mutex so we get freed
|
|
//
|
|
if (pRealSem->OwnerThread == SEM_EVENT) {
|
|
//
|
|
// This semaphore used to be a Wait/Clear only, need to verify
|
|
// that we block if currently not clear.
|
|
//
|
|
CheckIfClear = TRUE;
|
|
pRealSem->OwnerThread = (TID)SEM_DUAL;
|
|
}
|
|
|
|
//
|
|
// shared RAM sem - make sure a subsequent sem clear will wake us
|
|
//
|
|
if ((*(PULONG)hsem & 0xFFF00000) == 0xCCC00000) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosSemRequest on shared mem RAM: Sem %x, *Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(),hsem, *(PULONG)hsem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
#endif
|
|
if ((*(PULONG)hsem & 0xFFFC0000) == 0xCCC40000) {
|
|
CheckIfClear = TRUE;
|
|
}
|
|
// REQUST/CLEAR shared RAM sem
|
|
//
|
|
// *(PULONG) hsem |= 0x00040000;
|
|
//
|
|
__asm
|
|
{
|
|
mov eax, hsem
|
|
lock or dword ptr [eax], 0x00080000
|
|
}
|
|
}
|
|
|
|
if (CheckIfClear) {
|
|
|
|
//
|
|
// This semaphore used to be for Wait/Clear only,
|
|
// we have to make sure that we block if not cleared
|
|
//
|
|
|
|
//
|
|
// Wait for the event, so next clear wakes us, or we have it
|
|
//
|
|
rc = DosWaitEventSem (pRealSem->Event, lTimeOut);
|
|
if (rc != NO_ERROR) {
|
|
if (rc == ERROR_TIMEOUT) {
|
|
rc = ERROR_SEM_TIMEOUT;
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosSemRequest on SEM_EVENT, timeout on Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(),hsem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosSemRequest on SEM_EVENT, Error %d on Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(),rc, hsem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
#endif
|
|
}
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
DosSemRequest_retry:
|
|
if (NtTimeout) {
|
|
Od2StartTimeout(&StartTimeStamp);
|
|
}
|
|
Status = NtWaitForSingleObject(
|
|
pRealSem->Mutex,
|
|
TRUE, // Alertable
|
|
NtTimeout
|
|
);
|
|
|
|
if (Status == STATUS_SUCCESS || Status == STATUS_ABANDONED) {
|
|
|
|
// The semaphore is owned only in the case that the status is
|
|
// STATUS_SUCCESS or STATUS_ABONDONED (if it was, for example,
|
|
// STATUS_TIMEOUT, that means that the semaphore wasn't actually
|
|
// owned.
|
|
|
|
if ((*(PULONG)hsem == (ULONG)hsem) &&
|
|
!(pRealSem->FlagsByte & SYSSEM_PUBLIC)) {
|
|
//
|
|
// Exclusive System Semaphore,
|
|
// Mark this semaphore 'owned'
|
|
//
|
|
//
|
|
// take semaphore to set state
|
|
//
|
|
Status = Od2AcquireSync();
|
|
#if DBG
|
|
if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("[%d,%d] DosSemRequest (take it): failed to NtWaitForSingleObject on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
pRealSem->OwnerThread = (TID)Od2CurrentThreadId();
|
|
pRealSem->RequestCount = 0;
|
|
|
|
Status = Od2ReleaseSync();
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] DosSemRequest (take it): failed to NtReleaseMutant on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
if (pRealSem->OwnerThread != (TID)SEM_DUAL) {
|
|
pRealSem->OwnerThread = (TID)SEM_MUTEX_NOT_OWNED;
|
|
}
|
|
}
|
|
}
|
|
|
|
no_wait:
|
|
if (Status == STATUS_SUCCESS) {
|
|
|
|
rc = NO_ERROR;
|
|
}
|
|
else {
|
|
if (NT_SUCCESS(Status) ) {
|
|
if (Status == STATUS_TIMEOUT) {
|
|
rc = ERROR_SEM_TIMEOUT;
|
|
}
|
|
else if (Status == STATUS_ABANDONED) {
|
|
#if DBG
|
|
DbgPrint("[%d,%d] DosSemRequest NT semaphore status ABONDONED\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId());
|
|
#endif // DBG
|
|
rc = ERROR_SEM_OWNER_DIED;
|
|
}
|
|
else if (Status == STATUS_USER_APC) {
|
|
#if DBG
|
|
DbgPrint("[%d,%d] WARNING !!! DosSemRequest was broken by APC\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId()
|
|
);
|
|
#endif
|
|
if (Od2ContinueTimeout(&StartTimeStamp, NtTimeout) == STATUS_SUCCESS) {
|
|
goto DosSemRequest_retry;
|
|
}
|
|
else {
|
|
rc = ERROR_TIMEOUT;
|
|
}
|
|
}
|
|
else if (Status == STATUS_ALERTED) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("[%d,%d] DosSemRequest ALERTED\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId());
|
|
}
|
|
#endif
|
|
rc = ERROR_INTERRUPT;
|
|
}
|
|
else {
|
|
// This is some success status that we don't know about.
|
|
// To be more secure print the message.
|
|
#if DBG
|
|
DbgPrint("[%d,%d] DosSemRequest BUGBUG Unknown success status = %x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(), Status);
|
|
#endif // DBG
|
|
rc = ERROR_INTERRUPT;
|
|
}
|
|
} else {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("DosSemRequest: error at NtWaitForSingleObject, %x\n",
|
|
Status);
|
|
}
|
|
#endif
|
|
rc = Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// In the ill case where it used both as a mutex and as an event,
|
|
// we Reset the event too
|
|
//
|
|
|
|
if (pRealSem->OwnerThread == (TID)SEM_DUAL) {
|
|
|
|
APIRET rc1;
|
|
|
|
rc1 = DosResetEventSem (pRealSem->Event, &Dummy);
|
|
|
|
if (rc1 == ERROR_ALREADY_RESET)
|
|
rc1 = NO_ERROR;
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
if (rc1 != NO_ERROR) {
|
|
DbgPrint ("DosSemRequest: error at DosResetEvent %d\n",
|
|
rc1);
|
|
}
|
|
}
|
|
#endif
|
|
if (rc == NO_ERROR && rc1 != NO_ERROR) {
|
|
rc = rc1;
|
|
}
|
|
}
|
|
|
|
if (rc == NO_ERROR) {
|
|
|
|
if (*(PULONG)hsem != (ULONG)hsem) {
|
|
//
|
|
// RAM Semaphore:
|
|
// OS/2 1.X Apps expects the semaphore location
|
|
// last two bits to be actually 1 (undocumented)
|
|
//
|
|
//
|
|
// *(PULONG) hsem |= 1;
|
|
//
|
|
__asm
|
|
{
|
|
mov eax,hsem
|
|
lock or dword ptr [eax], 1
|
|
}
|
|
}
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
if (firsttime) {
|
|
DbgPrint ("DosSemRequest 1st time succeeded: Sem %x, NtSem %lx, Event %lx\n",
|
|
hsem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
else {
|
|
DbgPrint ("[TID %x]: DosSemRequest succeeded Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(),hsem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
}
|
|
if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
|
|
((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
|
|
((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
|
|
((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
|
|
KdPrint(("[%d,%d] DosSemRequest(%x, *=%x): exiting OK\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem));
|
|
}
|
|
#endif // DBG
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
#if DBG
|
|
if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
|
|
((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
|
|
((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
|
|
((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
|
|
KdPrint(("[%d,%d] DosSemRequest(%x, *=%x): exiting, rc=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hsem,
|
|
*(PULONG)hsem,
|
|
rc));
|
|
}
|
|
#endif // DBG
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosOpenSem(
|
|
OUT PHSYSSEM phSem,
|
|
IN PSZ pszSemName
|
|
)
|
|
{
|
|
ULONG Sem;
|
|
APIRET rc = NO_ERROR;
|
|
POS21X_SEM pRealSem;
|
|
NTSTATUS Status;
|
|
|
|
try {
|
|
Od2ProbeForWrite( phSem, sizeof( HSYSSEM ), 1 );
|
|
Od2ProbeForRead( pszSemName, 2, 1 );
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP ();
|
|
}
|
|
|
|
Status = Od2AcquireSync();
|
|
#if DBG
|
|
if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("[%d,%d] DosOpenSem: failed to NtWaitForSingleObject on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
|
|
rc = Od2OpenSem(
|
|
NULL,
|
|
&pRealSem,
|
|
pszSemName,
|
|
TRUE);
|
|
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("DosOpenSem: error calling Od2OpenSem, %d\n", rc);
|
|
}
|
|
#endif
|
|
|
|
Status = Od2ReleaseSync();
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] DosOpenSem: failed to NtReleaseMutant on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
return rc;
|
|
}
|
|
|
|
Sem = (ULONG) *phSem = (ULONG) pRealSem;
|
|
*phSem = (POS21X_SEM)(FLATTOFARPTR(Sem));
|
|
if (pRealSem->FlagsByte == 0) {
|
|
//
|
|
// This sys sem was not created by this process, and
|
|
// is opened the first time by this process, assume public syssem
|
|
// BUGBUG we need to reimplement exclusive sys sem to get the
|
|
// full OS/2 semantics across processes
|
|
//
|
|
pRealSem->FlagsByte |= SYSSEM_PUBLIC;
|
|
}
|
|
|
|
Status = Od2ReleaseSync();
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("[%d,%d] DosOpenSem: failed to NtReleaseMutant on sync sem, Status=%x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
Status);
|
|
}
|
|
#endif
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
APIRET
|
|
DosMuxSemWait(
|
|
OUT PUSHORT pisemCleared,
|
|
IN PMUXSEMLIST pmsxl,
|
|
IN LONG lTimeOut
|
|
)
|
|
{
|
|
APIRET rc = NO_ERROR;
|
|
NTSTATUS Status;
|
|
USHORT i;
|
|
HANDLE NtHandles[ 16 ]; // Handles to actually block on
|
|
LARGE_INTEGER CapturedTimeout;
|
|
PLARGE_INTEGER NtTimeout;
|
|
ULONG Sem;
|
|
HSEM FlatSem;
|
|
POS21X_SEM pRealSem;
|
|
|
|
BOOLEAN firsttime;
|
|
BOOLEAN CheckCurrentOwner = FALSE;
|
|
//
|
|
// Capture the timeout value and convert it into an NT timeout value.
|
|
//
|
|
|
|
NtTimeout = Od2CaptureTimeout( lTimeOut, (PLARGE_INTEGER)&CapturedTimeout );
|
|
|
|
//
|
|
// probe index pointer and pmsxl buffer
|
|
//
|
|
|
|
try {
|
|
Od2ProbeForWrite( pisemCleared, sizeof( USHORT ), 1 );
|
|
|
|
//
|
|
// probe count first, then actual array
|
|
//
|
|
Od2ProbeForRead(pmsxl, sizeof(USHORT),1);
|
|
Od2ProbeForRead(&pmsxl->amxs, sizeof(MUXSEM)*(pmsxl->cmxs),1);
|
|
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
//
|
|
// Go over the array of semaphores.
|
|
// for each semaphore check if it's event is posted.
|
|
// If posted - sempahore is clear, return index.
|
|
// If not posted, add to NtHandles array
|
|
//
|
|
|
|
for (i = 0; i < pmsxl->cmxs; i++,CheckCurrentOwner = FALSE) {
|
|
//
|
|
// Check validity of MUXSEM entry
|
|
//
|
|
|
|
if (pmsxl->amxs[i].zero != 0)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
Sem = (ULONG) (pmsxl->amxs[i].hsem);
|
|
FlatSem = FARPTRTOFLAT(Sem);
|
|
try {
|
|
Od2ProbeForWrite( (PVOID)FlatSem, sizeof( ULONG ), 1 );
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP ();
|
|
}
|
|
|
|
// If the semaphore will be created, will be checked if it must be
|
|
// created in initially busy state.
|
|
|
|
pRealSem = Od2LookupOrCreateSem (FlatSem, &firsttime, SEM_FROM_REQUESTWAIT);
|
|
|
|
if (pRealSem == NULL)
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
if (*(PULONG)FlatSem != (ULONG)FlatSem) {
|
|
if (pRealSem->OwnerThread != (TID)SEM_DUAL && pRealSem->OwnerThread != (TID)SEM_EVENT) {
|
|
if (pRealSem->OwnerThread == (TID)SEM_AT_INIT) {
|
|
pRealSem->OwnerThread = (TID)SEM_EVENT; // mark it as a WAIT/CLEAR semaphore, no owner
|
|
}
|
|
else {
|
|
//
|
|
// This semaphore used to be a Request/Clear only, need to verify
|
|
// that we block if currently owned.
|
|
//
|
|
CheckCurrentOwner = TRUE;
|
|
pRealSem->OwnerThread = (TID)SEM_DUAL;
|
|
}
|
|
}
|
|
|
|
if (firsttime) {
|
|
if ((*(PULONG)FlatSem & 0xFFF00000) != 0xCCC00000) {
|
|
//
|
|
// private mem RAM sem: set value and return
|
|
//
|
|
*(PULONG)FlatSem = (ULONG)pRealSem;
|
|
}
|
|
else {
|
|
*(PULONG)FlatSem |= 0x00040000; // WAIT/CLEAR shared RAM sem
|
|
}
|
|
*pisemCleared = i;
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosMuxSemWait: 1st time success. sem was cleared. Index %d, Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(),*pisemCleared, FlatSem, pRealSem->Mutex, pRealSem->Event);
|
|
}
|
|
#endif
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
//
|
|
// make sure that any subsequent semclear will post
|
|
// this semaphore's event
|
|
//
|
|
if ((*(PULONG)FlatSem & 0xFFF00000) == 0xCCC00000) {
|
|
//
|
|
// RAM sem in shared memory.
|
|
// make sure that subsequent sem clear will wake us
|
|
//
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("DosMuxSemWait on shared mem RAM: Index %d, Sem %x, *Sem %x, NtSem %lx, Event %lx\n",
|
|
*pisemCleared, FlatSem, *(PULONG)FlatSem, pRealSem->Mutex,pRealSem->Event );
|
|
}
|
|
#endif
|
|
if ((*(PULONG)FlatSem & 0xFFFC0000) == 0xCCC80000) {
|
|
CheckCurrentOwner = TRUE;
|
|
}
|
|
*(PULONG)FlatSem |= 0x00040000; // WAIT/CLEAR shared RAM sem
|
|
}
|
|
}
|
|
|
|
if (CheckCurrentOwner) {
|
|
SEMAPHORE_BASIC_INFORMATION SemInfo;
|
|
ULONG Dummy;
|
|
NTSTATUS Status;
|
|
//
|
|
// This semaphore used to be for Request/Clear only,
|
|
// we have to make sure that if someone owns it we block
|
|
//
|
|
|
|
//
|
|
// query the mutex, to see if owned
|
|
//
|
|
Status = NtQuerySemaphore(
|
|
pRealSem->Mutex,
|
|
SemaphoreBasicInformation,
|
|
(PVOID)(&SemInfo),
|
|
sizeof(SemInfo),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("DosMuxSemWait: error in NtQuerySemaphore, %lx\n", Status);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
if (SemInfo.CurrentCount == 0) {
|
|
|
|
//
|
|
// Sempahore is not signaled i.e. it is not clear
|
|
// block ourselves by reset of event before wait
|
|
//
|
|
rc = DosResetEventSem (pRealSem->Event, &Dummy);
|
|
|
|
if (rc == ERROR_ALREADY_RESET)
|
|
rc = NO_ERROR;
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
if (rc != NO_ERROR) {
|
|
DbgPrint ("DosMuxSemWait: error at DosResetEvenSem, error %d\n",
|
|
rc);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
*
|
|
rc = DosQueryEventSem(pRealSem->Event, &PostCount);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("DosMuxSemWait: error in DosQueryEventSem %d \n", rc);
|
|
}
|
|
#endif
|
|
return (rc);
|
|
}
|
|
|
|
if (PostCount != 0) {
|
|
//
|
|
// Found a posted semaphore:
|
|
// Perform DosWaitEventSem to lower post count
|
|
// and return
|
|
//
|
|
rc = DosWaitEventSem (pRealSem->Event, 0L);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosMuxSemWait: Unexpected error %d. Index %d\n",
|
|
Od2CurrentThreadId(),rc, *pisemCleared);
|
|
}
|
|
#endif
|
|
return rc;
|
|
}
|
|
*pisemCleared = i;
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosMuxSemWait: success. sem was cleared. Index %d, Sem %x, NtSem %lx, Event %lx\n",
|
|
Od2CurrentThreadId(),*pisemCleared, FlatSem, pRealSem->Mutex, pRealSem->Event);
|
|
}
|
|
#endif
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
*
|
|
*/
|
|
rc = Od2GetSemNtEvent(
|
|
FlatSem,
|
|
&NtHandles[i]);
|
|
}
|
|
|
|
//
|
|
// Now, that we scanned the whole pmsxl structure and
|
|
// have a list of Nt Handles to block on, let's block
|
|
// on it
|
|
//
|
|
|
|
retry:
|
|
Status = NtWaitForMultipleObjects(
|
|
(CHAR)i,
|
|
NtHandles,
|
|
WaitAny,
|
|
TRUE, // Alertable
|
|
NtTimeout
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
if (Status <= STATUS_WAIT_63) {
|
|
*pisemCleared = (USHORT)(Status & 0x3F);
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint ("[TID %x]: DosMuxSemWait: success at NtWait. Index %d\n",
|
|
Od2CurrentThreadId(),*pisemCleared);
|
|
}
|
|
#endif
|
|
Sem = (ULONG) (pmsxl->amxs[*pisemCleared].hsem);
|
|
FlatSem = FARPTRTOFLAT(Sem);
|
|
if ((*(PULONG)FlatSem != (ULONG)FlatSem) &&
|
|
((*(PULONG)FlatSem & 0xFFF00000) != 0xCCC00000)) {
|
|
//
|
|
// Private RAM semaphores:
|
|
// OS/2 1.X apps (SQL 1.11) expect sem location to be 0
|
|
//
|
|
*(PULONG)FlatSem = 0;
|
|
}
|
|
rc = NO_ERROR;
|
|
}
|
|
else
|
|
if (Status == STATUS_ABANDONED) {
|
|
rc = ERROR_SEM_OWNER_DIED;
|
|
}
|
|
else
|
|
if (Status == STATUS_TIMEOUT) {
|
|
rc = ERROR_SEM_TIMEOUT;
|
|
}
|
|
else
|
|
if (Status == STATUS_USER_APC) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("MuxSemWait Status STATUS_USER_APC\n");
|
|
}
|
|
#endif
|
|
rc = ERROR_SS_RETRY;
|
|
}
|
|
else
|
|
if (Status == STATUS_ALERTED) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("MuxSemWait Status STATUS_ALERTED\n");
|
|
}
|
|
#endif
|
|
rc = ERROR_SS_RETRY;
|
|
}
|
|
else {
|
|
rc = Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE);
|
|
}
|
|
}
|
|
else {
|
|
rc = Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE);
|
|
}
|
|
|
|
if (rc == ERROR_SS_RETRY) {
|
|
goto retry;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosFSRamSemRequest(
|
|
IN PDOSFSRSEM16 pdosfsrs,
|
|
IN LONG lTimeOut
|
|
)
|
|
{
|
|
APIRET rc = NO_ERROR;
|
|
BOOLEAN HackPmPrintDrive = FALSE;
|
|
PULONG pSem;
|
|
PUSHORT puSemIndex;
|
|
|
|
//
|
|
// cb must be 14 (1.21 PRM)
|
|
//
|
|
try {
|
|
Od2ProbeForWrite( pdosfsrs, sizeof( DOSFRSEM16 ), 1 );
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP ();
|
|
}
|
|
if (pdosfsrs->cb != 14) {
|
|
if (pdosfsrs->cb == 12) {
|
|
//
|
|
// special hack for some print drivers on OS/2,
|
|
// we have a shared segment with semaphores pointers,
|
|
// indexed by the USHORT left off pdosfsrs->sem
|
|
//
|
|
HackPmPrintDrive = TRUE;
|
|
#if DBG
|
|
DbgPrint("DosFSRamSemRequest called with cb=12\n", rc);
|
|
#endif
|
|
if (pHackPrinterDriverSem == 0) {
|
|
//
|
|
// No thread in this process used this hack yet -
|
|
// See if a previous process created it
|
|
//
|
|
USHORT sel;
|
|
APIRET rc = DosGetShrSeg("\\SHAREMEM\\OS2SSPRD", &sel);
|
|
if (rc != NO_ERROR) {
|
|
if (rc == ERROR_FILE_NOT_FOUND) {
|
|
//
|
|
// Create the segment with the semaphores pointers.
|
|
// The first ULONG is the index to the next available
|
|
// index
|
|
//
|
|
rc = DosAllocShrSeg((sizeof(ULONG)) * NUMOFPRINTDRIVERSEM,
|
|
"\\SHAREMEM\\OS2SSPRD",
|
|
&sel);
|
|
}
|
|
else {
|
|
#if DBG
|
|
DbgPrint("DosFSRamSemRequest - internal error\n");
|
|
#endif
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
pHackPrinterDriverSem = (PULONG)(SELTOFLAT(sel));
|
|
*pHackPrinterDriverSem = 1;
|
|
}
|
|
}
|
|
else {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("DosFSRamSemRequest - invalid FSRSEM.cb %d\n", pdosfsrs->cb);
|
|
}
|
|
#endif
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
if (HackPmPrintDrive) {
|
|
//
|
|
// Take the next available index
|
|
//
|
|
puSemIndex = (PUSHORT)(&pdosfsrs->sem);
|
|
if (*puSemIndex == 0){
|
|
//
|
|
// first time this FSR is used
|
|
//
|
|
if (*pHackPrinterDriverSem == NUMOFPRINTDRIVERSEM) {
|
|
//
|
|
// No More Slots
|
|
//
|
|
#if DBG
|
|
DbgPrint("DosFSRamSemRequest - Not Enough Slots for PM Driver hack\n");
|
|
#endif
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pSem = pHackPrinterDriverSem + sizeof(ULONG) * (*pHackPrinterDriverSem);
|
|
*puSemIndex = (USHORT)(*pHackPrinterDriverSem);
|
|
*pHackPrinterDriverSem = *pHackPrinterDriverSem + 1;
|
|
}
|
|
else {
|
|
//
|
|
// use the index stored in the sem value
|
|
//
|
|
pSem = pHackPrinterDriverSem + sizeof(ULONG) * (*puSemIndex);
|
|
}
|
|
}
|
|
else {
|
|
pSem = (PULONG)(&pdosfsrs->sem);
|
|
}
|
|
|
|
//
|
|
// if not owned - set to owned, use count 1
|
|
// and return
|
|
//
|
|
|
|
if (pdosfsrs->pid == 0) {
|
|
//
|
|
// Perform a Request on the semaphore, to ensure that
|
|
// other threads will now block
|
|
//
|
|
rc = DosSemRequest((HSEM)pSem, lTimeOut);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("DosFSRamSemRequest: Illegal error from DosSemRequest. %d\n", rc);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
pdosfsrs->pid = (USHORT)Od2Process->Pib.ProcessId;
|
|
pdosfsrs->tid = (USHORT)(Od2CurrentThreadId());
|
|
pdosfsrs->cUsage = 1;
|
|
pdosfsrs->client = 0;
|
|
}
|
|
return(rc);
|
|
}
|
|
//
|
|
// if we are inside Exit List and the owner process is
|
|
// the caller's process, then force cUsage to 1 and
|
|
// thread to caller, else block.
|
|
//
|
|
|
|
if (Od2ExitListInProgress && (pdosfsrs->pid == (USHORT)Od2Process->Pib.ProcessId) ) {
|
|
rc = ERROR_SEM_OWNER_DIED;
|
|
pdosfsrs->tid = (USHORT)(Od2CurrentThreadId());
|
|
pdosfsrs->cUsage = 1;
|
|
return(rc);
|
|
|
|
}
|
|
|
|
//
|
|
// if owned by calling thread - increment cUsage
|
|
//
|
|
if (pdosfsrs->pid == (USHORT)Od2Process->Pib.ProcessId &&
|
|
pdosfsrs->tid == (USHORT)(Od2CurrentThreadId()) ) {
|
|
pdosfsrs->cUsage++;
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
//
|
|
// now we have to block on the semaphore
|
|
//
|
|
rc = DosSemRequest((HSEM)pSem, lTimeOut);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("DosFSRamSemRequest: error from DosSemRequest. %d\n", rc);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
pdosfsrs->pid = (USHORT)Od2Process->Pib.ProcessId;
|
|
pdosfsrs->tid = (USHORT)(Od2CurrentThreadId());
|
|
pdosfsrs->cUsage = 1;
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
|
|
APIRET
|
|
DosFSRamSemClear(
|
|
IN PDOSFSRSEM16 pdosfsrs
|
|
)
|
|
{
|
|
APIRET rc = NO_ERROR;
|
|
BOOLEAN HackPmPrintDrive = FALSE;
|
|
PULONG pSem;
|
|
PUSHORT puSemIndex;
|
|
|
|
try {
|
|
Od2ProbeForWrite( pdosfsrs, sizeof( DOSFRSEM16 ), 1 );
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP ();
|
|
}
|
|
//
|
|
// cb must be 14 (1.21 PRM)
|
|
//
|
|
if (pdosfsrs->cb != 14) {
|
|
if (pdosfsrs->cb == 12) {
|
|
//
|
|
// special hack for some print drivers on OS/2,
|
|
// we have a shared segment with semaphores pointers,
|
|
// indexed by the USHORT left off pdosfsrs->sem
|
|
//
|
|
HackPmPrintDrive = TRUE;
|
|
#if DBG
|
|
DbgPrint("DosFSRamSemClear - was called with cb=12\n", rc);
|
|
#endif
|
|
if (pHackPrinterDriverSem == 0) {
|
|
//
|
|
// No thread in this process used this hack yet -
|
|
// See if a previous process created it
|
|
//
|
|
USHORT sel;
|
|
APIRET rc = DosGetShrSeg("\\SHAREMEM\\OS2SSPRD", &sel);
|
|
if (rc != NO_ERROR) {
|
|
if (rc == ERROR_FILE_NOT_FOUND) {
|
|
//
|
|
// Create the segment with the semaphores pointers.
|
|
// The first ULONG is the index to the next available
|
|
// index
|
|
//
|
|
rc = DosAllocShrSeg((sizeof(ULONG)) * NUMOFPRINTDRIVERSEM,
|
|
"\\SHAREMEM\\OS2SSPRD",
|
|
&sel);
|
|
}
|
|
else {
|
|
#if DBG
|
|
DbgPrint("DosFSRamSemClear - internal error\n");
|
|
#endif
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
pHackPrinterDriverSem = (PULONG)(SELTOFLAT(sel));
|
|
*pHackPrinterDriverSem = 1;
|
|
}
|
|
}
|
|
else {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("DosFSRamSemClear - invalid FSRSEM. cb=%d\n", pdosfsrs->cb);
|
|
}
|
|
#endif
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
//
|
|
// if not owned - return
|
|
//
|
|
|
|
if (pdosfsrs->pid == 0) {
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
if (HackPmPrintDrive) {
|
|
//
|
|
// Take the next available index
|
|
//
|
|
puSemIndex = (PUSHORT)(&pdosfsrs->sem);
|
|
if (*puSemIndex == 0){
|
|
//
|
|
// first time this FSR is used
|
|
//
|
|
if (*pHackPrinterDriverSem == NUMOFPRINTDRIVERSEM) {
|
|
//
|
|
// No More Slots
|
|
//
|
|
#if DBG
|
|
DbgPrint("DosFSRamSemClear - Not Enough Slots for PM Driver hack\n");
|
|
#endif
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pSem = pHackPrinterDriverSem + sizeof(ULONG) * (*pHackPrinterDriverSem);
|
|
*puSemIndex = (USHORT)*pHackPrinterDriverSem;
|
|
*pHackPrinterDriverSem = *pHackPrinterDriverSem + 1;
|
|
}
|
|
else {
|
|
//
|
|
// use the index stored in the sem value
|
|
//
|
|
pSem = pHackPrinterDriverSem + sizeof(ULONG) * (*puSemIndex);
|
|
}
|
|
}
|
|
else {
|
|
pSem = (PULONG)(&pdosfsrs->sem);
|
|
}
|
|
//
|
|
// if owned by calling thread - decrement cUsage.
|
|
// if reached 0 - clear semaphore
|
|
//
|
|
if (pdosfsrs->pid == (USHORT)Od2Process->Pib.ProcessId &&
|
|
pdosfsrs->tid == (USHORT)(Od2CurrentThreadId()) ) {
|
|
if (--(pdosfsrs->cUsage) == 0) {
|
|
//
|
|
// need to really clear - remove ownership before we release
|
|
// blocking threads
|
|
//
|
|
pdosfsrs->pid = 0;
|
|
pdosfsrs->tid = 0;
|
|
rc = DosSemClear((HSEM)pSem);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("DosFSRamSemClear: Illegal error from DosSemClear. %d\n", rc);
|
|
}
|
|
#endif
|
|
return(rc);
|
|
}
|
|
return(NO_ERROR);
|
|
}
|
|
else {
|
|
return(NO_ERROR);
|
|
}
|
|
}
|
|
|
|
//
|
|
// FSRAM sem owned by another thread - return error
|
|
//
|
|
#if DBG
|
|
IF_OD2_DEBUG ( SEMAPHORES ) {
|
|
DbgPrint("DosFSRamSemClear called by a thread. Sem owned by another thread\n");
|
|
}
|
|
#endif
|
|
|
|
return ERROR_EXCL_SEM_ALREADY_OWNED ;
|
|
}
|