- Implemented waitable console handles.

- Removed a fake event after a input event to empty the queue in CsrReadInputEvent.

svn path=/trunk/; revision=11653
This commit is contained in:
Hartmut Birr 2004-11-14 18:47:10 +00:00
parent 26b8d50a75
commit 349e167cae
7 changed files with 136 additions and 106 deletions

View file

@ -606,6 +606,15 @@ typedef struct
{ {
} CSRSS_SET_CONSOLE_OUTPUT_CP_REPLY, *PCSRSS_SET_CONSOLE_OUTPUT_CP_REPLY; } CSRSS_SET_CONSOLE_OUTPUT_CP_REPLY, *PCSRSS_SET_CONSOLE_OUTPUT_CP_REPLY;
typedef struct
{
} CSRSS_GET_INPUT_WAIT_HANDLE_REQUEST, *PCSRSS_GET_INPUT_WAIT_HANDLE_REQUEST;
typedef struct
{
HANDLE InputWaitHandle;
} CSRSS_GET_INPUT_WAIT_HANDLE_REPLY, *PCSRSS_GET_INPUT_WAIT_HANDLE_REPLY;
#define CSRSS_MAX_WRITE_CONSOLE_REQUEST \ #define CSRSS_MAX_WRITE_CONSOLE_REQUEST \
(MAX_MESSAGE_DATA - sizeof(ULONG) - sizeof(CSRSS_WRITE_CONSOLE_REQUEST)) (MAX_MESSAGE_DATA - sizeof(ULONG) - sizeof(CSRSS_WRITE_CONSOLE_REQUEST))
@ -677,6 +686,7 @@ typedef struct
#define CSRSS_SET_CONSOLE_CP (0x32) #define CSRSS_SET_CONSOLE_CP (0x32)
#define CSRSS_GET_CONSOLE_OUTPUT_CP (0x33) #define CSRSS_GET_CONSOLE_OUTPUT_CP (0x33)
#define CSRSS_SET_CONSOLE_OUTPUT_CP (0x34) #define CSRSS_SET_CONSOLE_OUTPUT_CP (0x34)
#define CSRSS_GET_INPUT_WAIT_HANDLE (0x35)
/* Keep in sync with definition below. */ /* Keep in sync with definition below. */
#define CSRSS_REQUEST_HEADER_SIZE (LPC_MESSAGE_BASE_SIZE + sizeof(ULONG)) #define CSRSS_REQUEST_HEADER_SIZE (LPC_MESSAGE_BASE_SIZE + sizeof(ULONG))
@ -741,6 +751,7 @@ typedef struct
CSRSS_SET_CONSOLE_CP_REQUEST SetConsoleCodePage; CSRSS_SET_CONSOLE_CP_REQUEST SetConsoleCodePage;
CSRSS_GET_CONSOLE_OUTPUT_CP_REQUEST GetConsoleOutputCodePage; CSRSS_GET_CONSOLE_OUTPUT_CP_REQUEST GetConsoleOutputCodePage;
CSRSS_SET_CONSOLE_OUTPUT_CP_REQUEST SetConsoleOutputCodePage; CSRSS_SET_CONSOLE_OUTPUT_CP_REQUEST SetConsoleOutputCodePage;
CSRSS_GET_INPUT_WAIT_HANDLE_REQUEST GetConsoleInputWaitHandle;
} Data; } Data;
}; };
}; };
@ -795,6 +806,7 @@ typedef struct
CSRSS_SET_CONSOLE_CP_REPLY SetConsoleCodePage; CSRSS_SET_CONSOLE_CP_REPLY SetConsoleCodePage;
CSRSS_GET_CONSOLE_OUTPUT_CP_REPLY GetConsoleOutputCodePage; CSRSS_GET_CONSOLE_OUTPUT_CP_REPLY GetConsoleOutputCodePage;
CSRSS_SET_CONSOLE_OUTPUT_CP_REPLY SetConsoleOutputCodePage; CSRSS_SET_CONSOLE_OUTPUT_CP_REPLY SetConsoleOutputCodePage;
CSRSS_GET_INPUT_WAIT_HANDLE_REPLY GetConsoleInputWaitHandle;
} Data; } Data;
}; };
}; };

