#include <errno.h>
#include <mutex.h>
#include <semaphore.h>
+#include <hal_proc.h>
// Configuration
#define DEBUG_TRACE_TICKETS 0 // Trace ticket counts
#define DEBUG_TRACE_STATE 0 // Trace state changes (sleep/wake)
-#define SEMAPHORE_DEBUG 0
+#define SEMAPHORE_DEBUG 0 // Debug semaphores
// --- Schedulers ---
#define SCHED_UNDEF 0
};
// === IMPORTS ===
-extern void ArchThreads_Init(void);
-extern void Proc_CallFaultHandler(tThread *Thread);
-extern void Proc_DumpThreadCPUState(tThread *Thread);
-extern int GetCPUNum(void);
// === PROTOTYPES ===
void Threads_Init(void);
Log_Debug("Threads", "Offsets of tThread");
Log_Debug("Threads", ".Priority = %i", offsetof(tThread, Priority));
+ Log_Debug("Threads", ".KernelStack = %i", offsetof(tThread, KernelStack));
// Create Initial Task
#if SCHEDULER_TYPE == SCHED_RR_PRI
}
/**
- * \fn tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
* \brief Clone the TCB of the current thread
- * \param Err Error pointer
* \param Flags Flags for something... (What is this for?)
*/
-tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
+tThread *Threads_CloneTCB(Uint Flags)
{
tThread *cur, *new;
int i;
// Allocate and duplicate
new = malloc(sizeof(tThread));
- if(new == NULL) { *Err = -ENOMEM; return NULL; }
+ if(new == NULL) { errno = -ENOMEM; return NULL; }
memcpy(new, cur, sizeof(tThread));
new->CurCPU = -1;
}
/**
- * \fn tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
- * \brief Clone the TCB of the current thread
+ * \brief Clone the TCB of the kernel thread
*/
tThread *Threads_CloneThreadZero(void)
{
- tThread *cur, *new;
+ tThread *new;
int i;
- cur = Proc_GetCurThread();
// Allocate and duplicate
new = malloc(sizeof(tThread));
new->LastMessage = NULL;
// Set State
- new->Remaining = new->Quantum = cur->Quantum;
- new->Priority = cur->Priority;
+ new->Remaining = new->Quantum = DEFAULT_QUANTUM;
+ new->Priority = DEFAULT_PRIORITY;
new->bInstrTrace = 0;
// Set Signal Handlers
new->CurFaultNum = 0;
- new->FaultHandler = cur->FaultHandler;
+ new->FaultHandler = 0;
for( i = 0; i < NUM_CFG_ENTRIES; i ++ )
{
- switch(cCONFIG_TYPES[i])
- {
- default:
- new->Config[i] = cur->Config[i];
- break;
- case CFGT_HEAPSTR:
- if(cur->Config[i])
- new->Config[i] = (Uint) strdup( (void*)cur->Config[i] );
- else
- new->Config[i] = 0;
- break;
- }
+ new->Config[i] = 0;
}
// Maintain a global list of threads
}
break;
- // Brains!... You cannot kill
+ // Brains!... You cannot kill something that is already dead
case THREAD_STAT_ZOMBIE:
Log_Warning("Threads", "Threads_Kill - Thread %p(%i,%s) is undead, you cannot kill it",
Thread, Thread->TID, Thread->ThreadName);
// Save exit status
Thread->RetStatus = Status;
-
+
+ SHORTREL( &Thread->IsLocked );
+
// Don't Zombie if we are being killed because our parent is
if(Status == -1)
{
Thread->Status = THREAD_STAT_DEAD;
Threads_AddToDelete( Thread );
+ SHORTREL( &glThreadListLock );
} else {
Thread->Status = THREAD_STAT_ZOMBIE;
+ SHORTREL( &glThreadListLock );
// Wake parent
Threads_Wake( Thread->Parent );
}
Log("Thread %i went *hurk* (%i)", Thread->TID, Status);
- // Release spinlocks
- SHORTREL( &glThreadListLock );
- SHORTREL( &Thread->IsLocked ); // TODO: We may not actually be released...
-
// And, reschedule
- if(isCurThread) {
+ if(isCurThread)
+ {
for( ;; )
- HALT();
+ Proc_Reschedule();
}
}
*/
void Threads_Yield(void)
{
- tThread *thread = Proc_GetCurThread();
- thread->Remaining = 0;
- //while(thread->Remaining == 0)
- HALT();
+// Log("Threads_Yield: by %p", __builtin_return_address(0));
+ Proc_Reschedule();
}
/**
// Release Spinlock
SHORTREL( &glThreadListLock );
-
- while(cur->Status != THREAD_STAT_ACTIVE) HALT();
+
+ while(cur->Status != THREAD_STAT_ACTIVE) {
+ Proc_Reschedule();
+ if( cur->Status != THREAD_STAT_ACTIVE )
+ Log("%i - Huh? why am I up? zzzz...", cur->TID);
+ }
}
/**
- * \fn int Threads_Wake( tThread *Thread )
* \brief Wakes a sleeping/waiting thread up
* \param Thread Thread to wake
* \return Boolean Failure (Returns ERRNO)
// Remove from sleeping queue
Threads_int_DelFromQueue(&gSleepingThreads, Thread);
+ SHORTREL( &glThreadListLock );
Threads_AddActive( Thread );
#if DEBUG_TRACE_STATE
Log("Threads_Sleep: %p (%i %s) woken", Thread, Thread->TID, Thread->ThreadName);
#endif
- SHORTREL( &glThreadListLock );
return -EOK;
case THREAD_STAT_SEMAPHORESLEEP: {
sem->LastSignaling = prev;
}
- SHORTLOCK( &glThreadListLock );
+ Thread->RetStatus = 0; // It didn't get anything
Threads_AddActive( Thread );
- SHORTREL( &glThreadListLock );
#if DEBUG_TRACE_STATE
Log("Threads_Sleep: %p(%i %s) woken from semaphore", Thread, Thread->TID, Thread->ThreadName);
if( Thread->Status == THREAD_STAT_ACTIVE ) {
tThread *cur = Proc_GetCurThread();
- Warning("WTF, CPU%i %p (%i %s) is adding %p (%i %s) when it is active",
+ Log_Warning("Threads", "WTF, %p CPU%i %p (%i %s) is adding %p (%i %s) when it is active",
+ __builtin_return_address(0),
GetCPUNum(), cur, cur->TID, cur->ThreadName, Thread, Thread->TID, Thread->ThreadName);
SHORTREL( &glThreadListLock );
return ;
/**
* \brief Removes the current thread from the active queue
- * \warning This should ONLY be called with task switches disabled
+ * \warning This should ONLY be called with the lock held
* \return Current thread pointer
*/
tThread *Threads_RemActive(void)
{
tThread *ret = Proc_GetCurThread();
-
- SHORTLOCK( &glThreadListLock );
+
+ if( !IS_LOCKED(&glThreadListLock) ) {
+ Log_KernelPanic("Threads", "Threads_RemActive called without lock held");
+ return NULL;
+ }
// Delete from active queue
#if SCHEDULER_TYPE == SCHED_RR_PRI
GetCPUNum(), ret, ret->TID, ret->ThreadName, giFreeTickets);
#endif
- SHORTREL( &glThreadListLock );
-
return ret;
}
// Double Fault? Oh, F**k
if(thread->CurFaultNum != 0) {
+ Log_Warning("Threads", "Threads_Fault: Double fault on %i", thread->TID);
Threads_Kill(thread, -1); // For now, just kill
HALT();
}
*/
void Threads_SegFault(tVAddr Addr)
{
- Warning("Thread #%i committed a segfault at address %p", Proc_GetCurThread()->TID, Addr);
+ tThread *cur = Proc_GetCurThread();
+ cur->bInstrTrace = 0;
+ Log_Warning("Threads", "Thread #%i committed a segfault at address %p", cur->TID, Addr);
+ MM_DumpTables(0, USER_MAX);
Threads_Fault( 1 );
//Threads_Exit( 0, -1 );
}
if( gaThreads_NoTaskSwitch[CPU] )
return Last;
-
// Lock thread list
SHORTLOCK( &glThreadListLock );
}
// If we fall onto the same queue again, special handling is
// needed
- if( i == Last->Priority ) {
+ if( Last && Last->Status == THREAD_STAT_ACTIVE && i == Last->Priority ) {
tThread *savedThread = thread;
// Find the next unscheduled thread in the list
SHORTREL(&glThreadListLock);
return NULL;
}
+ if( thread->Status != THREAD_STAT_ACTIVE ) {
+ LogF("Oops, Thread %i (%s) is not active\n", thread->TID, thread->ThreadName);
+ }
}
#elif SCHEDULER_TYPE == SCHED_RR_SIM
{
// Make the new thread non-schedulable
thread->CurCPU = CPU;
+ thread->Remaining = thread->Quantum;
SHORTREL( &glThreadListLock );
#endif
SHORTREL( &Sem->Protector ); // Release first to make sure it is released
- SHORTREL( &glThreadListLock );
- while(us->Status == THREAD_STAT_SEMAPHORESLEEP) Threads_Yield();
+ SHORTREL( &glThreadListLock );
+ while( us->Status == THREAD_STAT_SEMAPHORESLEEP )
+ {
+ Threads_Yield();
+ if(us->Status == THREAD_STAT_SEMAPHORESLEEP)
+ Log_Warning("Threads", "Semaphore %p %s:%s re-schedulued while asleep",
+ Sem, Sem->ModName, Sem->Name);
+ }
+ #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
+ Log("Semaphore %p %s:%s woken", Sem, Sem->ModName, Sem->Name);
+ #endif
// We're only woken when there's something avaliable (or a signal arrives)
us->WaitPointer = NULL;
}
SHORTREL( &Sem->Protector );
+ #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
+ Log("Semaphore %p %s:%s took %i by wait",
+ Sem, Sem->ModName, Sem->Name, taken);
+ #endif
+
return taken;
}
#endif
// Wake the sleeper
- SHORTLOCK( &glThreadListLock );
+// SHORTLOCK( &glThreadListLock );
if( toWake->Status != THREAD_STAT_ACTIVE )
Threads_AddActive(toWake);
else
Warning("Thread %p (%i %s) is already awake", toWake, toWake->TID, toWake->ThreadName);
- SHORTREL( &glThreadListLock );
+// SHORTREL( &glThreadListLock );
}
SHORTREL( &Sem->Protector );