[KERNEL32]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 8 Dec 2012 00:39:24 +0000 (00:39 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 8 Dec 2012 00:39:24 +0000 (00:39 +0000)
- Simplify IntGetConsoleInput and IntReadConsole.

[CONSRV]
- Implement event waiting for reading console input buffer with CSR wait blocks. This replaces the event-based waiting which, after being moved from client-side (kernel32) to server-side (see r57721), made all consoles hang when one of them was waiting for new input.

TODO: Dereference all the waits in Console->ReadWaitQueue.

svn path=/branches/ros-csrss/; revision=57817

dll/win32/kernel32/client/console/readwrite.c
include/reactos/subsys/win/conmsg.h
win32ss/user/consrv/coninput.c
win32ss/user/consrv/conio.h
win32ss/user/consrv/console.c

index 5cda806..0e1adae 100644 (file)
@@ -57,6 +57,7 @@ IntReadConsole(HANDLE hConsoleInput,
                               ReadConsoleRequest->BufferSize,
                               (PVOID*)&ReadConsoleRequest->Buffer);
 
+    /* Set up the data to send to the Console Server */
     ReadConsoleRequest->ConsoleHandle = hConsoleInput;
     ReadConsoleRequest->Unicode = bUnicode;
     ReadConsoleRequest->NrCharactersToRead = (WORD)nNumberOfCharsToRead;
@@ -71,31 +72,42 @@ IntReadConsole(HANDLE hConsoleInput,
         ReadConsoleRequest->CtrlWakeupMask = pInputControl->dwCtrlWakeupMask;
     }
 
+    /* Call the server */
     Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
                                  CaptureBuffer,
                                  CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepReadConsole),
                                  sizeof(CSRSS_READ_CONSOLE));
-    if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = ApiMessage.Status))
+
+    /* Check for success */
+    if (NT_SUCCESS(Status) || NT_SUCCESS(Status = ApiMessage.Status))
     {
-        DPRINT1("CSR returned error in ReadConsole\n");
-        CsrFreeCaptureBuffer(CaptureBuffer);
-        BaseSetLastNTError(Status);
-        return FALSE;
-    }
+        memcpy(lpBuffer,
+               ReadConsoleRequest->Buffer,
+               ReadConsoleRequest->NrCharactersRead * CharSize);
 
-    memcpy(lpBuffer,
-           ReadConsoleRequest->Buffer,
-           ReadConsoleRequest->NrCharactersRead * CharSize);
+        if (lpNumberOfCharsRead != NULL)
+            *lpNumberOfCharsRead = ReadConsoleRequest->NrCharactersRead;
 
-    if (lpNumberOfCharsRead != NULL)
-        *lpNumberOfCharsRead = ReadConsoleRequest->NrCharactersRead;
+        if (pInputControl && pInputControl->nLength == sizeof(CONSOLE_READCONSOLE_CONTROL))
+            pInputControl->dwControlKeyState = ReadConsoleRequest->ControlKeyState;
+    }
+    else
+    {
+        DPRINT1("CSR returned error in ReadConsole\n");
 
-    if (pInputControl && pInputControl->nLength == sizeof(CONSOLE_READCONSOLE_CONTROL))
-        pInputControl->dwControlKeyState = ReadConsoleRequest->ControlKeyState;
+        if (lpNumberOfCharsRead != NULL)
+            *lpNumberOfCharsRead = 0;
+
+        /* Error out */
+        BaseSetLastNTError(Status /* ApiMessage.Status */);
+    }
 
     CsrFreeCaptureBuffer(CaptureBuffer);
 
-    return TRUE;
+    /* Return TRUE or FALSE */
+    // return TRUE;
+    return (ReadConsoleRequest->NrCharactersRead > 0);
+    // return NT_SUCCESS(ApiMessage.Status);
 }
 
 
