15 IRX_ID(
"Multi_Thread_Manager", 2, 3);
26 struct alarm *alarm_alloc()
29 if (list_empty(&thctx.alarm_pool)) {
32 alarm->tag.id = thctx.alarm_id;
34 alarm = list_first_entry(&thctx.alarm_pool,
struct alarm, alarm_list);
35 list_remove(&
alarm->alarm_list);
43 if (
alarm->tag.id >= 33) {
44 heap_free(&
alarm->tag);
46 list_insert(&thctx.alarm_pool, &
alarm->alarm_list);
54 list_for_each (i, list, alarm_list) {
55 if (
alarm->target < i->target) {
60 list_insert(&i->alarm_list, &
alarm->alarm_list);
67 list_remove(&
thread->queue);
69 weaker = list_first_entry(&
event->waiters,
struct thread, queue);
70 list_for_each (weaker, &
event->waiters, queue) {
71 if (priority < weaker->priority) {
76 list_insert(&weaker->queue, &
thread->queue);
79 void update_timer_compare(
int timid, u64 time,
struct list_head *alarm_list)
81 struct alarm *prev, *i;
82 u32 counter, new_compare = 0;
85 prev = list_first_entry(alarm_list,
struct alarm, alarm_list);
87 if (!list_empty(alarm_list)) {
88 list_for_each (i, alarm_list, alarm_list) {
89 if (i->target >= prev->target + thctx.unk4c8) {
97 if (prev->target - time >= thctx.unk4c8) {
98 new_compare = prev->target;
100 counter = GetTimerCounter(timid);
101 new_compare = counter + thctx.unk4c8;
104 SetTimerCompare(timid, new_compare);
107 unsigned int thread_delay_cb(
void *user)
111 list_remove(&
thread->queue);
112 thread->status = THS_READY;
113 readyq_insert_back(
thread);
114 thctx.run_next = NULL;
119 int check_thread_stack()
122 stack_remaining = (u32)&stack_remaining - (u32)thctx.current_thread->stack_top;
124 if (stack_remaining < 0xa8) {
126 Kprintf(
"CheckThreadStack()\n");
127 thread_leave(0, 0, 0, 0);
130 return stack_remaining;
133 void *heap_alloc(u16 tag, u32 bytes)
135 struct heaptag *ptr = AllocHeapMemory(thctx.heap, bytes);
137 memset(ptr, 0, bytes);
144 int heap_free(
struct heaptag *tag)
147 return FreeHeapMemory(thctx.heap, tag);
159 int thread_leave(
int ret1,
int ret2,
int intr_state,
int release)
161 register u32 a0 __asm__(
"a0") = ret1;
162 register u32 a1 __asm__(
"a1") = ret2;
163 register u32 a2 __asm__(
"a2") = intr_state;
164 register s32 result __asm__(
"v0");
167 thctx.current_thread->reason_counter = &thctx.current_thread->thread_preemption_count;
169 thctx.current_thread->reason_counter = &thctx.current_thread->release_count;
172 __asm__ __volatile__(
"li $v0, 0x20\n"
175 :
"r"(a0),
"r"(a1),
"r"(a2)
183 if (
thread->priority < thctx.current_thread->priority) {
184 thctx.current_thread->status = THS_READY;
185 readyq_insert_front(thctx.current_thread);
189 return thread_leave(KE_OK, 0, intr_state, 0);
191 thread->status = THS_READY;
192 readyq_insert_back(
thread);
199 int thread_init_and_start(
struct thread *
thread,
int intr_state)
205 thread->saved_regs->unk = -2;
208 thread->saved_regs->ra = (u32)ExitThread;
210 thread->saved_regs->sr = 0x404;
213 thread->saved_regs->I_CTRL = 1;
215 list_remove(&
thread->queue);
217 return thread_start(
thread, intr_state);
223 printf(
"\r\nIOP Realtime Kernel Ver. 2.2\r\n Copyright 1999-2002 (C) Sony Computer Entertainment Inc. \r\n");
230 ChangeThreadPriority(
TH_SELF, 126);
231 if (!next->callback) {
233 DelayThread(1000000);
242 u32 hi = thctx.time_hi;
243 u32 counter = GetTimerCounter(thctx.timer_id);
245 if (counter >= thctx.time_lo) {
246 thctx.time_lo = counter;
261 static u32 ntz(u32 x)
268 if ((x & 0x0000FFFF) == 0) {
272 if ((x & 0x000000FF) == 0) {
276 if ((x & 0x0000000F) == 0) {
280 if ((x & 0x00000003) == 0) {
289 for (
int i = 0; i < 4; i++) {
290 if (thctx.queue_map[i]) {
291 return ntz(thctx.queue_map[i]) + 32 * i;
303 Kprintf(
"\nThread (thid=%x, #%d) stack overflow\n Stack = %x, Stack size = %x, SP=%x\n",
310 img_info = FindImageInfo(
thread->entry);
312 name = img_info->name;
314 Kprintf(
" Module Name = %s\n", name);
321 void do_delete_thread()
325 while (!list_empty(&thctx.delete_queue)) {
326 thread = list_first_entry(&thctx.delete_queue,
struct thread, queue);
327 if (
thread->attr & TH_CLEAR_STACK) {
331 FreeSysMemory(
thread->stack_top);
332 list_remove(&
thread->queue);
333 list_remove(&
thread->thread_list);
340 struct thread *cur, *new_;
343 cur = thctx.current_thread;
344 thctx.run_next = thctx.current_thread;
346 prio = readyq_highest();
351 Kprintf(
"Panic: not found ready Thread\n");
355 new_ = list_first_entry(&thctx.ready_queue[prio],
struct thread, queue);
357 if (thctx.current_thread->status ==
THS_RUN) {
358 if (thctx.debug_flags & 4) {
359 Kprintf(
" THS_RUN cp=%d : hp=%d ", cur->priority, prio);
362 if (prio < cur->priority) {
363 if (thctx.debug_flags & 4) {
364 Kprintf(
" readyq = %x, newrun = %x:%d, prio = %d",
365 &thctx.ready_queue[prio],
371 readyq_remove(new_, prio);
373 thctx.run_next = new_;
374 cur->status = THS_READY;
375 readyq_insert_front(cur);
378 if (thctx.debug_flags & 4) {
379 Kprintf(
" not THS_RUN ");
381 Kprintf(
" readyq = %x, newrun = %x:%d, prio = %d",
382 &thctx.ready_queue[prio],
388 readyq_remove(new_, prio);
390 thctx.run_next = new_;
393 if ((thctx.debug_flags & 4) != 0)
402 if ((thctx.debug_flags & 3) != 0) {
403 if ((thctx.debug_flags & 3) == 1)
404 Kprintf(
"[%3d->", thctx.current_thread->tag.id);
405 if ((thctx.debug_flags & 3) == 2)
406 Kprintf(
"switch_context(%x:%x,pc=%x,ei=%x =>%x:%d)\n",
411 thctx.current_thread,
412 thctx.current_thread->tag.id);
415 thctx.current_thread->saved_regs = ctx;
416 if ((u32)ctx < (u32)thctx.current_thread->stack_top) {
417 report_stack_overflow(thctx.current_thread);
420 if (!thctx.run_next) {
421 if (!list_empty(&thctx.delete_queue)) {
428 if (thctx.current_thread == thctx.run_next) {
429 thctx.thread_resume_count++;
431 timer = thctx.timer_func();
432 new_time = add64(0, timer - thctx.last_timer, thctx.current_thread->run_clocks_hi, thctx.current_thread->run_clocks_lo);
434 thctx.current_thread->run_clocks_lo = (u32)new_time;
435 thctx.current_thread->run_clocks_hi = (u32)(new_time >> 32);
436 thctx.thread_switch_count++;
437 (*thctx.current_thread->reason_counter)++;
440 thctx.current_thread = thctx.run_next;
442 if ((thctx.debug_flags & 3) != 0) {
443 if ((thctx.debug_flags & 3) == 1)
444 Kprintf(
"%3d]", thctx.run_next->tag.id);
445 if ((thctx.debug_flags & 3) == 2)
446 Kprintf(
" switch_context --> %x:%x,pc=%x,ei=%x =>%x:%d\n",
447 thctx.run_next->saved_regs,
448 thctx.run_next->saved_regs->unk,
449 thctx.run_next->saved_regs->pc,
450 thctx.run_next->saved_regs->I_CTRL,
452 thctx.run_next->tag.id);
456 if (thctx.debug_flags & 0x20) {
457 _sw(~(1 << ((thctx.run_next->tag.id - 1) & 7)), 0xbf802070);
460 return thctx.run_next->saved_regs;
463 int preempt_cb(
int unk)
465 if (thctx.run_next != thctx.current_thread) {
466 thctx.current_thread->reason_counter = &thctx.current_thread->irq_preemption_count;
479 int timer_handler(
void *user)
483 u32 status, counter, ret;
486 status = GetTimerStatus(thctx->timer_id);
487 counter = GetTimerCounter(thctx->timer_id);
490 if (status & 0x1000) {
492 thctx->time_lo = counter;
496 if (status & 0x800) {
497 list_for_each_safe (
alarm, &thctx->alarm, alarm_list) {
498 counter = GetTimerCounter(thctx->timer_id);
499 status = GetTimerStatus(thctx->timer_id);
500 if (counter < thctx->time_lo && (status & 0x1000)) {
502 thctx->time_lo = counter;
505 time = as_u64(thctx->time_hi, counter);
506 if (time < alarm->target) {
511 list_remove(&
alarm->alarm_list);
513 if (
alarm->tag.id == 1) {
514 alarm->target += 0x100000000;
519 thctx->alarm_count--;
523 if (ret < thctx->min_wait) {
524 ret = thctx->min_wait;
527 alarm->target += ret;
530 alarm_insert(&thctx->alarm,
alarm);
533 update_timer_compare(thctx->timer_id, time, &thctx->alarm);
544 s32 timer_id, timer_irq;
549 thctx.unk_clock_mult = 0x1200;
550 thctx.unk_clock_div = 125;
552 bootmode = QueryBootMode(7);
553 if (bootmode && *bootmode == 200) {
554 thctx.unk_clock_mult = 25;
555 thctx.unk_clock_div = 1;
558 USec2SysClock(100, &compare);
560 thctx.min_wait = compare.lo;
561 thctx.unk4c8 = 2 * compare.lo;
563 timer_id = AllocHardTimer(1, 32, 1);
564 thctx.timer_id = timer_id;
565 thctx.timer_func = GetTimerReadFunc(timer_id);
566 timer_irq = GetHardTimerIntrCode(timer_id);
569 list_init(&thctx.alarm);
570 list_init(&thctx.alarm_pool);
573 alarm = alarm_alloc();
574 list_insert(&thctx.alarm, &
alarm->alarm_list);
575 USec2SysClock(2000, &compare);
577 alarm->target = 0x100000000LL - compare.lo;
579 thctx.alarm_count = 1;
581 for (
int i = 0; i < 32; i++) {
584 alarm->tag.id = thctx.alarm_id;
588 SetTimerMode(timer_id, 0);
589 SetTimerCompare(timer_id, compare.lo);
590 SetTimerCounter(timer_id, 0);
591 SetTimerMode(timer_id, 0x70);
597 int _start(
int argc,
char **argv)
599 struct thread *idle, *current;
605 if (RegisterNonAutoLinkEntries(&_exp_thrdman)) {
606 return MODULE_NO_RESIDENT_END;
609 if (RegisterLibraryEntries(&_exp_thbase)) {
610 return MODULE_NO_RESIDENT_END;
614 RegisterLibraryEntries(&_exp_thevent);
615 RegisterLibraryEntries(&_exp_thsemap);
616 RegisterLibraryEntries(&_exp_thmsgbx);
617 RegisterLibraryEntries(&_exp_thfpool);
618 RegisterLibraryEntries(&_exp_thvpool);
620 memset(&thctx, 0,
sizeof(thctx));
621 thctx.debug_flags = DEBUG_FLAGS;
623 list_init(&thctx.semaphore);
624 list_init(&thctx.event_flag);
625 list_init(&thctx.mbox);
626 list_init(&thctx.vpool);
627 list_init(&thctx.fpool);
628 list_init(&thctx.sleep_queue);
629 list_init(&thctx.delay_queue);
632 list_init(&thctx.dormant_queue);
633 list_init(&thctx.delete_queue);
634 list_init(&thctx.thread_list);
636 for (
int i = 0; i < 128; i++) {
637 list_init(&thctx.ready_queue[i]);
640 thctx.heap = CreateHeap(2048, 1);
643 idle = heap_alloc(TAG_THREAD,
sizeof(*idle));
644 idle->tag.id = ++thctx.thread_id;
645 idle->stack_size = 512;
646 idle->stack_top = AllocSysMemory(1, 512, 0);
647 idle->init_priority = 127;
648 idle->priority = 127;
650 idle->status = THS_READY;
651 idle->entry = idle_thread;
652 idle->saved_regs = idle->stack_top + (((idle->stack_size << 2) >> 2) - RESERVED_REGCTX_SIZE);
653 memset(idle->saved_regs, 0, RESERVED_REGCTX_SIZE);
656 idle->saved_regs->unk = -2;
657 idle->saved_regs->sp = (u32)&idle->saved_regs[1];
658 idle->saved_regs->gp = (u32)idle->gp;
659 idle->saved_regs->fp = idle->saved_regs->sp;
660 idle->saved_regs->ra = (u32)ExitThread;
661 idle->saved_regs->sr = (idle->attr & 0xF0000000) | 0x404;
662 idle->saved_regs->sr |= idle->attr & 8;
663 idle->saved_regs->pc = (u32)idle->entry;
664 idle->saved_regs->I_CTRL = 1;
666 list_insert(&thctx.thread_list, &idle->thread_list);
667 thctx.idle_thread = idle;
668 readyq_insert_back(idle);
671 current = heap_alloc(TAG_THREAD,
sizeof(*current));
672 current->tag.id = ++thctx.thread_id;
675 current->stack_size = QueryBlockSize(&i);
676 current->stack_top = QueryBlockTopAddress(&i);
677 current->init_priority = 8;
678 current->priority = 1;
679 current->attr = TH_C;
681 current->gp = GetGP();
683 list_insert(&thctx.thread_list, ¤t->thread_list);
684 thctx.current_thread = current;
685 thctx.run_next = current;
686 current->queue.next = NULL;
687 current->queue.prev = NULL;
690 SetShouldPreemptCb(preempt_cb);
696 thctx.sytem_status_flag = CreateEventFlag(&flag);
698 BootMode = QueryBootMode(4);
700 SetEventFlag(thctx.sytem_status_flag, 1 << (*BootMode & 3));
703 RegisterPostBootCallback(post_boot_callback_1, 2, 0);
704 RegisterPostBootCallback(post_boot_callback_2, 3, 0);
709 return MODULE_RESIDENT_END;