View file

@ -1,4 +1,4 @@
/* $Id: console.c,v 1.82 2004/11/02 20:42:05 weiden Exp $ /* $Id: console.c,v 1.83 2004/11/14 18:47:09 hbirr Exp $
* *
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries * PROJECT: ReactOS system libraries
@ -559,7 +559,7 @@ GetConsoleHardwareState (HANDLE hConsole,
/* /*
* @unimplemented * @implemented
*/ */
DWORD STDCALL DWORD STDCALL
GetConsoleInputWaitHandle (VOID) GetConsoleInputWaitHandle (VOID)
@ -567,9 +567,19 @@ GetConsoleInputWaitHandle (VOID)
* Undocumented * Undocumented
*/ */
{ {
DPRINT1("GetConsoleInputWaitHandle() UNIMPLEMENTED!\n"); CSRSS_API_REQUEST Request;
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); CSRSS_API_REPLY Reply;
return FALSE; NTSTATUS Status;
Request.Type = CSRSS_GET_INPUT_WAIT_HANDLE;
Status = CsrClientCallServer(&Request, &Reply, sizeof(CSRSS_API_REQUEST),
sizeof(CSRSS_API_REPLY));
if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Reply.Status))
{
SetLastErrorByStatus(Status);
return 0;
}
return (DWORD) Reply.Data.GetConsoleInputWaitHandle.InputWaitHandle;
} }

View file