@@ -142,10 +154,7 @@ IntGetConsoleInput(HANDLE hConsoleInput,
     GetConsoleInputRequest->ConsoleHandle = hConsoleInput;
     GetConsoleInputRequest->Unicode = bUnicode;
     GetConsoleInputRequest->bRead = bRead;
-    if (bRead == TRUE)
-    {
-        GetConsoleInputRequest->InputsRead = 0;
-    }
+    GetConsoleInputRequest->InputsRead = 0;
     GetConsoleInputRequest->Length = nLength;
 
     /* Call the server */
@@ -155,9 +164,30 @@ IntGetConsoleInput(HANDLE hConsoleInput,
                                  sizeof(CSRSS_GET_CONSOLE_INPUT));
     DPRINT("Server returned: %x\n", ApiMessage.Status);
 
-/** For Read only **
-    if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = ApiMessage.Status))
+    /* Check for success */
+    if (NT_SUCCESS(Status) || NT_SUCCESS(Status = ApiMessage.Status))
+    {
+        /* Return the number of events read */
+        DPRINT("Events read: %lx\n", GetConsoleInputRequest->InputsRead);
+
+        if (lpNumberOfEventsRead != NULL)
+            *lpNumberOfEventsRead = GetConsoleInputRequest->InputsRead;
+
+        /* Copy into the buffer */
+        DPRINT("Copying to buffer\n");
+        RtlCopyMemory(lpBuffer,
+                      GetConsoleInputRequest->InputRecord,
+                      sizeof(INPUT_RECORD) * GetConsoleInputRequest->InputsRead);
+    }
+    else
     {
+        if (lpNumberOfEventsRead != NULL)
+            *lpNumberOfEventsRead = 0;
+
+        /* Error out */
+        BaseSetLastNTError(ApiMessage.Status);
+
+/*********
         // BaseSetLastNTError(Status); ????
         if (GetConsoleInputRequest->InputsRead == 0)
         {
@@ -170,75 +200,15 @@ IntGetConsoleInput(HANDLE hConsoleInput,
             /\* FIXME - fail gracefully in case we already read at least one record? *\/
             // break;
         }
+*********/
     }
-**/
-
-    /**
-     ** TODO: !! Simplify the function !!
-     **/
-    if (bRead == TRUE) // ReadConsoleInput call.
-    {
-        /* Check for success */
-        if (NT_SUCCESS(Status) || NT_SUCCESS(Status = ApiMessage.Status))
-        {
-            /* Return the number of events read */
-            DPRINT("Events read: %lx\n", GetConsoleInputRequest->InputsRead/*Length*/);
-
-            if (lpNumberOfEventsRead != NULL)
-                *lpNumberOfEventsRead = GetConsoleInputRequest->InputsRead/*Length*/;
-
-            /* Copy into the buffer */
-            DPRINT("Copying to buffer\n");
-            RtlCopyMemory(lpBuffer,
-                          GetConsoleInputRequest->InputRecord,
-                          sizeof(INPUT_RECORD) * GetConsoleInputRequest->InputsRead/*Length*/);
-        }
-        else
-        {
-            if (lpNumberOfEventsRead != NULL)
-                *lpNumberOfEventsRead = 0;
-
-            /* Error out */
-            BaseSetLastNTError(ApiMessage.Status);
-        }
-
-        /* Release the capture buffer */
-        CsrFreeCaptureBuffer(CaptureBuffer);
 
-        return (GetConsoleInputRequest->InputsRead > 0);
-    }
-    else // PeekConsoleInput call.
-    {
-        /* Check for success */
-        if (NT_SUCCESS(Status) || NT_SUCCESS(ApiMessage.Status))
-        {
-            /* Return the number of events read */
-            DPRINT("Events read: %lx\n", GetConsoleInputRequest->Length);
-
-            if (lpNumberOfEventsRead != NULL)
-                *lpNumberOfEventsRead = GetConsoleInputRequest->Length;
-
-            /* Copy into the buffer */
-            DPRINT("Copying to buffer\n");
-            RtlCopyMemory(lpBuffer,
-                          GetConsoleInputRequest->InputRecord,
-                          sizeof(INPUT_RECORD) * GetConsoleInputRequest->Length);
-        }
-        else
-        {
-            if (lpNumberOfEventsRead != NULL)
-                *lpNumberOfEventsRead = 0;
-
-            /* Error out */
-            BaseSetLastNTError(ApiMessage.Status);
-        }
-
-        /* Release the capture buffer */
-        CsrFreeCaptureBuffer(CaptureBuffer);
+    /* Release the capture buffer */
+    CsrFreeCaptureBuffer(CaptureBuffer);
 
-        /* Return TRUE or FALSE */
-        return NT_SUCCESS(ApiMessage.Status);
-    }
+    /* Return TRUE or FALSE */
+    return (GetConsoleInputRequest->InputsRead > 0);
+    // return NT_SUCCESS(ApiMessage.Status);
 }
 
 
index 513307a..62b98f2 100644 (file)
@@ -147,7 +147,6 @@ typedef struct
     BOOL Unicode;
     WORD NrCharactersToRead;
     WORD NrCharactersRead;
-    HANDLE EventHandle;
 
     UNICODE_STRING ExeName;
     DWORD CtrlWakeupMask;
@@ -326,14 +325,10 @@ typedef struct
     BOOL Unicode;
     BOOL bRead; // TRUE --> Read ; FALSE --> Peek
 
-    DWORD Length;
-    INPUT_RECORD* InputRecord;
-
-    /** For Read **/
     ULONG InputsRead;
-    // INPUT_RECORD Input;
-    BOOL MoreEvents;
-    HANDLE Event;
+
+    ULONG Length;
+    PINPUT_RECORD InputRecord;
 } CSRSS_GET_CONSOLE_INPUT, *PCSRSS_GET_CONSOLE_INPUT;
 
 typedef struct
index a02c41f..49263c6 100644 (file)
     MultiByteToWideChar((Console)->CodePage, 0, (sChar), 1, (dWChar), 1)
 
 
