extern tIDT gIDT[];
extern void APWait(void); // 16-bit AP pause code
extern void APStartup(void); // 16-bit AP startup code
-extern void NewTaskHeader(tThread *Thread, void *Fcn, int nArgs, ...); // Actually takes cdecl args
extern Uint Proc_CloneInt(Uint *ESP, Uint32 *CR3, int bNoUserClone);
extern Uint32 gaInitPageDir[1024]; // start.asm
extern char Kernel_Stack_Top[];
//tThread *Proc_GetCurThread(void);
void Proc_ChangeStack(void);
// int Proc_NewKThread(void (*Fcn)(void*), void *Data);
+void NewTaskHeader(tThread *Thread, void (*Fcn)(void*), void *Data); // Actually takes cdecl args
// int Proc_Clone(Uint *Err, Uint Flags);
Uint Proc_MakeUserStack(void);
//void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);
void Proc_CallUser(Uint32 UserIP, Uint32 UserSP, const void *StackData, size_t StackDataLen);
//void Proc_CallFaultHandler(tThread *Thread);
//void Proc_DumpThreadCPUState(tThread *Thread);
-void Proc_Scheduler(int CPU);
+void Proc_HandleEventTimer(int CPU);
// === GLOBALS ===
// --- Multiprocessing ---
cpu->Current->ThreadName = strdup("Idle Thread");
Threads_SetPriority( cpu->Current, -1 ); // Never called randomly
cpu->Current->Quantum = 1; // 1 slice quantum
- for(;;) {
+ LOG("Idle thread for CPU %i ready", GetCPUNum());
+ for(;;)
+ {
__asm__ __volatile__ ("sti"); // Make sure interrupts are enabled
- __asm__ __volatile__ ("hlt");
- Proc_Reschedule();
+ Proc_Reschedule(); // Reshedule
+ __asm__ __volatile__ ("hlt"); // And wait for an interrupt if we get scheduled again
}
}
tTID Proc_NewKThread(void (*Fcn)(void*), void *Data)
{
- Uint esp;
- tThread *newThread;
-
- newThread = Threads_CloneTCB(0);
+ tThread *newThread = Threads_CloneTCB(0);
if(!newThread) return -1;
// Create new KStack
free(newThread);
return -1;
}
+
+ LOG("%p(%i %s) SP=%p", newThread, newThread->TID, newThread->ThreadName, newThread->KernelStack);
- esp = newThread->KernelStack;
+ Uint esp = newThread->KernelStack;
*(Uint*)(esp-=4) = (Uint)Data; // Data (shadowed)
- *(Uint*)(esp-=4) = 1; // Number of params
*(Uint*)(esp-=4) = (Uint)Fcn; // Function to call
*(Uint*)(esp-=4) = (Uint)newThread; // Thread ID
+ *(Uint*)(esp-=4) = (Uint)0; // Empty return address
newThread->SavedState.ESP = esp;
newThread->SavedState.EIP = (Uint)&NewTaskHeader;
return newThread->TID;
}
-#if 0
-tPID Proc_NewProcess(Uint Flags, void (*Fcn)(void*), size_t SaveSize, const void *Data)
+void NewTaskHeader(tThread *NewThread, void (*Fcn)(void*), void *Data)
{
- tThread *newThread = Threads_CloneTCB(CLONE_VM);
- return 0;
+ LOG("NewThread=%p, Fcn=%p, Data=%p", NewThread, Fcn, Data);
+ __asm__ __volatile__ ("mov %0, %%dr0" : : "r"(NewThread));
+ SHORTREL(&glThreadListLock);
+ Fcn(Data);
+
+ Threads_Exit(0, 0);
+ for(;;);
}
-#endif
/**
* \fn int Proc_Clone(Uint *Err, Uint Flags)
*/
tPID Proc_Clone(Uint Flags)
{
- tThread *newThread;
tThread *cur = Proc_GetCurThread();
- Uint eip;
// Sanity, please
if( !(Flags & CLONE_VM) ) {
}
// New thread
- newThread = Threads_CloneTCB(Flags);
+ tThread *newThread = Threads_CloneTCB(Flags);
if(!newThread) return -1;
ASSERT(newThread->Process);
- //ASSERT(CheckMem(newThread->Process, sizeof(tProcess)));
- //LOG("newThread->Process = %p", newThread->Process);
newThread->KernelStack = cur->KernelStack;
// Clone state
- eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->Process->MemState.CR3, Flags & CLONE_NOUSER);
+ Uint eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->Process->MemState.CR3, Flags & CLONE_NOUSER);
if( eip == 0 ) {
+ SHORTREL( &glThreadListLock );
+ LOG("In new thread");
return 0;
}
//ASSERT(newThread->Process);
Warning("Proc_SpawnWorker - Out of heap space!\n");
return NULL;
}
+ LOG("new = (%i %s)", new->TID, new->ThreadName);
// Create the stack contents
stack_contents[3] = (Uint)Data;
- stack_contents[2] = 1;
- stack_contents[1] = (Uint)Fcn;
- stack_contents[0] = (Uint)new;
+ stack_contents[2] = (Uint)Fcn;
+ stack_contents[1] = (Uint)new;
+ stack_contents[0] = 0;
// Create a new worker stack (in PID0's address space)
new->KernelStack = MM_NewWorkerStack(stack_contents, sizeof(stack_contents));
void Proc_Reschedule(void)
{
- tThread *nextthread, *curthread;
int cpu = GetCPUNum();
// TODO: Wait for the lock?
- if(IS_LOCKED(&glThreadListLock)) return;
+ if(IS_LOCKED(&glThreadListLock)) {
+ LOG("Thread list locked, not rescheduling");
+ return;
+ }
- curthread = Proc_GetCurThread();
-
- nextthread = Threads_GetNextToRun(cpu, curthread);
-
- if(!nextthread || nextthread == curthread)
- return ;
-
- #if DEBUG_TRACE_SWITCH
- // HACK: Ignores switches to the idle threads
- if( nextthread->TID == 0 || nextthread->TID > giNumCPUs )
+ SHORTLOCK(&glThreadListLock);
+
+ tThread *curthread = Proc_GetCurThread();
+ tThread *nextthread = Threads_GetNextToRun(cpu, curthread);
+
+ if(nextthread && nextthread != curthread)
{
- LogF("\nSwitching CPU %i to %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n",
- GetCPUNum(),
- nextthread, nextthread->TID, nextthread->ThreadName,
- nextthread->Process->MemState.CR3,
- nextthread->SavedState.EIP,
- nextthread->SavedState.ESP
- );
- LogF("OldCR3 = %P\n", curthread->Process->MemState.CR3);
- }
- #endif
+ #if DEBUG_TRACE_SWITCH
+ // HACK: Ignores switches to the idle threads
+ //if( nextthread->TID == 0 || nextthread->TID > giNumCPUs )
+ {
+ LogF("\nSwitching CPU %i to %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n",
+ GetCPUNum(),
+ nextthread, nextthread->TID, nextthread->ThreadName,
+ nextthread->Process->MemState.CR3,
+ nextthread->SavedState.EIP,
+ nextthread->SavedState.ESP
+ );
+ LogF(" from %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n",
+ curthread, curthread->TID, curthread->ThreadName,
+ curthread->Process->MemState.CR3,
+ curthread->SavedState.EIP,
+ curthread->SavedState.ESP
+ );
+ }
+ #endif
- // Update CPU state
- gaCPUs[cpu].Current = nextthread;
- gaCPUs[cpu].LastTimerThread = NULL;
- gTSSs[cpu].ESP0 = nextthread->KernelStack-4;
- __asm__ __volatile__("mov %0, %%db0\n\t" : : "r"(nextthread) );
+ // Update CPU state
+ gaCPUs[cpu].Current = nextthread;
+ gaCPUs[cpu].LastTimerThread = NULL;
+ gTSSs[cpu].ESP0 = nextthread->KernelStack-4;
+ __asm__ __volatile__("mov %0, %%db0\n\t" : : "r"(nextthread) );
- // Save FPU/MMX/XMM/SSE state
- if( curthread && curthread->SavedState.SSE )
- {
- Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF );
- curthread->SavedState.bSSEModified = 0;
- Proc_DisableSSE();
- }
+ // Save FPU/MMX/XMM/SSE state
+ if( curthread && curthread->SavedState.SSE )
+ {
+ Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF );
+ curthread->SavedState.bSSEModified = 0;
+ Proc_DisableSSE();
+ }
- if( curthread )
- {
- SwitchTasks(
- nextthread->SavedState.ESP, &curthread->SavedState.ESP,
- nextthread->SavedState.EIP, &curthread->SavedState.EIP,
- nextthread->Process->MemState.CR3
- );
- }
- else
- {
- SwitchTasks(
- nextthread->SavedState.ESP, 0,
- nextthread->SavedState.EIP, 0,
- nextthread->Process->MemState.CR3
- );
+ if( curthread )
+ {
+ SwitchTasks(
+ nextthread->SavedState.ESP, &curthread->SavedState.ESP,
+ nextthread->SavedState.EIP, &curthread->SavedState.EIP,
+ nextthread->Process->MemState.CR3
+ );
+ }
+ else
+ {
+ SwitchTasks(
+ nextthread->SavedState.ESP, 0,
+ nextthread->SavedState.EIP, 0,
+ nextthread->Process->MemState.CR3
+ );
+ }
}
-
- return ;
+
+ SHORTREL(&glThreadListLock);
}
/**
- * \fn void Proc_Scheduler(int CPU)
- * \brief Swap current thread and clears dead threads
+ * \brief Handle the per-CPU timer ticking
+
*/
-void Proc_Scheduler(int CPU)
+void Proc_HandleEventTimer(int CPU)
{
- #if USE_MP
- if( GetCPUNum() )
- gpMP_LocalAPIC->EOI.Val = 0;
- else
- #endif
- outb(0x20, 0x20);
- __asm__ __volatile__ ("sti");
-
// Call the timer update code
Timer_CallTimers();
// If two ticks happen within the same task, and it's not an idle task, swap
if( gaCPUs[CPU].Current->TID > giNumCPUs && gaCPUs[CPU].Current == gaCPUs[CPU].LastTimerThread )
{
+ const tThread* const t = gaCPUs[CPU].Current;
+ LOG("Preempting thread %p(%i %s)", t, t->TID, t->ThreadName);
Proc_Reschedule();
}
* threads.c
* - Common Thread Control
*/
+#define DEBUG 0
#include <acess.h>
#include <threads.h>
#include <threads_int.h>
*/
tThread *Threads_CloneTCB(Uint Flags)
{
- tThread *cur, *new;
- cur = Proc_GetCurThread();
+ tThread *cur = Proc_GetCurThread();
// Allocate and duplicate
- new = malloc(sizeof(tThread));
+ tThread *new = malloc(sizeof(tThread));
if(new == NULL) { errno = -ENOMEM; return NULL; }
memcpy(new, cur, sizeof(tThread));
void Threads_int_WaitForStatusEnd(enum eThreadStatus Status)
{
tThread *us = Proc_GetCurThread();
+ LOG("us = %p(%i %s), status=%i", us, us->TID, us->ThreadName, Status);
ASSERT(Status != THREAD_STAT_ACTIVE);
ASSERT(Status != THREAD_STAT_DEAD);
while( us->Status == Status )
// Single-list round-robin
// -----------------------------------
tThread *thread = gActiveThreads.Head;
+ LOG("thread = %p", thread);
if( thread )
{
gActiveThreads.Head = thread->Next;
*/
tThread *Threads_GetNextToRun(int CPU, tThread *Last)
{
- // If this CPU has the lock, we must let it complete
- if( CPU_HAS_LOCK( &glThreadListLock ) )
- return Last;
+ ASSERT( CPU_HAS_LOCK(&glThreadListLock) );
// Don't change threads if the current CPU has switches disabled
- if( gaThreads_NoTaskSwitch[CPU] )
+ if( gaThreads_NoTaskSwitch[CPU] ) {
+ LOG("- Denied");
return Last;
-
- // Lock thread list
- SHORTLOCK( &glThreadListLock );
+ }
// Make sure the current (well, old) thread is marked as de-scheduled
if(Last) Last->CurCPU = -1;
// No active threads, just take a nap
if(giNumActiveThreads == 0) {
- SHORTREL( &glThreadListLock );
+ LOG("- No active");
#if DEBUG_TRACE_TICKETS
Log("No active threads");
#endif
// Call actual scheduler
tThread *thread = Threads_int_GetRunnable();
-
+
// Anything to do?
if( thread )
{
Warning("No runnable thread for CPU%i", CPU);
}
- SHORTREL( &glThreadListLock );
-
return thread;
}