Some interesting facts : ------------------------- - threads are rescheduled after every interrupt, in dispatch handler - same priorities are controlled by "round robin" // ---------------------------------------------------------------------------- struct OSThread { // theese offsets are correct (see os/OSContext.h) OSContext context; +0 { u32 gpr[32]; +0 u32 cr; +128 u32 lr; +132 u32 ctr; +136 u32 xer; +140 f64 fpr[32]; +144 u32 fpscr_pad; +400 u32 fpscr; +404 u32 srr0; +408 u32 srr1; +412 u16 mode; +416 u16 state; +418 u32 gqr[8]; +420 f64 psf[32]; +456 } OSContext; // all offsets are correct u16 state; +712 u16 attr; +714 s32 suspend; +716 OSPriority priority; +720 OSPriority base; +724 void* val; +728 OSThreadQueue* queue; +732 OSThreadLink link; OSThread* next; +736 OSThread* prev; +740 OSThreadQueue queueJoin; OSThread* head; +744 OSThread* tail; +748 OSMutex* mutex; +752 OSMutexQueue queueMutex; OSMutex* head; +756 OSMutex* tail; +760 OSThreadLink linkActive; OSThread* next; +764 OSThread* prev; +768 u8* stackBase; +772 u32* stackEnd; +776 }; // definitions, locals etc static u32 RunQueueBits; static BOOL RunQueueHint; static s32 Reschedule; OSThreadQueue RunQueue[32]; OSThread IdleThread; // +256 OSThread DefaultThread; // +1040 OSContext IdleContext; // +1824 // from os/OSLoMem.h OSThread *__OSDefaultThread AT_ADDRESS(OS_BASE_CACHED | 0x00D8); OSThreadLink __OSLinkActive AT_ADDRESS(OS_BASE_CACHED | 0x00DC); OSThread *__OSCurrentThread AT_ADDRESS(OS_BASE_CACHED | 0x00E4); // ---------------------------------------------------------------------------- // OSThread.c // TODO : check teh damn offsets void __OSThreadInit(void) { OSThread *thread; OSPriority prio; DefaultThread.state = OS_THREAD_STATE_RUNNING; DefaultThread.attr = OS_THREAD_ATTR_DETACH; DefaultThread.priority = DefaultThread.base = 16; DefaultThread.suspend = 0; DefaultThread.val = (void *)0xffffffff; DefaultThread.mutex = NULL; OSInitThreadQueue(&DefaultThread.queueJoin); DefaultThread.queueMutex.head = DefaultThread.queueMutex.tail = NULL; __OSDefaultThread = &DefaultThread; OSClearContext(&DefaultThread.context); OSSetCurrentContext(&DefaultThread.context); DefaultThread.stackBase = _stack_addr; DefaultThread.stackEnd = _stack_end; *DefaultThread.stackEnd = OS_THREAD_STACK_MAGIC; RunQueueHint = FALSE; RunQueueBits = 0; __OSCurrentThread = &DefaultThread; for(prio=OS_PRIORITY_MIN; prio<=OS_PRIORITY_MAX; prio++) { OSInitThreadQueue(&RunQueue[prio]); } // // start active threads queue // OSInitThreadQueue(&__OSLinkActive); if((thread = __OSLinkActive.tail) == NULL) { __OSLinkActive.head = &DefaultThread; } else { thread.next = &DefaultThread; } DefaultThread.prev = thread; DefaultThread.next = NULL; __OSLinkActive.tail = &DefaultThread; OSClearContext(&IdleContext.context); Reschedule = 0; } void OSInitThreadQueue(OSThreadQueue *queue) { queue->head = queue->tail = NULL; } OSThread *OSGetCurrentThread(void) { return __OSCurrentThread; } void __OSSwitchThread(OSThread *nextThread) { __OSCurrentThread = nextThread; OSSetCurrentContext(nextThread->context); OSLoadContext(nextThread->context); } BOOL OSIsThreadSuspended(OSThread *thread) { return (thread->suspend > 0) ? (TRUE) : (FALSE); } BOOL OSIsThreadTerminated(OSThread *thread) { return (thread->state == OS_THREAD_STATE_MORIBUND) ? ( TRUE ) : ( (thread->state == 0) ? ( TRUE ) : ( FALSE ); ) ; } BOOL __OSIsThreadActive(OSThread *thread) { OSThread *active; if(thread->state != 0) { return FALSE; } // // try to find thread in active threads // active = __OSLinkActive.head while(active) { // our thread is in active threads queue if(active == thread) { return TRUE; } // get next thread from list active = active->linkActive.next; } // this thread isn't active return FALSE; } s32 OSDisableScheduler() { BOOL enabled = OSDisableInterrupts(); s32 count = Reschedule++; OSRestoreInterrupts(enabled); return count; } s32 OSEnableScheduler() { BOOL enabled = OSDisableInterrupts(); s32 count = Reschedule--; OSRestoreInterrupts(enabled); return count; } void SetRun(OSThread *thread) { OSThread *__prev; thread->queue = &RunQueue[thread->priority]; if((__prev = thread->queue.tail) == NULL) { thread->queue.head = thread; } else { __prev->link.next = thread; } thread->link.prev = __prev; thread->link.next = NULL; thread->queue->prev = thread; RunQueueBits |= 1 << (31 - thread->priotity); RunQueueHint = TRUE; }