+typedef struct _GET_INPUT_INFO
+{
+    PCONSOLE_PROCESS_DATA ProcessData;
+    PCSRSS_CONSOLE Console;
+} GET_INPUT_INFO, *PGET_INPUT_INFO;
+
+
 /* PRIVATE FUNCTIONS **********************************************************/
 
 static VOID FASTCALL
@@ -79,7 +86,13 @@ ConioProcessChar(PCSRSS_CONSOLE Console,
         return STATUS_INSUFFICIENT_RESOURCES;
     ConInRec->InputEvent = *InputEvent;
     InsertTailList(&Console->InputEvents, &ConInRec->ListEntry);
+
     SetEvent(Console->ActiveEvent);
+    CsrNotifyWait(&Console->ReadWaitQueue,
+                  WaitAny,
+                  NULL,
+                  NULL);
+
     return STATUS_SUCCESS;
 }
 
@@ -289,159 +302,361 @@ ConioProcessKey(MSG *msg, PCSRSS_CONSOLE Console, BOOL TextMode)
     ConioProcessChar(Console, &er);
 }
 
+static NTSTATUS
+WaitBeforeReading(IN PGET_INPUT_INFO InputInfo,
+                  IN PCSR_API_MESSAGE ApiMessage,
+                  IN CSR_WAIT_FUNCTION WaitFunction OPTIONAL,
+                  IN BOOL CreateWaitBlock OPTIONAL)
+{
+    if (CreateWaitBlock)
+    {
+        PGET_INPUT_INFO CapturedInputInfo;
 
-/* PUBLIC APIS ****************************************************************/
+        CapturedInputInfo = HeapAlloc(ConSrvHeap, 0, sizeof(GET_INPUT_INFO));
+        if (!CapturedInputInfo) return STATUS_NO_MEMORY;
 
-CSR_API(SrvGetConsoleInput)
-{
-    NTSTATUS Status;
-    PCSRSS_GET_CONSOLE_INPUT GetConsoleInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputRequest;
-    PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
-    PCSRSS_CONSOLE Console;
-    PLIST_ENTRY CurrentInput;
-    ConsoleInput* Input;
+        memmove(CapturedInputInfo, InputInfo, sizeof(GET_INPUT_INFO));
 
-    DWORD Length;
-    PINPUT_RECORD InputRecord;
+        if (!CsrCreateWait(&InputInfo->Console->ReadWaitQueue,
+                           WaitFunction,
+                           CsrGetClientThread(),
+                           ApiMessage,
+                           CapturedInputInfo,
+                           NULL))
+        {
+            HeapFree(ConSrvHeap, 0, CapturedInputInfo);
+            return STATUS_NO_MEMORY;
+        }
+    }
 
-    DPRINT("SrvGetConsoleInput\n");
+    /* Wait for input */
+    return STATUS_PENDING;
+}
 
-    Status = ConioLockConsole(ProcessData, GetConsoleInputRequest->ConsoleHandle, &Console, GENERIC_READ);
-    if(!NT_SUCCESS(Status)) return Status;
+static NTSTATUS
+ReadInputBuffer(IN PGET_INPUT_INFO InputInfo,
+                IN BOOL Wait,
+                IN PCSR_API_MESSAGE ApiMessage,
+                IN BOOL CreateWaitBlock OPTIONAL);
+
+// Wait function CSR_WAIT_FUNCTION
+static BOOLEAN
+ReadInputBufferThread(IN PLIST_ENTRY WaitList,
+                      IN PCSR_THREAD WaitThread,
+                      IN PCSR_API_MESSAGE WaitApiMessage,
+                      IN PVOID WaitContext,
+                      IN PVOID WaitArgument1,
+                      IN PVOID WaitArgument2,
+                      IN ULONG WaitFlags)
+{
+    NTSTATUS Status;
+    PCSRSS_GET_CONSOLE_INPUT GetConsoleInputRequest = &((PCONSOLE_API_MESSAGE)WaitApiMessage)->Data.GetConsoleInputRequest;
+    PGET_INPUT_INFO InputInfo = (PGET_INPUT_INFO)WaitContext;
 
-    if (!CsrValidateMessageBuffer(ApiMessage,
-                                  (PVOID*)&GetConsoleInputRequest->InputRecord,
-                                  GetConsoleInputRequest->Length,
-                                  sizeof(INPUT_RECORD)))
+    Status = ReadInputBuffer(InputInfo,
+                             GetConsoleInputRequest->bRead,
+                             WaitApiMessage,
+                             FALSE);
+
+    if (Status != STATUS_PENDING)
     {
-        return STATUS_INVALID_PARAMETER;
+        WaitApiMessage->Status = Status;
+        HeapFree(ConSrvHeap, 0, InputInfo);
     }
 
-    InputRecord = GetConsoleInputRequest->InputRecord;
-    Length = GetConsoleInputRequest->Length;
+    return (Status == STATUS_PENDING ? FALSE : TRUE);
+}
 
-/*
-    if (!Win32CsrValidateBuffer(ProcessData->Process, InputRecord, Length, sizeof(INPUT_RECORD)))
+static NTSTATUS
+ReadInputBuffer(IN PGET_INPUT_INFO InputInfo,
+                IN BOOL Wait,   // TRUE --> Read ; FALSE --> Peek
+                IN PCSR_API_MESSAGE ApiMessage,
+                IN BOOL CreateWaitBlock OPTIONAL)
+{
+    if (IsListEmpty(&InputInfo->Console->InputEvents))
     {
-        ConioUnlockConsole(Console);
-        return STATUS_ACCESS_VIOLATION;
+        if (Wait)
+        {
+            return WaitBeforeReading(InputInfo,
+                                     ApiMessage,
+                                     ReadInputBufferThread,
+                                     CreateWaitBlock);
+        }
+        else
+        {
+            /* No input available and we don't wait, so we return success */
+            return STATUS_SUCCESS;
+        }
     }
