/*++ Copyright (c) 1989 Microsoft Corporation Module Name: dllevent.c Abstract: This module implements the OS/2 V2.0 Event Semaphore API Calls. Author: Steve Wood (stevewo) 07-Feb-1990 Revision History: --*/ #define INCL_OS2V20_SEMAPHORES #define INCL_OS2V20_ERRORS #include "os2dll.h" APIRET DosCreateEventSem( IN PSZ ObjectName, OUT PHEV EventHandle, IN ULONG CreateAttributes, IN BOOL32 InitialState ) { NTSTATUS Status; OS2_API_MSG m; POS2_DOSCREATEEVENTSEM_MSG a = &m.u.DosCreateEventSem; POS2_DOSCLOSEEVENTSEM_MSG a1 = &m.u.DosCloseEventSem; POS2_CAPTURE_HEADER CaptureBuffer; APIRET rc; BOOLEAN SharedSem; POR2_HANDLE_TABLE SemaphoreTable; OD2_SEMAPHORE Semaphore; // // Validate the simple parameters // if ((CreateAttributes & ~DC_SEM_SHARED) || ((InitialState != TRUE) && (InitialState != FALSE)) ) { return( ERROR_INVALID_PARAMETER ); } // // probe handle pointer // try { Od2ProbeForWrite( (PVOID)EventHandle, sizeof( EventHandle ), 1 ); } except( EXCEPTION_EXECUTE_HANDLER ) { Od2ExitGP(); } // // Capture and validate any semaphore name. // rc = Od2CaptureObjectName( ObjectName, CANONICALIZE_SEMAPHORE, 0, &CaptureBuffer, &a->ObjectName ); if (rc != NO_ERROR) { return( rc ); } // // Determine if a shared or private semaphore. // if (CaptureBuffer != NULL || CreateAttributes & DC_SEM_SHARED) { SharedSem = TRUE; } else { SharedSem = FALSE; } // // Get the pointer to either the shared or private semaphore table, // creating it if necessary. // SemaphoreTable = Od2GetSemaphoreTable( SharedSem, TRUE ); if (!SemaphoreTable) { if (CaptureBuffer != NULL) { Od2FreeCaptureBuffer( CaptureBuffer ); } return( ERROR_NOT_ENOUGH_MEMORY ); } // // Mark the fact that we are creating a semaphore handle. // a->HandleIndex = 0xFFFFFFFF; if (SharedSem) { // // Shared semaphore. Set the shared semaphore attribute and pass // the call to the OS/2 subsystem to create the system wide semaphore // handle value. // a->CreateAttributes = CreateAttributes | DC_SEM_SHARED; a->InitialState = (BOOLEAN)InitialState; rc = Od2CallSubsystem( &m, CaptureBuffer, Os2CreateEventSem, sizeof( *a ) ); // // Free any capture buffer, since the subsystem has saved away any // semaphore name in its table. // if (CaptureBuffer != NULL) { Od2FreeCaptureBuffer( CaptureBuffer ); } // // Return if an error was discovered. // if (rc != NO_ERROR) { return( rc ); } // // At this point, the semaphore handle index has been stored in // a->HandleIndex by the OS/2 subsystem and a->NtEventHandle contains // an NT handle to the NT Event. // } else { // // Private semaphore. Create an NT NotificationEvent that will // be used to implement the semantics of an OS/2 2.0 Event Semaphore. // Status = NtCreateEvent( &a->NtEventHandle, EVENT_ALL_ACCESS, NULL, NotificationEvent, (BOOLEAN) InitialState ); // // Return an error if unable to create the NT event. // if (!NT_SUCCESS( Status )) { return( ERROR_NOT_ENOUGH_MEMORY ); } } // // Initialize the OS/2 Semaphore structure. // Semaphore.Type = Od2EventSem; Semaphore.Shared = SharedSem; Semaphore.PointerCount = 0; Semaphore.OpenCount = 1; Semaphore.u.Value = (PVOID)a->NtEventHandle; // // Create an entry in the appropriate semaphore table, which will copy // the semaphore structure into the table entry and return an index to // the entry in a->HandleIndex // if (!Or2CreateHandle( SemaphoreTable, &a->HandleIndex, (PVOID)&Semaphore ) ) { // // Unable to create the entry. Close the NT event handle, as // it will not be used. If this is a shared semaphore created, then // call the OS/2 subsystem to close our reference to this shared // OS/2 semaphore. // NtClose( a->NtEventHandle ); if (SharedSem) { a1->HandleIndex = a->HandleIndex; Od2CallSubsystem( &m, NULL, Os2CloseEventSem, sizeof( *a1 ) ); } // // Return an error. // return( ERROR_NOT_ENOUGH_MEMORY ); } // // Success. Store a valid OS/2 2.0 Semaphore handle in the location // specified by the caller and return success to the caller. // *EventHandle = Od2ConstructSemaphoreHandle( SharedSem, a->HandleIndex ); return( NO_ERROR ); } APIRET DosOpenEventSem( IN PSZ ObjectName, IN OUT PHEV EventHandle ) { OS2_API_MSG m; POS2_DOSOPENEVENTSEM_MSG a = &m.u.DosOpenEventSem; POS2_DOSCLOSEEVENTSEM_MSG a1 = &m.u.DosCloseEventSem; POS2_CAPTURE_HEADER CaptureBuffer; POR2_HANDLE_TABLE SemaphoreTable; OD2_SEMAPHORE NewSemaphore; POD2_SEMAPHORE Semaphore; BOOLEAN SharedSem; APIRET rc; // // probe handle pointer // try { Od2ProbeForWrite( (PVOID)EventHandle, sizeof( EventHandle ), 1 ); } except( EXCEPTION_EXECUTE_HANDLER ) { Od2ExitGP(); } // // Capture and validate any semaphore name. // rc = Od2CaptureObjectName( ObjectName, CANONICALIZE_SEMAPHORE, 0, &CaptureBuffer, &a->ObjectName ); if (rc != NO_ERROR) { return( rc ); } // // Determine if opening the semaphore by name or by handle. // if (CaptureBuffer != NULL) { // // If a semaphore name was given, then we are opening the semaphore // by name, so call the OS/2 Subsystem to do the name lookup. // a->HandleIndex = 0xFFFFFFFF; rc = Od2CallSubsystem( &m, CaptureBuffer, Os2OpenEventSem, sizeof( *a ) ); // // Free any capture buffer, since the name has served its purpose // at this point. // if (CaptureBuffer != NULL) { Od2FreeCaptureBuffer( CaptureBuffer ); RtlZeroMemory( &a->ObjectName, sizeof( a->ObjectName ) ); } // // Return if an error was discovered. // if (rc != NO_ERROR) { return( rc ); } // // At this point, the semaphore handle has been stored in // a->HandleIndex by the OS/2 subsystem but a->NtEventHandle is still // uninitialized, since we don't know if this is the first reference // to this shared semaphore by this process. Set the shared semaphore // flag. // SharedSem = TRUE; // // If the caller specified both the name and the handle, make sure // the named mapped to the same handle value that they specified. // if (*EventHandle != NULL && *EventHandle != Od2ConstructSemaphoreHandle( SharedSem, a->HandleIndex ) ) { return( ERROR_INVALID_PARAMETER ); } } else { // // Opening by handle. Validate the handle and get the shared/private // flag. // rc = Od2ValidateSemaphoreHandle( *EventHandle, &SharedSem, &a->HandleIndex ); // // Return if invalid handle. // if (rc != NO_ERROR) { return( rc ); } } // // Get the pointer to either the shared or private semaphore table. // Creating is okay if this is a shared semaphore open. Return the // appropriate error code if table does not exist or cant be created. // SemaphoreTable = Od2GetSemaphoreTable( SharedSem, SharedSem ); if (!SemaphoreTable) { return( SharedSem ? ERROR_NOT_ENOUGH_MEMORY : ERROR_INVALID_HANDLE ); } // // Now lock the semaphore table while we figure out what we are doing and // do it. // AcquireHandleTableLock( SemaphoreTable ); // // See if the semaphore handle maps to an allocated entry in the table. // Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable, a->HandleIndex, TRUE ); if (Semaphore == NULL || *(PULONG)Semaphore == 0) { // // No entry in the table for this semaphore handle. Error if not // a shared semaphore. // if (!SharedSem) { rc = ERROR_INVALID_HANDLE; } else { // // This is the first usage of this shared semaphore handle by // the calling process, so call the OS/2 subsystem so that it // can bump its reference count. // rc = Od2CallSubsystem( &m, NULL, Os2OpenEventSem, sizeof( *a ) ); if (rc == NO_ERROR) { // // If we succeeded, then the semaphore was not deleted // in between the two calls to the subsystem, so add an // entry for this handle in the semaphore table, using the // NT Event handle we got from the subsystem. // NewSemaphore.Type = Od2EventSem; NewSemaphore.Shared = TRUE; NewSemaphore.PointerCount = 0; NewSemaphore.OpenCount = 1; NewSemaphore.u.Value = (PVOID)a->NtEventHandle; if (!Or2CreateHandle( SemaphoreTable, &a->HandleIndex, (PVOID)&NewSemaphore ) ) { // // Unable to create the entry. Close the NT event // handle, as it will not be used. Then call the // OS/2 subsystem to close our reference to this shared // OS/2 semaphore. Set the appropriate error code. // NtClose( a->NtEventHandle ); a1->HandleIndex = a->HandleIndex; Od2CallSubsystem( &m, NULL, Os2CloseEventSem, sizeof( *a1 ) ); rc = ERROR_NOT_ENOUGH_MEMORY; } } } } // // Entry in semaphore table exists, so make sure it is an Event semaphore. // Set the appropriate error code if not. // else if (Semaphore->Type != Od2EventSem) { rc = ERROR_INVALID_HANDLE; } // // Entry in semaphore table is for an Event semaphore, see if the OpenCount // is about to overflow, and set the appropriate error code if it is. // else if (Semaphore->OpenCount == 0xFFFF) { rc = ERROR_TOO_MANY_OPENS; } // // Everything is okay, so bump the open count in the semaphore table entry. // else { Semaphore->OpenCount++; } // // All done mucking about, so release the semaphore table lock. // ReleaseHandleTableLock( SemaphoreTable ); // // If no errors, store a valid OS/2 2.0 Semaphore handle in the location // specified by the caller and return success to the caller. // if (rc == NO_ERROR) { *EventHandle = Od2ConstructSemaphoreHandle( SharedSem, a->HandleIndex ); } // // Return an error code to the caller. // return( rc ); } APIRET DosCloseEventSem( IN HEV EventHandle ) { OS2_API_MSG m; POS2_DOSCLOSEEVENTSEM_MSG a = &m.u.DosCloseEventSem; POR2_HANDLE_TABLE SemaphoreTable; POD2_SEMAPHORE Semaphore; HANDLE NtEventHandle; BOOLEAN SharedSem; APIRET rc; // // 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( EventHandle, &SharedSem, &a->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, a->HandleIndex, FALSE ); if (Semaphore == NULL) { return( ERROR_INVALID_HANDLE ); } // // Entry in semaphore table exists, so make sure it is an Event semaphore. // Return an error if not, after unlock the table first. // if (Semaphore->Type != Od2EventSem) { ReleaseHandleTableLock( SemaphoreTable ); return( ERROR_INVALID_HANDLE ); } // // Entry in semaphore table is for an Event semaphore, so decrement the // OpenCount and see if it has gone to zero. // if (--Semaphore->OpenCount == 0) { // // OpenCount is now zero, so we can really close the semaphore // and delete the entry in the semaphore table. // // // First make sure that no thread in this process is waiting on this // event. If there is one waiting on it, increment the open count and // return an error. // //if { !(Od2Process->Pib.Status & PS_EXITLIST) && (Od2SearchForWaitingThread( Semaphore )) ) { // Semaphore->OpenCount++; // ReleaseHandleTableLock( SemaphoreTable ); // rc = ERROR_SEM_BUSY; // } // //else { // // Okay to really close this event semaphore. First destroy // the handle, which will unlock the handle table. // NtEventHandle = Semaphore->u.EventHandle; Or2DestroyHandle( SemaphoreTable, a->HandleIndex ); NtClose( NtEventHandle ); // // If this is a shared semaphore, call the subsystem so that it // can decrement its open count, as this process is not longer // using the shared semaphore handle. // if (SharedSem) { rc = Od2CallSubsystem( &m, NULL, Os2CloseEventSem, sizeof( *a ) ); } // } } else { // // OpenCount is still non-zero, so just release the semaphore table // lock. // ReleaseHandleTableLock( SemaphoreTable ); } // // Return any error code to the caller. // return( rc ); } APIRET DosResetEventSem( IN HEV EventHandle, OUT PULONG PostCount ) { POR2_HANDLE_TABLE SemaphoreTable; POD2_SEMAPHORE Semaphore; BOOLEAN SharedSem; ULONG HandleIndex; APIRET rc; NTSTATUS Status; HANDLE NtEventHandle; LONG NtEventCount; // // 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( EventHandle, &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 exists, so make sure it is an Event semaphore. // Return an error if not, after unlock the table first. // if (Semaphore->Type != Od2EventSem) { ReleaseHandleTableLock( SemaphoreTable ); 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 when the semaphore is reset. // NtEventHandle = Semaphore->u.EventHandle; ReleaseHandleTableLock( SemaphoreTable ); // // Call the NT system service to reset the event's signal count. // Status = NtResetEvent( NtEventHandle, &NtEventCount ); if (NT_SUCCESS( Status )) { #if DBG IF_OD2_DEBUG ( SEMAPHORES ) { DbgPrint ("DosResetEventSem Handle %lx, PreviousCount %lx\n", NtEventHandle, NtEventCount); } #endif // // If successful, the map the NT signal count into the 64K limitation // implemented by OS/2 2.0 // try { if (NtEventCount > 0xFFFF) { *PostCount = 0xFFFF; } else { *PostCount = NtEventCount; } } except( EXCEPTION_EXECUTE_HANDLER ) { Od2ExitGP(); } // // If the event was already reset, let the caller know, although this // is a non-fatal error. // if (rc == NO_ERROR) { if (NtEventCount == 0) { rc = ERROR_ALREADY_RESET; } } } else { // // If the NT system service failed, then some other thread must // have closed the semaphore so return an error. // rc = ERROR_INVALID_HANDLE; } // // Return any error code to the caller. // return( rc ); } APIRET DosPostEventSem( IN HEV EventHandle ) { POR2_HANDLE_TABLE SemaphoreTable; POD2_SEMAPHORE Semaphore; BOOLEAN SharedSem; ULONG HandleIndex; APIRET rc; NTSTATUS Status; HANDLE NtEventHandle; LONG NtEventCount; // // 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( EventHandle, &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 exists, so make sure it is an Event semaphore. // Return an error if not, after unlock the table first. // if (Semaphore->Type != Od2EventSem) { ReleaseHandleTableLock( SemaphoreTable ); 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 when the semaphore is set. // NtEventHandle = Semaphore->u.EventHandle; ReleaseHandleTableLock( SemaphoreTable ); // // Call the NT system service to set (increment) the event's signal // count. // Status = NtSetEvent( NtEventHandle, &NtEventCount ); if (NT_SUCCESS( Status )) { #if DBG IF_OD2_DEBUG ( SEMAPHORES ) { DbgPrint ("DosPostEventSem Handle %lx, PreviousCount %lx\n", NtEventHandle, NtEventCount); } #endif // // If successful, see if this the signal count has exceeded the 64K // limitation implemented by OS/2 2.0 and return the appropriate // error code. // if (NtEventCount != 0) { if (NtEventCount >= 0xFFFF) { rc = ERROR_TOO_MANY_POSTS; } else { rc = ERROR_ALREADY_POSTED; } } } else { // // If the NT system service failed, then some other thread must // have closed the semaphore so return an error. // rc = ERROR_INVALID_HANDLE; } // // Return any error code to the caller. // return( rc ); } APIRET DosWaitEventSem( IN HEV EventHandle, IN ULONG Timeout ) { POR2_HANDLE_TABLE SemaphoreTable; POD2_SEMAPHORE Semaphore; BOOLEAN SharedSem; ULONG HandleIndex; APIRET rc; NTSTATUS Status; HANDLE NtEventHandle; LARGE_INTEGER CapturedTimeout; PLARGE_INTEGER NtTimeout; LARGE_INTEGER StartTimeStamp; // // 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( EventHandle, &SharedSem, &HandleIndex ); if (rc != NO_ERROR) { return( rc ); } // // Capture the timeout value and convert it into an NT timeout value. // NtTimeout = Od2CaptureTimeout( Timeout, (PLARGE_INTEGER)&CapturedTimeout ); // // Get the pointer to either the shared or private semaphore table. // Table must exist. Return an error if it does not. // DosWaitEventSem_retry: if (NtTimeout) { Od2StartTimeout(&StartTimeStamp); } 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 exists, so make sure it is an Event semaphore. // Return an error if not, after unlock the table first. // if (Semaphore->Type != Od2EventSem) { ReleaseHandleTableLock( SemaphoreTable ); 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 waiting. // NtEventHandle = Semaphore->u.EventHandle; // // Call the NT system service to wait for this event to be signalled. // This is an alertable wait, since by definition all OS/2 waits are // alertable. // Od2ThreadWaitingOnSemaphore( SemaphoreTable, Semaphore, TRUE ); Status = NtWaitForSingleObject( NtEventHandle, TRUE, NtTimeout ); Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable, HandleIndex, FALSE ); if (Semaphore == NULL) { ASSERT(FALSE); return( ERROR_INVALID_HANDLE ); } // // Entry in semaphore table exists, so make sure it is an Event semaphore. // Return an error if not, after unlock the table first. // if (Semaphore->Type != Od2EventSem) { ReleaseHandleTableLock( SemaphoreTable ); ASSERT(FALSE); return( ERROR_INVALID_HANDLE ); } ReleaseHandleTableLock( SemaphoreTable ); Od2ThreadWaitingOnSemaphore( SemaphoreTable, Semaphore, FALSE ); if (NT_SUCCESS( Status )) { if (Status == STATUS_SUCCESS) { } else if (Status == STATUS_ABANDONED) { rc = ERROR_SEM_OWNER_DIED; } else if (Status == STATUS_TIMEOUT) { rc = ERROR_TIMEOUT; } else if (Status == STATUS_USER_APC) { #if DBG DbgPrint("[%d,%d] WARNING !!! DosWaitEventSem was broken by APC\n", Od2Process->Pib.ProcessId, Od2CurrentThreadId() ); #endif if (Od2ContinueTimeout(&StartTimeStamp, NtTimeout) == STATUS_SUCCESS) { goto DosWaitEventSem_retry; } else { rc = ERROR_TIMEOUT; } } else if (Status == STATUS_ALERTED) { #if DBG IF_OD2_DEBUG ( SEMAPHORES ) { DbgPrint("[%d,%d] DosWaitEventSem ALERTED\n", Od2Process->Pib.ProcessId, Od2CurrentThreadId()); } #endif rc = ERROR_INTERRUPT; } else { // Some success status that we don't know about. We will // be safe in this case and will print appropriate message. #if DBG DbgPrint("[%d,%d] DosWaitEventSem BUGBUG Unkownd success status = %x\n", Od2Process->Pib.ProcessId, Od2CurrentThreadId(), Status); #endif rc = ERROR_INTERRUPT; } } else { // // If the NT system service failed, then some other thread must // have closed the semaphore so return an error or this thread was // alerted out of the wait. Return the appropriate error code. // if (Status == STATUS_INVALID_HANDLE) { rc = ERROR_INVALID_HANDLE; } else { rc = Or2MapStatus( Status ); } } // // Return any error code to the caller. // return( rc ); } APIRET DosQueryEventSem( IN HEV EventHandle, OUT PULONG PostCount ) { POR2_HANDLE_TABLE SemaphoreTable; POD2_SEMAPHORE Semaphore; BOOLEAN SharedSem; ULONG HandleIndex; APIRET rc; NTSTATUS Status; EVENT_BASIC_INFORMATION EventInformation; HANDLE NtEventHandle; // // 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( EventHandle, &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 exists, so make sure it is an Event semaphore. // Return an error if not, after unlock the table first. // if (Semaphore->Type != Od2EventSem) { ReleaseHandleTableLock( SemaphoreTable ); 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. // NtEventHandle = Semaphore->u.EventHandle; ReleaseHandleTableLock( SemaphoreTable ); // // Call the NT system service to query the event's signal count. // Status = NtQueryEvent( Semaphore->u.EventHandle, EventBasicInformation, (PVOID)&EventInformation, sizeof( EventInformation ), NULL ); if (NT_SUCCESS( Status )) { #if DBG IF_OD2_DEBUG ( SEMAPHORES ) { DbgPrint ("DosQueryEventSem Handle %lx, Count %lx\n", NtEventHandle,EventInformation.EventState ); } #endif // // If successful, the map the NT signal count into the 64K limitation // implemented by OS/2 2.0 // try { if ((ULONG)EventInformation.EventState > 0xFFFF) { *PostCount = 0xFFFF; } else { *PostCount = (ULONG)EventInformation.EventState; } } except( EXCEPTION_EXECUTE_HANDLER ) { Od2ExitGP(); } } else { // // If the NT system service failed, then some other thread must // have closed the semaphore so return an error. // rc = ERROR_INVALID_HANDLE; } // // Return any error code to the caller. // return( rc ); }