1984 lines
52 KiB
C
1984 lines
52 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
synch.c
|
||
|
||
Abstract:
|
||
|
||
This module implements all Win32 syncronization
|
||
objects.
|
||
|
||
Author:
|
||
|
||
Mark Lucovsky (markl) 19-Sep-1990
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "basedll.h"
|
||
|
||
//
|
||
// Critical Section Services
|
||
//
|
||
|
||
VOID
|
||
InitializeCriticalSection(
|
||
LPCRITICAL_SECTION lpCriticalSection
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A critical section object is initialized using
|
||
Win32InitializeCriticalSection.
|
||
|
||
Once a critical section object has been initialized threads within a
|
||
single process may enter and exit critical sections using the
|
||
critical section object. A critical section object may not me moved
|
||
or copied. The application must also not modify the insides of the
|
||
object, but must treat it as logically opaque.
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
lpCriticalSection - Supplies the address of a critical section object
|
||
to be initialized. It is the callers resposibility to allocate
|
||
the storage used by a critical section object.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
Status = RtlInitializeCriticalSection(lpCriticalSection);
|
||
if ( !NT_SUCCESS(Status) ){
|
||
RtlRaiseStatus(Status);
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
InitializeCriticalSectionAndSpinCount(
|
||
LPCRITICAL_SECTION lpCriticalSection,
|
||
DWORD dwSpinCount
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A critical section object is initialized using
|
||
Win32InitializeCriticalSection.
|
||
|
||
Once a critical section object has been initialized threads within a
|
||
single process may enter and exit critical sections using the
|
||
critical section object. A critical section object may not me moved
|
||
or copied. The application must also not modify the insides of the
|
||
object, but must treat it as logically opaque.
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
lpCriticalSection - Supplies the address of a critical section object
|
||
to be initialized. It is the callers resposibility to allocate
|
||
the storage used by a critical section object.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
BOOL rv;
|
||
|
||
rv = TRUE;
|
||
Status = RtlInitializeCriticalSectionAndSpinCount(lpCriticalSection,dwSpinCount);
|
||
if ( !NT_SUCCESS(Status) ){
|
||
BaseSetLastNTError(Status);
|
||
rv = FALSE;
|
||
}
|
||
return rv;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Event Services
|
||
//
|
||
HANDLE
|
||
APIENTRY
|
||
CreateEventA(
|
||
LPSECURITY_ATTRIBUTES lpEventAttributes,
|
||
BOOL bManualReset,
|
||
BOOL bInitialState,
|
||
LPCSTR lpName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
ANSI thunk to CreateEventW
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PUNICODE_STRING Unicode;
|
||
ANSI_STRING AnsiString;
|
||
NTSTATUS Status;
|
||
LPCWSTR NameBuffer;
|
||
|
||
NameBuffer = NULL;
|
||
if ( ARGUMENT_PRESENT(lpName) ) {
|
||
Unicode = &NtCurrentTeb()->StaticUnicodeString;
|
||
RtlInitAnsiString(&AnsiString,lpName);
|
||
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
if ( Status == STATUS_BUFFER_OVERFLOW ) {
|
||
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
}
|
||
return NULL;
|
||
}
|
||
NameBuffer = (LPCWSTR)Unicode->Buffer;
|
||
}
|
||
|
||
return CreateEventW(
|
||
lpEventAttributes,
|
||
bManualReset,
|
||
bInitialState,
|
||
NameBuffer
|
||
);
|
||
}
|
||
|
||
|
||
HANDLE
|
||
APIENTRY
|
||
CreateEventW(
|
||
LPSECURITY_ATTRIBUTES lpEventAttributes,
|
||
BOOL bManualReset,
|
||
BOOL bInitialState,
|
||
LPCWSTR lpName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
An event object is created and a handle opened for access to the
|
||
object with the CreateEvent function.
|
||
|
||
The CreateEvent function creates an event object with the specified
|
||
initial state. If an event is in the Signaled state (TRUE), a wait
|
||
operation on the event does not block. If the event is in the Not-
|
||
Signaled state (FALSE), a wait operation on the event blocks until
|
||
the specified event attains a state of Signaled, or the timeout
|
||
value is exceeded.
|
||
|
||
In addition to the STANDARD_RIGHTS_REQUIRED access flags, the following
|
||
object type specific access flags are valid for event objects:
|
||
|
||
- EVENT_MODIFY_STATE - Modify state access (set and reset) to
|
||
the event is desired.
|
||
|
||
- SYNCHRONIZE - Synchronization access (wait) to the event is
|
||
desired.
|
||
|
||
- EVENT_ALL_ACCESS - This set of access flags specifies all of
|
||
the possible access flags for an event object.
|
||
|
||
|
||
Arguments:
|
||
|
||
lpEventAttributes - An optional parameter that may be used to
|
||
specify the attributes of the new event. If the parameter is
|
||
not specified, then the event is created without a security
|
||
descriptor, and the resulting handle is not inherited on process
|
||
creation.
|
||
|
||
bManualReset - Supplies a flag which if TRUE specifies that the
|
||
event must be manually reset. If the value is FALSE, then after
|
||
releasing a single waiter, the system automaticaly resets the
|
||
event.
|
||
|
||
bInitialState - The initial state of the event object, one of TRUE
|
||
or FALSE. If the InitialState is specified as TRUE, the event's
|
||
current state value is set to one, otherwise it is set to zero.
|
||
|
||
lpName - Optional unicode name of event
|
||
|
||
Return Value:
|
||
|
||
NON-NULL - Returns a handle to the new event. The handle has full
|
||
access to the new event and may be used in any API that requires
|
||
a handle to an event object.
|
||
|
||
FALSE/NULL - The operation failed. Extended error status is available
|
||
using GetLastError.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
OBJECT_ATTRIBUTES Obja;
|
||
POBJECT_ATTRIBUTES pObja;
|
||
HANDLE Handle;
|
||
UNICODE_STRING ObjectName;
|
||
PWCHAR pstrNewObjName = NULL;
|
||
|
||
if ( ARGUMENT_PRESENT(lpName) ) {
|
||
|
||
if (gpTermsrvFormatObjectName &&
|
||
(pstrNewObjName = gpTermsrvFormatObjectName(lpName))) {
|
||
|
||
RtlInitUnicodeString(&ObjectName,pstrNewObjName);
|
||
|
||
} else {
|
||
|
||
RtlInitUnicodeString(&ObjectName,lpName);
|
||
}
|
||
|
||
pObja = BaseFormatObjectAttributes(&Obja,lpEventAttributes,&ObjectName);
|
||
}
|
||
else {
|
||
pObja = BaseFormatObjectAttributes(&Obja,lpEventAttributes,NULL);
|
||
}
|
||
|
||
Status = NtCreateEvent(
|
||
&Handle,
|
||
EVENT_ALL_ACCESS,
|
||
pObja,
|
||
bManualReset ? NotificationEvent : SynchronizationEvent,
|
||
(BOOLEAN)bInitialState
|
||
);
|
||
|
||
if (pstrNewObjName) {
|
||
RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
|
||
}
|
||
|
||
if ( NT_SUCCESS(Status) ) {
|
||
if ( Status == STATUS_OBJECT_NAME_EXISTS ) {
|
||
SetLastError(ERROR_ALREADY_EXISTS);
|
||
}
|
||
else {
|
||
SetLastError(0);
|
||
}
|
||
return Handle;
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
HANDLE
|
||
APIENTRY
|
||
OpenEventA(
|
||
DWORD dwDesiredAccess,
|
||
BOOL bInheritHandle,
|
||
LPCSTR lpName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
ANSI thunk to OpenNamedEventW
|
||
|
||
--*/
|
||
|
||
{
|
||
PUNICODE_STRING Unicode;
|
||
ANSI_STRING AnsiString;
|
||
NTSTATUS Status;
|
||
|
||
if ( ARGUMENT_PRESENT(lpName) ) {
|
||
Unicode = &NtCurrentTeb()->StaticUnicodeString;
|
||
RtlInitAnsiString(&AnsiString,lpName);
|
||
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
if ( Status == STATUS_BUFFER_OVERFLOW ) {
|
||
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
}
|
||
return NULL;
|
||
}
|
||
}
|
||
else {
|
||
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||
return NULL;
|
||
}
|
||
|
||
return OpenEventW(
|
||
dwDesiredAccess,
|
||
bInheritHandle,
|
||
(LPCWSTR)Unicode->Buffer
|
||
);
|
||
}
|
||
|
||
HANDLE
|
||
APIENTRY
|
||
OpenEventW(
|
||
DWORD dwDesiredAccess,
|
||
BOOL bInheritHandle,
|
||
LPCWSTR lpName
|
||
)
|
||
{
|
||
OBJECT_ATTRIBUTES Obja;
|
||
UNICODE_STRING ObjectName;
|
||
NTSTATUS Status;
|
||
HANDLE Object;
|
||
PWCHAR pstrNewObjName = NULL;
|
||
|
||
if ( !lpName ) {
|
||
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||
return NULL;
|
||
}
|
||
|
||
if (gpTermsrvFormatObjectName &&
|
||
(pstrNewObjName = gpTermsrvFormatObjectName(lpName))) {
|
||
|
||
RtlInitUnicodeString(&ObjectName,pstrNewObjName);
|
||
|
||
} else {
|
||
|
||
RtlInitUnicodeString(&ObjectName,lpName);
|
||
}
|
||
|
||
|
||
InitializeObjectAttributes(
|
||
&Obja,
|
||
&ObjectName,
|
||
(bInheritHandle ? OBJ_INHERIT : 0),
|
||
BaseGetNamedObjectDirectory(),
|
||
NULL
|
||
);
|
||
|
||
Status = NtOpenEvent(
|
||
&Object,
|
||
dwDesiredAccess,
|
||
&Obja
|
||
);
|
||
|
||
if (pstrNewObjName) {
|
||
RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
|
||
}
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
BaseSetLastNTError(Status);
|
||
return NULL;
|
||
}
|
||
return Object;
|
||
}
|
||
|
||
BOOL
|
||
SetEvent(
|
||
HANDLE hEvent
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
An event can be set to the signaled state (TRUE) with the SetEvent
|
||
function.
|
||
|
||
Setting the event causes the event to attain a state of Signaled,
|
||
which releases all currently waiting threads (for manual reset
|
||
events), or a single waiting thread (for automatic reset events).
|
||
|
||
Arguments:
|
||
|
||
hEvent - Supplies an open handle to an event object. The
|
||
handle must have EVENT_MODIFY_STATE access to the event.
|
||
|
||
Return Value:
|
||
|
||
TRUE - The operation was successful
|
||
|
||
FALSE/NULL - The operation failed. Extended error status is available
|
||
using GetLastError.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
Status = NtSetEvent(hEvent,NULL);
|
||
if ( NT_SUCCESS(Status) ) {
|
||
return TRUE;
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
ResetEvent(
|
||
HANDLE hEvent
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The state of an event is set to the Not-Signaled state (FALSE) using
|
||
the ClearEvent function.
|
||
|
||
Once the event attains a state of Not-Signaled, any threads which
|
||
wait on the event block, awaiting the event to become Signaled. The
|
||
reset event service sets the event count to zero for the state of
|
||
the event.
|
||
|
||
Arguments:
|
||
|
||
hEvent - Supplies an open handle to an event object. The
|
||
handle must have EVENT_MODIFY_STATE access to the event.
|
||
|
||
Return Value:
|
||
|
||
TRUE - The operation was successful
|
||
|
||
FALSE/NULL - The operation failed. Extended error status is available
|
||
using GetLastError.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
Status = NtClearEvent(hEvent);
|
||
if ( NT_SUCCESS(Status) ) {
|
||
return TRUE;
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
PulseEvent(
|
||
HANDLE hEvent
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
An event can be set to the Signaled state and reset to the Not-
|
||
Signaled state atomically with the PulseEvent function.
|
||
|
||
Pulsing the event causes the event to attain a state of Signaled,
|
||
release appropriate threads, and then reset the event. When no
|
||
waiters are currently waiting on the event, pulsing an event causes
|
||
the event to release no threads and end up in the Not-Signaled
|
||
state. With waiters waiting on an event, pulsing an event has a
|
||
different effect for manual reset events that it does for automatic
|
||
reset events. For manual reset events, pulsing releases all waiters
|
||
and then leaves the event in the Not-Signaled state. For automatic
|
||
reset events, pulsing the event releases a single waiter and then
|
||
leaves the event in the Not-Signaled state.
|
||
|
||
Arguments:
|
||
|
||
hEvent - Supplies an open handle to an event object. The
|
||
handle must have EVENT_MODIFY_STATE access to the event.
|
||
|
||
Return Value:
|
||
|
||
TRUE - The operation was successful
|
||
|
||
FALSE/NULL - The operation failed. Extended error status is available
|
||
using GetLastError.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
Status = NtPulseEvent(hEvent,NULL);
|
||
if ( NT_SUCCESS(Status) ) {
|
||
return TRUE;
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Semaphore Services
|
||
//
|
||
|
||
HANDLE
|
||
APIENTRY
|
||
CreateSemaphoreA(
|
||
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
|
||
LONG lInitialCount,
|
||
LONG lMaximumCount,
|
||
LPCSTR lpName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
ANSI thunk to CreateSemaphoreW
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PUNICODE_STRING Unicode;
|
||
ANSI_STRING AnsiString;
|
||
NTSTATUS Status;
|
||
LPCWSTR NameBuffer;
|
||
|
||
NameBuffer = NULL;
|
||
if ( ARGUMENT_PRESENT(lpName) ) {
|
||
Unicode = &NtCurrentTeb()->StaticUnicodeString;
|
||
RtlInitAnsiString(&AnsiString,lpName);
|
||
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
if ( Status == STATUS_BUFFER_OVERFLOW ) {
|
||
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
}
|
||
return NULL;
|
||
}
|
||
NameBuffer = (LPCWSTR)Unicode->Buffer;
|
||
}
|
||
|
||
return CreateSemaphoreW(
|
||
lpSemaphoreAttributes,
|
||
lInitialCount,
|
||
lMaximumCount,
|
||
NameBuffer
|
||
);
|
||
}
|
||
|
||
|
||
HANDLE
|
||
APIENTRY
|
||
CreateSemaphoreW(
|
||
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
|
||
LONG lInitialCount,
|
||
LONG lMaximumCount,
|
||
LPCWSTR lpName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A semaphore object is created and a handle opened for access to the
|
||
object with the CreateSemaphore function.
|
||
|
||
The CreateSemaphore function causes a semaphore object to be created
|
||
which contains the specified initial and maximum counts.
|
||
|
||
In addition to the STANDARD_RIGHTS_REQUIRED access flags, the
|
||
following object type specific access flags are valid for semaphore
|
||
objects:
|
||
|
||
- SEMAPHORE_MODIFY_STATE - Modify state access (release) to the
|
||
semaphore is desired.
|
||
|
||
- SYNCHRONIZE - Synchronization access (wait) to the semaphore
|
||
is desired.
|
||
|
||
- SEMAPHORE_ALL_ACCESS - This set of access flags specifies all
|
||
of the possible access flags for a semaphore object.
|
||
|
||
|
||
Arguments:
|
||
|
||
lpSemaphoreAttributes - An optional parameter that may be used to
|
||
specify the attributes of the new semaphore. If the parameter
|
||
is not specified, then the semaphore is created without a
|
||
security descriptor, , and the resulting handle is not inherited
|
||
on process creation.
|
||
|
||
lInitialCount - The initial count for the semaphore, this value
|
||
must be positive and less than or equal to the maximum count.
|
||
|
||
lMaximumCount - The maximum count for the semaphore, this value
|
||
must be greater than zero..
|
||
|
||
lpName - Supplies an optional unicode name for the object.
|
||
|
||
Return Value:
|
||
|
||
NON-NULL - Returns a handle to the new semaphore. The handle has
|
||
full access to the new semaphore and may be used in any API that
|
||
requires a handle to a semaphore object.
|
||
|
||
FALSE/NULL - The operation failed. Extended error status is available
|
||
using GetLastError.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
OBJECT_ATTRIBUTES Obja;
|
||
POBJECT_ATTRIBUTES pObja;
|
||
HANDLE Handle;
|
||
UNICODE_STRING ObjectName;
|
||
PWCHAR pstrNewObjName = NULL;
|
||
|
||
if ( ARGUMENT_PRESENT(lpName) ) {
|
||
|
||
if (gpTermsrvFormatObjectName &&
|
||
(pstrNewObjName = gpTermsrvFormatObjectName(lpName))) {
|
||
|
||
RtlInitUnicodeString(&ObjectName,pstrNewObjName);
|
||
|
||
} else {
|
||
|
||
RtlInitUnicodeString(&ObjectName,lpName);
|
||
}
|
||
pObja = BaseFormatObjectAttributes(&Obja,lpSemaphoreAttributes,&ObjectName);
|
||
}
|
||
else {
|
||
pObja = BaseFormatObjectAttributes(&Obja,lpSemaphoreAttributes,NULL);
|
||
}
|
||
|
||
Status = NtCreateSemaphore(
|
||
&Handle,
|
||
SEMAPHORE_ALL_ACCESS,
|
||
pObja,
|
||
lInitialCount,
|
||
lMaximumCount
|
||
);
|
||
|
||
if (pstrNewObjName) {
|
||
RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
|
||
}
|
||
|
||
if ( NT_SUCCESS(Status) ) {
|
||
if ( Status == STATUS_OBJECT_NAME_EXISTS ) {
|
||
SetLastError(ERROR_ALREADY_EXISTS);
|
||
}
|
||
else {
|
||
SetLastError(0);
|
||
}
|
||
return Handle;
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
|
||
HANDLE
|
||
APIENTRY
|
||
OpenSemaphoreA(
|
||
DWORD dwDesiredAccess,
|
||
BOOL bInheritHandle,
|
||
LPCSTR lpName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
ANSI thunk to OpenSemaphoreW
|
||
|
||
--*/
|
||
|
||
{
|
||
PUNICODE_STRING Unicode;
|
||
ANSI_STRING AnsiString;
|
||
NTSTATUS Status;
|
||
|
||
if ( ARGUMENT_PRESENT(lpName) ) {
|
||
Unicode = &NtCurrentTeb()->StaticUnicodeString;
|
||
RtlInitAnsiString(&AnsiString,lpName);
|
||
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
if ( Status == STATUS_BUFFER_OVERFLOW ) {
|
||
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
}
|
||
return NULL;
|
||
}
|
||
}
|
||
else {
|
||
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||
return NULL;
|
||
}
|
||
|
||
return OpenSemaphoreW(
|
||
dwDesiredAccess,
|
||
bInheritHandle,
|
||
(LPCWSTR)Unicode->Buffer
|
||
);
|
||
}
|
||
|
||
HANDLE
|
||
APIENTRY
|
||
OpenSemaphoreW(
|
||
DWORD dwDesiredAccess,
|
||
BOOL bInheritHandle,
|
||
LPCWSTR lpName
|
||
)
|
||
{
|
||
OBJECT_ATTRIBUTES Obja;
|
||
UNICODE_STRING ObjectName;
|
||
NTSTATUS Status;
|
||
HANDLE Object;
|
||
PWCHAR pstrNewObjName = NULL;
|
||
|
||
if ( !lpName ) {
|
||
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||
return NULL;
|
||
}
|
||
|
||
if (gpTermsrvFormatObjectName &&
|
||
(pstrNewObjName = gpTermsrvFormatObjectName(lpName))) {
|
||
|
||
RtlInitUnicodeString(&ObjectName,pstrNewObjName);
|
||
|
||
} else {
|
||
|
||
RtlInitUnicodeString(&ObjectName,lpName);
|
||
}
|
||
|
||
InitializeObjectAttributes(
|
||
&Obja,
|
||
&ObjectName,
|
||
(bInheritHandle ? OBJ_INHERIT : 0),
|
||
BaseGetNamedObjectDirectory(),
|
||
NULL
|
||
);
|
||
|
||
Status = NtOpenSemaphore(
|
||
&Object,
|
||
dwDesiredAccess,
|
||
&Obja
|
||
);
|
||
|
||
if (pstrNewObjName) {
|
||
RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
|
||
}
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
BaseSetLastNTError(Status);
|
||
return NULL;
|
||
}
|
||
return Object;
|
||
}
|
||
|
||
|
||
BOOL
|
||
ReleaseSemaphore(
|
||
HANDLE hSemaphore,
|
||
LONG lReleaseCount,
|
||
LPLONG lpPreviousCount
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A semaphore object can be released with the ReleaseSemaphore
|
||
function.
|
||
|
||
When the semaphore is released, the current count of the semaphore
|
||
is incremented by the ReleaseCount. Any threads that are waiting
|
||
for the semaphore are examined to see if the current semaphore value
|
||
is sufficient to satisfy their wait.
|
||
|
||
If the value specified by ReleaseCount would cause the maximum count
|
||
for the semaphore to be exceeded, then the count for the semaphore
|
||
is not affected and an error status is returned.
|
||
|
||
|
||
Arguments:
|
||
|
||
hSemaphore - Supplies an open handle to a semaphore object. The
|
||
handle must have SEMAPHORE_MODIFY_STATE access to the semaphore.
|
||
|
||
lReleaseCount - The release count for the semaphore. The count
|
||
must be greater than zero and less than the maximum value
|
||
specified for the semaphore.
|
||
|
||
lpPreviousCount - An optional pointer to a variable that receives
|
||
the previous count for the semaphore.
|
||
|
||
Return Value:
|
||
|
||
TRUE - The operation was successful
|
||
|
||
FALSE/NULL - The operation failed. Extended error status is available
|
||
using GetLastError.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
Status = NtReleaseSemaphore(hSemaphore,lReleaseCount,lpPreviousCount);
|
||
if ( NT_SUCCESS(Status) ) {
|
||
return TRUE;
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Mutex Services
|
||
//
|
||
|
||
HANDLE
|
||
APIENTRY
|
||
CreateMutexA(
|
||
LPSECURITY_ATTRIBUTES lpMutexAttributes,
|
||
BOOL bInitialOwner,
|
||
LPCSTR lpName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
ANSI thunk to CreateMutexW
|
||
|
||
--*/
|
||
|
||
{
|
||
PUNICODE_STRING Unicode;
|
||
ANSI_STRING AnsiString;
|
||
NTSTATUS Status;
|
||
LPCWSTR NameBuffer;
|
||
|
||
NameBuffer = NULL;
|
||
if ( ARGUMENT_PRESENT(lpName) ) {
|
||
Unicode = &NtCurrentTeb()->StaticUnicodeString;
|
||
RtlInitAnsiString(&AnsiString,lpName);
|
||
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
if ( Status == STATUS_BUFFER_OVERFLOW ) {
|
||
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
NameBuffer = (LPCWSTR)Unicode->Buffer;
|
||
}
|
||
|
||
return CreateMutexW(
|
||
lpMutexAttributes,
|
||
bInitialOwner,
|
||
NameBuffer
|
||
);
|
||
}
|
||
|
||
HANDLE
|
||
APIENTRY
|
||
CreateMutexW(
|
||
LPSECURITY_ATTRIBUTES lpMutexAttributes,
|
||
BOOL bInitialOwner,
|
||
LPCWSTR lpName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A mutex object can be created and a handle opened for access to the
|
||
object with the CreateMutex function.
|
||
|
||
A new mutex object is created and a handle opened to the object with
|
||
ownership as determined by the InitialOwner parameter. The status
|
||
of the newly created mutex object is set to not abandoned.
|
||
|
||
In addition to the STANDARD_RIGHTS_REQUIRED access flags, the
|
||
following object type specific access flags are valid for mutex
|
||
objects:
|
||
|
||
- MUTEX_MODIFY_STATE - Modify access to the mutex is desired.
|
||
This allows a process to release a mutex.
|
||
|
||
- SYNCHRONIZE - Synchronization access (wait or release) to the
|
||
mutex object is desired.
|
||
|
||
- MUTEX_ALL_ACCESS - All possible types of access to the mutex
|
||
object are desired.
|
||
|
||
|
||
Arguments:
|
||
|
||
lpMutexAttributes - An optional parameter that may be used to specify
|
||
the attributes of the new mutex. If the parameter is not
|
||
specified, then the mutex is created without a security
|
||
descriptor, and the resulting handle is not inherited on process
|
||
creation.
|
||
|
||
bInitialOwner - A boolean value that determines whether the creator
|
||
of the object desires immediate ownership of the mutex object.
|
||
|
||
|
||
lpName - Supplies an optional unicode name for the mutex.
|
||
|
||
Return Value:
|
||
|
||
NON-NULL - Returns a handle to the new mutex. The handle has full
|
||
access to the new mutex and may be used in any API that
|
||
requires a handle to a mutex object.
|
||
|
||
FALSE/NULL - The operation failed. Extended error status is available
|
||
using GetLastError.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
OBJECT_ATTRIBUTES Obja;
|
||
POBJECT_ATTRIBUTES pObja;
|
||
HANDLE Handle;
|
||
UNICODE_STRING ObjectName;
|
||
PWCHAR pstrNewObjName = NULL;
|
||
|
||
if ( ARGUMENT_PRESENT(lpName) ) {
|
||
|
||
if (gpTermsrvFormatObjectName &&
|
||
(pstrNewObjName = gpTermsrvFormatObjectName(lpName))) {
|
||
|
||
RtlInitUnicodeString(&ObjectName,pstrNewObjName);
|
||
|
||
} else {
|
||
|
||
RtlInitUnicodeString(&ObjectName,lpName);
|
||
}
|
||
pObja = BaseFormatObjectAttributes(&Obja,lpMutexAttributes,&ObjectName);
|
||
}
|
||
else {
|
||
pObja = BaseFormatObjectAttributes(&Obja,lpMutexAttributes,NULL);
|
||
}
|
||
|
||
|
||
Status = NtCreateMutant(
|
||
&Handle,
|
||
MUTANT_ALL_ACCESS,
|
||
pObja,
|
||
(BOOLEAN)bInitialOwner
|
||
);
|
||
|
||
if (pstrNewObjName) {
|
||
RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
|
||
}
|
||
|
||
if ( NT_SUCCESS(Status) ) {
|
||
if ( Status == STATUS_OBJECT_NAME_EXISTS ) {
|
||
SetLastError(ERROR_ALREADY_EXISTS);
|
||
}
|
||
else {
|
||
SetLastError(0);
|
||
}
|
||
return Handle;
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
HANDLE
|
||
APIENTRY
|
||
OpenMutexA(
|
||
DWORD dwDesiredAccess,
|
||
BOOL bInheritHandle,
|
||
LPCSTR lpName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
ANSI thunk to OpenMutexW
|
||
|
||
--*/
|
||
|
||
{
|
||
PUNICODE_STRING Unicode;
|
||
ANSI_STRING AnsiString;
|
||
NTSTATUS Status;
|
||
|
||
if ( ARGUMENT_PRESENT(lpName) ) {
|
||
Unicode = &NtCurrentTeb()->StaticUnicodeString;
|
||
RtlInitAnsiString(&AnsiString,lpName);
|
||
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
if ( Status == STATUS_BUFFER_OVERFLOW ) {
|
||
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
}
|
||
return NULL;
|
||
}
|
||
}
|
||
else {
|
||
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||
return NULL;
|
||
}
|
||
|
||
return OpenMutexW(
|
||
dwDesiredAccess,
|
||
bInheritHandle,
|
||
(LPCWSTR)Unicode->Buffer
|
||
);
|
||
}
|
||
|
||
HANDLE
|
||
APIENTRY
|
||
OpenMutexW(
|
||
DWORD dwDesiredAccess,
|
||
BOOL bInheritHandle,
|
||
LPCWSTR lpName
|
||
)
|
||
{
|
||
OBJECT_ATTRIBUTES Obja;
|
||
UNICODE_STRING ObjectName;
|
||
NTSTATUS Status;
|
||
HANDLE Object;
|
||
PWCHAR pstrNewObjName = NULL;
|
||
|
||
if ( !lpName ) {
|
||
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||
return NULL;
|
||
}
|
||
|
||
if (gpTermsrvFormatObjectName &&
|
||
(pstrNewObjName = gpTermsrvFormatObjectName(lpName))) {
|
||
|
||
RtlInitUnicodeString(&ObjectName,pstrNewObjName);
|
||
|
||
} else {
|
||
|
||
RtlInitUnicodeString(&ObjectName,lpName);
|
||
}
|
||
|
||
InitializeObjectAttributes(
|
||
&Obja,
|
||
&ObjectName,
|
||
(bInheritHandle ? OBJ_INHERIT : 0),
|
||
BaseGetNamedObjectDirectory(),
|
||
NULL
|
||
);
|
||
|
||
Status = NtOpenMutant(
|
||
&Object,
|
||
dwDesiredAccess,
|
||
&Obja
|
||
);
|
||
|
||
if (pstrNewObjName) {
|
||
RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
|
||
}
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
BaseSetLastNTError(Status);
|
||
return NULL;
|
||
}
|
||
return Object;
|
||
}
|
||
|
||
BOOL
|
||
ReleaseMutex(
|
||
HANDLE hMutex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Ownership of a mutex object can be released with the ReleaseMutex
|
||
function.
|
||
|
||
A mutex object can only be released by a thread that currently owns
|
||
the mutex object. When the mutex is released, the current count of
|
||
the mutex object is incremented by one. If the resultant count is
|
||
one, then the mutex object is no longer owned. Any threads that are
|
||
waiting for the mutex object are examined to see if their wait can
|
||
be satisfied.
|
||
|
||
Arguments:
|
||
|
||
hMutex - An open handle to a mutex object. The handle must
|
||
have MUTEX_MODIFY_STATE access to the mutex.
|
||
|
||
Return Value:
|
||
|
||
TRUE - The operation was successful
|
||
|
||
FALSE/NULL - The operation failed. Extended error status is available
|
||
using GetLastError.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
Status = NtReleaseMutant(hMutex,NULL);
|
||
if ( NT_SUCCESS(Status) ) {
|
||
return TRUE;
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Wait Services
|
||
//
|
||
|
||
DWORD
|
||
WaitForSingleObject(
|
||
HANDLE hHandle,
|
||
DWORD dwMilliseconds
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A wait operation on a waitable object is accomplished with the
|
||
WaitForSingleObject function.
|
||
|
||
Waiting on an object checks the current state of the object. If the
|
||
current state of the object allows continued execution, any
|
||
adjustments to the object state are made (for example, decrementing
|
||
the semaphore count for a semaphore object) and the thread continues
|
||
execution. If the current state of the object does not allow
|
||
continued execution, the thread is placed into the wait state
|
||
pending the change of the object's state or time-out.
|
||
|
||
Arguments:
|
||
|
||
hHandle - An open handle to a waitable object. The handle must have
|
||
SYNCHRONIZE access to the object.
|
||
|
||
dwMilliseconds - A time-out value that specifies the relative time,
|
||
in milliseconds, over which the wait is to be completed. A
|
||
timeout value of 0 specified that the wait is to timeout
|
||
immediately. This allows an application to test an object to
|
||
determine if it is in the signaled state. A timeout value of -1
|
||
specifies an infinite timeout period.
|
||
|
||
Return Value:
|
||
|
||
WAIT_TIME_OUT - Indicates that the wait was terminated due to the
|
||
TimeOut conditions.
|
||
|
||
0 - indicates the specified object attained a Signaled
|
||
state thus completing the wait.
|
||
|
||
WAIT_ABANDONED - indicates the specified object attained a Signaled
|
||
state but was abandoned.
|
||
|
||
--*/
|
||
|
||
{
|
||
return WaitForSingleObjectEx(hHandle,dwMilliseconds,FALSE);
|
||
}
|
||
|
||
DWORD
|
||
APIENTRY
|
||
WaitForSingleObjectEx(
|
||
HANDLE hHandle,
|
||
DWORD dwMilliseconds,
|
||
BOOL bAlertable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A wait operation on a waitable object is accomplished with the
|
||
WaitForSingleObjectEx function.
|
||
|
||
Waiting on an object checks the current state of the object. If the
|
||
current state of the object allows continued execution, any
|
||
adjustments to the object state are made (for example, decrementing
|
||
the semaphore count for a semaphore object) and the thread continues
|
||
execution. If the current state of the object does not allow
|
||
continued execution, the thread is placed into the wait state
|
||
pending the change of the object's state or time-out.
|
||
|
||
If the bAlertable parameter is FALSE, the only way the wait
|
||
terminates is because the specified timeout period expires, or
|
||
because the specified object entered the signaled state. If the
|
||
bAlertable parameter is TRUE, then the wait can return due to any
|
||
one of the above wait termination conditions, or because an I/O
|
||
completion callback terminated the wait early (return value of
|
||
WAIT_IO_COMPLETION).
|
||
|
||
Arguments:
|
||
|
||
hHandle - An open handle to a waitable object. The handle must have
|
||
SYNCHRONIZE access to the object.
|
||
|
||
dwMilliseconds - A time-out value that specifies the relative time,
|
||
in milliseconds, over which the wait is to be completed. A
|
||
timeout value of 0 specified that the wait is to timeout
|
||
immediately. This allows an application to test an object to
|
||
determine if it is in the signaled state. A timeout value of
|
||
0xffffffff specifies an infinite timeout period.
|
||
|
||
bAlertable - Supplies a flag that controls whether or not the
|
||
wait may terminate early due to an I/O completion callback.
|
||
A value of TRUE allows this API to complete early due to an I/O
|
||
completion callback. A value of FALSE will not allow I/O
|
||
completion callbacks to terminate this call early.
|
||
|
||
Return Value:
|
||
|
||
WAIT_TIME_OUT - Indicates that the wait was terminated due to the
|
||
TimeOut conditions.
|
||
|
||
0 - indicates the specified object attained a Signaled
|
||
state thus completing the wait.
|
||
|
||
0xffffffff - The wait terminated due to an error. GetLastError may be
|
||
used to get additional error information.
|
||
|
||
WAIT_ABANDONED - indicates the specified object attained a Signaled
|
||
state but was abandoned.
|
||
|
||
WAIT_IO_COMPLETION - The wait terminated due to one or more I/O
|
||
completion callbacks.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
LARGE_INTEGER TimeOut;
|
||
PLARGE_INTEGER pTimeOut;
|
||
PPEB Peb;
|
||
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
|
||
|
||
RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
|
||
__try {
|
||
|
||
Peb = NtCurrentPeb();
|
||
switch( HandleToUlong(hHandle) ) {
|
||
case STD_INPUT_HANDLE: hHandle = Peb->ProcessParameters->StandardInput;
|
||
break;
|
||
case STD_OUTPUT_HANDLE: hHandle = Peb->ProcessParameters->StandardOutput;
|
||
break;
|
||
case STD_ERROR_HANDLE: hHandle = Peb->ProcessParameters->StandardError;
|
||
break;
|
||
}
|
||
|
||
if (CONSOLE_HANDLE(hHandle) && VerifyConsoleIoHandle(hHandle)) {
|
||
hHandle = GetConsoleInputWaitHandle();
|
||
}
|
||
|
||
pTimeOut = BaseFormatTimeOut(&TimeOut,dwMilliseconds);
|
||
rewait:
|
||
Status = NtWaitForSingleObject(hHandle,(BOOLEAN)bAlertable,pTimeOut);
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
BaseSetLastNTError(Status);
|
||
Status = (NTSTATUS)0xffffffff;
|
||
}
|
||
else {
|
||
if ( bAlertable && Status == STATUS_ALERTED ) {
|
||
goto rewait;
|
||
}
|
||
}
|
||
} __finally {
|
||
RtlDeactivateActivationContextUnsafeFast(&Frame);
|
||
}
|
||
|
||
return (DWORD)Status;
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
SignalObjectAndWait(
|
||
HANDLE hObjectToSignal,
|
||
HANDLE hObjectToWaitOn,
|
||
DWORD dwMilliseconds,
|
||
BOOL bAlertable
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
LARGE_INTEGER TimeOut;
|
||
PLARGE_INTEGER pTimeOut;
|
||
PPEB Peb;
|
||
|
||
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
|
||
|
||
RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
|
||
__try {
|
||
Peb = NtCurrentPeb();
|
||
switch( HandleToUlong(hObjectToWaitOn) ) {
|
||
case STD_INPUT_HANDLE: hObjectToWaitOn = Peb->ProcessParameters->StandardInput;
|
||
break;
|
||
case STD_OUTPUT_HANDLE: hObjectToWaitOn = Peb->ProcessParameters->StandardOutput;
|
||
break;
|
||
case STD_ERROR_HANDLE: hObjectToWaitOn = Peb->ProcessParameters->StandardError;
|
||
break;
|
||
}
|
||
|
||
if (CONSOLE_HANDLE(hObjectToWaitOn) && VerifyConsoleIoHandle(hObjectToWaitOn)) {
|
||
hObjectToWaitOn = GetConsoleInputWaitHandle();
|
||
}
|
||
|
||
pTimeOut = BaseFormatTimeOut(&TimeOut,dwMilliseconds);
|
||
rewait:
|
||
Status = NtSignalAndWaitForSingleObject(
|
||
hObjectToSignal,
|
||
hObjectToWaitOn,
|
||
(BOOLEAN)bAlertable,
|
||
pTimeOut
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
BaseSetLastNTError(Status);
|
||
Status = (NTSTATUS)0xffffffff;
|
||
}
|
||
else {
|
||
if ( bAlertable && Status == STATUS_ALERTED ) {
|
||
goto rewait;
|
||
}
|
||
}
|
||
} __finally {
|
||
RtlDeactivateActivationContextUnsafeFast(&Frame);
|
||
}
|
||
|
||
return (DWORD)Status;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
WaitForMultipleObjects(
|
||
DWORD nCount,
|
||
CONST HANDLE *lpHandles,
|
||
BOOL bWaitAll,
|
||
DWORD dwMilliseconds
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A wait operation on multiple waitable objects (up to
|
||
MAXIMUM_WAIT_OBJECTS) is accomplished with the WaitForMultipleObjects
|
||
function.
|
||
|
||
Arguments:
|
||
|
||
nCount - A count of the number of objects that are to be waited on.
|
||
|
||
lpHandles - An array of object handles. Each handle must have
|
||
SYNCHRONIZE access to the associated object.
|
||
|
||
bWaitAll - A flag that supplies the wait type. A value of TRUE
|
||
indicates a "wait all". A value of false indicates a "wait
|
||
any".
|
||
|
||
dwMilliseconds - A time-out value that specifies the relative time,
|
||
in milliseconds, over which the wait is to be completed. A
|
||
timeout value of 0 specified that the wait is to timeout
|
||
immediately. This allows an application to test an object to
|
||
determine if it is in the signaled state. A timeout value of -1
|
||
specifies an infinite timeout period.
|
||
|
||
Return Value:
|
||
|
||
WAIT_TIME_OUT - indicates that the wait was terminated due to the
|
||
TimeOut conditions.
|
||
|
||
0 to MAXIMUM_WAIT_OBJECTS-1, indicates, in the case of wait for any
|
||
object, the object number which satisfied the wait. In the case
|
||
of wait for all objects, the value only indicates that the wait
|
||
was completed successfully.
|
||
|
||
WAIT_ABANDONED_0 to (WAIT_ABANDONED_0)+(MAXIMUM_WAIT_OBJECTS - 1),
|
||
indicates, in the case of wait for any object, the object number
|
||
which satisfied the event, and that the object which satisfied
|
||
the event was abandoned. In the case of wait for all objects,
|
||
the value indicates that the wait was completed successfully and
|
||
at least one of the objects was abandoned.
|
||
|
||
--*/
|
||
|
||
{
|
||
return WaitForMultipleObjectsEx(nCount,lpHandles,bWaitAll,dwMilliseconds,FALSE);
|
||
}
|
||
|
||
DWORD
|
||
APIENTRY
|
||
WaitForMultipleObjectsEx(
|
||
DWORD nCount,
|
||
CONST HANDLE *lpHandles,
|
||
BOOL bWaitAll,
|
||
DWORD dwMilliseconds,
|
||
BOOL bAlertable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A wait operation on multiple waitable objects (up to
|
||
MAXIMUM_WAIT_OBJECTS) is accomplished with the
|
||
WaitForMultipleObjects function.
|
||
|
||
This API can be used to wait on any of the specified objects to
|
||
enter the signaled state, or all of the objects to enter the
|
||
signaled state.
|
||
|
||
If the bAlertable parameter is FALSE, the only way the wait
|
||
terminates is because the specified timeout period expires, or
|
||
because the specified objects entered the signaled state. If the
|
||
bAlertable parameter is TRUE, then the wait can return due to any one of
|
||
the above wait termination conditions, or because an I/O completion
|
||
callback terminated the wait early (return value of
|
||
WAIT_IO_COMPLETION).
|
||
|
||
Arguments:
|
||
|
||
nCount - A count of the number of objects that are to be waited on.
|
||
|
||
lpHandles - An array of object handles. Each handle must have
|
||
SYNCHRONIZE access to the associated object.
|
||
|
||
bWaitAll - A flag that supplies the wait type. A value of TRUE
|
||
indicates a "wait all". A value of false indicates a "wait
|
||
any".
|
||
|
||
dwMilliseconds - A time-out value that specifies the relative time,
|
||
in milliseconds, over which the wait is to be completed. A
|
||
timeout value of 0 specified that the wait is to timeout
|
||
immediately. This allows an application to test an object to
|
||
determine if it is in the signaled state. A timeout value of
|
||
0xffffffff specifies an infinite timeout period.
|
||
|
||
bAlertable - Supplies a flag that controls whether or not the
|
||
wait may terminate early due to an I/O completion callback.
|
||
A value of TRUE allows this API to complete early due to an I/O
|
||
completion callback. A value of FALSE will not allow I/O
|
||
completion callbacks to terminate this call early.
|
||
|
||
Return Value:
|
||
|
||
WAIT_TIME_OUT - indicates that the wait was terminated due to the
|
||
TimeOut conditions.
|
||
|
||
0 to MAXIMUM_WAIT_OBJECTS-1, indicates, in the case of wait for any
|
||
object, the object number which satisfied the wait. In the case
|
||
of wait for all objects, the value only indicates that the wait
|
||
was completed successfully.
|
||
|
||
0xffffffff - The wait terminated due to an error. GetLastError may be
|
||
used to get additional error information.
|
||
|
||
WAIT_ABANDONED_0 to (WAIT_ABANDONED_0)+(MAXIMUM_WAIT_OBJECTS - 1),
|
||
indicates, in the case of wait for any object, the object number
|
||
which satisfied the event, and that the object which satisfied
|
||
the event was abandoned. In the case of wait for all objects,
|
||
the value indicates that the wait was completed successfully and
|
||
at least one of the objects was abandoned.
|
||
|
||
WAIT_IO_COMPLETION - The wait terminated due to one or more I/O
|
||
completion callbacks.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
LARGE_INTEGER TimeOut;
|
||
PLARGE_INTEGER pTimeOut;
|
||
DWORD i;
|
||
LPHANDLE HandleArray;
|
||
HANDLE Handles[ 8 ];
|
||
PPEB Peb;
|
||
|
||
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
|
||
|
||
RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
|
||
__try {
|
||
if (nCount > 8) {
|
||
HandleArray = (LPHANDLE) RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), nCount*sizeof(HANDLE));
|
||
if (HandleArray == NULL) {
|
||
BaseSetLastNTError(STATUS_NO_MEMORY);
|
||
return 0xffffffff;
|
||
}
|
||
} else {
|
||
HandleArray = Handles;
|
||
}
|
||
RtlCopyMemory(HandleArray,(LPVOID)lpHandles,nCount*sizeof(HANDLE));
|
||
|
||
Peb = NtCurrentPeb();
|
||
for (i=0;i<nCount;i++) {
|
||
switch( HandleToUlong(HandleArray[i]) ) {
|
||
case STD_INPUT_HANDLE: HandleArray[i] = Peb->ProcessParameters->StandardInput;
|
||
break;
|
||
case STD_OUTPUT_HANDLE: HandleArray[i] = Peb->ProcessParameters->StandardOutput;
|
||
break;
|
||
case STD_ERROR_HANDLE: HandleArray[i] = Peb->ProcessParameters->StandardError;
|
||
break;
|
||
}
|
||
|
||
if (CONSOLE_HANDLE(HandleArray[i]) && VerifyConsoleIoHandle(HandleArray[i])) {
|
||
HandleArray[i] = GetConsoleInputWaitHandle();
|
||
}
|
||
}
|
||
|
||
pTimeOut = BaseFormatTimeOut(&TimeOut,dwMilliseconds);
|
||
rewait:
|
||
Status = NtWaitForMultipleObjects(
|
||
(CHAR)nCount,
|
||
HandleArray,
|
||
bWaitAll ? WaitAll : WaitAny,
|
||
(BOOLEAN)bAlertable,
|
||
pTimeOut
|
||
);
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
BaseSetLastNTError(Status);
|
||
Status = (NTSTATUS)0xffffffff;
|
||
}
|
||
else {
|
||
if ( bAlertable && Status == STATUS_ALERTED ) {
|
||
goto rewait;
|
||
}
|
||
}
|
||
|
||
if (HandleArray != Handles) {
|
||
RtlFreeHeap(RtlProcessHeap(), 0, HandleArray);
|
||
}
|
||
} __finally {
|
||
RtlDeactivateActivationContextUnsafeFast(&Frame);
|
||
}
|
||
|
||
return (DWORD)Status;
|
||
}
|
||
|
||
VOID
|
||
Sleep(
|
||
DWORD dwMilliseconds
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The execution of the current thread can be delayed for a specified
|
||
interval of time with the Sleep function.
|
||
|
||
The Sleep function causes the current thread to enter a
|
||
waiting state until the specified interval of time has passed.
|
||
|
||
Arguments:
|
||
|
||
dwMilliseconds - A time-out value that specifies the relative time,
|
||
in milliseconds, over which the wait is to be completed. A
|
||
timeout value of 0 specified that the wait is to timeout
|
||
immediately. This allows an application to test an object to
|
||
determine if it is in the signaled state. A timeout value of -1
|
||
specifies an infinite timeout period.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
SleepEx(dwMilliseconds,FALSE);
|
||
}
|
||
|
||
DWORD
|
||
APIENTRY
|
||
SleepEx(
|
||
DWORD dwMilliseconds,
|
||
BOOL bAlertable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The execution of the current thread can be delayed for a specified
|
||
interval of time with the SleepEx function.
|
||
|
||
The SleepEx function causes the current thread to enter a waiting
|
||
state until the specified interval of time has passed.
|
||
|
||
If the bAlertable parameter is FALSE, the only way the SleepEx
|
||
returns is when the specified time interval has passed. If the
|
||
bAlertable parameter is TRUE, then the SleepEx can return due to the
|
||
expiration of the time interval (return value of 0), or because an
|
||
I/O completion callback terminated the SleepEx early (return value
|
||
of WAIT_IO_COMPLETION).
|
||
|
||
Arguments:
|
||
|
||
dwMilliseconds - A time-out value that specifies the relative time,
|
||
in milliseconds, over which the wait is to be completed. A
|
||
timeout value of 0 specified that the wait is to timeout
|
||
immediately. A timeout value of -1 specifies an infinite
|
||
timeout period.
|
||
|
||
bAlertable - Supplies a flag that controls whether or not the
|
||
SleepEx may terminate early due to an I/O completion callback.
|
||
A value of TRUE allows this API to complete early due to an I/O
|
||
completion callback. A value of FALSE will not allow I/O
|
||
completion callbacks to terminate this call early.
|
||
|
||
Return Value:
|
||
|
||
0 - The SleepEx terminated due to expiration of the time interval.
|
||
|
||
WAIT_IO_COMPLETION - The SleepEx terminated due to one or more I/O
|
||
completion callbacks.
|
||
|
||
--*/
|
||
{
|
||
LARGE_INTEGER TimeOut;
|
||
PLARGE_INTEGER pTimeOut;
|
||
NTSTATUS Status;
|
||
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
|
||
|
||
RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
|
||
__try {
|
||
pTimeOut = BaseFormatTimeOut(&TimeOut,dwMilliseconds);
|
||
if (pTimeOut == NULL) {
|
||
//
|
||
// If Sleep( -1 ) then delay for the longest possible integer
|
||
// relative to now.
|
||
//
|
||
|
||
TimeOut.LowPart = 0x0;
|
||
TimeOut.HighPart = 0x80000000;
|
||
pTimeOut = &TimeOut;
|
||
}
|
||
|
||
rewait:
|
||
Status = NtDelayExecution(
|
||
(BOOLEAN)bAlertable,
|
||
pTimeOut
|
||
);
|
||
if ( bAlertable && Status == STATUS_ALERTED ) {
|
||
goto rewait;
|
||
}
|
||
} __finally {
|
||
RtlDeactivateActivationContextUnsafeFast(&Frame);
|
||
}
|
||
|
||
return Status == STATUS_USER_APC ? WAIT_IO_COMPLETION : 0;
|
||
}
|
||
|
||
HANDLE
|
||
WINAPI
|
||
CreateWaitableTimerA(
|
||
LPSECURITY_ATTRIBUTES lpTimerAttributes,
|
||
BOOL bManualReset,
|
||
LPCSTR lpTimerName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
ANSI thunk to CreateWaitableTimerW
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PUNICODE_STRING Unicode;
|
||
ANSI_STRING AnsiString;
|
||
NTSTATUS Status;
|
||
LPCWSTR NameBuffer;
|
||
|
||
NameBuffer = NULL;
|
||
if ( ARGUMENT_PRESENT(lpTimerName) ) {
|
||
Unicode = &NtCurrentTeb()->StaticUnicodeString;
|
||
RtlInitAnsiString(&AnsiString,lpTimerName);
|
||
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
if ( Status == STATUS_BUFFER_OVERFLOW ) {
|
||
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
}
|
||
return NULL;
|
||
}
|
||
NameBuffer = (LPCWSTR)Unicode->Buffer;
|
||
}
|
||
|
||
return CreateWaitableTimerW(
|
||
lpTimerAttributes,
|
||
bManualReset,
|
||
NameBuffer
|
||
);
|
||
}
|
||
|
||
HANDLE
|
||
WINAPI
|
||
CreateWaitableTimerW(
|
||
LPSECURITY_ATTRIBUTES lpTimerAttributes,
|
||
BOOL bManualReset,
|
||
LPCWSTR lpTimerName
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
OBJECT_ATTRIBUTES Obja;
|
||
POBJECT_ATTRIBUTES pObja;
|
||
HANDLE Handle;
|
||
UNICODE_STRING ObjectName;
|
||
|
||
if ( ARGUMENT_PRESENT(lpTimerName) ) {
|
||
RtlInitUnicodeString(&ObjectName,lpTimerName);
|
||
pObja = BaseFormatObjectAttributes(&Obja,lpTimerAttributes,&ObjectName);
|
||
}
|
||
else {
|
||
pObja = BaseFormatObjectAttributes(&Obja,lpTimerAttributes,NULL);
|
||
}
|
||
|
||
Status = NtCreateTimer(
|
||
&Handle,
|
||
TIMER_ALL_ACCESS,
|
||
pObja,
|
||
bManualReset ? NotificationTimer : SynchronizationTimer
|
||
);
|
||
|
||
if ( NT_SUCCESS(Status) ) {
|
||
if ( Status == STATUS_OBJECT_NAME_EXISTS ) {
|
||
SetLastError(ERROR_ALREADY_EXISTS);
|
||
}
|
||
else {
|
||
SetLastError(0);
|
||
}
|
||
return Handle;
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
HANDLE
|
||
WINAPI
|
||
OpenWaitableTimerA(
|
||
DWORD dwDesiredAccess,
|
||
BOOL bInheritHandle,
|
||
LPCSTR lpTimerName
|
||
)
|
||
{
|
||
PUNICODE_STRING Unicode;
|
||
ANSI_STRING AnsiString;
|
||
NTSTATUS Status;
|
||
|
||
if ( ARGUMENT_PRESENT(lpTimerName) ) {
|
||
Unicode = &NtCurrentTeb()->StaticUnicodeString;
|
||
RtlInitAnsiString(&AnsiString,lpTimerName);
|
||
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
if ( Status == STATUS_BUFFER_OVERFLOW ) {
|
||
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
||
}
|
||
else {
|
||
BaseSetLastNTError(Status);
|
||
}
|
||
return NULL;
|
||
}
|
||
}
|
||
else {
|
||
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||
return NULL;
|
||
}
|
||
|
||
return OpenWaitableTimerW(
|
||
dwDesiredAccess,
|
||
bInheritHandle,
|
||
(LPCWSTR)Unicode->Buffer
|
||
);
|
||
}
|
||
|
||
|
||
HANDLE
|
||
WINAPI
|
||
OpenWaitableTimerW(
|
||
DWORD dwDesiredAccess,
|
||
BOOL bInheritHandle,
|
||
LPCWSTR lpTimerName
|
||
)
|
||
{
|
||
OBJECT_ATTRIBUTES Obja;
|
||
UNICODE_STRING ObjectName;
|
||
NTSTATUS Status;
|
||
HANDLE Object;
|
||
|
||
if ( !lpTimerName ) {
|
||
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||
return NULL;
|
||
}
|
||
RtlInitUnicodeString(&ObjectName,lpTimerName);
|
||
|
||
InitializeObjectAttributes(
|
||
&Obja,
|
||
&ObjectName,
|
||
(bInheritHandle ? OBJ_INHERIT : 0),
|
||
BaseGetNamedObjectDirectory(),
|
||
NULL
|
||
);
|
||
|
||
Status = NtOpenTimer(
|
||
&Object,
|
||
dwDesiredAccess,
|
||
&Obja
|
||
);
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
BaseSetLastNTError(Status);
|
||
return NULL;
|
||
}
|
||
return Object;
|
||
}
|
||
|
||
static
|
||
VOID
|
||
CALLBACK
|
||
BasepTimerAPCProc(
|
||
PVOID pvContext,
|
||
ULONG TimerLowValue,
|
||
LONG TimerHighValue
|
||
)
|
||
{
|
||
PBASE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK ActivationBlock = (PBASE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK) pvContext;
|
||
const PVOID CallbackContext = ActivationBlock->CallbackContext;
|
||
const PTIMERAPCROUTINE TimerAPCRoutine = (PTIMERAPCROUTINE) ActivationBlock->CallbackFunction;
|
||
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActivationFrame = { sizeof(ActivationFrame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
|
||
const PACTIVATION_CONTEXT ActivationContext = ActivationBlock->ActivationContext;
|
||
|
||
if ((ActivationBlock->Flags & BASE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK_FLAG_DO_NOT_FREE_AFTER_CALLBACK) == 0) {
|
||
BasepFreeActivationContextActivationBlock(ActivationBlock);
|
||
}
|
||
|
||
RtlActivateActivationContextUnsafeFast(&ActivationFrame, ActivationContext);
|
||
__try {
|
||
(*TimerAPCRoutine)(CallbackContext, TimerLowValue, TimerHighValue);
|
||
} __finally {
|
||
RtlDeactivateActivationContextUnsafeFast(&ActivationFrame);
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
WINAPI
|
||
SetWaitableTimer(
|
||
HANDLE hTimer,
|
||
const LARGE_INTEGER *lpDueTime,
|
||
LONG lPeriod,
|
||
PTIMERAPCROUTINE pfnCompletionRoutine,
|
||
LPVOID lpArgToCompletionRoutine,
|
||
BOOL fResume
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
PBASE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK ActivationBlock = NULL;
|
||
PTIMER_APC_ROUTINE TimerApcRoutine = (PTIMER_APC_ROUTINE) pfnCompletionRoutine;
|
||
PVOID TimerApcContext = lpArgToCompletionRoutine;
|
||
|
||
// If there's an APC routine to call and we have a non-default activation
|
||
// context active for this thread, we need to allocate a little chunk of heap
|
||
// to pass to the APC callback.
|
||
if (pfnCompletionRoutine != NULL) {
|
||
DWORD dwActivationBlockAllocationFlags = BASEP_ALLOCATE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK_FLAG_DO_NOT_ALLOCATE_IF_PROCESS_DEFAULT;
|
||
|
||
// If it's a periodic timer, don't free the block until the timer is cancelled.
|
||
if (lPeriod > 0)
|
||
dwActivationBlockAllocationFlags |= BASEP_ALLOCATE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK_FLAG_DO_NOT_FREE_AFTER_CALLBACK;
|
||
|
||
Status = BasepAllocateActivationContextActivationBlock(dwActivationBlockAllocationFlags, pfnCompletionRoutine, lpArgToCompletionRoutine, &ActivationBlock);
|
||
if (!NT_SUCCESS(Status)) {
|
||
BaseSetLastNTError(Status);
|
||
return FALSE;
|
||
}
|
||
|
||
if (ActivationBlock != NULL) {
|
||
TimerApcRoutine = &BasepTimerAPCProc;
|
||
TimerApcContext = ActivationBlock;
|
||
}
|
||
}
|
||
|
||
Status = NtSetTimer(
|
||
hTimer,
|
||
(PLARGE_INTEGER) lpDueTime,
|
||
TimerApcRoutine, // will be NULL if pfnCompletionRoutine was null
|
||
TimerApcContext,
|
||
(BOOLEAN) fResume,
|
||
lPeriod,
|
||
NULL
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
if (ActivationBlock != NULL)
|
||
BasepFreeActivationContextActivationBlock(ActivationBlock);
|
||
BaseSetLastNTError(Status);
|
||
return FALSE;
|
||
} else {
|
||
if ( Status == STATUS_TIMER_RESUME_IGNORED ) {
|
||
SetLastError(ERROR_NOT_SUPPORTED);
|
||
} else {
|
||
SetLastError(ERROR_SUCCESS);
|
||
}
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
WINAPI
|
||
CancelWaitableTimer(
|
||
HANDLE hTimer
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
Status = NtCancelTimer(hTimer, NULL);
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
BaseSetLastNTError(Status);
|
||
return FALSE;
|
||
}
|
||
else {
|
||
return TRUE;
|
||
}
|
||
}
|