sdk-core v2026.11.05
PS2 SDK - core tier (build-critical EE/IOP modules)
Loading...
Searching...
No Matches
thbase.c
1#include "thbase.h"
2#include "loadcore.h"
3#include "sysclib.h"
4#include "sysmem.h"
5#include "kerr.h"
6#include "intrman.h"
7#include "thsemap.h"
8#include "xthbase.h"
9#include "xtimrman.h"
10#include <defs.h>
11
12#include "thcommon.h"
13
14static void clock_mul(iop_sys_clock_t *dst, iop_sys_clock_t *src, u32 mul);
15static void clock_div(iop_sys_clock_t *dst, iop_sys_clock_t *src, u32 d, u32 *r);
16
17static struct thread *refer_thread(int thid, int current);
18
19static void thread_get_run_stats(struct thread *thread, iop_thread_run_status_t *stat);
20static void thread_get_status(struct thread *thread, iop_thread_info_t *info);
21
22struct thread_context *GetThreadCtx()
23{
24 return &thctx;
25}
26
27int CreateThread(iop_thread_t *thparam)
28{
29 struct thread *thread;
30 void *stack;
31 int state;
32
33 if (QueryIntrContext()) {
34 return KE_ILLEGAL_CONTEXT;
35 }
36
37 if (thparam->attr & ~(TH_ASM | TH_C | TH_UMODE | TH_NO_FILLSTACK | TH_CLEAR_STACK)) {
38 return KE_ILLEGAL_ATTR;
39 }
40
41 if (thparam->priority > 126) {
42 return KE_ILLEGAL_PRIORITY;
43 }
44
45 if ((u32)thparam->thread & 3) {
46 return KE_ILLEGAL_ENTRY;
47 }
48
49 if (thparam->stacksize < 0x130) {
50 return KE_ILLEGAL_STACK_SIZE;
51 }
52
53 CpuSuspendIntr(&state);
54
55 thread = heap_alloc(TAG_THREAD, sizeof(*thread));
56 if (!thread) {
57 CpuResumeIntr(state);
58 return KE_NO_MEMORY;
59 }
60
61 thparam->stacksize = ALIGN_256(thparam->stacksize);
62 stack = AllocSysMemory(1, thparam->stacksize, 0);
63 if (!stack) {
64 heap_free(&thread->tag);
65 CpuResumeIntr(state);
66 return KE_NO_MEMORY;
67 }
68
69 thread->tag.id = ++thctx.thread_id;
70 thread->entry = thparam->thread;
71 thread->stack_size = thparam->stacksize;
72 thread->stack_top = stack;
73 thread->init_priority = thparam->priority;
74 thread->attr = thparam->attr;
75 thread->option = thparam->option;
76 thread->status = THS_DORMANT;
77 thread->gp = GetGP();
78
79 list_insert(&thctx.thread_list, &thread->thread_list);
80
81 if ((thread->attr & TH_NO_FILLSTACK) == 0) {
82 // why -0x30?
83 memset(thread->stack_top, 0xff, thread->stack_size - 0x30);
84 }
85
86 CpuResumeIntr(state);
87
88 return MAKE_HANDLE(thread);
89}
90
91int DeleteThread(int thid)
92{
93 struct thread *thread;
94 int state;
95
96 if (QueryIntrContext()) {
97 return KE_ILLEGAL_CONTEXT;
98 }
99
100 if (thid == 0) {
101 return KE_ILLEGAL_THID;
102 }
103
104 CpuSuspendIntr(&state);
105
106 thread = HANDLE_PTR(thid);
107 if (!HANDLE_VERIFY(thid, TAG_THREAD) || thread == thctx.idle_thread) {
108 CpuResumeIntr(state);
109 return KE_UNKNOWN_THID;
110 }
111
112 if (thread->status != THS_DORMANT) {
113 CpuResumeIntr(state);
114 return KE_NOT_DORMANT;
115 }
116
117 if (thread->attr & TH_CLEAR_STACK) {
118 memset(thread->stack_top, 0, thread->stack_size);
119 }
120
121 FreeSysMemory(thread->stack_top);
122 list_remove(&thread->queue);
123 list_remove(&thread->thread_list);
124 heap_free(&thread->tag);
125
126 CpuResumeIntr(state);
127
128 return KE_OK;
129}
130
131int StartThread(int thid, void *arg)
132{
133 struct thread *thread;
134 u32 reg_offset;
135 int state;
136
137 if (QueryIntrContext()) {
138 return KE_ILLEGAL_CONTEXT;
139 }
140
141 if (thid == 0) {
142 return KE_ILLEGAL_THID;
143 }
144
145 CpuSuspendIntr(&state);
146
147 thread = HANDLE_PTR(thid);
148 if (!HANDLE_VERIFY(thid, TAG_THREAD)) {
149 CpuResumeIntr(state);
150 return KE_UNKNOWN_THID;
151 }
152
153 if (thread->status != THS_DORMANT) {
154 CpuResumeIntr(state);
155 return KE_NOT_DORMANT;
156 }
157
158 // zero out register state
159 reg_offset = ALIGN(thread->stack_size) - RESERVED_REGCTX_SIZE;
160 thread->saved_regs = thread->stack_top + reg_offset;
161 memset(thread->saved_regs, 0, RESERVED_REGCTX_SIZE);
162
163 thread->saved_regs->a0 = (u32)arg;
164
165 return thread_init_and_start(thread, state);
166}
167
168int StartThreadArgs(int thid, int args, void *argp)
169{
170 struct thread *thread;
171 u32 arg_offset, reg_offset;
172 int state;
173
174 if (QueryIntrContext()) {
175 return KE_ILLEGAL_CONTEXT;
176 }
177
178 if (thid == 0) {
179 return KE_ILLEGAL_THID;
180 }
181
182 CpuSuspendIntr(&state);
183
184 thread = HANDLE_PTR(thid);
185 if (!HANDLE_VERIFY(thid, TAG_THREAD)) {
186 CpuResumeIntr(state);
187 return KE_UNKNOWN_THID;
188 }
189
190 if (thread->status != THS_DORMANT) {
191 CpuResumeIntr(state);
192 return KE_NOT_DORMANT;
193 }
194
195 // stash the args at the bottom of stack
196 arg_offset = ALIGN(thread->stack_size) - ALIGN(args);
197 if (args > 0 && argp) {
198 memcpy(thread->stack_top + arg_offset, argp, args);
199 }
200
201 // BUG: memset was done before setting saved_regs in the struct
202 // would probably derefence null on a newly created thread
203 // memset(thread->saved_regs, 0, RESERVED_REGCTX_SIZE);
204
205 reg_offset = arg_offset - RESERVED_REGCTX_SIZE;
206 thread->saved_regs = thread->stack_top + reg_offset;
207
208 memset(thread->saved_regs, 0, RESERVED_REGCTX_SIZE);
209
210 thread->saved_regs->a0 = args;
211 thread->saved_regs->a1 = (u32)thread->stack_top + arg_offset;
212
213 return thread_init_and_start(thread, state);
214}
215
216int ExitThread()
217{
218 int state;
219
220 if (QueryIntrContext()) {
221 return KE_ILLEGAL_CONTEXT;
222 }
223
224 CpuSuspendIntr(&state);
225 thctx.current_thread->status = THS_DORMANT;
226 list_insert(&thctx.dormant_queue, &thctx.current_thread->queue);
227 thctx.run_next = NULL;
228 thread_leave(0, 0, state, 1);
229
230 Kprintf("panic ! Thread DORMANT !\n");
231 __builtin_trap();
232
233 return KE_OK;
234}
235
236int ExitDeleteThread()
237{
238 int state;
239
240 if (QueryIntrContext()) {
241 return KE_ILLEGAL_CONTEXT;
242 }
243
244 CpuSuspendIntr(&state);
245 thctx.current_thread->status = THS_DORMANT;
246 list_insert(&thctx.delete_queue, &thctx.current_thread->queue);
247 thctx.run_next = NULL;
248 thread_leave(0, 0, state, 1);
249
250 Kprintf("panic ! Thread ExitDeleted !\n");
251 __builtin_trap();
252
253 return KE_OK;
254}
255
256int TerminateThread(int thid)
257{
258 struct thread *thread;
259 int state;
260
261 if (QueryIntrContext()) {
262 return KE_ILLEGAL_CONTEXT;
263 }
264
265 CpuSuspendIntr(&state);
266
267 thread = HANDLE_PTR(thid);
268 if (!HANDLE_VERIFY(thid, TAG_THREAD)) {
269 CpuResumeIntr(state);
270 return KE_UNKNOWN_THID;
271 }
272
273 if (thread->status == THS_DORMANT) {
274 CpuResumeIntr(state);
275 return KE_DORMANT;
276 }
277
278 if (thread->status == THS_READY) {
279 readyq_remove(thread, thread->priority);
280 } else {
281 list_remove(&thread->queue);
282 if (thread->wait_type == TSW_DELAY) {
283 CancelAlarm(thread_delay_cb, thread);
284 } else if (thread->wait_type >= TSW_DELAY && thread->wait_type <= TSW_FPL) {
285 thread->wait_event->waiter_count--;
286 }
287 }
288
289 thread->status = THS_DORMANT;
290 list_insert(&thctx.dormant_queue, &thread->queue);
291
292 CpuResumeIntr(state);
293 return KE_OK;
294}
295
296int iTerminateThread(int thid)
297{
298 struct thread *thread;
299
300 if (!QueryIntrContext()) {
301 return KE_ILLEGAL_CONTEXT;
302 }
303
304 if (thid == 0) {
305 return KE_ILLEGAL_THID;
306 }
307
308 thread = HANDLE_PTR(thid);
309 if (!HANDLE_VERIFY(thid, TAG_THREAD)) {
310 return KE_UNKNOWN_THID;
311 }
312
313 if (thread->status == THS_DORMANT) {
314 return KE_DORMANT;
315 }
316
317 if (thread == thctx.current_thread) {
318 thctx.run_next = NULL;
319 } else {
320 if (thread->status == THS_READY) {
321 readyq_remove(thread, thread->priority);
322 } else {
323 list_remove(&thread->queue);
324
325 if (thread->status == THS_WAIT) {
326 if (thread->wait_type == TSW_DELAY) {
327 iCancelAlarm(thread_delay_cb, thread);
328 } else {
329 thread->wait_event->waiter_count--;
330 }
331 }
332 }
333 }
334
335 thread->status = THS_DORMANT;
336 list_insert(&thctx.dormant_queue, &thread->queue);
337
338 return KE_OK;
339}
340
341int DisableDispatchThread(void)
342{
343 return KE_ERROR;
344}
345
346int EnableDispatchThread(void)
347{
348 return KE_ERROR;
349}
350
351int ChangeThreadPriority(int thid, int priority)
352{
353 struct thread *thread;
354 int state;
355
356 if (QueryIntrContext()) {
357 return KE_ILLEGAL_CONTEXT;
358 }
359
360 CpuSuspendIntr(&state);
361
362 if (thid == 0) {
363 thread = thctx.current_thread;
364 } else {
365 thread = HANDLE_PTR(thid);
366 if (!HANDLE_VERIFY(thid, TAG_THREAD)) {
367 CpuResumeIntr(state);
368 return KE_UNKNOWN_THID;
369 }
370
371 if (thread->status == THS_DORMANT) {
372 CpuResumeIntr(state);
373 return KE_DORMANT;
374 }
375 }
376
377 if (priority) {
378 if (priority - 1 >= 126) {
379 CpuResumeIntr(state);
380 return KE_ILLEGAL_PRIORITY;
381 }
382 } else {
383 priority = thctx.current_thread->priority;
384 }
385
386 if (thread == thctx.current_thread) {
387 if (priority >= readyq_highest()) {
388 thread->status = THS_READY;
389 thread->priority = priority;
390 readyq_insert_back(thread);
391 thctx.run_next = NULL;
392
393 return thread_leave(KE_OK, 0, state, 0);
394 }
395
396 thread->priority = priority;
397 } else {
398 if (thread->status == THS_READY) {
399 readyq_remove(thread, thread->priority);
400 thread->priority = priority;
401
402 return thread_start(thread, state);
403 }
404
405 // BUG: there was no check for TSW_DELAY here
406 // in which case there would be a usec value in the wait_event union.
407 //
408 // Added check to prevent dereferencing garbage.
409
410 if (thread->status == THS_WAIT && thread->wait_type != TSW_DELAY) {
411 if (thread->wait_event->attr & SA_THPRI) {
412 waitlist_insert(thread, thread->wait_event, priority);
413 }
414 }
415 }
416
417 CpuResumeIntr(state);
418 return KE_OK;
419}
420
421int iChangeThreadPriority(int thid, int priority)
422{
423 struct thread *thread;
424
425 if (!QueryIntrContext()) {
426 return KE_ILLEGAL_CONTEXT;
427 }
428
429 if (thid == 0) {
430 return KE_ILLEGAL_THID;
431 }
432
433 thread = HANDLE_PTR(thid);
434 if (!HANDLE_VERIFY(thid, TAG_THREAD)) {
435 return KE_UNKNOWN_THID;
436 }
437
438 if (thread->status == THS_DORMANT) {
439 return KE_DORMANT;
440 }
441
442 if (priority == 0) {
443 priority = thctx.current_thread->priority;
444 }
445
446 if (priority - 1 >= 126) {
447 return KE_ILLEGAL_PRIORITY;
448 }
449
450 if (thread == thctx.current_thread) {
451 thread->status = THS_READY;
452 } else {
453 if (thread->status != THS_READY) {
454 thread->priority = priority;
455 if (thread->status != THS_WAIT || thread->wait_type == TSW_DELAY) {
456 return KE_OK;
457 }
458
459 if ((thread->wait_event->attr & 1) == 0) {
460 return 0;
461 }
462
463 waitlist_insert(thread, thread->wait_event, priority);
464 }
465 }
466
467 thread->priority = priority;
468 readyq_insert_back(thread);
469 thctx.run_next = NULL;
470
471 return KE_OK;
472}
473
474int RotateThreadReadyQueue(int priority)
475{
476 struct thread *thread;
477 int state;
478
479 if (QueryIntrContext()) {
480 return KE_ILLEGAL_CONTEXT;
481 }
482
483 if (priority >= 127) {
484 return KE_ILLEGAL_PRIORITY;
485 }
486
487 CpuSuspendIntr(&state);
488
489 thread = thctx.current_thread;
490
491 if (priority == 0) {
492 priority = thread->priority;
493 }
494
495 if (list_empty(&thctx.ready_queue[priority])) {
496 CpuResumeIntr(state);
497 return KE_OK;
498 }
499
500 if (priority != thread->priority) {
501 thread = list_first_entry(&thctx.ready_queue[priority], struct thread, queue);
502 list_remove(&thread->queue);
503 list_insert(&thctx.ready_queue[priority], &thread->queue);
504
505 CpuResumeIntr(state);
506 return KE_OK;
507 }
508
509 thread->status = THS_READY;
510 readyq_insert_back(thread);
511 thctx.run_next = 0;
512 return thread_leave(KE_OK, 0, state, 0);
513}
514
515int iRotateThreadReadyQueue(int priority)
516{
517 struct thread *thread;
518
519 if (!QueryIntrContext()) {
520 return KE_ILLEGAL_CONTEXT;
521 }
522
523 thread = thctx.current_thread;
524
525 if (priority) {
526 if (priority >= 126) {
527 return KE_ILLEGAL_PRIORITY;
528 }
529 } else {
530 priority = readyq_highest();
531 if (thread->priority < priority) {
532 priority = thread->priority;
533 }
534 }
535
536 if (list_empty(&thctx.ready_queue[priority])) {
537 return KE_OK;
538 }
539
540 if (priority == thread->priority) {
541 thread->status = THS_READY;
542 readyq_insert_back(thread);
543 thctx.run_next = NULL;
544 } else {
545 thread = list_first_entry(&thctx.ready_queue[priority], struct thread, queue);
546 list_remove(&thread->queue);
547 list_insert(&thctx.ready_queue[priority], &thread->queue);
548 }
549
550 return KE_OK;
551}
552
553int ReleaseWaitThread(int thid)
554{
555 struct thread *thread;
556 int state;
557
558 if (QueryIntrContext()) {
559 return KE_ILLEGAL_CONTEXT;
560 }
561
562 if (thid == 0) {
563 return KE_ILLEGAL_THID;
564 }
565
566 CpuSuspendIntr(&state);
567
568 thread = HANDLE_PTR(thid);
569 if (thread == thctx.current_thread) {
570 CpuResumeIntr(state);
571 return KE_ILLEGAL_THID;
572 }
573
574 if (!HANDLE_VERIFY(thid, TAG_THREAD)) {
575 CpuResumeIntr(state);
576 return KE_UNKNOWN_THID;
577 }
578
579 if (thread->status != THS_WAIT) {
580 CpuResumeIntr(state);
581 return KE_NOT_WAIT;
582 }
583
584 thread->saved_regs->v0 = KE_RELEASE_WAIT;
585 list_remove(&thread->queue);
586 thread->status = THS_READY;
587
588 if (thread->wait_type == TSW_DELAY) {
589 CancelAlarm(thread_delay_cb, thread);
590 } else {
591 thread->wait_event->waiter_count--;
592 }
593
594 return thread_start(thread, state);
595}
596
597int iReleaseWaitThread(int thid)
598{
599 struct thread *thread;
600
601 if (!QueryIntrContext()) {
602 return KE_ILLEGAL_CONTEXT;
603 }
604
605 if (thid == 0) {
606 return KE_ILLEGAL_THID;
607 }
608
609 thread = HANDLE_PTR(thid);
610
611 if (!HANDLE_VERIFY(thid, TAG_THREAD)) {
612 return KE_UNKNOWN_THID;
613 }
614
615 if (thread->status != THS_WAIT) {
616 return KE_NOT_WAIT;
617 }
618
619 thread->saved_regs->v0 = KE_RELEASE_WAIT;
620 list_remove(&thread->queue);
621 thread->status = THS_READY;
622
623 if (thread->wait_type == TSW_DELAY) {
624 iCancelAlarm(thread_delay_cb, thread);
625 } else {
626 thread->wait_event->waiter_count--;
627 }
628
629 readyq_insert_back(thread);
630 thctx.run_next = NULL;
631
632 return KE_OK;
633}
634
635int GetThreadId(void)
636{
637 if (QueryIntrContext()) {
638 return KE_ILLEGAL_CONTEXT;
639 }
640
641 return MAKE_HANDLE(thctx.current_thread);
642}
643
644int CheckThreadStack(void)
645{
646 if (QueryIntrContext()) {
647 return KE_OK;
648 }
649
650 return check_thread_stack();
651}
652
653int ReferThreadStatus(int thid, iop_thread_info_t *info)
654{
655 struct thread *thread;
656 int state;
657
658 if (QueryIntrContext()) {
659 return KE_ILLEGAL_CONTEXT;
660 }
661
662 CpuSuspendIntr(&state);
663
664 thread = refer_thread(thid, 1);
665 if (thread < 0) {
666 CpuResumeIntr(state);
667 return (int)thread;
668 }
669
670 thread_get_status(thread, info);
671
672 CpuResumeIntr(state);
673
674 return KE_OK;
675}
676
677int iReferThreadStatus(int thid, iop_thread_info_t *info)
678{
679 struct thread *thread;
680
681 if (thid == 0) {
682 return KE_ILLEGAL_THID;
683 }
684
685 thread = HANDLE_PTR(thid);
686
687 if (!HANDLE_VERIFY(thid, TAG_THREAD)) {
688 return KE_UNKNOWN_THID;
689 }
690
691 thread_get_status(thread, info);
692
693 return KE_OK;
694}
695
696int SleepThread(void)
697{
698 struct thread *thread;
699 int state;
700
701 if (QueryIntrContext()) {
702 return KE_ILLEGAL_CONTEXT;
703 }
704
705 if (CpuSuspendIntr(&state) == KE_CPUDI && (thctx.debug_flags & 8)) {
706 Kprintf("WARNING: SleepThread KE_CAN_NOT_WAIT\n");
707 }
708 check_thread_stack();
709
710 thread = thctx.current_thread;
711
712 if (thread->wakeup_count != 0) {
713 thread->wakeup_count--;
714 CpuResumeIntr(state);
715 return KE_OK;
716 }
717
718 thread->status = THS_WAIT;
719 thread->wait_type = TSW_SLEEP;
720 thread->wait_event = NULL;
721 // thread->wait_return = 0;
722 thctx.run_next = NULL;
723
724 list_insert(&thctx.sleep_queue, &thread->queue);
725
726 return thread_leave(KE_OK, 0, state, 1);
727}
728
729int WakeupThread(int thid)
730{
731 struct thread *thread;
732 int state;
733
734 if (QueryIntrContext()) {
735 return KE_ILLEGAL_CONTEXT;
736 }
737
738 if (thid == 0) {
739 return KE_ILLEGAL_THID;
740 }
741
742 CpuSuspendIntr(&state);
743
744 thread = HANDLE_PTR(thid);
745 if (thread == thctx.current_thread) {
746 return KE_ILLEGAL_THID;
747 }
748
749 if (!HANDLE_VERIFY(thid, TAG_THREAD)) {
750 return KE_UNKNOWN_THID;
751 }
752
753 if (thread->status == THS_DORMANT) {
754 CpuResumeIntr(state);
755 return KE_DORMANT;
756 }
757
758 if (thread->status == THS_WAIT && thread->wait_type == TSW_SLEEP) {
759 list_remove(&thread->queue);
760 thread->status = THS_READY;
761
762 return thread_start(thread, state);
763 }
764
765 thread->wakeup_count++;
766
767 CpuResumeIntr(state);
768
769 return KE_OK;
770}
771
772int iWakeupThread(int thid)
773{
774 struct thread *thread;
775
776 if (!QueryIntrContext()) {
777 return KE_ILLEGAL_CONTEXT;
778 }
779
780 if (thid == 0) {
781 return KE_ILLEGAL_THID;
782 }
783
784 thread = HANDLE_PTR(thid);
785 if (!HANDLE_VERIFY(thid, TAG_THREAD)) {
786 return KE_UNKNOWN_THID;
787 }
788
789 if (thread->status == THS_DORMANT) {
790 return KE_DORMANT;
791 }
792
793 if (thread->status == THS_WAIT && thread->wait_type == TSW_SLEEP) {
794 list_remove(&thread->queue);
795 thread->status = THS_READY;
796 readyq_insert_back(thread);
797 thctx.run_next = NULL;
798 } else {
799 thread->wakeup_count++;
800 }
801
802 return KE_OK;
803}
804
805int CancelWakeupThread(int thid)
806{
807 struct thread *thread;
808 int state, wakeup_count;
809
810 if (QueryIntrContext()) {
811 return KE_ILLEGAL_CONTEXT;
812 }
813
814 CpuSuspendIntr(&state);
815 if (thid) {
816 thread = HANDLE_PTR(thid);
817 if (!HANDLE_VERIFY(thid, TAG_THREAD)) {
818 CpuResumeIntr(state);
819 return KE_UNKNOWN_THID;
820 }
821 } else {
822 thread = thctx.current_thread;
823 }
824
825 wakeup_count = thread->wakeup_count;
826 thread->wakeup_count = 0;
827
828 CpuResumeIntr(state);
829 return wakeup_count;
830}
831
832int iCancelWakeupThread(int thid)
833{
834 struct thread *thread;
835 int wakeup_count;
836
837 if (!QueryIntrContext()) {
838 return KE_ILLEGAL_CONTEXT;
839 }
840
841 if (thid == 0) {
842 return KE_ILLEGAL_THID;
843 }
844
845 thread = HANDLE_PTR(thid);
846 if (!HANDLE_VERIFY(thid, TAG_THREAD)) {
847 return KE_UNKNOWN_THID;
848 }
849
850 wakeup_count = thread->wakeup_count;
851 thread->wakeup_count = 0;
852
853 return wakeup_count;
854}
855
856int SuspendThread(int thid)
857{
858 return KE_ERROR;
859}
860
861int iSuspendThread(int thid)
862{
863 return KE_ERROR;
864}
865
866int ResumeThread(int thid)
867{
868 return KE_ERROR;
869}
870
871int iResumeThread(int thid)
872{
873 return KE_ERROR;
874}
875
876int DelayThread(int usec)
877{
878 iop_sys_clock_t clock;
879 struct thread *thread;
880 int ret, state;
881
882 if (QueryIntrContext()) {
883 return KE_ILLEGAL_CONTEXT;
884 }
885
886 USec2SysClock(usec, &clock);
887 if (CpuSuspendIntr(&state) == KE_CPUDI && (thctx.debug_flags & 8)) {
888 Kprintf("WARNING: DelayThread KE_CAN_NOT_WAIT\n");
889 }
890 check_thread_stack();
891
892 thread = thctx.current_thread;
893
894 ret = SetAlarm(&clock, thread_delay_cb, thread);
895 if (ret != KE_OK) {
896 CpuResumeIntr(state);
897 return ret;
898 }
899
900 thread->status = THS_WAIT;
901 thread->wait_type = TSW_DELAY;
902 thread->wait_usecs = usec;
903 // thread->wait_return = 0;
904
905 thctx.run_next = NULL;
906 list_insert(&thctx.delay_queue, &thread->queue);
907
908 return thread_leave(KE_OK, 0, state, 1);
909}
910
911
912int GetSystemTime(iop_sys_clock_t *sys_clock)
913{
914 return CpuInvokeInKmode(read_sys_time, sys_clock);
915}
916
917int SetAlarm(iop_sys_clock_t *sys_clock, unsigned int (*alarm_cb)(void *userdata), void *arg)
918{
919 iop_sys_clock_t systime;
920 struct alarm *alarm;
921 int state;
922 u64 time;
923
924 if (QueryIntrContext()) {
925 return KE_ILLEGAL_CONTEXT;
926 }
927
928 CpuSuspendIntr(&state);
929
930 if (!list_empty(&thctx.alarm)) {
931 list_for_each (alarm, &thctx.alarm, alarm_list) {
932 if (alarm->cb == alarm_cb && alarm->userptr == arg) {
933 CpuResumeIntr(state);
934 return KE_FOUND_HANDLER;
935 }
936 }
937 }
938
939 alarm = alarm_alloc();
940 if (!alarm) {
941 CpuResumeIntr(state);
942 return KE_NO_MEMORY;
943 }
944
945 if (sys_clock->hi == 0 && sys_clock->lo < thctx.min_wait) {
946 sys_clock->lo = thctx.min_wait;
947 }
948
949 GetSystemTime(&systime);
950 // as_u64(systime.hi, systime.lo); // ???
951
952 alarm->target = add64(sys_clock->hi, sys_clock->lo, systime.hi, systime.lo);
953 alarm->cb = alarm_cb;
954 alarm->userptr = arg;
955 thctx.alarm_count++;
956 alarm_insert(&thctx.alarm, alarm);
957
958 GetSystemTime(&systime);
959 time = as_u64(systime.hi, systime.lo);
960 update_timer_compare(thctx.timer_id, time, &thctx.alarm);
961
962 CpuResumeIntr(state);
963
964 return KE_OK;
965}
966
967int iSetAlarm(iop_sys_clock_t *sys_clock, unsigned int (*alarm_cb)(void *userdata), void *arg)
968{
969 struct alarm *alarm;
970 iop_sys_clock_t systime;
971 u64 time;
972
973 if (!QueryIntrContext()) {
974 return KE_ILLEGAL_CONTEXT;
975 }
976
977 list_for_each (alarm, &thctx.alarm, alarm_list) {
978 if (alarm->cb == alarm_cb && alarm->userptr == arg) {
979 return KE_FOUND_HANDLER;
980 }
981 }
982
983 alarm = alarm_alloc();
984 if (!alarm) {
985 return KE_NO_MEMORY;
986 }
987
988 if (sys_clock->hi == 0 && sys_clock->lo < thctx.min_wait) {
989 sys_clock->lo = thctx.min_wait;
990 }
991
992 read_sys_time(&systime);
993 // as_u64(systime.hi, systime.lo);
994 alarm->target = add64(sys_clock->hi, sys_clock->lo, systime.hi, systime.lo);
995 alarm->cb = alarm_cb;
996 alarm->userptr = arg;
997 thctx.alarm_count++;
998 alarm_insert(&thctx.alarm, alarm);
999 read_sys_time(&systime);
1000 time = as_u64(systime.hi, systime.lo);
1001 update_timer_compare(thctx.timer_id, time, &thctx.alarm);
1002
1003 return KE_OK;
1004}
1005
1006int CancelAlarm(unsigned int (*alarm_cb)(void *userdata), void *arg)
1007{
1008 struct alarm *alarm;
1009 int state;
1010
1011 if (QueryIntrContext()) {
1012 return KE_ILLEGAL_CONTEXT;
1013 }
1014
1015 CpuSuspendIntr(&state);
1016
1017 if (list_empty(&thctx.alarm)) {
1018 CpuResumeIntr(state);
1019 return KE_NOTFOUND_HANDLER;
1020 }
1021
1022 list_for_each (alarm, &thctx.alarm, alarm_list) {
1023 if (alarm->cb == alarm_cb && alarm->userptr == arg) {
1024 list_remove(&alarm->alarm_list);
1025 alarm_free(alarm);
1026 thctx.alarm_count--;
1027
1028 CpuResumeIntr(state);
1029 return KE_OK;
1030 }
1031 }
1032
1033 CpuResumeIntr(state);
1034
1035 return KE_NOTFOUND_HANDLER;
1036}
1037
1038int iCancelAlarm(unsigned int (*alarm_cb)(void *userdata), void *arg)
1039{
1040 struct alarm *alarm;
1041
1042 if (!QueryIntrContext()) {
1043 return KE_ILLEGAL_CONTEXT;
1044 }
1045
1046 if (list_empty(&thctx.alarm)) {
1047 return KE_NOTFOUND_HANDLER;
1048 }
1049
1050 list_for_each (alarm, &thctx.alarm, alarm_list) {
1051 if (alarm->cb == alarm_cb && alarm->userptr == arg) {
1052 list_remove(&alarm->alarm_list);
1053 alarm_free(alarm);
1054 thctx.alarm_count--;
1055
1056 return KE_OK;
1057 }
1058 }
1059
1060 return KE_NOTFOUND_HANDLER;
1061}
1062
1063void USec2SysClock(u32 usec, iop_sys_clock_t *sys_clock)
1064{
1065 sys_clock->hi = 0;
1066 sys_clock->lo = usec;
1067 clock_mul(sys_clock, sys_clock, thctx.unk_clock_mult);
1068 clock_div(sys_clock, sys_clock, thctx.unk_clock_div, NULL);
1069}
1070
1071void SysClock2USec(iop_sys_clock_t *sys_clock, u32 *sec, u32 *usec)
1072{
1073 iop_sys_clock_t clock;
1074 clock_mul(&clock, sys_clock, thctx.unk_clock_div);
1075 clock_div(&clock, &clock, thctx.unk_clock_mult, NULL);
1076 clock_div(&clock, &clock, 1000000, usec);
1077 *sec = clock.lo;
1078}
1079
1080int GetSystemStatusFlag()
1081{
1082 return thctx.sytem_status_flag;
1083}
1084
1085int GetThreadCurrentPriority(void)
1086{
1087 if (QueryIntrContext()) {
1088 return KE_ILLEGAL_CONTEXT;
1089 }
1090
1091 return thctx.current_thread->priority;
1092}
1093
1094unsigned int GetSystemTimeLow(void)
1095{
1096 return GetTimerCounter(thctx.timer_id);
1097}
1098
1099int ReferSystemStatus(iop_sys_status_t *info, size_t size)
1100{
1101 int state, ret;
1102 if (size < sizeof(*info)) {
1103 return KE_ERROR;
1104 }
1105
1106 memset(info, 0, size);
1107
1108 ret = CpuSuspendIntr(&state);
1109
1110 if (QueryIntrContext()) {
1111 info->status = TSS_NOTHREAD;
1112 } else if (ret == KE_CPUDI) {
1113 info->status = TSS_DISABLEINTR;
1114 } else {
1115 info->status = TSS_THREAD;
1116 }
1117
1118 info->systemLowTimerWidth = 32;
1119 info->idleClocks.hi = thctx.idle_thread->run_clocks_hi;
1120 info->idleClocks.lo = thctx.idle_thread->run_clocks_lo;
1121 info->threadSwitchCount = thctx.thread_switch_count;
1122 info->comesOutOfIdleCount = thctx.idle_thread->irq_preemption_count;
1123
1124 CpuResumeIntr(state);
1125
1126 return KE_OK;
1127}
1128
1129int ReferThreadRunStatus(int thid, iop_thread_run_status_t *stat, size_t size)
1130{
1131 struct thread *thread;
1132 int state;
1133
1134 if (QueryIntrContext()) {
1135 return KE_ILLEGAL_CONTEXT;
1136 }
1137
1138 CpuSuspendIntr(&state);
1139
1140 thread = refer_thread(thid, 1);
1141 if ((int)thread <= 0) {
1142 CpuResumeIntr(state);
1143 return (int)thread;
1144 }
1145
1146 if (size < sizeof(*stat)) {
1147 CpuResumeIntr(state);
1148 return KE_ILLEGAL_SIZE;
1149 }
1150
1151 memset(stat, 0, size);
1152 thread_get_run_stats(thread, stat);
1153
1154 CpuResumeIntr(state);
1155 return KE_OK;
1156}
1157
1158/*
1159 * Gets the minimum stack size left so far
1160 * only works if stack filling was not disabled
1161 */
1162int GetThreadStackFreeSize(int thid)
1163{
1164 struct thread *thread;
1165 u32 stack_size, i;
1166 u32 *stack;
1167 int state;
1168
1169 if (QueryIntrContext()) {
1170 return KE_ILLEGAL_CONTEXT;
1171 }
1172
1173 CpuSuspendIntr(&state);
1174
1175 thread = refer_thread(thid, 1);
1176 if ((int)thread < 0) {
1177 CpuResumeIntr(state);
1178 return (int)thread;
1179 }
1180
1181 stack = thread->stack_top;
1182 stack_size = thread->stack_size / 4;
1183 CpuResumeIntr(state);
1184
1185 for (i = 0; i < stack_size; i++) {
1186 if (stack[i] != -1) {
1187 return i * 4;
1188 }
1189 }
1190
1191 return i * 4;
1192}
1193
1194
1195int GetThreadmanIdList(int type, int *readbuf, int readbufsize, int *objectcount)
1196{
1197 int state, write_count, obj_count;
1198
1199 if (QueryIntrContext()) {
1200 return KE_ILLEGAL_CONTEXT;
1201 }
1202
1203 CpuSuspendIntr(&state);
1204
1205 write_count = 0;
1206 obj_count = 0;
1207
1208 switch (type) {
1209 case TMID_Thread: {
1210 struct thread *thread;
1211 list_for_each (thread, &thctx.thread_list, thread_list) {
1212 if (thread != thctx.idle_thread) {
1213 if (write_count < readbufsize) {
1214 *readbuf++ = MAKE_HANDLE(thread);
1215 write_count++;
1216 }
1217 obj_count++;
1218 }
1219 }
1220 } break;
1221 case TMID_Semaphore: {
1222 struct semaphore *sema;
1223 list_for_each (sema, &thctx.semaphore, sema_list) {
1224 if (write_count < readbufsize) {
1225 *readbuf++ = MAKE_HANDLE(sema);
1226 write_count++;
1227 }
1228 obj_count++;
1229 }
1230 } break;
1231 case TMID_EventFlag: {
1232 struct event_flag *evf;
1233 list_for_each (evf, &thctx.event_flag, evf_list) {
1234 if (write_count < readbufsize) {
1235 *readbuf++ = MAKE_HANDLE(evf);
1236 write_count++;
1237 }
1238 obj_count++;
1239 }
1240 } break;
1241 case TMID_Mbox: {
1242 struct mbox *mbx;
1243 list_for_each (mbx, &thctx.mbox, mbox_list) {
1244 if (write_count < readbufsize) {
1245 *readbuf++ = MAKE_HANDLE(mbx);
1246 write_count++;
1247 }
1248 obj_count++;
1249 }
1250 } break;
1251 case TMID_Vpl: {
1252 struct vpool *vpl;
1253 list_for_each (vpl, &thctx.vpool, vpl_list) {
1254 if (write_count < readbufsize) {
1255 *readbuf++ = MAKE_HANDLE(vpl);
1256 write_count++;
1257 }
1258 obj_count++;
1259 }
1260 } break;
1261 case TMID_Fpl: {
1262 struct fpool *fpl;
1263 list_for_each (fpl, &thctx.fpool, fpl_list) {
1264 if (write_count < readbufsize) {
1265 *readbuf++ = MAKE_HANDLE(fpl);
1266 write_count++;
1267 }
1268 obj_count++;
1269 }
1270 } break;
1271 case TMID_SleepThread: {
1272 struct thread *thread;
1273 list_for_each (thread, &thctx.sleep_queue, queue) {
1274 if (write_count < readbufsize) {
1275 *readbuf++ = MAKE_HANDLE(thread);
1276 write_count++;
1277 }
1278 obj_count++;
1279 }
1280 } break;
1281 case TMID_DelayThread: {
1282 struct thread *thread;
1283 list_for_each (thread, &thctx.delay_queue, queue) {
1284 if (write_count < readbufsize) {
1285 *readbuf++ = MAKE_HANDLE(thread);
1286 write_count++;
1287 }
1288 obj_count++;
1289 }
1290 } break;
1291 case TMID_DormantThread: {
1292 struct thread *thread;
1293 list_for_each (thread, &thctx.dormant_queue, queue) {
1294 if (write_count < readbufsize) {
1295 *readbuf++ = MAKE_HANDLE(thread);
1296 write_count++;
1297 }
1298 obj_count++;
1299 }
1300 } break;
1301 default: {
1302 struct heaptag *tag = HANDLE_PTR(type);
1303 struct thread *thread;
1304 struct event *event;
1305
1306 if (type < 0 || tag->tag < TAG_SEMA || tag->tag > TAG_FPL || tag->id != HANDLE_ID(type)) {
1307 CpuResumeIntr(state);
1308 return KE_ILLEGAL_TYPE;
1309 }
1310
1311 switch (tag->tag) {
1312 case TAG_SEMA:
1313 event = &((struct semaphore *)tag)->event;
1314 break;
1315 case TAG_EVF:
1316 event = &((struct event_flag *)tag)->event;
1317 break;
1318 case TAG_MBX:
1319 event = &((struct mbox *)tag)->event;
1320 break;
1321 case TAG_VPL:
1322 event = &((struct vpool *)tag)->event;
1323 break;
1324 case TAG_FPL:
1325 event = &((struct fpool *)tag)->event;
1326 break;
1327 }
1328
1329 list_for_each (thread, &event->waiters, queue) {
1330 if (write_count < readbufsize) {
1331 *readbuf++ = MAKE_HANDLE(thread);
1332 write_count++;
1333 }
1334 obj_count++;
1335 }
1336 }
1337 }
1338
1339 CpuResumeIntr(state);
1340
1341 if (objectcount) {
1342 *objectcount = obj_count;
1343 }
1344
1345 return write_count;
1346}
1347
1348static void clock_mul(iop_sys_clock_t *dst, iop_sys_clock_t *src, u32 mul)
1349{
1350 u64 res;
1351 res = (u64)src->hi << 32 | src->lo;
1352 res *= mul;
1353 if (dst) {
1354 dst->hi = res >> 32;
1355 dst->lo = res;
1356 }
1357}
1358
1359// TODO clean up
1360static void clock_div(iop_sys_clock_t *dst, iop_sys_clock_t *src, u32 d, u32 *r)
1361{
1362 int v4;
1363 u32 hi;
1364 u32 lo;
1365 u32 v7;
1366 u32 v8;
1367 u32 v9;
1368 int i;
1369 unsigned int v11;
1370 u32 v12;
1371 u32 v13;
1372
1373 v4 = 0;
1374 hi = src->hi;
1375 lo = src->lo;
1376 v7 = hi / d;
1377 v8 = hi % d;
1378 v9 = v7;
1379 for (i = 0; i < 4; ++i) {
1380 v11 = (v8 << 8) | (lo >> 24);
1381 lo <<= 8;
1382 v12 = v11 / d;
1383 v4 = (v4 << 8) | (v9 >> 24);
1384 v13 = v11 % d;
1385 v8 = v11 % d;
1386 v9 = (v9 << 8) + v12;
1387 }
1388 if (dst) {
1389 dst->hi = v4;
1390 dst->lo = v9;
1391 }
1392 if (r) {
1393 *r = v13;
1394 }
1395}
1396
1397
1398static struct thread *refer_thread(int thid, int current)
1399{
1400 struct thread *thread;
1401
1402 if (!thid && current) {
1403 return thctx.current_thread;
1404 }
1405
1406 thread = HANDLE_PTR(thid);
1407 if (!HANDLE_VERIFY(thid, TAG_THREAD)) {
1408 return (struct thread *)KE_UNKNOWN_THID;
1409 }
1410
1411 return thread;
1412}
1413
1414static void thread_get_status(struct thread *thread, iop_thread_info_t *info)
1415{
1416 memset(info, 0, sizeof(*info));
1417 info->status = thread->status;
1418 info->currentPriority = thread->priority;
1419 info->initPriority = thread->init_priority;
1420 info->entry = thread->entry;
1421 info->stack = thread->stack_top;
1422 info->stackSize = thread->stack_size;
1423 info->gpReg = (void *)thread->gp;
1424 info->attr = thread->attr;
1425 info->option = thread->option;
1426
1427 if (thread->status == THS_WAIT) {
1428 info->waitType = thread->wait_type;
1429 if (thread->wait_type == TSW_DELAY) {
1430 info->waitId = thread->wait_usecs;
1431 } else {
1432 switch (thread->wait_type) {
1433 case TSW_SEMA:
1434 info->waitId = MAKE_HANDLE(container_of(thread->wait_event, struct semaphore, event));
1435 break;
1436 case TSW_EVENTFLAG:
1437 info->waitId = MAKE_HANDLE(container_of(thread->wait_event, struct event_flag, event));
1438 break;
1439 case TSW_MBX:
1440 info->waitId = MAKE_HANDLE(container_of(thread->wait_event, struct mbox, event));
1441 break;
1442 case TSW_FPL:
1443 info->waitId = MAKE_HANDLE(container_of(thread->wait_event, struct fpool, event));
1444 break;
1445 case TSW_VPL:
1446 info->waitId = MAKE_HANDLE(container_of(thread->wait_event, struct vpool, event));
1447 break;
1448 default:
1449 // shouldn't happen
1450 break;
1451 }
1452 }
1453 }
1454
1455 info->wakeupCount = thread->wakeup_count;
1456 if (thread->status == THS_DORMANT || thread->status == THS_RUN) {
1457 info->regContext = 0;
1458 } else {
1459 info->regContext = (long *)thread->saved_regs;
1460 }
1461}
1462
1463static void thread_get_run_stats(struct thread *thread, iop_thread_run_status_t *stat)
1464{
1465 stat->status = thread->status;
1466 stat->currentPriority = thread->priority;
1467
1468 if (thread->status == THS_WAIT) {
1469 stat->waitType = thread->wait_type;
1470 if (thread->wait_type == TSW_DELAY) {
1471 stat->waitId = thread->wait_usecs;
1472 } else {
1473 switch (thread->wait_type) {
1474 case TSW_SEMA:
1475 stat->waitId = MAKE_HANDLE(container_of(thread->wait_event, struct semaphore, event));
1476 break;
1477 case TSW_EVENTFLAG:
1478 stat->waitId = MAKE_HANDLE(container_of(thread->wait_event, struct event_flag, event));
1479 break;
1480 case TSW_MBX:
1481 stat->waitId = MAKE_HANDLE(container_of(thread->wait_event, struct mbox, event));
1482 break;
1483 case TSW_FPL:
1484 stat->waitId = MAKE_HANDLE(container_of(thread->wait_event, struct fpool, event));
1485 break;
1486 case TSW_VPL:
1487 stat->waitId = MAKE_HANDLE(container_of(thread->wait_event, struct vpool, event));
1488 break;
1489 default:
1490 // shouldn't happen
1491 break;
1492 }
1493 }
1494 }
1495
1496 stat->wakeupCount = thread->wakeup_count;
1497 if (thread->status != THS_DORMANT && thread->status != THS_RUN) {
1498 stat->regContext = (long *)thread->saved_regs;
1499 }
1500
1501 stat->runClocks.hi = thread->run_clocks_hi;
1502 stat->runClocks.lo = thread->run_clocks_lo;
1503 stat->intrPreemptCount = thread->irq_preemption_count;
1504 stat->threadPreemptCount = thread->thread_preemption_count;
1505 stat->releaseCount = thread->release_count;
1506}
int CpuResumeIntr(int state)
Definition intrman.c:217
int CpuInvokeInKmode(void *function,...)
int QueryIntrContext(void)
int CpuSuspendIntr(int *state)
Definition intrman.c:195
#define THS_RUN
Definition kernel.h:219
int thread_leave(int unk, int unk2, int intr_state, int release)
Definition thcommon.c:159