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.
613 lines
17 KiB
613 lines
17 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
srvmuxwt.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the OS/2 V2.0 Shared MuxWait Semaphore API Calls.
|
|
|
|
Author:
|
|
|
|
Steve Wood (stevewo) 07-Feb-1990
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#define INCL_OS2V20_SEMAPHORES
|
|
#define INCL_OS2V20_ERRORS
|
|
#include "os2srv.h"
|
|
|
|
APIRET
|
|
Os2AddMuxWait(
|
|
IN POS2_MUXWAIT_SEMAPHORE MuxWait,
|
|
IN PSEMRECORD MuxWaitEntry
|
|
)
|
|
{
|
|
POS2_MUXWAIT_RECORD MuxWaitRecord;
|
|
POS2_SEMAPHORE Semaphore;
|
|
USHORT i;
|
|
|
|
if (MuxWait->CountMuxWaitRecords == DCMW_MAX_SEMRECORDS) {
|
|
return( ERROR_TOO_MANY_SEMAPHORES );
|
|
}
|
|
|
|
//
|
|
// 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 = (POS2_SEMAPHORE)Or2MapHandle(
|
|
Os2SharedSemaphoreTable,
|
|
(ULONG)MuxWaitEntry->hsemCur,
|
|
TRUE
|
|
);
|
|
if (Semaphore == NULL) {
|
|
return( ERROR_INVALID_HANDLE );
|
|
}
|
|
|
|
//
|
|
// Now see if this semaphore is already in the MuxWait semaphore.
|
|
// Return an error if it is.
|
|
//
|
|
|
|
MuxWaitRecord = &MuxWait->MuxWaitRecords[ 0 ];
|
|
for (i=0; i<MuxWait->CountMuxWaitRecords; i++) {
|
|
if (MuxWaitRecord->Semaphore == Semaphore) {
|
|
return( ERROR_DUPLICATE_HANDLE );
|
|
}
|
|
|
|
MuxWaitRecord++;
|
|
}
|
|
|
|
|
|
//
|
|
// Entry in semaphore table exists, so make sure it is not a MuxWait
|
|
// semaphore. Also make sure it is that same type of semaphore as the
|
|
// first semaphore. Also make sure if the MuxWait semaphore that all
|
|
// the component semaphores are also shared. Return an error if any
|
|
// of these conditions are not met.
|
|
//
|
|
|
|
if (Semaphore->Type == Os2MuxWaitSem) {
|
|
return( ERROR_WRONG_TYPE );
|
|
}
|
|
|
|
if (MuxWait->CountMuxWaitRecords == 0) {
|
|
MuxWait->Type = Semaphore->Type;
|
|
}
|
|
else
|
|
if (Semaphore->Type != MuxWait->Type) {
|
|
return( ERROR_WRONG_TYPE );
|
|
}
|
|
|
|
//
|
|
// At this point everything is copasthetic, so fill in the next available
|
|
// record in the MuxWait semaphore.
|
|
//
|
|
|
|
MuxWaitRecord->SemHandleIndex = (ULONG)MuxWaitEntry->hsemCur;
|
|
MuxWaitRecord->UserKey = MuxWaitEntry->ulUser;
|
|
MuxWaitRecord->Semaphore = Os2ReferenceSemaphore( Semaphore );
|
|
MuxWait->CountMuxWaitRecords++;
|
|
|
|
return( NO_ERROR );
|
|
}
|
|
|
|
|
|
APIRET
|
|
Os2DeleteMuxWait(
|
|
IN POS2_MUXWAIT_SEMAPHORE MuxWait,
|
|
IN ULONG MuxWaitEntryIndex,
|
|
IN ULONG SemHandleIndex OPTIONAL
|
|
)
|
|
{
|
|
POS2_MUXWAIT_RECORD MuxWaitRecord;
|
|
USHORT i;
|
|
|
|
if (MuxWait->CountMuxWaitRecords == 0) {
|
|
return( ERROR_EMPTY_MUXWAIT );
|
|
}
|
|
|
|
MuxWaitRecord = &MuxWait->MuxWaitRecords[ 0 ];
|
|
for (i=0; i<MuxWait->CountMuxWaitRecords; i++) {
|
|
if (ARGUMENT_PRESENT( SemHandleIndex )) {
|
|
if (MuxWaitRecord->SemHandleIndex == SemHandleIndex) {
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
if ((ULONG)i == MuxWaitEntryIndex) {
|
|
break;
|
|
}
|
|
|
|
MuxWaitRecord++;
|
|
}
|
|
|
|
if (i == MuxWait->CountMuxWaitRecords) {
|
|
return( ERROR_INVALID_HANDLE );
|
|
}
|
|
|
|
Os2DereferenceSemaphore( MuxWaitRecord->Semaphore );
|
|
for (; i<MuxWait->CountMuxWaitRecords-1; i++) {
|
|
*MuxWaitRecord = *(MuxWaitRecord+1);
|
|
MuxWaitRecord++;
|
|
}
|
|
MuxWaitRecord->Semaphore = NULL;
|
|
MuxWaitRecord->SemHandleIndex = 0;
|
|
MuxWaitRecord->UserKey = 0;
|
|
MuxWait->CountMuxWaitRecords -= 1;
|
|
|
|
return( NO_ERROR );
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
Os2DosCreateMuxWaitSem(
|
|
IN POS2_THREAD t,
|
|
IN POS2_API_MSG m
|
|
)
|
|
{
|
|
POS2_DOSCREATEMUXWAITSEM_MSG a = &m->u.DosCreateMuxWaitSem;
|
|
OS2_SEMAPHORE Semaphore;
|
|
POS2_MUXWAIT_SEMAPHORE MuxWait;
|
|
PSEMRECORD MuxWaitEntries;
|
|
APIRET rc;
|
|
ULONG i;
|
|
|
|
UNREFERENCED_PARAMETER(t);
|
|
Semaphore.PointerCount = 0;
|
|
Semaphore.OpenCount = 1;
|
|
Semaphore.Type = Os2MuxWaitSem;
|
|
rc = Os2ProcessSemaphoreName( &a->ObjectName,
|
|
&Semaphore,
|
|
NULL
|
|
);
|
|
|
|
if (rc != NO_ERROR) {
|
|
ReleaseHandleTableLock( Os2SharedSemaphoreTable );
|
|
m->ReturnedErrorValue = rc;
|
|
return( TRUE );
|
|
}
|
|
|
|
//
|
|
// Private semaphore. Allocate the muxwait semaphore structure.
|
|
// Return error if not enough memory to allocate the structure.
|
|
//
|
|
|
|
MuxWait = RtlAllocateHeap( Os2Heap, 0, sizeof( *MuxWait ) );
|
|
if (MuxWait == NULL) {
|
|
ReleaseHandleTableLock( Os2SharedSemaphoreTable );
|
|
m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
|
|
return( TRUE );
|
|
}
|
|
|
|
//
|
|
// Initialize the muxwait semaphore sturcture to contain zero records.
|
|
//
|
|
|
|
MuxWait->CountMuxWaitRecords = 0;
|
|
MuxWait->Type = 0;
|
|
MuxWait->WaitAll = (USHORT)((a->CreateAttributes & DCMW_WAIT_ALL) != 0);
|
|
MuxWait->Reserved = 0;
|
|
|
|
|
|
//
|
|
// Loop over the input array of SEMRECORDs adding them one at a time
|
|
// to the muxwait semaphore. Bail out of loop if any errors occur.
|
|
//
|
|
|
|
MuxWaitEntries = a->MuxWaitEntries;
|
|
for (i=0; i<a->CountMuxWaitEntries; i++) {
|
|
rc = Os2AddMuxWait( MuxWait,
|
|
MuxWaitEntries
|
|
);
|
|
if (rc != NO_ERROR) {
|
|
break;
|
|
}
|
|
else {
|
|
MuxWaitEntries++;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// All done. If successful, store the address of the muxwait structure
|
|
// in the semaphore structure.
|
|
//
|
|
|
|
if (rc == NO_ERROR) {
|
|
Semaphore.u.MuxWait = MuxWait;
|
|
}
|
|
|
|
if (rc != NO_ERROR ||
|
|
!Or2CreateHandle( Os2SharedSemaphoreTable,
|
|
&a->HandleIndex,
|
|
(PVOID)&Semaphore
|
|
)
|
|
) {
|
|
RtlFreeHeap( Os2Heap, 0, MuxWait );
|
|
if (rc == NO_ERROR) {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
ReleaseHandleTableLock( Os2SharedSemaphoreTable );
|
|
|
|
m->ReturnedErrorValue = rc;
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
Os2DosOpenMuxWaitSem(
|
|
IN POS2_THREAD t,
|
|
IN POS2_API_MSG m
|
|
)
|
|
{
|
|
POS2_DOSOPENMUXWAITSEM_MSG a = &m->u.DosOpenMuxWaitSem;
|
|
POS2_SEMAPHORE Semaphore;
|
|
APIRET rc;
|
|
|
|
UNREFERENCED_PARAMETER(t);
|
|
rc = Os2ProcessSemaphoreName( &a->ObjectName,
|
|
NULL,
|
|
&a->HandleIndex
|
|
);
|
|
|
|
if (rc != NO_ERROR || a->ObjectName.Length != 0) {
|
|
ReleaseHandleTableLock( Os2SharedSemaphoreTable );
|
|
m->ReturnedErrorValue = rc;
|
|
return( TRUE );
|
|
}
|
|
|
|
Semaphore = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
|
|
a->HandleIndex,
|
|
TRUE
|
|
);
|
|
if (Semaphore == NULL) {
|
|
rc = ERROR_INVALID_HANDLE;
|
|
}
|
|
else {
|
|
Semaphore->OpenCount++;
|
|
}
|
|
|
|
ReleaseHandleTableLock( Os2SharedSemaphoreTable );
|
|
|
|
m->ReturnedErrorValue = rc;
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
Os2DosCloseMuxWaitSem(
|
|
IN POS2_THREAD t,
|
|
IN POS2_API_MSG m
|
|
)
|
|
{
|
|
POS2_DOSCLOSEMUXWAITSEM_MSG a = &m->u.DosCloseMuxWaitSem;
|
|
POS2_SEMAPHORE Semaphore;
|
|
POS2_MUXWAIT_SEMAPHORE MuxWait;
|
|
USHORT i;
|
|
APIRET rc;
|
|
|
|
UNREFERENCED_PARAMETER(t);
|
|
Semaphore = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
|
|
a->HandleIndex,
|
|
FALSE
|
|
);
|
|
if (Semaphore == NULL) {
|
|
rc = ERROR_INVALID_HANDLE;
|
|
}
|
|
else {
|
|
rc = NO_ERROR;
|
|
|
|
if (--Semaphore->OpenCount == 0) {
|
|
MuxWait = (POS2_MUXWAIT_SEMAPHORE)Os2DestroySemaphore(
|
|
Semaphore,
|
|
a->HandleIndex
|
|
);
|
|
|
|
for (i=0; i<MuxWait->CountMuxWaitRecords; i++) {
|
|
Os2DeleteMuxWait( MuxWait, i, 0 );
|
|
}
|
|
RtlFreeHeap( Os2Heap, 0, MuxWait );
|
|
}
|
|
else {
|
|
ReleaseHandleTableLock( Os2SharedSemaphoreTable );
|
|
}
|
|
}
|
|
|
|
m->ReturnedErrorValue = rc;
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
Os2DosWaitMuxWaitSem(
|
|
IN POS2_THREAD t,
|
|
IN POS2_API_MSG m
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
POS2_DOSWAITMUXWAITSEM_MSG a = &m->u.DosWaitMuxWaitSem;
|
|
POS2_MUXWAIT_SEMAPHORE MuxWait;
|
|
POS2_MUXWAIT_RECORD MuxWaitRecord;
|
|
POS2_SEMAPHORE Semaphore;
|
|
APIRET rc;
|
|
USHORT i;
|
|
HANDLE NtHandles[ MAXIMUM_WAIT_OBJECTS ];
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
retry:
|
|
Semaphore = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
|
|
a->HandleIndex,
|
|
FALSE
|
|
);
|
|
if (Semaphore == NULL) {
|
|
m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
|
|
return( TRUE );
|
|
}
|
|
|
|
//
|
|
// Entry in semaphore table exists, so make sure it is an MuxWait semaphore.
|
|
// Return an error if not, after unlock the table first.
|
|
//
|
|
|
|
if (Semaphore->Type != Os2MuxWaitSem) {
|
|
ReleaseHandleTableLock( Os2SharedSemaphoreTable );
|
|
m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
|
|
return( TRUE );
|
|
}
|
|
|
|
MuxWait = Semaphore->u.MuxWait;
|
|
|
|
if (MuxWait->CountMuxWaitRecords == 0) {
|
|
ReleaseHandleTableLock( Os2SharedSemaphoreTable );
|
|
m->ReturnedErrorValue = ERROR_EMPTY_MUXWAIT;
|
|
return( TRUE );
|
|
}
|
|
|
|
MuxWaitRecord = &MuxWait->MuxWaitRecords[ 0 ];
|
|
for (i=0; i<MuxWait->CountMuxWaitRecords; i++) {
|
|
NtHandles[ i ] = MuxWaitRecord->Semaphore->u.Value;
|
|
MuxWaitRecord++;
|
|
}
|
|
|
|
Os2ThreadWaitingOnSemaphore( t, Semaphore, TRUE );
|
|
|
|
Status = NtWaitForMultipleObjects(
|
|
(CHAR)i,
|
|
NtHandles,
|
|
MuxWait->WaitAll ? WaitAll : WaitAny,
|
|
TRUE,
|
|
&a->Timeout
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
if (Status <= STATUS_WAIT_63) {
|
|
a->UserValue = MuxWait->MuxWaitRecords[ (ULONG)(Status & 0x3F)
|
|
].UserKey;
|
|
rc = NO_ERROR;
|
|
}
|
|
else
|
|
if (Status == STATUS_ABANDONED) {
|
|
rc = ERROR_SEM_OWNER_DIED;
|
|
}
|
|
else
|
|
if (Status == STATUS_TIMEOUT) {
|
|
rc = ERROR_TIMEOUT;
|
|
}
|
|
else
|
|
if (Status == STATUS_USER_APC || Status == STATUS_ALERTED) {
|
|
rc = ERROR_SS_RETRY;
|
|
}
|
|
else {
|
|
rc = Or2MapNtStatusToOs2Error(Status, ERROR_SEM_TIMEOUT);
|
|
}
|
|
}
|
|
else {
|
|
rc = Or2MapNtStatusToOs2Error( Status, ERROR_SEM_TIMEOUT );
|
|
}
|
|
|
|
Os2ThreadWaitingOnSemaphore( t, Semaphore, FALSE );
|
|
|
|
if (rc == ERROR_SS_RETRY) {
|
|
goto retry;
|
|
}
|
|
|
|
m->ReturnedErrorValue = rc;
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
Os2DosAddMuxWaitSem(
|
|
IN POS2_THREAD t,
|
|
IN POS2_API_MSG m
|
|
)
|
|
{
|
|
POS2_DOSADDMUXWAITSEM_MSG a = &m->u.DosAddMuxWaitSem;
|
|
POS2_SEMAPHORE Semaphore;
|
|
|
|
UNREFERENCED_PARAMETER(t);
|
|
|
|
//
|
|
// 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 = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
|
|
a->HandleIndex,
|
|
FALSE
|
|
);
|
|
if (Semaphore == NULL) {
|
|
m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
|
|
return( TRUE );
|
|
}
|
|
|
|
//
|
|
// Entry in semaphore table exists, so make sure it is an MuxWait semaphore.
|
|
// Return an error if not, after unlock the table first.
|
|
//
|
|
|
|
if (Semaphore->Type != Os2MuxWaitSem) {
|
|
ReleaseHandleTableLock( Os2SharedSemaphoreTable );
|
|
m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
|
|
return( TRUE );
|
|
}
|
|
|
|
m->ReturnedErrorValue = Os2AddMuxWait( Semaphore->u.MuxWait,
|
|
&a->MuxWaitEntry
|
|
);
|
|
|
|
ReleaseHandleTableLock( Os2SharedSemaphoreTable );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
Os2DosDeleteMuxWaitSem(
|
|
IN POS2_THREAD t,
|
|
IN POS2_API_MSG m
|
|
)
|
|
{
|
|
POS2_DOSDELETEMUXWAITSEM_MSG a = &m->u.DosDeleteMuxWaitSem;
|
|
POS2_SEMAPHORE Semaphore;
|
|
|
|
UNREFERENCED_PARAMETER(t);
|
|
//
|
|
// 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 = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
|
|
a->HandleIndex,
|
|
FALSE
|
|
);
|
|
if (Semaphore == NULL) {
|
|
m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
|
|
return( TRUE );
|
|
}
|
|
|
|
//
|
|
// Entry in semaphore table exists, so make sure it is an MuxWait semaphore.
|
|
// Return an error if not, after unlock the table first.
|
|
//
|
|
|
|
if (Semaphore->Type != Os2MuxWaitSem) {
|
|
ReleaseHandleTableLock( Os2SharedSemaphoreTable );
|
|
m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
|
|
return( TRUE );
|
|
}
|
|
|
|
m->ReturnedErrorValue = Os2DeleteMuxWait( Semaphore->u.MuxWait,
|
|
0,
|
|
a->EntryHandleIndex
|
|
);
|
|
|
|
ReleaseHandleTableLock( Os2SharedSemaphoreTable );
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
Os2InternalAlertMuxWaiter(
|
|
IN POS2_THREAD t,
|
|
IN POS2_API_MSG m
|
|
)
|
|
{
|
|
POS2_ALERTMUXWAITER_MSG a = &m->u.AlertMuxWaiter;
|
|
POS2_THREAD Thread;
|
|
NTSTATUS Status;
|
|
|
|
Thread = Os2LocateThreadByThreadId( m, t, a->ThreadId );
|
|
Status = NtAlertThread( Thread->ThreadHandle );
|
|
if (!NT_SUCCESS( Status )) {
|
|
m->ReturnedErrorValue = Or2MapNtStatusToOs2Error( Status, ERROR_SEM_TIMEOUT );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
Os2DosQueryMuxWaitSem(
|
|
IN POS2_THREAD t,
|
|
IN POS2_API_MSG m
|
|
)
|
|
{
|
|
POS2_DOSQUERYMUXWAITSEM_MSG a = &m->u.DosQueryMuxWaitSem;
|
|
PSEMRECORD MuxWaitEntries;
|
|
POS2_MUXWAIT_SEMAPHORE MuxWait;
|
|
POS2_MUXWAIT_RECORD MuxWaitRecord;
|
|
POS2_SEMAPHORE Semaphore;
|
|
USHORT i;
|
|
|
|
|
|
UNREFERENCED_PARAMETER(t);
|
|
//
|
|
// 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 = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
|
|
a->HandleIndex,
|
|
FALSE
|
|
);
|
|
if (Semaphore == NULL) {
|
|
m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
|
|
return( TRUE );
|
|
}
|
|
|
|
//
|
|
// Entry in semaphore table exists, so make sure it is an MuxWait semaphore.
|
|
// Return an error if not, after unlock the table first.
|
|
//
|
|
|
|
if (Semaphore->Type != Os2MuxWaitSem) {
|
|
ReleaseHandleTableLock( Os2SharedSemaphoreTable );
|
|
m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
|
|
return( TRUE );
|
|
}
|
|
|
|
MuxWait = Semaphore->u.MuxWait;
|
|
if (a->CountMuxWaitEntries < (ULONG)(MuxWait->CountMuxWaitRecords)) {
|
|
m->ReturnedErrorValue = ERROR_PARAM_TOO_SMALL;
|
|
}
|
|
else {
|
|
a->CreateAttributes = DC_SEM_SHARED |
|
|
(MuxWait->WaitAll ? DCMW_WAIT_ALL : DCMW_WAIT_ANY);
|
|
MuxWaitEntries = a->MuxWaitEntries;
|
|
MuxWaitRecord = &MuxWait->MuxWaitRecords[ 0 ];
|
|
for (i=0; i<MuxWait->CountMuxWaitRecords; i++) {
|
|
MuxWaitEntries->hsemCur = (HSEM)MuxWaitRecord->SemHandleIndex;
|
|
MuxWaitEntries->ulUser = MuxWaitRecord->UserKey;
|
|
MuxWaitEntries++;
|
|
MuxWaitRecord++;
|
|
}
|
|
}
|
|
a->CountMuxWaitEntries = MuxWait->CountMuxWaitRecords;
|
|
|
|
ReleaseHandleTableLock( Os2SharedSemaphoreTable );
|
|
|
|
return( TRUE );
|
|
}
|