14IRX_ID(
"Multi_Thread_Manager", 2, 3);
25struct alarm *alarm_alloc()
28 if (list_empty(&thctx.alarm_pool)) {
31 alarm->tag.id = thctx.alarm_id;
33 alarm = list_first_entry(&thctx.alarm_pool,
struct alarm, alarm_list);
34 list_remove(&
alarm->alarm_list);
42 if (
alarm->tag.id >= 33) {
43 heap_free(&
alarm->tag);
45 list_insert(&thctx.alarm_pool, &
alarm->alarm_list);
53 list_for_each (i, list, alarm_list) {
54 if (
alarm->target < i->target) {
59 list_insert(&i->alarm_list, &
alarm->alarm_list);
66 list_remove(&
thread->queue);
68 weaker = list_first_entry(&
event->waiters,
struct thread, queue);
69 list_for_each (weaker, &
event->waiters, queue) {
70 if (priority < weaker->priority) {
75 list_insert(&weaker->queue, &
thread->queue);
78void update_timer_compare(
int timid, u64 time,
struct list_head *alarm_list)
80 struct alarm *prev, *i;
81 u32 counter, new_compare = 0;
84 prev = list_first_entry(alarm_list,
struct alarm, alarm_list);
86 if (!list_empty(alarm_list)) {
87 list_for_each (i, alarm_list, alarm_list) {
88 if (i->target >= prev->target + thctx.unk4c8) {
96 if (prev->target - time >= thctx.unk4c8) {
97 new_compare = prev->target;
99 counter = GetTimerCounter(timid);
100 new_compare = counter + thctx.unk4c8;
103 SetTimerCompare(timid, new_compare);
106unsigned int thread_delay_cb(
void *user)
110 list_remove(&
thread->queue);
111 thread->status = THS_READY;
112 readyq_insert_back(
thread);
113 thctx.run_next = NULL;
118int check_thread_stack()
121 stack_remaining = (u32)&stack_remaining - (u32)thctx.current_thread->stack_top;
123 if (stack_remaining < 0xa8) {
125 Kprintf(
"CheckThreadStack()\n");
126 thread_leave(0, 0, 0, 0);
129 return stack_remaining;
132void *heap_alloc(u16 tag, u32 bytes)
134 struct heaptag *ptr = AllocHeapMemory(thctx.heap, bytes);
136 memset(ptr, 0, bytes);
143int heap_free(
struct heaptag *tag)
146 return FreeHeapMemory(thctx.heap, tag);
158int thread_leave(
int ret1,
int ret2,
int intr_state,
int release)
160 register u32 a0 __asm__(
"a0") = ret1;
161 register u32 a1 __asm__(
"a1") = ret2;
162 register u32 a2 __asm__(
"a2") = intr_state;
163 register s32 result __asm__(
"v0");
166 thctx.current_thread->reason_counter = &thctx.current_thread->thread_preemption_count;
168 thctx.current_thread->reason_counter = &thctx.current_thread->release_count;
171 asm __volatile__(
"li $v0, 0x20\n"
174 :
"r"(a0),
"r"(a1),
"r"(a2)
182 if (
thread->priority < thctx.current_thread->priority) {
183 thctx.current_thread->status = THS_READY;
184 readyq_insert_front(thctx.current_thread);
188 return thread_leave(KE_OK, 0, intr_state, 0);
190 thread->status = THS_READY;
191 readyq_insert_back(
thread);
198int thread_init_and_start(
struct thread *
thread,
int intr_state)
204 thread->saved_regs->unk = -2;
207 thread->saved_regs->ra = (u32)ExitThread;
209 thread->saved_regs->sr = 0x404;
212 thread->saved_regs->I_CTRL = 1;
214 list_remove(&
thread->queue);
216 return thread_start(
thread, intr_state);
222 printf(
"\r\nIOP Realtime Kernel Ver. 2.2\r\n Copyright 1999-2002 (C) Sony Computer Entertainment Inc. \r\n");
229 ChangeThreadPriority(0, 126);
230 if (!next->callback) {
232 DelayThread(1000000);
241 u32 hi = thctx.time_hi;
242 u32 counter = GetTimerCounter(thctx.timer_id);
244 if (counter >= thctx.time_lo) {
245 thctx.time_lo = counter;
267 if ((x & 0x0000FFFF) == 0) {
271 if ((x & 0x000000FF) == 0) {
275 if ((x & 0x0000000F) == 0) {
279 if ((x & 0x00000003) == 0) {
288 for (
int i = 0; i < 4; i++) {
289 if (thctx.queue_map[i]) {
290 return ntz(thctx.queue_map[i]) + 32 * i;
302 Kprintf(
"\nThread (thid=%x, #%d) stack overflow\n Stack = %x, Stack size = %x, SP=%x\n",
309 img_info = FindImageInfo(
thread->entry);
311 name = img_info->name;
313 Kprintf(
" Module Name = %s\n", name);
320void do_delete_thread()
324 while (!list_empty(&thctx.delete_queue)) {
325 thread = list_first_entry(&thctx.delete_queue,
struct thread, queue);
326 if (
thread->attr & TH_CLEAR_STACK) {
330 FreeSysMemory(
thread->stack_top);
331 list_remove(&
thread->queue);
332 list_remove(&
thread->thread_list);
342 cur = thctx.current_thread;
343 thctx.run_next = thctx.current_thread;
345 prio = readyq_highest();
350 Kprintf(
"Panic: not found ready Thread\n");
354 new = list_first_entry(&thctx.ready_queue[prio],
struct thread, queue);
356 if (thctx.current_thread->status ==
THS_RUN) {
357 if (thctx.debug_flags & 4) {
358 Kprintf(
" THS_RUN cp=%d : hp=%d ", cur->priority, prio);
361 if (prio < cur->priority) {
362 if (thctx.debug_flags & 4) {
363 Kprintf(
" readyq = %x, newrun = %x:%d, prio = %d",
364 &thctx.ready_queue[prio],
370 readyq_remove(
new, prio);
372 thctx.run_next =
new;
373 cur->status = THS_READY;
374 readyq_insert_front(cur);
377 if (thctx.debug_flags & 4) {
378 Kprintf(
" not THS_RUN ");
380 Kprintf(
" readyq = %x, newrun = %x:%d, prio = %d",
381 &thctx.ready_queue[prio],
387 readyq_remove(
new, prio);
389 thctx.run_next =
new;
392 if ((thctx.debug_flags & 4) != 0)
401 if ((thctx.debug_flags & 3) != 0) {
402 if ((thctx.debug_flags & 3) == 1)
403 Kprintf(
"[%3d->", thctx.current_thread->tag.id);
404 if ((thctx.debug_flags & 3) == 2)
405 Kprintf(
"switch_context(%x:%x,pc=%x,ei=%x =>%x:%d)\n",
410 thctx.current_thread,
411 thctx.current_thread->tag.id);
414 thctx.current_thread->saved_regs = ctx;
415 if ((u32)ctx < (u32)thctx.current_thread->stack_top) {
416 report_stack_overflow(thctx.current_thread);
419 if (!thctx.run_next) {
420 if (!list_empty(&thctx.delete_queue)) {
427 if (thctx.current_thread == thctx.run_next) {
428 thctx.thread_resume_count++;
430 timer = thctx.timer_func();
431 new_time = add64(0, timer - thctx.last_timer, thctx.current_thread->run_clocks_hi, thctx.current_thread->run_clocks_lo);
433 thctx.current_thread->run_clocks_lo = (u32)new_time;
434 thctx.current_thread->run_clocks_hi = (u32)(new_time >> 32);
435 thctx.thread_switch_count++;
436 (*thctx.current_thread->reason_counter)++;
439 thctx.current_thread = thctx.run_next;
441 if ((thctx.debug_flags & 3) != 0) {
442 if ((thctx.debug_flags & 3) == 1)
443 Kprintf(
"%3d]", thctx.run_next->tag.id);
444 if ((thctx.debug_flags & 3) == 2)
445 Kprintf(
" switch_context --> %x:%x,pc=%x,ei=%x =>%x:%d\n",
446 thctx.run_next->saved_regs,
447 thctx.run_next->saved_regs->unk,
448 thctx.run_next->saved_regs->pc,
449 thctx.run_next->saved_regs->I_CTRL,
451 thctx.run_next->tag.id);
455 if (thctx.debug_flags & 0x20) {
456 _sw(~(1 << ((thctx.run_next->tag.id - 1) & 7)), 0xbf802070);
459 return thctx.run_next->saved_regs;
462int preempt_cb(
int unk)
464 if (thctx.run_next != thctx.current_thread) {
465 thctx.current_thread->reason_counter = &thctx.current_thread->irq_preemption_count;
478int timer_handler(
void *user)
482 u32 status, counter, ret;
485 status = GetTimerStatus(thctx->timer_id);
486 counter = GetTimerCounter(thctx->timer_id);
489 if (status & 0x1000) {
491 thctx->time_lo = counter;
495 if (status & 0x800) {
496 list_for_each_safe (
alarm, &thctx->alarm, alarm_list) {
497 counter = GetTimerCounter(thctx->timer_id);
498 status = GetTimerStatus(thctx->timer_id);
499 if (counter < thctx->time_lo && (status & 0x1000)) {
501 thctx->time_lo = counter;
504 time = as_u64(thctx->time_hi, counter);
505 if (time < alarm->target) {
510 list_remove(&
alarm->alarm_list);
512 if (
alarm->tag.id == 1) {
513 alarm->target += 0x100000000;
518 thctx->alarm_count--;
522 if (ret < thctx->min_wait) {
523 ret = thctx->min_wait;
526 alarm->target += ret;
529 alarm_insert(&thctx->alarm,
alarm);
532 update_timer_compare(thctx->timer_id, time, &thctx->alarm);
543 s32 timer_id, timer_irq;
548 thctx.unk_clock_mult = 0x1200;
549 thctx.unk_clock_div = 125;
551 bootmode = QueryBootMode(7);
552 if (bootmode && *bootmode == 200) {
553 thctx.unk_clock_mult = 25;
554 thctx.unk_clock_div = 1;
557 USec2SysClock(100, &compare);
559 thctx.min_wait = compare.lo;
560 thctx.unk4c8 = 2 * compare.lo;
562 timer_id = AllocHardTimer(1, 32, 1);
563 thctx.timer_id = timer_id;
564 thctx.timer_func = GetTimerReadFunc(timer_id);
565 timer_irq = GetHardTimerIntrCode(timer_id);
568 list_init(&thctx.alarm);
569 list_init(&thctx.alarm_pool);
572 alarm = alarm_alloc();
573 list_insert(&thctx.alarm, &
alarm->alarm_list);
574 USec2SysClock(2000, &compare);
576 alarm->target = 0x100000000LL - compare.lo;
578 thctx.alarm_count = 1;
580 for (
int i = 0; i < 32; i++) {
583 alarm->tag.id = thctx.alarm_id;
587 SetTimerMode(timer_id, 0);
588 SetTimerCompare(timer_id, compare.lo);
589 SetTimerCounter(timer_id, 0);
590 SetTimerMode(timer_id, 0x70);
596int _start(
int argc,
char **argv)
598 struct thread *idle, *current;
604 if (RegisterNonAutoLinkEntries(&_exp_thrdman)) {
605 return MODULE_NO_RESIDENT_END;
608 if (RegisterLibraryEntries(&_exp_thbase)) {
609 return MODULE_NO_RESIDENT_END;
613 RegisterLibraryEntries(&_exp_thevent);
614 RegisterLibraryEntries(&_exp_thsemap);
615 RegisterLibraryEntries(&_exp_thmsgbx);
616 RegisterLibraryEntries(&_exp_thfpool);
617 RegisterLibraryEntries(&_exp_thvpool);
619 memset(&thctx, 0,
sizeof(thctx));
620 thctx.debug_flags = DEBUG_FLAGS;
622 list_init(&thctx.semaphore);
623 list_init(&thctx.event_flag);
624 list_init(&thctx.mbox);
625 list_init(&thctx.vpool);
626 list_init(&thctx.fpool);
627 list_init(&thctx.sleep_queue);
628 list_init(&thctx.delay_queue);
631 list_init(&thctx.dormant_queue);
632 list_init(&thctx.delete_queue);
633 list_init(&thctx.thread_list);
635 for (
int i = 0; i < 128; i++) {
636 list_init(&thctx.ready_queue[i]);
639 thctx.heap = CreateHeap(2048, 1);
642 idle = heap_alloc(TAG_THREAD,
sizeof(*idle));
643 idle->tag.id = ++thctx.thread_id;
644 idle->stack_size = 512;
645 idle->stack_top = AllocSysMemory(1, 512, 0);
646 idle->init_priority = 127;
647 idle->priority = 127;
649 idle->status = THS_READY;
650 idle->entry = idle_thread;
651 idle->saved_regs = idle->stack_top + (((idle->stack_size << 2) >> 2) - RESERVED_REGCTX_SIZE);
652 memset(idle->saved_regs, 0, RESERVED_REGCTX_SIZE);
654 asm __volatile__(
"sw $gp, %0\n"
657 idle->saved_regs->unk = -2;
658 idle->saved_regs->sp = (u32)&idle->saved_regs[1];
659 idle->saved_regs->gp = idle->gp;
660 idle->saved_regs->fp = idle->saved_regs->sp;
661 idle->saved_regs->ra = (u32)ExitThread;
662 idle->saved_regs->sr = (idle->attr & 0xF0000000) | 0x404;
663 idle->saved_regs->sr |= idle->attr & 8;
664 idle->saved_regs->pc = (u32)idle->entry;
665 idle->saved_regs->I_CTRL = 1;
667 list_insert(&thctx.thread_list, &idle->thread_list);
668 thctx.idle_thread = idle;
669 readyq_insert_back(idle);
672 current = heap_alloc(TAG_THREAD,
sizeof(*current));
673 current->tag.id = ++thctx.thread_id;
676 current->stack_size = QueryBlockSize(&i);
677 current->stack_top = QueryBlockTopAddress(&i);
678 current->init_priority = 8;
679 current->priority = 1;
680 current->attr = TH_C;
683 asm __volatile__(
"sw $gp, %0\n"
684 :
"=m"(current->gp)::);
686 list_insert(&thctx.thread_list, ¤t->thread_list);
687 thctx.current_thread = current;
688 thctx.run_next = current;
689 current->queue.next = NULL;
690 current->queue.prev = NULL;
693 SetShouldPreemptCb(preempt_cb);
699 thctx.sytem_status_flag = CreateEventFlag(&flag);
701 BootMode = QueryBootMode(4);
703 SetEventFlag(thctx.sytem_status_flag, 1 << (*BootMode & 3));
706 RegisterPostBootCallback(post_boot_callback_1, 2, 0);
707 RegisterPostBootCallback(post_boot_callback_2, 3, 0);
712 return MODULE_RESIDENT_END;
int CpuResumeIntr(int state)
int RegisterIntrHandler(int irq, int mode, int(*handler)(void *), void *arg)
void SetNewCtxCb(void *cb)
int CpuSuspendIntr(int *state)