mirror of https://github.com/tongzx/nt5src
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.
1983 lines
52 KiB
1983 lines
52 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
}
|