/* * @implemented */ DWORD WINAPI SignalObjectAndWait(IN HANDLE hObjectToSignal, IN HANDLE hObjectToWaitOn, IN DWORD dwMilliseconds, IN BOOL bAlertable) { PLARGE_INTEGER TimePtr; LARGE_INTEGER Time; NTSTATUS Status; RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx; /* APCs must execute with the default activation context */ if (bAlertable) { /* Setup the frame */ RtlZeroMemory(&ActCtx, sizeof(ActCtx)); ActCtx.Size = sizeof(ActCtx); ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER; RtlActivateActivationContextUnsafeFast(&ActCtx, NULL); } /* Get real handle */ hObjectToWaitOn = TranslateStdHandle(hObjectToWaitOn); /* Check for console handle */ if ((IsConsoleHandle(hObjectToWaitOn)) && (VerifyConsoleIoHandle(hObjectToWaitOn))) { /* Get the real wait handle */ hObjectToWaitOn = GetConsoleInputWaitHandle(); } /* Convert the timeout */ TimePtr = BaseFormatTimeOut(&Time, dwMilliseconds); /* Start wait loop */ do { /* Do the wait */ Status = NtSignalAndWaitForSingleObject(hObjectToSignal, hObjectToWaitOn, (BOOLEAN)bAlertable, TimePtr); if (!NT_SUCCESS(Status)) { /* The wait failed */ BaseSetLastNTError(Status); Status = WAIT_FAILED; } } while ((Status == STATUS_ALERTED) && (bAlertable)); /* Cleanup the activation context */ if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx); /* Return wait status */ return Status; }
DWORD WINAPI SignalObjectAndWait( HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable ) { NTSTATUS Status; LARGE_INTEGER TimeOut; PLARGE_INTEGER pTimeOut; PPEB Peb; Peb = NtCurrentPeb(); switch( (DWORD)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; } } return (DWORD)Status; }
/* * @implemented */ HANDLE WINAPI RegisterWaitForSingleObjectEx(IN HANDLE hObject, IN WAITORTIMERCALLBACK Callback, IN PVOID Context, IN ULONG dwMilliseconds, IN ULONG dwFlags) { NTSTATUS Status; HANDLE hNewWaitObject; /* Get real handle */ hObject = TranslateStdHandle(hObject); /* Check for console handle */ if ((IsConsoleHandle(hObject)) && (VerifyConsoleIoHandle(hObject))) { /* Get the real wait handle */ hObject = GetConsoleInputWaitHandle(); } /* Register the wait */ Status = RtlRegisterWait(&hNewWaitObject, hObject, Callback, Context, dwMilliseconds, dwFlags); if (!NT_SUCCESS(Status)) { /* Return failure */ BaseSetLastNTError(Status); return NULL; } /* Return the object */ return hNewWaitObject; }
/* * @implemented */ DWORD WINAPI WaitForMultipleObjectsEx(IN DWORD nCount, IN CONST HANDLE *lpHandles, IN BOOL bWaitAll, IN DWORD dwMilliseconds, IN BOOL bAlertable) { PLARGE_INTEGER TimePtr; LARGE_INTEGER Time; PHANDLE HandleBuffer; HANDLE Handle[8]; DWORD i; NTSTATUS Status; RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx; /* APCs must execute with the default activation context */ if (bAlertable) { /* Setup the frame */ RtlZeroMemory(&ActCtx, sizeof(ActCtx)); ActCtx.Size = sizeof(ActCtx); ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER; RtlActivateActivationContextUnsafeFast(&ActCtx, NULL); } /* Check if we have more handles then we locally optimize */ if (nCount > 8) { /* Allocate a buffer for them */ HandleBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nCount * sizeof(HANDLE)); if (!HandleBuffer) { /* No buffer, fail the wait */ SetLastError(ERROR_NOT_ENOUGH_MEMORY); if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx); return WAIT_FAILED; } } else { /* Otherwise, use our local buffer */ HandleBuffer = Handle; } /* Copy the handles into our buffer and loop them all */ RtlCopyMemory(HandleBuffer, (LPVOID)lpHandles, nCount * sizeof(HANDLE)); for (i = 0; i < nCount; i++) { /* Check what kind of handle this is */ HandleBuffer[i] = TranslateStdHandle(HandleBuffer[i]); /* Check for console handle */ if ((IsConsoleHandle(HandleBuffer[i])) && (VerifyConsoleIoHandle(HandleBuffer[i]))) { /* Get the real wait handle */ HandleBuffer[i] = GetConsoleInputWaitHandle(); } } /* Convert the timeout */ TimePtr = BaseFormatTimeOut(&Time, dwMilliseconds); /* Start wait loop */ do { /* Do the wait */ Status = NtWaitForMultipleObjects(nCount, HandleBuffer, bWaitAll ? WaitAll : WaitAny, (BOOLEAN)bAlertable, TimePtr); if (!NT_SUCCESS(Status)) { /* Wait failed */ BaseSetLastNTError(Status); Status = WAIT_FAILED; } } while ((Status == STATUS_ALERTED) && (bAlertable)); /* Check if we didn't use our local buffer */ if (HandleBuffer != Handle) { /* Free the allocated one */ RtlFreeHeap(RtlGetProcessHeap(), 0, HandleBuffer); } /* Cleanup the activation context */ if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx); /* Return wait status */ return Status; }
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; 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( (DWORD)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); } return (DWORD)Status; }
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; Peb = NtCurrentPeb(); switch( (DWORD)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; } } return (DWORD)Status; }
static DWORD WINAPI ConsoleEventThread(LPVOID Parameter) { HANDLE ConsoleInput = (HANDLE)Parameter; HANDLE WaitHandles[2]; DWORD WaitResult; /* * For optimization purposes, Windows (and hence ReactOS, too, for * compatibility reasons) uses a static buffer if no more than five * input records are read. Otherwise a new buffer is used. * The client-side expects that we know this behaviour. * See consrv/coninput.c * * We exploit here this optimization by also using a buffer of 5 records. */ INPUT_RECORD InputRecords[5]; ULONG NumRecords, i; WaitHandles[0] = VdmTaskEvent; WaitHandles[1] = GetConsoleInputWaitHandle(); while (VdmRunning) { /* Make sure the task event is signaled */ WaitResult = WaitForMultipleObjects(ARRAYSIZE(WaitHandles), WaitHandles, TRUE, INFINITE); switch (WaitResult) { case WAIT_OBJECT_0 + 0: case WAIT_OBJECT_0 + 1: break; default: return GetLastError(); } /* Wait for an input record */ if (!ReadConsoleInputExW(ConsoleInput, InputRecords, ARRAYSIZE(InputRecords), &NumRecords, CONSOLE_READ_CONTINUE)) { DWORD LastError = GetLastError(); DPRINT1("Error reading console input (0x%p, %lu) - Error %lu\n", ConsoleInput, NumRecords, LastError); return LastError; } // ASSERT(NumRecords != 0); if (NumRecords == 0) { DPRINT1("Got NumRecords == 0!\n"); continue; } /* Dispatch the events */ for (i = 0; i < NumRecords; i++) { /* Check the event type */ switch (InputRecords[i].EventType) { /* * Hardware events */ case KEY_EVENT: KeyboardEventHandler(&InputRecords[i].Event.KeyEvent); break; case MOUSE_EVENT: MouseEventHandler(&InputRecords[i].Event.MouseEvent); break; case WINDOW_BUFFER_SIZE_EVENT: ScreenEventHandler(&InputRecords[i].Event.WindowBufferSizeEvent); break; /* * Interface events */ case MENU_EVENT: MenuEventHandler(&InputRecords[i].Event.MenuEvent); break; case FOCUS_EVENT: FocusEventHandler(&InputRecords[i].Event.FocusEvent); break; default: DPRINT1("Unknown input event type 0x%04x\n", InputRecords[i].EventType); break; } } /* Let the console subsystem queue some new events */ Sleep(10); } return 0; }