Ejemplo n.º 1
0
        /// <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);
        }