X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Farch%2Fx86%2Fproc.c;h=48a3c1a054fb78350e332e905517c532d004d300;hb=b574da4b635c3c030757e0877e7a947c5b4a4871;hp=0f9f449f3a94e8b67ac92d3fe49f68a3f8560b46;hpb=ef2ef0b76dca5bd5ee3b80fb7f831f89fc81f80d;p=tpg%2Facess2.git diff --git a/Kernel/arch/x86/proc.c b/Kernel/arch/x86/proc.c index 0f9f449f..48a3c1a0 100644 --- a/Kernel/arch/x86/proc.c +++ b/Kernel/arch/x86/proc.c @@ -12,9 +12,6 @@ // === CONSTANTS === #define SWITCH_MAGIC 0xFFFACE55 // There is no code in this area -#define DEFAULT_QUANTUM 10 -#define DEFAULT_TICKETS 5 -#define MAX_TICKETS 10 #define TIMER_DIVISOR 11931 //~100Hz // === IMPORTS === @@ -22,59 +19,32 @@ extern tGDT gGDT[]; extern Uint GetEIP(); // start.asm extern Uint32 gaInitPageDir[1024]; // start.asm extern void Kernel_Stack_Top; +extern volatile int giThreadListLock; +extern int giNumCPUs; +extern int giNextTID; +extern int giTotalTickets; +extern int giNumActiveThreads; +extern tThread gThreadZero; +extern tThread *gActiveThreads; +extern tThread *gSleepingThreads; +extern tThread *gDeleteThreads; +extern tThread *Threads_GetNextToRun(int CPU); // === PROTOTYPES === -void Proc_Start(); +void ArchThreads_Init(); +tThread *Proc_GetCurThread(); void Proc_ChangeStack(); int Proc_Clone(Uint *Err, Uint Flags); -void Proc_Exit(); -void Proc_Yield(); -void Proc_Sleep(); -static tThread *Proc_int_GetPrevThread(tThread **List, tThread *Thread); void Proc_Scheduler(); -Sint64 now(); -Uint rand(); // === GLOBALS === -// -- Core Thread -- -tThread gThreadZero = { - NULL, 0, // Next, Lock - THREAD_STAT_ACTIVE, // Status - 0, 0, // TID, TGID - 0, 0, // UID, GID - "ThreadZero", // Name - 0, 0, 0, // ESP, EBP, EIP (Set on switch) - #if USE_PAE - {0,0,0}, // PML4 Entries - #else - (Uint)&gaInitPageDir-KERNEL_BASE, // CR3 - #endif - (Uint)&Kernel_Stack_Top, // Kernel Stack (Unused as it is PL0) - NULL, NULL, // Messages, Last Message - DEFAULT_QUANTUM, DEFAULT_QUANTUM, // Quantum, Remaining - DEFAULT_TICKETS, - {0} // Default config to zero - }; -// -- Processes -- -// --- Locks --- -volatile int giThreadListLock = 0; ///\note NEVER use a heap function while locked // --- Current State --- #if USE_MP -tThread **gCurrentThread = NULL; -# define CUR_THREAD gCurrentThread[0] +tThread *gCurrentThread[MAX_CPUS] = NULL; #else tThread *gCurrentThread = NULL; -# define CUR_THREAD gCurrentThread #endif -volatile int giNumActiveThreads = 0; -volatile int giTotalTickets = 0; -volatile Uint giNextTID = 1; -// --- Thread Lists --- -tThread *gActiveThreads = NULL; // Currently Running Threads -tThread *gSleepingThreads = NULL; // Sleeping Threads -tThread *gDeleteThreads = NULL; // Threads to delete // --- Multiprocessing --- - int giNumCPUs = 1; #if USE_MP tMPInfo *gMPTable = NULL; #endif @@ -88,13 +58,12 @@ tTSS gTSS0 = {0}; // === CODE === /** - * \fn void Proc_Start() + * \fn void ArchThreads_Init() * \brief Starts the process scheduler */ -void Proc_Start() +void ArchThreads_Init() { Uint pos = 0; - #if USE_MP // -- Initialise Multiprocessing // Find MP Floating Table @@ -156,38 +125,40 @@ void Proc_Start() } #endif + #if USE_MP + gCurrentThread[0] = &gThreadZero; + #else + gCurrentThread = &gThreadZero; + #endif + // Set timer frequency outb(0x43, 0x34); // Set Channel 0, Low/High, Rate Generator outb(0x40, TIMER_DIVISOR&0xFF); // Low Byte of Divisor outb(0x40, (TIMER_DIVISOR>>8)&0xFF); // High Byte - // Create Initial Task - gActiveThreads = &gThreadZero; - gCurrentThread = &gThreadZero; - giTotalTickets = gThreadZero.NumTickets; - giNumActiveThreads = 1; - // Create Per-Process Data Block MM_Allocate(MM_PPD_CFG); // Change Stacks Proc_ChangeStack(); - #if 1 - // Create Idle Task - if(Proc_Clone(0, 0) == 0) - { - gCurrentThread->ThreadName = "Idle Thread"; - Proc_SetTickets(0); // Never called randomly - gCurrentThread->Quantum = 1; // 1 slice quantum - for(;;) __asm__ __volatile__ ("hlt"); // Just yeilds - } - #endif - // Start Interrupts (and hence scheduler) __asm__ __volatile__("sti"); } +/** + * \fn tThread *Proc_GetCurThread() + * \brief Gets the current thread + */ +tThread *Proc_GetCurThread() +{ + #if USE_MP + return NULL; + #else + return gCurrentThread; + #endif +} + /** * \fn void Proc_ChangeStack() * \brief Swaps the current stack for a new one (in the proper stack reigon) @@ -211,7 +182,7 @@ void Proc_ChangeStack() return; } - curBase = gCurrentThread->KernelStack; + curBase = (Uint)&Kernel_Stack_Top; LOG("curBase = 0x%x, newBase = 0x%x", curBase, newBase); @@ -263,7 +234,7 @@ int Proc_Clone(Uint *Err, Uint Flags) // Initialise Memory Space (New Addr space or kernel stack) if(Flags & CLONE_VM) { newThread->TGID = newThread->TID; - newThread->CR3 = MM_Clone(); + newThread->MemState.CR3 = MM_Clone(); } else { Uint tmpEbp, oldEsp = esp; @@ -297,6 +268,7 @@ int Proc_Clone(Uint *Err, Uint Flags) newThread->Next = NULL; newThread->IsLocked = 0; newThread->TID = giNextTID++; + newThread->PTID = gCurrentThread->TID; // Clear message list (messages are not inherited) newThread->Messages = NULL; @@ -306,8 +278,8 @@ int Proc_Clone(Uint *Err, Uint Flags) newThread->Remaining = newThread->Quantum; // Save core machine state - newThread->ESP = esp; - newThread->EBP = ebp; + newThread->SavedState.ESP = esp; + newThread->SavedState.EBP = ebp; eip = GetEIP(); if(eip == SWITCH_MAGIC) { outb(0x20, 0x20); // ACK Timer and return as child @@ -315,9 +287,7 @@ int Proc_Clone(Uint *Err, Uint Flags) } // Set EIP as parent - newThread->EIP = eip; - - //Log(" Proc_Clone: giTimestamp = %i.%07i", (Uint)giTimestamp, (Uint)giPartMiliseconds/214); + newThread->SavedState.EIP = eip; // Lock list and add to active LOCK( &giThreadListLock ); @@ -330,18 +300,6 @@ int Proc_Clone(Uint *Err, Uint Flags) return newThread->TID; } -/** - * \fn void Proc_SetThreadName() - * \brief Sets the thread's name - */ -void Proc_SetThreadName(char *NewName) -{ - if( (Uint)CUR_THREAD->ThreadName > 0xC0400000 ) - free( CUR_THREAD->ThreadName ); - CUR_THREAD->ThreadName = malloc(strlen(NewName)+1); - strcpy(CUR_THREAD->ThreadName, NewName); -} - /** * \fn Uint Proc_MakeUserStack() * \brief Creates a new user stack @@ -434,153 +392,6 @@ void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char ** for(;;); } -/** - * \fn void Proc_Exit() - * \brief Kill the current process - */ -void Proc_Exit() -{ - tThread *thread; - tMsg *msg; - - ///\note Double lock is needed due to overlap of locks - - // Lock thread (stop us recieving messages) - LOCK( &gCurrentThread->IsLocked ); - - // Lock thread list - LOCK( &giThreadListLock ); - - // Get previous thread on list - thread = Proc_int_GetPrevThread( &gActiveThreads, gCurrentThread ); - if(!thread) { - Warning("Proc_Exit - Current thread is not on the active queue"); - return; - } - - // Clear Message Queue - while( gCurrentThread->Messages ) - { - msg = gCurrentThread->Messages->Next; - free( gCurrentThread->Messages ); - gCurrentThread->Messages = msg; - } - - gCurrentThread->Remaining = 0; // Clear Remaining Quantum - gCurrentThread->Quantum = 0; // Clear Quantum to indicate dead thread - thread->Next = gCurrentThread->Next; // Remove from active - - // Add to delete queue - if(gDeleteThreads) { - gCurrentThread->Next = gDeleteThreads; - gDeleteThreads = gCurrentThread; - } else { - gCurrentThread->Next = NULL; - gDeleteThreads = gCurrentThread; - } - - giNumActiveThreads --; - giTotalTickets -= gCurrentThread->NumTickets; - - // Mark thread as sleeping - gCurrentThread->Status = THREAD_STAT_DEAD; - - // Release spinlocks - RELEASE( &gCurrentThread->IsLocked ); // Released first so that it IS released - RELEASE( &giThreadListLock ); - __asm__ __volatile__ ("hlt"); -} - -/** - * \fn void Proc_Yield() - * \brief Yield remainder of timeslice - */ -void Proc_Yield() -{ - gCurrentThread->Quantum = 0; - __asm__ __volatile__ ("hlt"); -} - -/** - * \fn void Proc_Sleep() - * \brief Take the current process off the run queue - */ -void Proc_Sleep() -{ - tThread *thread; - - //Log("Proc_Sleep: %i going to sleep", gCurrentThread->TID); - - // Acquire Spinlock - LOCK( &giThreadListLock ); - - // Get thread before current thread - thread = Proc_int_GetPrevThread( &gActiveThreads, gCurrentThread ); - if(!thread) { - Warning("Proc_Sleep - Current thread is not on the active queue"); - return; - } - - // Don't sleep if there is a message waiting - if( gCurrentThread->Messages ) { - RELEASE( &giThreadListLock ); - return; - } - - // Unset remaining timeslices (force a task switch on timer fire) - gCurrentThread->Remaining = 0; - - // Remove from active list - thread->Next = gCurrentThread->Next; - - // Add to Sleeping List (at the top) - gCurrentThread->Next = gSleepingThreads; - gSleepingThreads = gCurrentThread; - - // Reduce the active count & ticket count - giNumActiveThreads --; - giTotalTickets -= gCurrentThread->NumTickets; - - // Mark thread as sleeping - gCurrentThread->Status = THREAD_STAT_SLEEPING; - - // Release Spinlock - RELEASE( &giThreadListLock ); - - __asm__ __volatile__ ("hlt"); -} - -/** - * \fn void Thread_Wake( tThread *Thread ) - * \brief Wakes a sleeping/waiting thread up - */ -void Thread_Wake(tThread *Thread) -{ - tThread *prev; - switch(Thread->Status) - { - case THREAD_STAT_ACTIVE: break; - case THREAD_STAT_SLEEPING: - LOCK( &giThreadListLock ); - prev = Proc_int_GetPrevThread(&gSleepingThreads, Thread); - prev->Next = Thread->Next; // Remove from sleeping queue - Thread->Next = gActiveThreads; // Add to active queue - gActiveThreads = Thread; - Thread->Status = THREAD_STAT_ACTIVE; - RELEASE( &giThreadListLock ); - break; - case THREAD_STAT_WAITING: - Warning("Thread_Wake - Waiting threads are not currently supported"); - break; - case THREAD_STAT_DEAD: - Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID); - break; - default: - Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status); - break; - } -} - /** * \fn int Proc_Demote(Uint *Err, int Dest, tRegs *Regs) * \brief Demotes a process to a lower permission level @@ -613,99 +424,6 @@ int Proc_Demote(Uint *Err, int Dest, tRegs *Regs) return 0; } -/** - * \fn void Proc_SetTickets(int Num) - * \brief Sets the 'priority' of a task - */ -void Proc_SetTickets(int Num) -{ - if(Num < 0) return; - if(Num > MAX_TICKETS) Num = MAX_TICKETS; - - LOCK( &giThreadListLock ); - giTotalTickets -= gCurrentThread->NumTickets; - gCurrentThread->NumTickets = Num; - giTotalTickets += Num; - //LOG("giTotalTickets = %i", giTotalTickets); - RELEASE( &giThreadListLock ); -} - -/** - * \fn tThread *Proc_GetThread(Uint TID) - * \brief Gets a thread given its TID - */ -tThread *Proc_GetThread(Uint TID) -{ - tThread *thread; - - // Search Active List - for(thread = gActiveThreads; - thread; - thread = thread->Next) - { - if(thread->TID == TID) - return thread; - } - - // Search Sleeping List - for(thread = gSleepingThreads; - thread; - thread = thread->Next) - { - if(thread->TID == TID) - return thread; - } - - return NULL; -} - -/** - * \fn static tThread *Proc_int_GetPrevThread(tThread *List, tThread *Thread) - * \brief Gets the previous entry in a thead linked list - */ -static tThread *Proc_int_GetPrevThread(tThread **List, tThread *Thread) -{ - tThread *ret; - // First Entry - if(*List == Thread) { - return (tThread*)List; - } else { - for(ret = *List; - ret->Next && ret->Next != Thread; - ret = ret->Next - ); - // Error if the thread is not on the list - if(!ret->Next || ret->Next != Thread) { - return NULL; - } - } - return ret; -} - -/** - * \fn void Proc_DumpThreads() - * \brief Dums a list of currently running threads - */ -void Proc_DumpThreads() -{ - tThread *thread; - - Log("Active Threads:"); - for(thread=gActiveThreads;thread;thread=thread->Next) - { - Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName); - Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum); - Log(" CR3 0x%x, KStack 0x%x", thread->CR3, thread->KernelStack); - } - Log("Sleeping Threads:"); - for(thread=gSleepingThreads;thread;thread=thread->Next) - { - Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName); - Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum); - Log(" CR3 0x%x, KStack 0x%x", thread->CR3, thread->KernelStack); - } -} - /** * \fn void Proc_Scheduler(int CPU) * \brief Swap current thread and clears dead threads @@ -713,7 +431,6 @@ void Proc_DumpThreads() void Proc_Scheduler(int CPU) { Uint esp, ebp, eip; - Uint number, ticket; tThread *thread; // If the spinlock is set, let it complete @@ -737,7 +454,7 @@ void Proc_Scheduler(int CPU) return; } - // Reduce remaining quantum + // Reduce remaining quantum and continue timeslice if non-zero if(gCurrentThread->Remaining--) return; // Reset quantum for next call gCurrentThread->Remaining = gCurrentThread->Quantum; @@ -749,38 +466,17 @@ void Proc_Scheduler(int CPU) if(eip == SWITCH_MAGIC) return; // Check if a switch happened // Save machine state - gCurrentThread->ESP = esp; - gCurrentThread->EBP = ebp; - gCurrentThread->EIP = eip; + gCurrentThread->SavedState.ESP = esp; + gCurrentThread->SavedState.EBP = ebp; + gCurrentThread->SavedState.EIP = eip; - // Special case: 1 thread - if(giNumActiveThreads == 1) - { - // Check if a switch is needed (NumActive can be 1 after a sleep) - if(gActiveThreads == gCurrentThread) return; - // Switch processes - gCurrentThread = gActiveThreads; - goto performSwitch; - } - - // Get the ticket number - ticket = number = rand() % giTotalTickets; - - // Find the next thread - for(thread=gActiveThreads;thread;thread=thread->Next) - { - if(thread->NumTickets > number) break; - number -= thread->NumTickets; - } + // Get next thread + thread = Threads_GetNextToRun(CPU); // Error Check - if(thread == NULL) - { - number = 0; - for(thread=gActiveThreads;thread;thread=thread->Next) - number += thread->NumTickets; - Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)", - giTotalTickets, number); + if(thread == NULL) { + Warning("Hmm... Threads_GetNextToRun returned NULL, I don't think this should happen.\n"); + return; } // Set current thread @@ -789,34 +485,14 @@ void Proc_Scheduler(int CPU) // Update Kernel Stack pointer gTSSs[CPU].ESP0 = thread->KernelStack; -performSwitch: // Set address space - //MM_SetCR3( gCurrentThread->CR3 ); - __asm__ __volatile__ ("mov %0, %%cr3"::"a"(gCurrentThread->CR3)); + __asm__ __volatile__ ("mov %0, %%cr3"::"a"(gCurrentThread->MemState.CR3)); // Switch threads __asm__ __volatile__ ( "mov %1, %%esp\n\t" "mov %2, %%ebp\n\t" "jmp *%3" : : - "a"(SWITCH_MAGIC), "b"(gCurrentThread->ESP), - "d"(gCurrentThread->EBP), "c"(gCurrentThread->EIP)); + "a"(SWITCH_MAGIC), "b"(gCurrentThread->SavedState.ESP), + "d"(gCurrentThread->SavedState.EBP), "c"(gCurrentThread->SavedState.EIP)); for(;;); // Shouldn't reach here } - -// --- Process Structure Access Functions --- -int Proc_GetPID() -{ - return gCurrentThread->TGID; -} -int Proc_GetTID() -{ - return gCurrentThread->TID; -} -int Proc_GetUID() -{ - return gCurrentThread->UID; -} -int Proc_GetGID() -{ - return gCurrentThread->GID; -}