/// <summary> /// Process the read/write queues of the specified pipe. /// </summary> /// <param name="pipe">The pipe to process.</param> /// <param name="OutProcess">The process which owns the pipe's outpoint.</param> /// <param name="InProcess">The process which owns the pipe's inpoint.</param> private static void ProcessPipeQueue(Pipe pipe, Process OutProcess, Process InProcess) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Checking first loop condition"); #endif while ((pipe.AreThreadsWaitingToWrite() && pipe.CanWrite()) || (pipe.AreThreadsWaitingToRead() && pipe.CanRead())) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Loop start"); #endif if (pipe.AreThreadsWaitingToWrite() && pipe.CanWrite()) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Pipe can write"); #endif /* - Dequeue thread to write * - Find thread to write * - Load pointer to request structure from thread's stack * - Write pipe * - Setup return values for thread * - Wake thread * - Loop back */ #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Dequeuing out thread id"); #endif UInt32 ThreadId; if (!pipe.DequeueToWrite(out ThreadId)) { break; } #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Getting out thread"); #endif Thread WriteThread = ProcessManager.GetThreadById(ThreadId, OutProcess); if (WriteThread == null) { break; } #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Writing pipe"); #endif WritePipeRequest* Request = (WritePipeRequest*)WriteThread.Param1; bool Successful = pipe.Write(Request->InBuffer, Request->Offset, Request->Length); if (Successful) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Write successful"); #endif WriteThread.Return1 = (uint)SystemCallResults.OK; WriteThread._Wake(); } else { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Write failed"); #endif WriteThread.Return1 = (uint)SystemCallResults.Fail; WriteThread._Wake(); } } else if (pipe.AreThreadsWaitingToRead() && pipe.CanRead()) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Pipe can read"); #endif /* - Dequeue thread to read * - Find thread to read * - Load pointer to request structure from thread's stack * - Read pipe * - Setup return values for thread * - Wake thread * - Loop back */ #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Dequeuing in thread id"); #endif UInt32 ThreadId; if (!pipe.DequeueToRead(out ThreadId)) { break; } #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Getting in thread"); #endif Thread ReadThread = ProcessManager.GetThreadById(ThreadId, InProcess); if (ReadThread == null) { break; } #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Reading pipe"); #endif ReadPipeRequest* Request = (ReadPipeRequest*)ReadThread.Param1; int BytesRead; bool Successful = pipe.Read(Request->OutBuffer, Request->Offset, Request->Length, out BytesRead); if (Successful) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Read successful"); #endif ReadThread.Return1 = (uint)SystemCallResults.OK; ReadThread.Return2 = (uint)BytesRead; ReadThread._Wake(); } else { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Read failed"); #endif ReadThread.Return1 = (uint)SystemCallResults.Fail; ReadThread._Wake(); } } #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Looping..."); #endif } }
/// <summary> /// Process the read/write queues of the specified pipe. /// </summary> /// <param name="pipe">The pipe to process.</param> /// <param name="OutProcess">The process which owns the pipe's outpoint.</param> /// <param name="InProcess">The process which owns the pipe's inpoint.</param> private static void ProcessPipeQueue(Pipe pipe, Process OutProcess, Process InProcess) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Checking first loop condition"); #endif while ((pipe.AreThreadsWaitingToWrite() && pipe.CanWrite()) || (pipe.AreThreadsWaitingToRead() && pipe.CanRead())) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Loop start"); #endif if (pipe.AreThreadsWaitingToWrite() && pipe.CanWrite()) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Pipe can write"); #endif /* - Dequeue thread to write * - Find thread to write * - Load pointer to request structure from thread's stack * - Write pipe * - Setup return values for thread * - Wake thread * - Loop back */ #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Dequeuing out thread id"); #endif UInt32 ThreadId; if (!pipe.DequeueToWrite(out ThreadId)) { break; } #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Getting out thread"); #endif Thread WriteThread = ProcessManager.GetThreadById(ThreadId, OutProcess); if (WriteThread == null) { break; } #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Writing pipe"); #endif ProcessManager.EnableKernelAccessToProcessMemory(OutProcess); WritePipeRequest *Request = (WritePipeRequest *)WriteThread.Param1; bool Successful = pipe.Write(Request->InBuffer, Request->Offset, Request->Length); if (Successful) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Write successful"); #endif WriteThread.Return1 = (uint)SystemCallResults.OK; } else { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Write failed"); #endif WriteThread.Return1 = (uint)SystemCallResults.Fail; } ProcessManager.DisableKernelAccessToProcessMemory(OutProcess); WriteThread._Wake(); } else if (pipe.AreThreadsWaitingToRead() && pipe.CanRead()) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Pipe can read"); #endif /* - Dequeue thread to read * - Find thread to read * - Load pointer to request structure from thread's stack * - Read pipe * - Setup return values for thread * - Wake thread * - Loop back */ #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Dequeuing in thread id"); #endif UInt32 ThreadId; if (!pipe.DequeueToRead(out ThreadId)) { break; } #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Getting in thread"); #endif Thread ReadThread = ProcessManager.GetThreadById(ThreadId, InProcess); if (ReadThread == null) { break; } #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Reading pipe"); #endif ProcessManager.EnableKernelAccessToProcessMemory(InProcess); ReadPipeRequest *Request = (ReadPipeRequest *)ReadThread.Param1; int BytesRead; bool Successful = pipe.Read(Request->OutBuffer, Request->Offset, Request->Length, out BytesRead); if (Successful) { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Read successful"); #endif ReadThread.Return1 = (uint)SystemCallResults.OK; ReadThread.Return2 = (uint)BytesRead; } else { #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Read failed"); #endif ReadThread.Return1 = (uint)SystemCallResults.Fail; } ProcessManager.DisableKernelAccessToProcessMemory(InProcess); ReadThread._Wake(); } #if PIPES_TRACE BasicConsole.WriteLine("ProcessPipeQueue: Looping..."); #endif } }
/// <summary> /// Attempts to read from the specified pipe. /// </summary> /// <remarks> /// Note that this function is non-blocking. It will, however, block a system caller thread by simply not returning it from /// the deferred system call. /// </remarks> /// <param name="PipeId">The Id of the pipe to read.</param> /// <param name="Blocking">Whether the read should be blocking or non-blocking.</param> /// <param name="CallerProcess">The process which made the call.</param> /// <param name="CallerThread">The thread which made the call.</param> /// <returns>See descriptions on <see cref="PipeManager.RWResults"/> values.</returns> public static RWResults ReadPipe(int PipeId, bool Blocking, Process CallerProcess, Thread CallerThread) { #if PIPES_TRACE BasicConsole.WriteLine("ReadPipe: Validating inputs"); #endif // Validate inputs // - Check pipe exists Pipe pipe = GetPipe(PipeId); if (pipe == null) { return(RWResults.Error); } #if PIPES_TRACE BasicConsole.WriteLine("ReadPipe: Checking caller allowed to write"); #endif // Check the caller is allowed to access the pipe if (!AllowedToReadPipe(pipe, CallerProcess.Id)) { return(RWResults.Error); } #if PIPES_TRACE BasicConsole.WriteLine("ReadPipe: Getting out process"); #endif // Get outpoint process Process OutProcess = ProcessManager.GetProcessById(pipe.Outpoint.ProcessId); if (OutProcess == null) { return(RWResults.Error); } #if PIPES_TRACE BasicConsole.WriteLine("ReadPipe: Getting in process"); #endif // Get inpoint process Process InProcess = ProcessManager.GetProcessById(pipe.Inpoint.ProcessId); if (InProcess == null) { return(RWResults.Error); } #if PIPES_TRACE BasicConsole.WriteLine("ReadPipe: Adding caller to read queue"); #endif // Add caller thread to the read queue pipe.QueueToRead(CallerThread.Id); ProcessManager.EnableKernelAccessToProcessMemory(CallerProcess); // Set up initial failure return value CallerThread.Return1 = (uint)SystemCallResults.Fail; ProcessManager.DisableKernelAccessToProcessMemory(CallerProcess); #if PIPES_TRACE BasicConsole.WriteLine("ReadPipe: Processing pipe queue"); #endif // Process the pipe queue ProcessPipeQueue(pipe, OutProcess, InProcess); bool Completed = !pipe.AreThreadsWaitingToRead(); if (!Blocking) { if (!Completed) { uint temp; bool removed = pipe.RemoveLastToRead(out temp); if (!removed || temp != CallerThread.Id) { BasicConsole.WriteLine("PipeManager: Error! Async read failed and then removing last from queue resulted in thread Id mismatch!"); } ProcessManager.EnableKernelAccessToProcessMemory(CallerProcess); CallerThread.Return1 = (uint)SystemCallResults.Fail; ProcessManager.DisableKernelAccessToProcessMemory(CallerProcess); CallerThread._Wake(); } } return(Completed ? RWResults.Complete : RWResults.Queued); }