Beispiel #1
0
        private static unsafe void ResetThread(uint threadID)
        {
            var thread = Threads[threadID];

            UninterruptibleMonitor.Enter(thread);
            try
            {
                if (thread.Status != ThreadStatus.Terminated)
                {
                    return;
                }

                if (thread.Process != null)
                {
                    var proc = thread.Process;
                    UninterruptibleMonitor.Enter(proc.Threads);
                    try
                    {
                        for (var i = 0; i < proc.Threads.Count; i++)
                        {
                            if (proc.Threads[i] == thread)
                            {
                                proc.Threads.RemoveAt(i);
                                break;
                            }
                        }
                    }
                    finally
                    {
                        UninterruptibleMonitor.Exit(proc.Threads);
                    }
                }

                if (KConfig.Log.Threads >= KLogLevel.Debug)
                {
                    KernelMessage.WriteLine("Disposing Thread {1} DebugName={0}", thread.DebugName, thread.ThreadID);
                }

                thread.FreeMemory();
                ThreadsAllocated--;

                thread.Status = ThreadStatus.Empty;
            }
            finally
            {
                UninterruptibleMonitor.Exit(thread);
            }
        }
Beispiel #2
0
 public static void ResetTerminatedThreads()
 {
     UninterruptibleMonitor.Enter(Threads);
     try
     {
         for (uint i = 0; i < ThreadCapacity; i++)
         {
             if (Threads[i].Status == ThreadStatus.Terminated)
             {
                 ResetThread(i);
             }
         }
     }
     finally
     {
         UninterruptibleMonitor.Exit(Threads);
     }
 }
