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