-*/
-
-    if (GetConsoleInputRequest->bRead) // Read input.
+    else
     {
-        GetConsoleInputRequest->Event = ProcessData->ConsoleEvent;
+        PCSRSS_GET_CONSOLE_INPUT GetConsoleInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputRequest;
+        PLIST_ENTRY CurrentInput;
+        ConsoleInput* Input;
+        ULONG Length = GetConsoleInputRequest->Length;
+        PINPUT_RECORD InputRecord = GetConsoleInputRequest->InputRecord;
 
-        while (Length > 0)
+        /* Only get input if there is any */
+        CurrentInput = InputInfo->Console->InputEvents.Flink;
+
+        while ( CurrentInput != &InputInfo->Console->InputEvents &&
+                GetConsoleInputRequest->InputsRead < Length )
         {
-            BOOLEAN Done = FALSE;
+            Input = CONTAINING_RECORD(CurrentInput, ConsoleInput, ListEntry);
 
-            // GetConsoleInputRequest->Event = ProcessData->ConsoleEvent;
+            GetConsoleInputRequest->InputsRead++;
+            *InputRecord = Input->InputEvent;
 
-            /* only get input if there is any */
-            CurrentInput = Console->InputEvents.Flink;
-            while (CurrentInput != &Console->InputEvents)
+            if (GetConsoleInputRequest->Unicode == FALSE)
             {
-                Input = CONTAINING_RECORD(CurrentInput, ConsoleInput, ListEntry);
-                CurrentInput = CurrentInput->Flink;
+                ConioInputEventToAnsi(InputInfo->Console, InputRecord);
+            }
 
-                if (Done)
-                {
-                    GetConsoleInputRequest->MoreEvents = TRUE;
-                    break;
-                }
+            InputRecord++;
+            CurrentInput = CurrentInput->Flink;
 
+            if (Wait) // TRUE --> Read, we remove inputs from the buffer ; FALSE --> Peek, we keep inputs.
+            {
                 RemoveEntryList(&Input->ListEntry);
+                HeapFree(ConSrvHeap, 0, Input);
+            }
+        }
 
-                if (!Done)
-                {
-                    GetConsoleInputRequest->InputsRead++;
-                    *InputRecord = Input->InputEvent;
-                    /* HACK */ Length--;
-
-                    // GetConsoleInputRequest->Input = Input->InputEvent;
-                    if (GetConsoleInputRequest->Unicode == FALSE)
-                    {
-                        // ConioInputEventToAnsi(Console, &GetConsoleInputRequest->Input);
-                        ConioInputEventToAnsi(Console, InputRecord);
-                    }
-
-                    InputRecord++;
-                    Done = TRUE;
-                }
+        if (IsListEmpty(&InputInfo->Console->InputEvents))
+        {
+            ResetEvent(InputInfo->Console->ActiveEvent);
+        }
 
-                HeapFree(ConSrvHeap, 0, Input);
+        /* We read all the inputs available, we return success */
+        return STATUS_SUCCESS;
+    }
+}
+
+static NTSTATUS
+ReadChars(IN PGET_INPUT_INFO InputInfo,
+          IN PCSR_API_MESSAGE ApiMessage,
+          IN BOOL CreateWaitBlock OPTIONAL);
+
+// Wait function CSR_WAIT_FUNCTION
+static BOOLEAN
+ReadCharsThread(IN PLIST_ENTRY WaitList,
+                IN PCSR_THREAD WaitThread,
+                IN PCSR_API_MESSAGE WaitApiMessage,
+                IN PVOID WaitContext,
+                IN PVOID WaitArgument1,
+                IN PVOID WaitArgument2,
+                IN ULONG WaitFlags)
+{
+    NTSTATUS Status;
+    PGET_INPUT_INFO InputInfo = (PGET_INPUT_INFO)WaitContext;
+
+    Status = ReadChars(InputInfo,
+                       WaitApiMessage,
+                       FALSE);
+
+    if (Status != STATUS_PENDING)
+    {
+        WaitApiMessage->Status = Status;
+        HeapFree(ConSrvHeap, 0, InputInfo);
+    }
+
+    return (Status == STATUS_PENDING ? FALSE : TRUE);
+}
+
+static NTSTATUS
+ReadChars(IN PGET_INPUT_INFO InputInfo,
+          IN PCSR_API_MESSAGE ApiMessage,
+          IN BOOL CreateWaitBlock OPTIONAL)
+{
+    BOOL WaitForMoreToRead = TRUE; // TRUE : Wait if more to read ; FALSE : Don't wait.
+
+    PCSRSS_READ_CONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
+    PLIST_ENTRY CurrentEntry;
+    ConsoleInput *Input;
+    PCHAR Buffer = (PCHAR)ReadConsoleRequest->Buffer;
+    PWCHAR UnicodeBuffer = (PWCHAR)Buffer;
+    ULONG nNumberOfCharsToRead = ReadConsoleRequest->NrCharactersToRead;
+
+    /* We haven't read anything (yet) */
+
+    if (InputInfo->Console->Mode & ENABLE_LINE_INPUT)
+    {
+        if (InputInfo->Console->LineBuffer == NULL)
+        {
+            /* Starting a new line */
+            InputInfo->Console->LineMaxSize = max(256, nNumberOfCharsToRead);
+            InputInfo->Console->LineBuffer = HeapAlloc(ConSrvHeap, 0, InputInfo->Console->LineMaxSize * sizeof(WCHAR));
+            if (InputInfo->Console->LineBuffer == NULL)
+            {
+                return STATUS_NO_MEMORY;
             }
+            InputInfo->Console->LineComplete = FALSE;
+            InputInfo->Console->LineUpPressed = FALSE;
+            InputInfo->Console->LineInsertToggle = 0;
+            InputInfo->Console->LineWakeupMask = ReadConsoleRequest->CtrlWakeupMask;
+            InputInfo->Console->LineSize = ReadConsoleRequest->NrCharactersRead;
+            InputInfo->Console->LinePos = InputInfo->Console->LineSize;
+
+            /*
+             * Pre-filling the buffer is only allowed in the Unicode API,
+             * so we don't need to worry about ANSI <-> Unicode conversion.
+             */
+            memcpy(InputInfo->Console->LineBuffer, Buffer, InputInfo->Console->LineSize * sizeof(WCHAR));
+            if (InputInfo->Console->LineSize == InputInfo->Console->LineMaxSize)
+            {
+                InputInfo->Console->LineComplete = TRUE;
+                InputInfo->Console->LinePos = 0;
+            }
+        }
 
-            if (Done)
-                Status = STATUS_SUCCESS;
-            else
-                Status = STATUS_PENDING;
+        /* If we don't have a complete line yet, process the pending input */
+        while ( !InputInfo->Console->LineComplete &&
+                !IsListEmpty(&InputInfo->Console->InputEvents) )
+        {
+            /* Remove input event from queue */
+            CurrentEntry = RemoveHeadList(&InputInfo->Console->InputEvents);
+            if (IsListEmpty(&InputInfo->Console->InputEvents))
+            {
+                ResetEvent(InputInfo->Console->ActiveEvent);
+            }
+            Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
 
-            if (IsListEmpty(&Console->InputEvents))
+            /* Only pay attention to key down */
+            if (KEY_EVENT == Input->InputEvent.EventType
+                    && Input->InputEvent.Event.KeyEvent.bKeyDown)
             {
-                ResetEvent(Console->ActiveEvent);
+                LineInputKeyDown(InputInfo->Console, &Input->InputEvent.Event.KeyEvent);
+                ReadConsoleRequest->ControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState;
             }
+            HeapFree(ConSrvHeap, 0, Input);
+        }
 
-            if (Status == STATUS_PENDING)
+        /* Check if we have a complete line to read from */
+        if (InputInfo->Console->LineComplete)
+        {
+            while ( ReadConsoleRequest->NrCharactersRead < nNumberOfCharsToRead &&
+                    InputInfo->Console->LinePos != InputInfo->Console->LineSize )
             {
-                if (GetConsoleInputRequest->InputsRead == 0)
+                WCHAR Char = InputInfo->Console->LineBuffer[InputInfo->Console->LinePos++];
+
+                if (ReadConsoleRequest->Unicode)
                 {
-                    Status = NtWaitForSingleObject(GetConsoleInputRequest->Event, FALSE, 0);
-                    if (!NT_SUCCESS(Status))
-                    {
-                        // BaseSetLastNTError(Status);
-                        break;
-                    }
+                    UnicodeBuffer[ReadConsoleRequest->NrCharactersRead] = Char;
                 }
                 else
                 {
-                    /* nothing more to read (waiting for more input??), let's just bail */
-                    break;
+                    ConsoleInputUnicodeCharToAnsiChar(InputInfo->Console,
+                                                      &Buffer[ReadConsoleRequest->NrCharactersRead],
+                                                      &Char);
                 }
+
+                ReadConsoleRequest->NrCharactersRead++;
             }
-            else // Status != STATUS_PENDING ; == STATUS_SUCCESS
+
+            if (InputInfo->Console->LinePos == InputInfo->Console->LineSize)
             {
-                if (!GetConsoleInputRequest->MoreEvents)
-                {
-                    /* nothing more to read, bail */
-                    break;
-                }
+                /* Entire line has been read */
+                HeapFree(ConSrvHeap, 0, InputInfo->Console->LineBuffer);
+                InputInfo->Console->LineBuffer = NULL;
             }
+
+            WaitForMoreToRead = FALSE;
         }
     }
-    else // Peek input.
+    else
     {
-        UINT NumInputs = 0;
-
-        if (!IsListEmpty(&Console->InputEvents))
+        /* Character input */
+        while ( ReadConsoleRequest->NrCharactersRead < nNumberOfCharsToRead &&
+                !IsListEmpty(&InputInfo->Console->InputEvents) )
         {
-            CurrentInput = Console->InputEvents.Flink;
-
-            while (CurrentInput != &Console->InputEvents && NumInputs < Length)
+            /* Remove input event from queue */
+            CurrentEntry = RemoveHeadList(&InputInfo->Console->InputEvents);
+            if (IsListEmpty(&InputInfo->Console->InputEvents))
             {
-                Input = CONTAINING_RECORD(CurrentInput, ConsoleInput, ListEntry);
+                ResetEvent(InputInfo->Console->ActiveEvent);
+            }
+            Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
 
-                ++NumInputs;
-                *InputRecord = Input->InputEvent;
+            /* Only pay attention to valid ascii chars, on key down */
+            if (KEY_EVENT == Input->InputEvent.EventType
+                    && Input->InputEvent.Event.KeyEvent.bKeyDown
+                    && Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar != L'\0')
+            {
+                WCHAR Char = Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar;
 
-                if (GetConsoleInputRequest->Unicode == FALSE)
+                if (ReadConsoleRequest->Unicode)
                 {
-                    ConioInputEventToAnsi(Console, InputRecord);
+                    UnicodeBuffer[ReadConsoleRequest->NrCharactersRead] = Char;
                 }
+                else
+                {
+                    ConsoleInputUnicodeCharToAnsiChar(InputInfo->Console,
+                                                      &Buffer[ReadConsoleRequest->NrCharactersRead],
+                                                      &Char);
+                }
+
+                ReadConsoleRequest->NrCharactersRead++;
 
-                InputRecord++;
-                CurrentInput = CurrentInput->Flink;
+                /* Did read something */
+                WaitForMoreToRead = FALSE;
             }
+            HeapFree(ConSrvHeap, 0, Input);
         }
+    }
+
+    /* We haven't completed a read, so start a wait */
+    if (WaitForMoreToRead == TRUE)
+    {
+        return WaitBeforeReading(InputInfo,
+                                 ApiMessage,
+                                 ReadCharsThread,
+                                 CreateWaitBlock);
+    }
+    else /* We read all what we wanted, we return success */
+    {
+        return STATUS_SUCCESS;
+    }
+}
 
