/// <summary> /// Attempts to write to 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 write.</param> /// <param name="Blocking">Whether the write 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 WritePipe(int PipeId, bool Blocking, Process CallerProcess, Thread CallerThread) { #if PIPES_TRACE BasicConsole.WriteLine("WritePipe: Validating inputs"); #endif // Validate inputs // - Check pipe exists Pipe pipe = GetPipe(PipeId); if (pipe == null) { return(RWResults.Error); } #if PIPES_TRACE BasicConsole.WriteLine("WritePipe: Checking caller allowed to write"); #endif // Check the caller is allowed to access the pipe if (!AllowedToWritePipe(pipe, CallerProcess.Id)) { return(RWResults.Error); } #if PIPES_TRACE BasicConsole.WriteLine("WritePipe: 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("WritePipe: 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("WritePipe: Adding caller to write queue"); #endif ProcessManager.EnableKernelAccessToProcessMemory(CallerProcess); // Add caller thread to the write queue WritePipeRequest *Request = (WritePipeRequest *)CallerThread.Param1; pipe.QueueToWrite(CallerThread.Id, Request->Length); // Set up initial failure return value CallerThread.Return1 = (uint)SystemCallResults.Fail; ProcessManager.DisableKernelAccessToProcessMemory(CallerProcess); #if PIPES_TRACE BasicConsole.WriteLine("WritePipe: Processing pipe queue"); #endif // Process the pipe queue ProcessPipeQueue(pipe, OutProcess, InProcess); bool Completed = !pipe.AreThreadsWaitingToWrite(); if (!Blocking) { if (!Completed) { uint temp; bool removed = pipe.RemoveLastToWrite(out temp); if (!removed || temp != CallerThread.Id) { BasicConsole.WriteLine("PipeManager: Error! Async write 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); }