Beispiel #3
0
        /// <summary>
        /// Create a new Thread.
        /// The new thread will not started automatically.
        /// </summary>
        public static unsafe Thread CreateThread(Process proc, ThreadStartOptions options)
        {
            Thread thread;
            uint   threadID;

            lock (SyncRoot)
            {
                threadID = FindEmptyThreadSlot();

                if (threadID == 0)
                {
                    ResetTerminatedThreads();
                    threadID = FindEmptyThreadSlot();

                    Assert.False(threadID == 0 && Enabled, "No more free Thread-Slots!");
                }

                thread        = Threads[threadID];
                thread.Status = ThreadStatus.Creating;
            }

            // Debug:
            //options.User = false;

            thread.User      = proc.User;
            thread.Debug     = options.Debug;
            thread.DebugName = options.DebugName;
            thread.Priority  = options.Priority;

            var stackSize  = options.StackSize;
            var argBufSize = options.ArgumentBufferSize;

            thread.ArgumentBufferSize = options.ArgumentBufferSize;

            var stackPages = KMath.DivCeil(stackSize, PhysicalPageManager.PageSize);

            if (KConfig.Log.Threads >= KLogLevel.Trace)
            {
                KernelMessage.WriteLine("Requesting {0} stack pages", stackPages);
            }

            var debugPadding = 8u;

            stackSize = stackPages * PhysicalPageManager.PageSize;
            var stack = new Pointer((void *)VirtualPageManager.AllocatePages(stackPages, new AllocatePageOptions {
                DebugName = "ThreadStack"
            }));

            PageTable.KernelTable.SetWritable((uint)stack, stackSize);

            if (thread.User && proc.PageTable != PageTable.KernelTable)
            {
                proc.PageTable.MapCopy(PageTable.KernelTable, (uint)stack, stackSize);
            }

            stackSize -= debugPadding;
            var stackBottom = stack + (int)stackSize;

            if (KConfig.Log.Threads >= KLogLevel.Trace)
            {
                KernelMessage.Write("Create Thread {0}. EntryPoint: {1:X8} Stack: {2:X8}-{3:X8} Type: ", threadID, options.MethodAddr, (uint)stack, (uint)stackBottom - 1);
            }

            if (KConfig.Log.Threads >= KLogLevel.Trace)
            {
                if (thread.User)
                {
                    KernelMessage.Write("User");
                }
                else
                {
                    KernelMessage.Write("Kernel");
                }
            }

            if (KConfig.Log.Threads >= KLogLevel.Trace)
            {
                if (thread.DebugName != null)
                {
                    KernelMessage.Write(" Thread DebugName: {0}", thread.DebugName);
                }
                if (thread.Process != null)
                {
                    KernelMessage.WriteLine(" Process: {0}", thread.Process.Path);
                }
            }

            // -- kernel stack
            thread.KernelStackSize = 4 * 4096;
            //thhread.tssAddr = RawVirtualFrameAllocator.RequestRawVirtalMemoryPages(1);
            PageTable.KernelTable.SetWritable(KernelStart.TssAddr, 4096);
            thread.KernelStack = VirtualPageManager.AllocatePages(
                KMath.DivCeil(thread.KernelStackSize, 4096),
                new AllocatePageOptions {
                DebugName = "ThreadKernelStack"
            });                                                               // TODO: Decrease Kernel Stack, because Stack have to be changed directly because of multi-threading.
            thread.KernelStackBottom = thread.KernelStack + thread.KernelStackSize;

            if (KConfig.Log.Threads >= KLogLevel.Trace)
            {
                KernelMessage.WriteLine("tssEntry: {0:X8}, tssKernelStack: {1:X8}-{2:X8}", KernelStart.TssAddr, thread.KernelStack, thread.KernelStackBottom - 1);
            }

            PageTable.KernelTable.SetWritable(thread.KernelStack, 256 * 4096);

            // ---
            uint stackStateOffset = 8;

            stackStateOffset += argBufSize;

            uint cS = KnownSegments.KernelCode;

            if (thread.User)
            {
                cS = KnownSegments.UserCode;
            }

            var stateSize = thread.User ? IDTTaskStack.Size : IDTStack.Size;

            thread.StackTop    = (uint)stack;
            thread.StackBottom = (uint)stackBottom;

            Intrinsic.Store32(stackBottom, 4, 0xFF00001);          // Debug Marker
            Intrinsic.Store32(stackBottom, 0, 0xFF00002);          // Debug Marker

            Intrinsic.Store32(stackBottom, -4, (uint)stackBottom);
            Intrinsic.Store32(stackBottom, -(8 + (int)argBufSize), SignalThreadTerminationMethodAddress.ToInt32());  // Address of method that will raise a interrupt signal to terminate thread

            uint argAddr = (uint)stackBottom - argBufSize;

            IDTTaskStack *stackState = null;

            if (thread.User)
            {
                stackState = (IDTTaskStack *)VirtualPageManager.AllocatePages(1, new AllocatePageOptions {
                    DebugName = "ThreadStackState"
                });
                if (proc.PageTable != PageTable.KernelTable)
                {
                    proc.PageTable.MapCopy(PageTable.KernelTable, (uint)stackState, IDTTaskStack.Size);
                }
            }
            else
            {
                stackState = (IDTTaskStack *)(stackBottom - 8 - IDTStack.Size); // IDTStackSize is correct - we don't need the Task-Members.
            }
            thread.StackState = stackState;

            if (thread.User && KConfig.Log.Threads >= KLogLevel.Trace)
            {
                KernelMessage.WriteLine("StackState at {0:X8}", (uint)stackState);
            }

            stackState->Stack.EFLAGS = X86_EFlags.Reserved1;
            if (thread.User)
            {
                // Never set this values for Non-User, otherwise you will override stack informations.
                stackState->TASK_SS  = KnownSegments.UserData;
                stackState->TASK_ESP = (uint)stackBottom - (uint)stackStateOffset;

                proc.PageTable.MapCopy(PageTable.KernelTable, thread.KernelStack, thread.KernelStackSize);
                proc.PageTable.MapCopy(PageTable.KernelTable, KernelStart.TssAddr, 4096);
            }
            if (thread.User && options.AllowUserModeIOPort)
            {
                byte IOPL = 3;
                stackState->Stack.EFLAGS = (X86_EFlags)((uint)stackState->Stack.EFLAGS).SetBits(12, 2, IOPL);
            }

            stackState->Stack.CS  = cS;
            stackState->Stack.EIP = options.MethodAddr;
            stackState->Stack.EBP = (uint)(stackBottom - (int)stackStateOffset).ToInt32();

            thread.DataSelector = thread.User ? KnownSegments.UserData : KnownSegments.KernelData;

            UninterruptibleMonitor.Enter(proc.Threads);
            try
            {
                thread.Process = proc;
                proc.Threads.Add(thread);
            }
            finally
            {
                UninterruptibleMonitor.Exit(proc.Threads);
            }

            ThreadsAllocated++;
            if (ThreadsAllocated > ThreadsMaxAllocated)
            {
                ThreadsMaxAllocated = ThreadsAllocated;
                if (KConfig.Log.Threads >= KLogLevel.Trace)
                {
                    KernelMessage.WriteLine("Threads Max Allocated: {0}. Allocated {0} Active: {1}", ThreadsMaxAllocated, ThreadsAllocated, GetActiveThreadCount());
                }
                if (KConfig.Log.Threads >= KLogLevel.Trace)
                {
                    DumpStats();
                }
            }
            else if (KConfig.Log.Threads >= KLogLevel.Debug)
            {
                KernelMessage.WriteLine("Threads Allocated {0} Active: {1}", ThreadsAllocated, GetActiveThreadCount());
            }
            return(thread);
        }