private static unsafe void ResetThread(uint threadID) { var thread = Threads[threadID]; UninterruptableMonitor.Enter(thread); try { if (thread.Status != ThreadStatus.Terminated) { return; } if (thread.Process != null) { var proc = thread.Process; UninterruptableMonitor.Enter(proc.Threads); try { for (var i = 0; i < proc.Threads.Count; i++) { if (proc.Threads[i] == thread) { proc.Threads.RemoveAt(i); break; } } } finally { UninterruptableMonitor.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 { UninterruptableMonitor.Exit(thread); } }
public static void ResetTerminatedThreads() { UninterruptableMonitor.Enter(Threads); try { for (uint i = 0; i < ThreadCapacity; i++) { if (Threads[i].Status == ThreadStatus.Terminated) { ResetThread(i); } } } finally { UninterruptableMonitor.Exit(Threads); } }
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 = 0x08; if (thread.User) { cS = 0x1B; } 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 = 0x23; 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 ? 0x23u : 0x10u; UninterruptableMonitor.Enter(proc.Threads); try { thread.Process = proc; proc.Threads.Add(thread); } finally { UninterruptableMonitor.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); }