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