-        GetConsoleInputRequest->Length = NumInputs;
 
-        Status = STATUS_SUCCESS;
+/* PUBLIC APIS ****************************************************************/
+
+CSR_API(SrvGetConsoleInput)
+{
+    NTSTATUS Status;
+    PCSRSS_GET_CONSOLE_INPUT GetConsoleInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputRequest;
+    PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
+    PCSRSS_CONSOLE Console;
+    GET_INPUT_INFO InputInfo;
+
+    DPRINT("SrvGetConsoleInput\n");
+
+    if (!CsrValidateMessageBuffer(ApiMessage,
+                                  (PVOID*)&GetConsoleInputRequest->InputRecord,
+                                  GetConsoleInputRequest->Length,
+                                  sizeof(INPUT_RECORD)))
+    {
+        return STATUS_INVALID_PARAMETER;
     }
 
+    Status = ConioLockConsole(ProcessData, GetConsoleInputRequest->ConsoleHandle, &Console, GENERIC_READ);
+    if(!NT_SUCCESS(Status)) return Status;
+
+    GetConsoleInputRequest->InputsRead = 0;
+
+    InputInfo.ProcessData = ProcessData; // ConsoleGetPerProcessData(CsrGetClientThread()->Process);
+    InputInfo.Console     = Console;
+
+    Status = ReadInputBuffer(&InputInfo,
+                             GetConsoleInputRequest->bRead,
+                             ApiMessage,
+                             TRUE);
+
     ConioUnlockConsole(Console);
 
+    if (Status == STATUS_PENDING)
+        *ReplyCode = CsrReplyPending;
+
     return Status;
 }
 