@ -1,4 +1,4 @@
/* $Id: wait.c,v 1.30 2004/10/02 10:19:38 hbirr Exp $ /* $Id: wait.c,v 1.31 2004/11/14 18:47:10 hbirr Exp $
* *
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries * PROJECT: ReactOS system libraries
@ -19,38 +19,8 @@
/* FUNCTIONS ****************************************************************/ /* FUNCTIONS ****************************************************************/
/* DWORD STDCALL
* Thread that waits for a console handle. Console handles only fire when GetConsoleInputWaitHandle (VOID);
* they're readable.
*/
DWORD STDCALL WaitForConsoleHandleThread( PVOID ConHandle ) {
DWORD AmtRead = 0;
INPUT_RECORD Buffer[1];
do {
PeekConsoleInputA( ConHandle, Buffer, 1, &AmtRead );
if( !AmtRead ) Sleep( 100 );
} while( AmtRead == 0 );
return 0;
}
/*
* Return a waitable object given a console handle
*/
DWORD GetWaiterForConsoleHandle( HANDLE ConHandle, PHANDLE Waitable ) {
DWORD ThreadId;
HANDLE WaitableHandle = CreateThread( 0,
0,
WaitForConsoleHandleThread,
ConHandle,
0,
&ThreadId );
*Waitable = WaitableHandle;
return WaitableHandle ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
}
/* /*
* @implemented * @implemented
@ -76,7 +46,6 @@ WaitForSingleObjectEx(HANDLE hHandle,
PLARGE_INTEGER TimePtr; PLARGE_INTEGER TimePtr;
LARGE_INTEGER Time; LARGE_INTEGER Time;
NTSTATUS Status; NTSTATUS Status;
BOOL CloseWaitHandle = FALSE;
/* Get real handle */ /* Get real handle */
switch ((ULONG)hHandle) switch ((ULONG)hHandle)
@ -97,15 +66,18 @@ WaitForSingleObjectEx(HANDLE hHandle,
/* Check for console handle */ /* Check for console handle */
if (IsConsoleHandle(hHandle)) if (IsConsoleHandle(hHandle))
{ {
if (VerifyConsoleIoHandle(hHandle)) if (!VerifyConsoleIoHandle(hHandle))
{ {
Status = GetWaiterForConsoleHandle( hHandle, &hHandle ); SetLastError (ERROR_INVALID_HANDLE);
if (!NT_SUCCESS(Status)) return WAIT_FAILED;
{ }
SetLastErrorByStatus (Status);
return FALSE; hHandle = (HANDLE)GetConsoleInputWaitHandle();
} if (hHandle == NULL || hHandle == INVALID_HANDLE_VALUE)
CloseWaitHandle = TRUE; {
SetLastError (ERROR_INVALID_HANDLE);
return WAIT_FAILED;
} }
} }
@ -123,12 +95,6 @@ WaitForSingleObjectEx(HANDLE hHandle,
(BOOLEAN) bAlertable, (BOOLEAN) bAlertable,
TimePtr); TimePtr);
if (CloseWaitHandle)
{
TerminateThread(hHandle, 0);
NtClose(hHandle);
}
if (HIWORD(Status)) if (HIWORD(Status))
{ {
SetLastErrorByStatus (Status); SetLastErrorByStatus (Status);
@ -169,24 +135,27 @@ WaitForMultipleObjectsEx(DWORD nCount,
PLARGE_INTEGER TimePtr; PLARGE_INTEGER TimePtr;
LARGE_INTEGER Time; LARGE_INTEGER Time;
PHANDLE HandleBuffer; PHANDLE HandleBuffer;
DWORD i,j; HANDLE Handle[3];
DWORD i;
NTSTATUS Status; NTSTATUS Status;
PBOOL FreeThisHandle;
DPRINT("nCount %lu\n", nCount); DPRINT("nCount %lu\n", nCount);
HandleBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nCount * (sizeof(HANDLE) + sizeof(BOOL)) ); if (nCount > 3)
FreeThisHandle = (PBOOL)(&HandleBuffer[nCount]);
if (HandleBuffer == NULL)
{ {
SetLastError(ERROR_NOT_ENOUGH_MEMORY); HandleBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nCount * sizeof(HANDLE));
return WAIT_FAILED; if (HandleBuffer == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return WAIT_FAILED;
}
}
else
{
HandleBuffer = Handle;
} }
for (i = 0; i < nCount; i++) for (i = 0; i < nCount; i++)
{ {
FreeThisHandle[i] = FALSE;
switch ((DWORD)lpHandles[i]) switch ((DWORD)lpHandles[i])
{ {
case STD_INPUT_HANDLE: case STD_INPUT_HANDLE:
@ -209,24 +178,24 @@ WaitForMultipleObjectsEx(DWORD nCount,
/* Check for console handle */ /* Check for console handle */
if (IsConsoleHandle(HandleBuffer[i])) if (IsConsoleHandle(HandleBuffer[i]))
{ {
if (VerifyConsoleIoHandle(HandleBuffer[i])) if (!VerifyConsoleIoHandle(HandleBuffer[i]))
{ {
Status = GetWaiterForConsoleHandle( HandleBuffer[i], if (HandleBuffer != Handle)
&HandleBuffer[i] ); {
if (!NT_SUCCESS(Status)) RtlFreeHeap(GetProcessHeap(),0,HandleBuffer);
{ }
/* We'll leak some handles unless we close the already SetLastError (ERROR_INVALID_HANDLE);
created handles */ return WAIT_FAILED;
for (j = 0; j < i; j++) }
if (FreeThisHandle[j]) HandleBuffer[i] = (HANDLE)GetConsoleInputWaitHandle();
NtClose(HandleBuffer[j]); if (HandleBuffer[i] == NULL || HandleBuffer[i] == INVALID_HANDLE_VALUE)
{
SetLastErrorByStatus (Status); if (HandleBuffer != Handle)
RtlFreeHeap(GetProcessHeap(),0,HandleBuffer); {
return FALSE; RtlFreeHeap(GetProcessHeap(),0,HandleBuffer);
} }
SetLastError (ERROR_INVALID_HANDLE);
FreeThisHandle[i] = TRUE; return WAIT_FAILED;
} }
} }
} }
@ -246,16 +215,11 @@ WaitForMultipleObjectsEx(DWORD nCount,
bWaitAll ? WaitAll : WaitAny, bWaitAll ? WaitAll : WaitAny,
(BOOLEAN)bAlertable, (BOOLEAN)bAlertable,
TimePtr); TimePtr);
if (HandleBuffer != Handle)
for (i = 0; i < nCount; i++)
if (FreeThisHandle[i])
{ {
TerminateThread(HandleBuffer[i], 0); RtlFreeHeap(RtlGetProcessHeap(), 0, HandleBuffer);
NtClose(HandleBuffer[i]);
} }
RtlFreeHeap(RtlGetProcessHeap(), 0, HandleBuffer);
if (Status == STATUS_TIMEOUT) if (Status == STATUS_TIMEOUT)
{ {
return WAIT_TIMEOUT; return WAIT_TIMEOUT;

View file

@ -1,4 +1,4 @@
/* $Id: process.c,v 1.35 2004/06/27 12:21:31 weiden Exp $ /* $Id: process.c,v 1.36 2004/11/14 18:47:10 hbirr Exp $
* *
* reactos/subsys/csrss/api/process.c * reactos/subsys/csrss/api/process.c
* *
@ -425,4 +425,23 @@ CSR_API(CsrDuplicateHandle)
return Reply->Status; return Reply->Status;
} }
CSR_API(CsrGetInputWaitHandle)
{
Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
if (ProcessData == NULL)
{
Reply->Data.GetConsoleInputWaitHandle.InputWaitHandle = INVALID_HANDLE_VALUE;
Reply->Status = STATUS_INVALID_PARAMETER;
}
else
{
Reply->Data.GetConsoleInputWaitHandle.InputWaitHandle = ProcessData->ConsoleEvent;
Reply->Status = STATUS_SUCCESS;
}
return Reply->Status;
}
/* EOF */ /* EOF */

View file

@ -1,4 +1,4 @@
/* $Id: api.h,v 1.6 2004/07/12 20:09:34 gvg Exp $ /* $Id: api.h,v 1.7 2004/11/14 18:47:10 hbirr Exp $
* *
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries * PROJECT: ReactOS system libraries
@ -124,6 +124,7 @@ CSR_API(CsrGetOutputHandle);
CSR_API(CsrCloseHandle); CSR_API(CsrCloseHandle);
CSR_API(CsrVerifyHandle); CSR_API(CsrVerifyHandle);
CSR_API(CsrDuplicateHandle); CSR_API(CsrDuplicateHandle);
CSR_API(CsrGetInputWaitHandle);
/* api/user.c */ /* api/user.c */
CSR_API(CsrRegisterServicesProcess); CSR_API(CsrRegisterServicesProcess);

View file

@ -1,4 +1,4 @@
/* $Id: init.c,v 1.29 2004/07/12 20:09:34 gvg Exp $ /* $Id: init.c,v 1.30 2004/11/14 18:47:10 hbirr Exp $
* *
* reactos/subsys/csrss/init.c * reactos/subsys/csrss/init.c
* *
@ -214,6 +214,7 @@ CSRSS_API_DEFINITION NativeDefinitions[] =
CSRSS_DEFINE_API(CSRSS_CLOSE_HANDLE, CsrCloseHandle), CSRSS_DEFINE_API(CSRSS_CLOSE_HANDLE, CsrCloseHandle),
CSRSS_DEFINE_API(CSRSS_VERIFY_HANDLE, CsrVerifyHandle), CSRSS_DEFINE_API(CSRSS_VERIFY_HANDLE, CsrVerifyHandle),
CSRSS_DEFINE_API(CSRSS_DUPLICATE_HANDLE, CsrDuplicateHandle), CSRSS_DEFINE_API(CSRSS_DUPLICATE_HANDLE, CsrDuplicateHandle),
CSRSS_DEFINE_API(CSRSS_GET_INPUT_WAIT_HANDLE, CsrGetInputWaitHandle),
{ 0, 0, 0, NULL } { 0, 0, 0, NULL }
}; };

View file

@ -1,4 +1,4 @@
/* $Id: conio.c,v 1.16 2004/11/02 20:42:06 weiden Exp $ /* $Id: conio.c,v 1.17 2004/11/14 18:47:10 hbirr Exp $
* *
* reactos/subsys/csrss/win32csr/conio.c * reactos/subsys/csrss/win32csr/conio.c
* *
@ -186,7 +186,7 @@ CsrInitConsole(PCSRSS_CONSOLE Console)
SecurityAttributes.lpSecurityDescriptor = NULL; SecurityAttributes.lpSecurityDescriptor = NULL;
SecurityAttributes.bInheritHandle = TRUE; SecurityAttributes.bInheritHandle = TRUE;
Console->ActiveEvent = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL); Console->ActiveEvent = CreateEventW(&SecurityAttributes, TRUE, FALSE, NULL);
if (NULL == Console->ActiveEvent) if (NULL == Console->ActiveEvent)
{ {
RtlFreeUnicodeString(&Console->Title); RtlFreeUnicodeString(&Console->Title);
@ -559,6 +559,11 @@ CSR_API(CsrReadConsole)
{ {
/* remove input event from queue */ /* remove input event from queue */
CurrentEntry = RemoveHeadList(&Console->InputEvents); CurrentEntry = RemoveHeadList(&Console->InputEvents);
if (IsListEmpty(&Console->InputEvents))
{
CHECKPOINT;
ResetEvent(Console->ActiveEvent);
}
Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry); Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
/* only pay attention to valid ascii chars, on key down */ /* only pay attention to valid ascii chars, on key down */
@ -1650,7 +1655,6 @@ CSR_API(CsrFillOutputChar)
ConioUnlockConsole(Console); ConioUnlockConsole(Console);
} }
Reply->Data.FillOutputReply.NrCharactersWritten = Written;
return Reply->Status; return Reply->Status;
} }
@ -1675,17 +1679,29 @@ CSR_API(CsrReadInputEvent)
} }
/* only get input if there is any */ /* only get input if there is any */
while (Console->InputEvents.Flink != &Console->InputEvents && ! Done) CurrentEntry = Console->InputEvents.Flink;
while (CurrentEntry != &Console->InputEvents)
{ {
CurrentEntry = RemoveHeadList(&Console->InputEvents);
Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry); Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
Done = !Input->Fake; CurrentEntry = CurrentEntry->Flink;
Reply->Data.ReadInputReply.Input = Input->InputEvent;
if (Request->Data.ReadInputRequest.Unicode == FALSE) if (Done && !Input->Fake)
{ {
ConioInputEventToAnsi(Console, &Reply->Data.ReadInputReply.Input); /* FIXME */ Reply->Data.ReadInputReply.MoreEvents = TRUE;
} break;
}
RemoveEntryList(&Input->ListEntry);
if (!Done && !Input->Fake)
{
Reply->Data.ReadInputReply.Input = Input->InputEvent;
if (Request->Data.ReadInputRequest.Unicode == FALSE)
{
ConioInputEventToAnsi(Console, &Reply->Data.ReadInputReply.Input);
}
Done = TRUE;
}
if (Input->InputEvent.EventType == KEY_EVENT) if (Input->InputEvent.EventType == KEY_EVENT)
{ {
@ -1698,18 +1714,24 @@ CSR_API(CsrReadInputEvent)
Console->WaitingChars--; Console->WaitingChars--;
} }
HeapFree(Win32CsrApiHeap, 0, Input); HeapFree(Win32CsrApiHeap, 0, Input);
Reply->Data.ReadInputReply.MoreEvents = (Console->InputEvents.Flink != &Console->InputEvents);
Status = STATUS_SUCCESS;
Console->EarlyReturn = FALSE; /* clear early return */
} }
if (! Done) if (Done)
{
Status = STATUS_SUCCESS;
Console->EarlyReturn = FALSE;
}
else
{ {
Status = STATUS_PENDING; Status = STATUS_PENDING;
Console->EarlyReturn = TRUE; /* mark for early return */ Console->EarlyReturn = TRUE; /* mark for early return */
} }
if (IsListEmpty(&Console->InputEvents))
{
ResetEvent(Console->ActiveEvent);
}
ConioUnlockConsole(Console); ConioUnlockConsole(Console);
return Reply->Status = Status; return Reply->Status = Status;
@ -2373,6 +2395,7 @@ CSR_API(CsrFlushInputBuffer)
/* Destroy the event */ /* Destroy the event */
HeapFree(Win32CsrApiHeap, 0, Input); HeapFree(Win32CsrApiHeap, 0, Input);
} }
ResetEvent(Console->ActiveEvent);
Console->WaitingChars=0; Console->WaitingChars=0;
ConioUnlockConsole(Console); ConioUnlockConsole(Console);