@@ -471,14 +686,6 @@ CSR_API(SrvWriteConsoleInput)
     InputRecord = WriteConsoleInputRequest->InputRecord;
     Length = WriteConsoleInputRequest->Length;
 
-/*
-    if (!Win32CsrValidateBuffer(ProcessData->Process, InputRecord, Length, sizeof(INPUT_RECORD)))
-    {
-        ConioUnlockConsole(Console);
-        return STATUS_ACCESS_VIOLATION;
-    }
-*/
-
     for (i = 0; i < Length && NT_SUCCESS(Status); i++)
     {
         if (!WriteConsoleInputRequest->Unicode &&
@@ -504,21 +711,12 @@ CSR_API(SrvReadConsole)
 {
     NTSTATUS Status;
     PCSRSS_READ_CONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
-    PLIST_ENTRY CurrentEntry;
-    ConsoleInput *Input;
-    PCHAR Buffer;
-    PWCHAR UnicodeBuffer;
-    ULONG i = 0;
-    ULONG nNumberOfCharsToRead, CharSize;
     PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
     PCSRSS_CONSOLE Console;
+    GET_INPUT_INFO InputInfo;
 
     DPRINT("SrvReadConsole\n");
 
-    CharSize = (ReadConsoleRequest->Unicode ? sizeof(WCHAR) : sizeof(CHAR));
-
-    nNumberOfCharsToRead = ReadConsoleRequest->NrCharactersToRead;
-
     if (!CsrValidateMessageBuffer(ApiMessage,
                                   (PVOID*)&ReadConsoleRequest->Buffer,
                                   ReadConsoleRequest->BufferSize,
@@ -527,155 +725,29 @@ CSR_API(SrvReadConsole)
         return STATUS_INVALID_PARAMETER;
     }
 
-    Buffer = (PCHAR)ReadConsoleRequest->Buffer;
-    UnicodeBuffer = (PWCHAR)Buffer;
-
-/*
-    if (!Win32CsrValidateBuffer(ProcessData->Process, Buffer, nNumberOfCharsToRead, CharSize))
-        return STATUS_ACCESS_VIOLATION;
-*/
-
-    Status = ConioLockConsole(ProcessData, ReadConsoleRequest->ConsoleHandle,
-                              &Console, GENERIC_READ);
-    if (!NT_SUCCESS(Status)) return Status;
-
-    Status = STATUS_SUCCESS;
-    ReadConsoleRequest->EventHandle = ProcessData->ConsoleEvent;
-
-/*** HACK: Enclosing do { ... } while (...) loop coming from kernel32 ***/
-do
-{
-    if (Status == STATUS_PENDING)
-    {
-        Status = NtWaitForSingleObject(ReadConsoleRequest->EventHandle,
-                                       FALSE,
-                                       0);
-        if (!NT_SUCCESS(Status))
-        {
-            DPRINT1("Wait for console input failed!\n");
-            break;
-        }
-    }
-/******/
-
-    if (ReadConsoleRequest->NrCharactersRead * sizeof(WCHAR) > nNumberOfCharsToRead * CharSize)
+    // if (Request->Data.ReadConsoleRequest.NrCharactersRead * sizeof(WCHAR) > nNumberOfCharsToRead * CharSize)
+    if (ReadConsoleRequest->NrCharactersRead > ReadConsoleRequest->NrCharactersToRead)
     {
-        // return STATUS_INVALID_PARAMETER;
-        Status = STATUS_INVALID_PARAMETER;
-        break;
-        // goto done;
+        return STATUS_INVALID_PARAMETER;
     }
 
-    // ReadConsoleRequest->EventHandle = ProcessData->ConsoleEvent;
+    Status = ConioLockConsole(ProcessData, ReadConsoleRequest->ConsoleHandle, &Console, GENERIC_READ);
+    if (!NT_SUCCESS(Status)) return Status;
 
-    Status = STATUS_PENDING; /* we haven't read anything (yet) */
-    if (Console->Mode & ENABLE_LINE_INPUT)
-    {
-        if (Console->LineBuffer == NULL)
-        {
-            /* Starting a new line */
-            Console->LineMaxSize = max(256, nNumberOfCharsToRead);
-            Console->LineBuffer = HeapAlloc(ConSrvHeap, 0, Console->LineMaxSize * sizeof(WCHAR));
-            if (Console->LineBuffer == NULL)
-            {
-                Status = STATUS_NO_MEMORY;
-                goto done;
-            }
-            Console->LineComplete = FALSE;
-            Console->LineUpPressed = FALSE;
-            Console->LineInsertToggle = 0;
-            Console->LineWakeupMask = ReadConsoleRequest->CtrlWakeupMask;
-            Console->LineSize = ReadConsoleRequest->NrCharactersRead;
-            Console->LinePos = Console->LineSize;
-            /* pre-filling the buffer is only allowed in the Unicode API,
-             * so we don't need to worry about conversion */
-            memcpy(Console->LineBuffer, Buffer, Console->LineSize * sizeof(WCHAR));
-            if (Console->LineSize == Console->LineMaxSize)
-            {
-                Console->LineComplete = TRUE;
-                Console->LinePos = 0;
-            }
-        }
+    ReadConsoleRequest->NrCharactersRead = 0;
 
-        /* If we don't have a complete line yet, process the pending input */
-        while (!Console->LineComplete && !IsListEmpty(&Console->InputEvents))
-        {
-            /* remove input event from queue */
-            CurrentEntry = RemoveHeadList(&Console->InputEvents);
-            if (IsListEmpty(&Console->InputEvents))
-            {
-                ResetEvent(Console->ActiveEvent);
-            }
-            Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
+    InputInfo.ProcessData = ProcessData; // ConsoleGetPerProcessData(CsrGetClientThread()->Process);
+    InputInfo.Console     = Console;
 
-            /* only pay attention to key down */
-            if (KEY_EVENT == Input->InputEvent.EventType
-                    && Input->InputEvent.Event.KeyEvent.bKeyDown)
-            {
-                LineInputKeyDown(Console, &Input->InputEvent.Event.KeyEvent);
-                ReadConsoleRequest->ControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState;
-            }
-            HeapFree(ConSrvHeap, 0, Input);
-        }
-
-        /* Check if we have a complete line to read from */
-        if (Console->LineComplete)
-        {
-            while (i < nNumberOfCharsToRead && Console->LinePos != Console->LineSize)
-            {
-                WCHAR Char = Console->LineBuffer[Console->LinePos++];
-                if (ReadConsoleRequest->Unicode)
-                    UnicodeBuffer[i++] = Char;
-                else
-                    ConsoleInputUnicodeCharToAnsiChar(Console, &Buffer[i++], &Char);
-            }
-            if (Console->LinePos == Console->LineSize)
-            {
-                /* Entire line has been read */
-                HeapFree(ConSrvHeap, 0, Console->LineBuffer);
-                Console->LineBuffer = NULL;
-            }
-            Status = STATUS_SUCCESS;
-        }
-    }
-    else
-    {
-        /* Character input */
-        while (i < nNumberOfCharsToRead && !IsListEmpty(&Console->InputEvents))
-        {
-            /* remove input event from queue */
-            CurrentEntry = RemoveHeadList(&Console->InputEvents);
-            if (IsListEmpty(&Console->InputEvents))
-            {
-                ResetEvent(Console->ActiveEvent);
-            }
-            Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
-
-            /* only pay attention to valid ascii chars, on key down */
-            if (KEY_EVENT == Input->InputEvent.EventType
-                    && Input->InputEvent.Event.KeyEvent.bKeyDown
-                    && Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar != L'\0')
-            {
-                WCHAR Char = Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar;
-                if (ReadConsoleRequest->Unicode)
-                    UnicodeBuffer[i++] = Char;
-                else
-                    ConsoleInputUnicodeCharToAnsiChar(Console, &Buffer[i++], &Char);
-                Status = STATUS_SUCCESS; /* did read something */
-            }
-            HeapFree(ConSrvHeap, 0, Input);
-        }
-    }
-done:
-    ReadConsoleRequest->NrCharactersRead = i;
-
-/******/
-}
-while (Status == STATUS_PENDING);
-/*** HACK: Enclosing do { ... } while (...) loop coming from kernel32 ***/
+    Status = ReadChars(&InputInfo,
+                       ApiMessage,
+                       TRUE);
 
     ConioUnlockConsole(Console);
 
+    if (Status == STATUS_PENDING)
+        *ReplyCode = CsrReplyPending;
+
     return Status;
 }
 
index f6558a5..bc71252 100644 (file)
@@ -53,6 +53,9 @@ typedef struct tagCSRSS_CONSOLE
     CRITICAL_SECTION Lock;
     struct tagCSRSS_CONSOLE *Prev, *Next; /* Next and Prev consoles in console wheel */
     HANDLE ActiveEvent;
+
+    LIST_ENTRY ReadWaitQueue;             /* List head for the queue of read wait blocks */
+
     LIST_ENTRY InputEvents;               /* List head for input event queue */
     PWCHAR LineBuffer;                    /* current line being input, in line buffered mode */
     WORD LineMaxSize;                     /* maximum size of line in characters (including CR+LF) */
index 7c76fcd..b9ca8d6 100644 (file)
@@ -114,6 +114,7 @@ CsrInitConsole(PCSRSS_CONSOLE Console, int ShowCmd)
     Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
     InitializeListHead(&Console->BufferList);
     Console->ActiveBuffer = NULL;
+    InitializeListHead(&Console->ReadWaitQueue);
     InitializeListHead(&Console->InputEvents);
     InitializeListHead(&Console->HistoryBuffers);
     Console->CodePage = GetOEMCP();
@@ -424,6 +425,8 @@ ConioDeleteConsole(Object_t *Object)
 
     DPRINT("ConioDeleteConsole\n");
 
+    /* TODO: Dereference all the waits in Console->ReadWaitQueue */
+
     /* Drain input event queue */
     while (Console->InputEvents.Flink != &Console->InputEvents)
     {