1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - OS
3 File: os_thread.c
4
5 Copyright 2003-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2008-09-26#$
14 $Rev: 8676 $
15 $Author: yada $
16 *---------------------------------------------------------------------------*/
17 #ifdef SDK_TWL
18 #include <twl/memorymap.h>
19 #else
20 #include <nitro/memorymap.h>
21 #endif
22
23 #include <nitro/os.h>
24 #include <nitro/mi.h>
25
26 //---------------------------------------------------------------------------
27
28 extern unsigned long SDK_SYS_STACKSIZE[];
29 extern unsigned long SDK_IRQ_STACKSIZE[];
30 #define OSi_SYS_STACKSIZE ((s32)SDK_SYS_STACKSIZE)
31 #define OSi_IRQ_STACKSIZE ((s32)SDK_IRQ_STACKSIZE)
32
33 //---- Stack CheckNumber
34 #ifdef SDK_ARM9
35 # define OSi_STACK_CHECKNUM_BOTTOM 0xfddb597dUL
36 # define OSi_STACK_CHECKNUM_TOP 0x7bf9dd5bUL
37 # define OSi_STACK_CHECKNUM_WARN 0x597dfbd9UL
38 #else
39 # define OSi_STACK_CHECKNUM_BOTTOM 0xd73bfdf7UL
40 # define OSi_STACK_CHECKNUM_TOP 0xfbdd37bbUL
41 # define OSi_STACK_CHECKNUM_WARN 0xbdf7db3dUL
42 #endif
43
44 //---- defs for launcher thread stack
45 #ifdef SDK_ARM9
46 extern void SDK_SECTION_ARENA_DTCM_START(void);
47 void SDK_AUTOLOAD_DTCM_END(void); // defined in LCF
48 # define OSi_LAUNCHER_STACK_LO_DEFAULT SDK_SECTION_ARENA_DTCM_START
49 # define OSi_LAUNCHER_STACK_HI_MAX (HW_DTCM_SVC_STACK - OSi_IRQ_STACKSIZE)
50 # define OSi_LAUNCHER_STACK_BOTTOM (HW_DTCM_SVC_STACK - OSi_IRQ_STACKSIZE)
51 #else
52 # define OSi_LAUNCHER_STACK_LO_DEFAULT HW_WRAM
53 # define OSi_LAUNCHER_STACK_HI_MAX (HW_PRV_WRAM_IRQ_STACK_END - OSi_IRQ_STACKSIZE)
54 # define OSi_LAUNCHER_STACK_BOTTOM (HW_PRV_WRAM_IRQ_STACK_END - OSi_IRQ_STACKSIZE)
55 #endif
56
57 //---- defs for idle thread
58 // for checkNumber and SVC stack (if defined)
59 #ifdef SDK_CONTEXT_HAS_SP_SVC
60 #define OSi_IDLE_CHECKNUM_SIZE ( sizeof(u32)*2 + HW_SVC_STACK_SIZE )
61 #else
62 #define OSi_IDLE_CHECKNUM_SIZE ( sizeof(u32)*2 )
63 #endif
64 // for SVC to stack out registers
65 #ifdef SDK_ARM9
66 #define OSi_IDLE_SVC_SIZE ( sizeof(u32)*32 ) // arm9 svc stacks 14 words and makes in 8byte-alignment
67 #else
68 #define OSi_IDLE_SVC_SIZE ( sizeof(u32)*16 ) // arm7 svc stacks 14 words
69 #endif
70 // stack size of idle thread
71 #define OSi_IDLE_THREAD_STACK_SIZE ( OSi_IDLE_CHECKNUM_SIZE + OSi_IDLE_SVC_SIZE )
72
73 #if defined(SDK_TCM_APPLY) && defined(SDK_ARM9)
74 #include <nitro/itcm_begin.h>
75 #endif
76 //---- threads
77 OSThread OSi_LauncherThread;
78 OSThread OSi_IdleThread;
79
80 //---- thread information
81 OSThreadInfo OSi_ThreadInfo;
82
83 //---- current thread pointer (for quick reference)
84 OSThread **OSi_CurrentThreadPtr;
85 #define OSi_GetCurrentThread() (*OSi_CurrentThreadPtr)
86
87 //---- thread initialization flag
88 BOOL OSi_IsThreadInitialized = FALSE;
89
90 //---- idle thread stack
91 u32 OSi_IdleThreadStack[OSi_IDLE_THREAD_STACK_SIZE / sizeof(u32)];
92
93 //---- system callback in switch thread ( maybe for profile )
94 void *OSi_SystemCallbackInSwitchThread = NULL;
95
96 //---- reschedule counter. if value>=0, do not reschedule.
97 u32 OSi_RescheduleCount = 0;
98 #if defined(SDK_TCM_APPLY) && defined(SDK_ARM9)
99 #include <nitro/itcm_end.h>
100 #endif
101
102 #ifdef SDK_THREAD_INFINITY
103 //---- thread id count
104 static int OSi_ThreadIdCount = 0;
105 #endif
106
107 void *OSi_StackForDestructor = NULL;
108
109
110 #ifndef SDK_THREAD_INFINITY
111 static int OSi_SearchFreeEntry(void);
112 #endif
113 static void OSi_CancelThreadAlarmForSleep(OSThread *thread);
114 static void OSi_InsertThreadToList(OSThread *thread);
115 static void OSi_RemoveThreadFromList(OSThread *thread);
116 static void OSi_SleepAlarmCallback(void *arg);
117 static void OSi_IdleThreadProc(void *);
118 void OSi_SetSystemCallbackInSwitchThread(void *callback);
119
120 static void OSi_ExitThread_ArgSpecified(OSThread *thread, void *arg);
121 static void OSi_ExitThread(void *arg);
122 static void OSi_ExitThread_Destroy(void);
123
124 #if defined(SDK_TCM_APPLY) && defined(SDK_ARM9)
125 #include <nitro/itcm_begin.h>
126 #endif
127 static void OSi_RescheduleThread(void);
128
129 #ifdef SDK_THREAD_INFINITY
130 /*---------------------------------------------------------------------------*
131 Name: OSi_GetUnusedThreadId
132
133 Description: Get an unused thread id.
134
135 Arguments: None.
136
137 Returns: Thread id (0-0x7fffffff) which is never used.
138 *---------------------------------------------------------------------------*/
OSi_GetUnusedThreadId(void)139 static int OSi_GetUnusedThreadId(void)
140 {
141 ++OSi_ThreadIdCount;
142 SDK_ASSERT(OSi_ThreadIdCount > 0); // Overflow check
143 return OSi_ThreadIdCount;
144 }
145 #endif /* ; */
146
147 /*---------------------------------------------------------------------------*
148 Name: OSi_InsertLinkToQueue
149
150 Description: Insert a thread into a thread queue.
151
152 Arguments: queue : Thread queue.
153 thread : Thread to insert.
154
155 Returns: None.
156 *---------------------------------------------------------------------------*/
OSi_InsertLinkToQueue(OSThreadQueue * queue,OSThread * thread)157 static void OSi_InsertLinkToQueue(OSThreadQueue *queue, OSThread *thread)
158 {
159 OSThread *next = queue->head;
160
161 while (next && next->priority <= thread->priority)
162 {
163 if (next == thread)
164 {
165 return;
166 }
167 next = next->link.next;
168 }
169
170 if (!next)
171 {
172 OSThread *prev = queue->tail;
173
174 if (!prev)
175 {
176 queue->head = thread;
177 }
178 else
179 {
180 prev->link.next = thread;
181 }
182
183 thread->link.prev = prev;
184 thread->link.next = NULL;
185 queue->tail = thread;
186 }
187 else
188 {
189 OSThread *prev = next->link.prev;
190
191 if (!prev)
192 {
193 queue->head = thread;
194 }
195 else
196 {
197 prev->link.next = thread;
198 }
199
200 thread->link.prev = prev;
201 thread->link.next = next;
202 next->link.prev = thread;
203 }
204 }
205
206 /*---------------------------------------------------------------------------*
207 Name: OSi_RemoveLinkFromQueue
208
209 Description: Remove the head thread from a thread queue.
210
211 Arguments: queue : Thread queue.
212
213 Returns: Thread pointer that was removed.
214 *---------------------------------------------------------------------------*/
OSi_RemoveLinkFromQueue(OSThreadQueue * queue)215 static OSThread *OSi_RemoveLinkFromQueue(OSThreadQueue *queue)
216 {
217 OSThread *t = queue->head;
218
219 if (t)
220 {
221 OSThread *next = t->link.next;
222
223 queue->head = next;
224
225 if (next)
226 {
227 next->link.prev = NULL;
228 }
229 else
230 {
231 queue->tail = NULL;
232 t->queue = NULL;
233 }
234 }
235
236 return t;
237 }
238
239 /*---------------------------------------------------------------------------*
240 Name: OSi_RemoveSpecifiedLinkFromQueue
241
242 Description: Remove the specified thread from a thread queue.
243
244 Arguments: queue : Thread queue.
245
246 Returns: Thread pointer that was removed.
247 *---------------------------------------------------------------------------*/
OSi_RemoveSpecifiedLinkFromQueue(OSThreadQueue * queue,OSThread * thread)248 static OSThread *OSi_RemoveSpecifiedLinkFromQueue(OSThreadQueue *queue, OSThread *thread)
249 {
250 OSThread *t = queue->head;
251 OSThread *next;
252 OSThread *prev;
253
254 while (t)
255 {
256 next = t->link.next;
257
258 if (t == thread)
259 {
260 prev = t->link.prev;
261
262 //---- whether this is a head link
263 if (queue->head == t)
264 {
265 queue->head = next;
266 }
267 else
268 {
269 prev->link.next = next;
270 }
271
272 //---- whether this is a tail link
273 if (queue->tail == t)
274 {
275 queue->tail = prev;
276 }
277 else
278 {
279 next->link.prev = prev;
280 }
281
282 break;
283 }
284
285 t = next;
286 }
287
288 return t;
289 }
290
291 /*---------------------------------------------------------------------------*
292 Name: OSi_RemoveMutexLinkFromQueue
293
294 Description: Removes mutex from mutex queue.
295
296 Arguments: queue : mutex queue
297
298 Returns: mutex pointer which is removed
299 *---------------------------------------------------------------------------*/
OSi_RemoveMutexLinkFromQueue(OSMutexQueue * queue)300 OSMutex *OSi_RemoveMutexLinkFromQueue(OSMutexQueue * queue)
301 {
302 OSMutex *t = queue->head;
303
304 if (t)
305 {
306 OSMutex *next = t->link.next;
307
308 queue->head = next;
309
310 if (next)
311 {
312 next->link.prev = NULL;
313 }
314 else
315 {
316 queue->tail = NULL;
317 }
318 }
319
320 return t;
321 }
322
323 /*---------------------------------------------------------------------------*
324 Name: OSi_SetSystemCallbackInSwitchThread
325
326 Description: Set system callback in switching thread.
327
328 Arguments: callback
329
330 Returns: None.
331 *---------------------------------------------------------------------------*/
OSi_SetSystemCallbackInSwitchThread(void * callback)332 void OSi_SetSystemCallbackInSwitchThread(void *callback)
333 {
334 OSi_SystemCallbackInSwitchThread = callback;
335 }
336
337 #ifndef SDK_THREAD_INFINITY
338 /*---------------------------------------------------------------------------*
339 Name: OSi_SearchFreeEntry
340
341 Description: Search for a free thread entry area.
342
343 Arguments: None.
344
345 Returns: 0 - OS_THREAD_MAX_NUM-1 ... entry index
346 -1 ... not found
347 *---------------------------------------------------------------------------*/
OSi_SearchFreeEntry(void)348 static int OSi_SearchFreeEntry(void)
349 {
350 int i;
351
352 for (i = 0; i < OS_THREAD_MAX_NUM; i++)
353 {
354 if (!OSi_ThreadInfo.entry[i])
355 {
356 return i;
357 }
358 }
359 return -1; // Not found
360 }
361 #endif
362
363 /*---------------------------------------------------------------------------*
364 Name: OSi_InsertThreadToList
365
366 Description: Insert a thread into the thread list, which is arranged by priority.
367
368 Arguments: Pointer to a thread.
369
370 Returns: None.
371 *---------------------------------------------------------------------------*/
OSi_InsertThreadToList(OSThread * thread)372 static void OSi_InsertThreadToList(OSThread *thread)
373 {
374 OSThread *t = OSi_ThreadInfo.list;
375 OSThread *pre = NULL;
376
377 while (t && t->priority < thread->priority)
378 {
379 pre = t;
380 t = t->next;
381 }
382
383 if (!pre)
384 {
385 thread->next = OSi_ThreadInfo.list;
386 OSi_ThreadInfo.list = thread;
387 }
388 else
389 {
390 thread->next = pre->next;
391 pre->next = thread;
392 }
393 }
394
395 /*---------------------------------------------------------------------------*
396 Name: OSi_RemoveThreadFromList
397
398 Description: Remove a thread from the thread list.
399
400 Arguments: Pointer to a thread.
401
402 Returns: None.
403 *---------------------------------------------------------------------------*/
OSi_RemoveThreadFromList(OSThread * thread)404 static void OSi_RemoveThreadFromList(OSThread *thread)
405 {
406 OSThread *t = OSi_ThreadInfo.list;
407 OSThread *pre = NULL;
408
409 while (t && t != thread)
410 {
411 pre = t;
412 t = t->next;
413 }
414
415 SDK_ASSERTMSG(t, "Cannot remove thread from list.");
416
417 if (!pre)
418 {
419 OSi_ThreadInfo.list = thread->next;
420 }
421 else
422 {
423 pre->next = thread->next;
424 }
425 }
426
427 /*---------------------------------------------------------------------------*
428 Name: OSi_RescheduleThread
429
430 Description: Switch to the runnable thread with the highest priority.
431 without interrupts disabled.
432
433 Arguments: None.
434
435 Returns: None or Never return.
436 *---------------------------------------------------------------------------*/
OSi_RescheduleThread(void)437 static void OSi_RescheduleThread(void)
438 {
439 //---- if scheduler is set to be disabled, do nothing.
440 if (OSi_RescheduleCount <= 0)
441 {
442 OSThreadInfo *info = &OSi_ThreadInfo;
443 if (info->irqDepth > 0 || OS_GetProcMode() == OS_PROCMODE_IRQ)
444 {
445 // If in IRQ, do rescheduling at end of IRQ handler
446 info->isNeedRescheduling = TRUE;
447 }
448 else
449 {
450 OSThread *currentThread, *nextThread;
451 currentThread = OSi_GetCurrentThread();
452 nextThread = OS_SelectThread();
453
454 if (currentThread == nextThread || !nextThread) // maybe nextThread != NULL
455 {
456 return; // Don't have to switch the current context
457 }
458
459 if (currentThread->state != OS_THREAD_STATE_TERMINATED
460 && OS_SaveContext(¤tThread->context))
461 {
462 return; // Return if go back via OS_LoadContext
463 }
464
465 //---- call thread switch callback for system
466 if (OSi_SystemCallbackInSwitchThread)
467 {
468 ((OSSwitchThreadCallback)OSi_SystemCallbackInSwitchThread) (currentThread,
469 nextThread);
470 }
471
472 //---- call thread switch callback for user
473 if (info->switchCallback)
474 {
475 ((OSSwitchThreadCallback)info->switchCallback) (currentThread, nextThread);
476 }
477
478 OS_SetCurrentThread(nextThread);
479
480 OS_LoadContext(&nextThread->context);
481 // Never reached
482 }
483 }
484 }
485
486 /*---------------------------------------------------------------------------*
487 Name: OS_InitThread
488
489 Description: Initialize the thread system.
490
491 Arguments: None.
492
493 Returns: None.
494 *---------------------------------------------------------------------------*/
OS_InitThread(void)495 void OS_InitThread(void)
496 {
497 void *stackLo;
498 #ifndef SDK_THREAD_INFINITY
499 int i;
500 #endif
501
502 if (OSi_IsThreadInitialized)
503 {
504 return;
505 }
506 OSi_IsThreadInitialized = TRUE;
507
508 #ifndef SDK_THREAD_INFINITY
509 //---- Set thread info
510 for (i = 0; i < OS_THREAD_MAX_NUM; i++)
511 {
512 OSi_ThreadInfo.entry[i] = NULL;
513 }
514 #endif
515
516 //---- set pointer to current thread buffer
517 // (for quick reference)
518 OSi_CurrentThreadPtr = &(OSi_ThreadInfo.current);
519
520 //---- Set up launcher thread
521 OSi_LauncherThread.priority = OS_THREAD_LAUNCHER_PRIORITY;
522 OSi_LauncherThread.id = 0;
523 OSi_LauncherThread.state = OS_THREAD_STATE_READY;
524 OSi_LauncherThread.next = NULL;
525
526 //---- clear profile pointer
527 OSi_LauncherThread.profiler = NULL;
528
529 //---- clear thread entry and listPtr
530 #ifndef SDK_THREAD_INFINITY
531 OSi_ThreadInfo.entry[0] = &OSi_LauncherThread;
532 #endif
533 OSi_ThreadInfo.list = &OSi_LauncherThread;
534
535 //---- let launch thread be current
536 OS_SetCurrentThread(&OSi_LauncherThread);
537
538 //---- StackLo
539 stackLo = (OSi_SYS_STACKSIZE <= 0) ?
540 (void *)((u32)OSi_LAUNCHER_STACK_LO_DEFAULT - OSi_SYS_STACKSIZE) :
541 (void *)((u32)OSi_LAUNCHER_STACK_HI_MAX - OSi_SYS_STACKSIZE);
542 SDK_ASSERT((u32)OSi_LAUNCHER_STACK_LO_DEFAULT <= (u32)stackLo
543 && (u32)stackLo <= (u32)OSi_LAUNCHER_STACK_HI_MAX);
544
545 //---- set Stack Bottom & Top
546 OSi_LauncherThread.stackBottom = (u32)OSi_LAUNCHER_STACK_BOTTOM;
547 OSi_LauncherThread.stackTop = (u32)stackLo;
548 OSi_LauncherThread.stackWarningOffset = 0;
549
550 //---- Set Stack CheckNumber
551 *(u32 *)(OSi_LauncherThread.stackBottom - sizeof(u32)*2) = OSi_STACK_CHECKNUM_BOTTOM;
552 *(u32 *)OSi_LauncherThread.stackTop = OSi_STACK_CHECKNUM_TOP;
553
554 //---- clear join queue
555 OS_InitThreadQueue(&OSi_LauncherThread.joinQueue);
556
557 #ifndef SDK_THREAD_INFINITY
558 //---- max number of thread
559 OSi_ThreadInfo.max_entry = OS_THREAD_MAX_NUM;
560 #endif
561
562 //---- around IRQ
563 OSi_ThreadInfo.isNeedRescheduling = FALSE;
564 OSi_ThreadInfo.irqDepth = 0;
565 SDK_ASSERTMSG(OSi_IRQ_STACKSIZE > 0, "IRQ STACKSIZE must be >0");
566
567 //---- store thread info pointer
568 #ifdef SDK_ARM9
569 OS_GetSystemWork()->threadinfo_mainp = &OSi_ThreadInfo;
570 #else
571 OS_GetSystemWork()->threadinfo_subp = &OSi_ThreadInfo;
572 #endif
573
574 //---- set thread switch callback
575 (void)OS_SetSwitchThreadCallback(NULL);
576
577 //---- idle thread
578 OS_CreateThread(&OSi_IdleThread,
579 OSi_IdleThreadProc,
580 (void *)NULL,
581 OSi_IdleThreadStack + OSi_IDLE_THREAD_STACK_SIZE / sizeof(u32),
582 OSi_IDLE_THREAD_STACK_SIZE,
583 OS_THREAD_PRIORITY_MAX /*pseudo. change at next line. */ );
584 OSi_IdleThread.priority = OS_THREAD_PRIORITY_MAX + 1; // lower priority than the lowest (=OS_THREAD_PRIORITY_MAX)
585 OSi_IdleThread.state = OS_THREAD_STATE_READY;
586 }
587
588 /*---------------------------------------------------------------------------*
589 Name: OS_IsThreadAvailable
590
591 Description: Checks if thread system is available.
592
593 Arguments: None.
594
595 Returns: TRUE if available, FALSE if not
596 *---------------------------------------------------------------------------*/
OS_IsThreadAvailable(void)597 asm BOOL OS_IsThreadAvailable( void )
598 {
599 ldr r0, =OSi_IsThreadInitialized
600 ldr r0, [r0, #0]
601 bx lr
602 }
603
604 /*---------------------------------------------------------------------------*
605 Name: OS_CreateThread
606
607 Description: Creates a new thread.
608
609 Arguments: thread: pointer of thread structure
610 func: function to start thread
611 arg: argument for func
612 stack: stack bottom address
613 stackSize: stack size (byte. must be aligned by 4)
614 prio: thread priority
615
616 Returns: None.
617 *---------------------------------------------------------------------------*/
OS_CreateThread(OSThread * thread,void (* func)(void *),void * arg,void * stack,u32 stackSize,u32 prio)618 void OS_CreateThread(OSThread *thread,
619 void (*func) (void *), void *arg, void *stack, u32 stackSize, u32 prio)
620 {
621 #define STACK_ALIGN 4
622
623 OSIntrMode enable;
624 int index;
625
626 SDK_ASSERTMSG(OSi_GetCurrentThread(), "thread system were not initialized");
627 SDK_ASSERTMSG(OS_THREAD_PRIORITY_MIN <= prio
628 && prio <= OS_THREAD_PRIORITY_MAX, "invalid priority");
629 SDK_ASSERTMSG(stackSize % STACK_ALIGN == 0, "stack size must be aligned by %d", STACK_ALIGN);
630 SDK_ASSERTMSG((u32)stack % STACK_ALIGN == 0, "stack must be aligned by %d", STACK_ALIGN);
631
632 enable = OS_DisableInterrupts();
633
634 #ifndef SDK_THREAD_INFINITY
635 //---- search free entry
636 if ((index = OSi_SearchFreeEntry()) < 0)
637 {
638 SDK_ASSERTMSG(index >= 0, "OS_CreateThread: thread entry not allocated");
639 (void)OS_RestoreInterrupts(enable);
640 return;
641 }
642 #else
643 index = OSi_GetUnusedThreadId();
644 #endif
645
646 //---- set up thread
647 thread->priority = prio;
648 thread->id = (u32)index;
649 thread->state = OS_THREAD_STATE_WAITING;
650
651 //---- clear profile pointer
652 thread->profiler = NULL;
653
654 //---- set thread entry and listPtr
655 #ifndef SDK_THREAD_INFINITY
656 OSi_ThreadInfo.entry[index] = thread;
657 #endif
658 OSi_InsertThreadToList(thread);
659
660 //---- set Stack Bottom & Top
661 thread->stackBottom = (u32)stack;
662 thread->stackTop = (u32)stack - stackSize;
663 thread->stackWarningOffset = 0;
664
665 //---- Set Stack CheckNumber
666 *(u32 *)(thread->stackBottom - sizeof(u32)*2) = OSi_STACK_CHECKNUM_BOTTOM; // minus for stack CheckNumber and padding
667 *(u32 *)thread->stackTop = OSi_STACK_CHECKNUM_TOP;
668
669 //---- clear join queue
670 OS_InitThreadQueue(&thread->joinQueue);
671
672 //---- Init context
673 OS_InitContext(&thread->context, (u32)func, (u32)stack - sizeof(u32)*2); // minus for stack CheckNumber and padding
674
675 thread->context.r[0] = (u32)arg; // argument for func
676 thread->context.lr = (u32)OS_ExitThread;
677
678 //---- clear Stack (except check code (=sizeof(u32)*2) and padding(sizeof(u32))
679 MI_CpuClear32((void *)((u32)stack - stackSize + sizeof(u32)), stackSize - sizeof(u32) * 2 - sizeof(u32) );
680
681 //---- clear mutex
682 thread->mutex = NULL;
683 #ifndef SDK_THREAD_INFINITY
684 thread->mutexQueueHead = NULL;
685 thread->mutexQueueTail = NULL;
686 #else
687 thread->mutexQueue.head = NULL;
688 thread->mutexQueue.tail = NULL;
689 #endif
690
691 //---- clear destructor
692 #ifdef SDK_THREAD_INFINITY
693 OS_SetThreadDestructor(thread, NULL);
694 #endif
695
696 //---- clear queue
697 #ifdef SDK_THREAD_INFINITY
698 thread->queue = NULL;
699 thread->link.prev = thread->link.next = NULL;
700
701 //---- clear specific member
702 MI_CpuClear32(&thread->specific[0], sizeof(void *) * OS_THREAD_SPECIFIC_MAX);
703 #endif
704
705 //---- clear alarm pointer for sleep
706 thread->alarmForSleep = NULL;
707
708 (void)OS_RestoreInterrupts(enable);
709 }
710
711
712 /*---------------------------------------------------------------------------*
713 Name: OS_ExitThread
714
715 Description: Terminates the current thread.
716
717 Arguments: None.
718
719 Returns: None.
720 *---------------------------------------------------------------------------*/
OS_ExitThread(void)721 void OS_ExitThread(void)
722 {
723 (void)OS_DisableInterrupts();
724
725 #ifdef SDK_THREAD_INFINITY
726 OSi_ExitThread_ArgSpecified(OS_GetCurrentThread(), 0);
727 #else
728 OSi_ExitThread_Destroy();
729 #endif
730 }
731
732
733 #ifdef SDK_THREAD_INFINITY
734 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
735 // OSi_ExitThread that takes the destructor stack into account.
736 // Be sure to call with interrupts disabled.
OSi_ExitThread_ArgSpecified(OSThread * thread,void * arg)737 static void OSi_ExitThread_ArgSpecified(OSThread *thread, void *arg)
738 {
739 if (OSi_StackForDestructor)
740 {
741 OS_InitContext(&thread->context, (u32)OSi_ExitThread, (u32)OSi_StackForDestructor);
742 thread->context.r[0] = (u32)arg;
743 thread->context.cpsr |= HW_PSR_IRQ_DISABLE;
744 thread->state = OS_THREAD_STATE_READY;
745 OS_LoadContext(&thread->context);
746 // Never Returns
747 }
748 else
749 {
750 OSi_ExitThread(arg);
751 // Never Returns
752 }
753 }
754 #endif
755
756
757 #ifdef SDK_THREAD_INFINITY
758 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
759 // Context switch destination referenced by OS_KillThread.
760 // Be sure to call with interrupts disabled.
OSi_ExitThread(void * arg)761 static void OSi_ExitThread(void *arg)
762 {
763 OSThread *currentThread = OSi_GetCurrentThread();
764 OSThreadDestructor destructor;
765
766 SDK_ASSERT(currentThread);
767
768 // Destructor processing
769 destructor = currentThread->destructor;
770 if (destructor)
771 {
772 currentThread->destructor = NULL;
773 destructor(arg);
774 (void)OS_DisableInterrupts(); // Disable interrupts again
775 }
776
777 OSi_ExitThread_Destroy(); // Never return
778 }
779 #endif
780
781 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
782 // Called when destroying the current thread from OS_DestroyThread.
783 // Be sure to call with interrupts disabled.
OSi_ExitThread_Destroy(void)784 static void OSi_ExitThread_Destroy(void)
785 {
786 OSThread *currentThread = OSi_GetCurrentThread();
787 SDK_ASSERT(currentThread);
788
789 #ifdef SDK_THREAD_INFINITY
790 (void)OS_DisableScheduler();
791 #endif
792
793 #ifndef SDK_THREAD_INFINITY
794 //---- current thread check
795 SDK_ASSERT(OSi_ThreadInfo.entry[currentThread->id] == currentThread);
796 #endif
797
798 //---- Release all the mutexes locked by the current thread
799 OSi_UnlockAllMutex(currentThread);
800
801
802 //---- remove from thread queue list
803 if (currentThread->queue)
804 {
805 (void)OSi_RemoveSpecifiedLinkFromQueue(currentThread->queue, currentThread);
806 }
807
808 //---- remove from thread list
809 OSi_RemoveThreadFromList(currentThread);
810
811 //---- delete this thread
812 #ifndef SDK_THREAD_INFINITY
813 OSi_ThreadInfo.entry[currentThread->id] = NULL;
814 #endif
815 currentThread->state = OS_THREAD_STATE_TERMINATED;
816
817 //---- wakeup threads that are waiting for the currentThread to terminate
818 #ifndef SDK_THREAD_INFINITY
819 OS_WakeupThread(¤tThread->joinQueue); // possible to never return
820 #else
821 OS_WakeupThread(¤tThread->joinQueue);
822 #endif
823
824 #ifdef SDK_THREAD_INFINITY
825 (void)OS_EnableScheduler();
826 #endif
827
828 OS_RescheduleThread(); // Never return
829
830 OS_Terminate();
831 }
832
833 // TEST ---------------------------------------------------------------------
834 #ifdef NITRO_UTEST_H__
835 static vu32 exitThreadStatus = 0;
836
exitThreadFunc(void * arg)837 static void exitThreadFunc(void *arg)
838 {
839 exitThreadStatus = 1;
840 (void)arg;
841 }
842
843 void UTEST_OS_ExitThread(void);
UTEST_OS_ExitThread(void)844 void UTEST_OS_ExitThread(void)
845 {
846 OSThread thread;
847 u32 stack[1024];
848
849 OS_Init();
850 OS_InitThread();
851
852 OS_CreateThread(&thread,
853 exitThreadFunc,
854 NULL,
855 stack + 1024, sizeof(stack), OS_GetThreadPriority(OS_GetCurrentThread()) - 1);
856 OS_WakeupThreadDirect(&thread);
857 OS_JoinThread(&thread);
858 UT_AssertEq(exitThreadStatus, 1);
859 }
860 #endif // ifdef NITRO_UTEST_H__
861
862 /*---------------------------------------------------------------------------*
863 Name: OS_DestroyThread
864
865 Description: Destroys specified thread.
866
867 Arguments: thread : thread to be destroyed
868
869 Returns: None.
870 *---------------------------------------------------------------------------*/
OS_DestroyThread(OSThread * thread)871 void OS_DestroyThread(OSThread *thread)
872 {
873 OSIntrMode enabled = OS_DisableInterrupts();
874
875 SDK_ASSERT(thread);
876
877 //---- check current thread
878 if (OS_GetCurrentThread() == thread)
879 {
880 OSi_ExitThread_Destroy();
881 // not reached
882 }
883
884 #ifdef SDK_THREAD_INFINITY
885 (void)OS_DisableScheduler();
886 #endif
887
888 //---- Release all the mutexes locked by the specified thread
889 OSi_UnlockAllMutex(thread);
890
891 //---- cancel alarm for sleep
892 OSi_CancelThreadAlarmForSleep(thread);
893
894 //---- remove from thread queue list
895 if (thread->queue)
896 {
897 (void)OSi_RemoveSpecifiedLinkFromQueue(thread->queue, thread);
898 }
899
900 //---- remove from thread list
901 OSi_RemoveThreadFromList(thread);
902
903 //---- delete thread
904 #ifndef SDK_THREAD_INFINITY
905 OSi_ThreadInfo.entry[thread->id] = NULL;
906 #endif
907 thread->state = OS_THREAD_STATE_TERMINATED;
908
909 //---- wake up the thread that is waiting for this thread to terminate
910 OS_WakeupThread(&thread->joinQueue);
911
912 #ifdef SDK_THREAD_INFINITY
913 (void)OS_EnableScheduler();
914 #endif
915 (void)OS_RestoreInterrupts(enabled);
916
917 OS_RescheduleThread();
918 }
919
920 /*---------------------------------------------------------------------------*
921 Name: OS_KillThread
922
923 Description: Switches PC to thread destructor to finalize thread.
924
925 Arguments: thread : thread to wait to finish
926 flag: argument for destructor
927
928 Returns: None.
929 *---------------------------------------------------------------------------*/
930 #ifdef SDK_THREAD_INFINITY
931 // TESTEE
932 static inline void OSi_KillThreadWithPriority(OSThread *thread, void *arg, u32 prio);
OSi_KillThreadWithPriority(OSThread * thread,void * arg,u32 prio)933 static inline void OSi_KillThreadWithPriority(OSThread *thread, void *arg, u32 prio)
934 {
935 SDK_ASSERT(thread);
936
937 {
938 u32 stack = (OSi_StackForDestructor) ? (u32)OSi_StackForDestructor : thread->stackBottom - sizeof(u32)*2; // minus for stack CheckNumber and padding
939
940 OS_InitContext(&thread->context, (u32)OSi_ExitThread, stack);
941 }
942 thread->context.r[0] = (u32)arg;
943 thread->context.cpsr |= HW_PSR_IRQ_DISABLE; // prohibit IRQ interrupts within the destructor
944
945 thread->state = OS_THREAD_STATE_READY;
946
947 (void)OS_DisableScheduler();
948 (void)OS_SetThreadPriority(thread, prio);
949 (void)OS_EnableScheduler();
950 }
951
952 // BODY
OS_KillThread(OSThread * thread,void * arg)953 void OS_KillThread(OSThread *thread, void *arg)
954 {
955 OS_KillThreadWithPriority(thread, arg, OS_GetThreadPriority(thread));
956 }
957
OS_KillThreadWithPriority(OSThread * thread,void * arg,u32 prio)958 void OS_KillThreadWithPriority(OSThread *thread, void *arg, u32 prio)
959 {
960 OSIntrMode enabled = OS_DisableInterrupts();
961
962 if (thread == OS_GetCurrentThread())
963 {
964 OSi_ExitThread_ArgSpecified(thread, arg);
965 // Never returns
966 }
967
968 //---- cancel alarm for sleep
969 OSi_CancelThreadAlarmForSleep(thread);
970
971 OSi_KillThreadWithPriority(thread, arg, prio);
972
973 OSi_RescheduleThread();
974 (void)OS_RestoreInterrupts(enabled);
975 }
976
977 // TEST ---------------------------------------------------------------------
978 #ifdef NITRO_UTEST_H__
979 // test1
980 void UTEST_OS_KillThread_1(void);
UTEST_OS_KillThread_1(void)981 void UTEST_OS_KillThread_1(void)
982 {
983 OSThread thread;
984 OSThread *t = &thread;
985 u32 flag;
986
987 OS_Init();
988 OS_InitThread();
989
990 t->stackBottom = 0x6789abcd;
991 t->state = OS_THREAD_STATE_TERMINATED;
992 OSi_KillThreadWithPriority(t, (void *)0x12345678, 16);
993
994 // Main register check inside context
995 UT_AssertEq(t->context.pc_plus4, (u32)OSi_ExitThread + 4); // OS_ExitThread
996 UT_AssertEq(t->context.r[0], (u32)0x12345678); // arg
997 flag = ((u32)OS_ExitThread & 1) ? (u32)HW_PSR_THUMB_STATE : (u32)HW_PSR_ARM_STATE;
998 UT_AssertEq(t->context.cpsr, (u32)HW_PSR_IRQ_DISABLE | HW_PSR_SYS_MODE | flag);
999 UT_AssertEq(t->context.sp, (u32)0x6789abcd - HW_SVC_STACK_SIZE);
1000
1001 // Check the state
1002 UT_AssertEq(t->state, OS_THREAD_STATE_READY);
1003 UT_AssertAsserted(OSi_KillThreadWithPriority(0, 0, 16));
1004 }
1005
1006 // test2
1007 static vu32 killThreadStatus = 0;
1008
killThreadDtor(void * arg)1009 static void killThreadDtor(void *arg)
1010 {
1011 killThreadStatus = 666;
1012 (void)arg;
1013 }
1014
killThreadFunc(void * arg)1015 static void killThreadFunc(void *arg)
1016 {
1017 OS_SetThreadDestructor(OS_GetCurrentThread(), killThreadDtor);
1018
1019 killThreadStatus = 1;
1020 while (1)
1021 {
1022 OS_SleepThread(NULL);
1023 killThreadStatus++;
1024 }
1025 (void)arg;
1026 }
1027
1028 void UTEST_OS_KillThread_2(void);
UTEST_OS_KillThread_2(void)1029 void UTEST_OS_KillThread_2(void)
1030 {
1031 OSThread thread;
1032 u32 stack[1024];
1033
1034 OS_Init();
1035 OS_InitThread();
1036
1037 OS_CreateThread(&thread,
1038 killThreadFunc,
1039 NULL,
1040 stack + 1024, sizeof(stack), OS_GetThreadPriority(OS_GetCurrentThread()) - 1);
1041 UT_AssertEq(killThreadStatus, 0);
1042
1043 OS_WakeupThreadDirect(&thread);
1044 UT_AssertEq(killThreadStatus, 1);
1045 UT_AssertEq(thread.destructor, killThreadDtor);
1046
1047 OS_WakeupThreadDirect(&thread);
1048 UT_AssertEq(killThreadStatus, 2);
1049
1050 OS_KillThread(&thread, 0);
1051 OS_JoinThread(&thread);
1052 UT_AssertEq(killThreadStatus, 666);
1053 }
1054 #endif // ifdef NITRO_UTEST_H__
1055 #endif // ifdef SDK_THREAD_INFINITY
1056
1057 /*---------------------------------------------------------------------------*
1058 Name: OSi_CancelThreadAlarmForSleep
1059
1060 Description: Cancel alarm used to sleep thread.
1061 If sleeping alarm is not set, do nothing.
1062
1063 Arguments: thread : Thread for which to cancel the alarm.
1064
1065 Returns: None.
1066 *---------------------------------------------------------------------------*/
OSi_CancelThreadAlarmForSleep(OSThread * thread)1067 static void OSi_CancelThreadAlarmForSleep(OSThread *thread)
1068 {
1069 OSAlarm *alarm = thread->alarmForSleep;
1070
1071 if (alarm)
1072 {
1073 OS_CancelAlarm(alarm);
1074 }
1075 }
1076
1077 /*---------------------------------------------------------------------------*
1078 Name: OS_JoinThread
1079
1080 Description: Waits for specified thread to terminated.
1081
1082 Arguments: thread : thread to wait to finish
1083
1084 Returns: None.
1085 *---------------------------------------------------------------------------*/
OS_JoinThread(OSThread * thread)1086 void OS_JoinThread(OSThread *thread)
1087 {
1088 OSIntrMode enabled = OS_DisableInterrupts();
1089
1090 SDK_ASSERT(thread);
1091
1092 //---- skip if thread is terminated already
1093 while(thread->state != OS_THREAD_STATE_TERMINATED)
1094 {
1095 OS_SleepThread(&thread->joinQueue);
1096 }
1097
1098 (void)OS_RestoreInterrupts(enabled);
1099 }
1100
1101 /*---------------------------------------------------------------------------*
1102 Name: OS_IsThreadTerminated
1103
1104 Description: Checks thread status whether it's terminated.
1105
1106 Arguments: thread : pointer to thread to be examined
1107
1108 Returns: TRUE if the thread is terminated. FALSE if not
1109 *---------------------------------------------------------------------------*/
OS_IsThreadTerminated(const OSThread * thread)1110 BOOL OS_IsThreadTerminated(const OSThread *thread)
1111 {
1112 SDK_ASSERT(thread);
1113 return (thread->state == OS_THREAD_STATE_TERMINATED) ? TRUE : FALSE;
1114 }
1115
1116 /*---------------------------------------------------------------------------*
1117 Name: OS_GetThreadStatus
1118
1119 Description: get thread status
1120
1121 Arguments: thread : pointer to thread
1122
1123 Returns:
1124 *---------------------------------------------------------------------------*/
OS_GetThreadStatus(const OSThread * thread)1125 OSThreadState OS_GetThreadStatus(const OSThread *thread)
1126 {
1127 SDK_ASSERT(thread);
1128 return thread->state;
1129 }
1130
1131 /*---------------------------------------------------------------------------*
1132 Name: OS_SleepThreadDirect
1133
1134 Description: Gets the thread into sleep status directly.
1135
1136 Arguments: thread: thread to sleep
1137 queue: waiting list queue (or NULL)
1138
1139 Returns: None.
1140 *---------------------------------------------------------------------------*/
OS_SleepThreadDirect(OSThread * thread,OSThreadQueue * queue)1141 void OS_SleepThreadDirect(OSThread *thread, OSThreadQueue *queue)
1142 {
1143 SDK_ASSERT(thread);
1144 SDK_ASSERT(thread->state != OS_THREAD_STATE_TERMINATED);
1145
1146 {
1147 OSIntrMode bak_intr = OS_DisableInterrupts();
1148
1149 if ( thread->state == OS_THREAD_STATE_READY )
1150 {
1151 if (queue)
1152 {
1153 #ifndef SDK_THREAD_INFINITY
1154 *queue |= (OSThreadQueue)(1UL << thread->id);
1155 #else
1156 thread->queue = queue;
1157 OSi_InsertLinkToQueue(queue, thread);
1158 #endif
1159 }
1160 thread->state = OS_THREAD_STATE_WAITING;
1161 OSi_RescheduleThread();
1162 }
1163 (void)OS_RestoreInterrupts(bak_intr);
1164 }
1165 }
1166
1167 /*---------------------------------------------------------------------------*
1168 Name: OS_SleepThread
1169
1170 Description: Gets the current thread into sleep status.
1171
1172 Arguments: Waiting list queue.
1173
1174 Returns: None.
1175 *---------------------------------------------------------------------------*/
OS_SleepThread(OSThreadQueue * queue)1176 void OS_SleepThread(OSThreadQueue *queue)
1177 {
1178 OSIntrMode enable;
1179 OSThread *currentThread;
1180
1181 enable = OS_DisableInterrupts();
1182 #ifndef SDK_THREAD_INFINITY
1183 {
1184 currentThread = OSi_GetCurrentThread();
1185 SDK_ASSERT(currentThread);
1186
1187 if (queue)
1188 {
1189 *queue |= (OSThreadQueue)(1UL << currentThread->id);
1190 }
1191
1192 currentThread->state = OS_THREAD_STATE_WAITING;
1193 OSi_RescheduleThread();
1194 }
1195 #else
1196 {
1197 currentThread = OSi_GetCurrentThread();
1198 SDK_ASSERT(currentThread);
1199
1200 if (queue)
1201 {
1202 currentThread->queue = queue;
1203 OSi_InsertLinkToQueue(queue, currentThread);
1204 }
1205
1206 currentThread->state = OS_THREAD_STATE_WAITING;
1207 OSi_RescheduleThread();
1208 }
1209 #endif
1210 (void)OS_RestoreInterrupts(enable);
1211 }
1212
1213 /*---------------------------------------------------------------------------*
1214 Name: OS_WakeupThread
1215
1216 Description: Gets threads out of sleep status.
1217
1218 Arguments: None.
1219
1220 Returns: None.
1221 *---------------------------------------------------------------------------*/
OS_WakeupThread(OSThreadQueue * queue)1222 void OS_WakeupThread(OSThreadQueue *queue)
1223 {
1224 OSIntrMode enable;
1225 #ifndef SDK_THREAD_INFINITY
1226 u32 mask;
1227 #else
1228 BOOL isNeedRescheduling = FALSE;
1229 #endif
1230 SDK_ASSERT(queue);
1231 enable = OS_DisableInterrupts();
1232
1233 #ifndef SDK_THREAD_INFINITY
1234 mask = (u32)*queue;
1235 if (mask)
1236 {
1237 //---- wakeup threads
1238 OSThread *t = OSi_ThreadInfo.list;
1239 while (t)
1240 {
1241 if (mask & (1UL << t->id))
1242 {
1243 t->state = OS_THREAD_STATE_READY;
1244 }
1245
1246 t = t->next;
1247 }
1248
1249 OS_InitThreadQueue(queue);
1250 OSi_RescheduleThread();
1251 }
1252 #else
1253 if (queue->head)
1254 {
1255 while (queue->head)
1256 {
1257 OSThread *thread = OSi_RemoveLinkFromQueue(queue);
1258
1259 thread->state = OS_THREAD_STATE_READY;
1260 thread->queue = NULL;
1261 thread->link.prev = thread->link.next = NULL;
1262 }
1263
1264 OS_InitThreadQueue(queue);
1265 OSi_RescheduleThread();
1266 }
1267 #endif
1268
1269 (void)OS_RestoreInterrupts(enable);
1270 }
1271
1272
1273 /*---------------------------------------------------------------------------*
1274 Name: OS_WakeupThreadDirect
1275
1276 Description: Gets threads out of sleep status directly.
1277
1278 Arguments: None.
1279
1280 Returns: None.
1281 *---------------------------------------------------------------------------*/
OS_WakeupThreadDirect(OSThread * thread)1282 void OS_WakeupThreadDirect(OSThread *thread)
1283 {
1284 OSIntrMode enable;
1285
1286 SDK_ASSERT(thread);
1287 SDK_ASSERT(thread->state != OS_THREAD_STATE_TERMINATED);
1288 enable = OS_DisableInterrupts();
1289 {
1290 thread->state = OS_THREAD_STATE_READY;
1291 OSi_RescheduleThread();
1292
1293 }
1294 (void)OS_RestoreInterrupts(enable);
1295 }
1296
1297
1298 /*---------------------------------------------------------------------------*
1299 Name: OS_SelectThread
1300
1301 Description: Select the runnable thread with the highest priority.
1302
1303 Arguments: None.
1304
1305 Returns: Pointer to the thread that must run.
1306 NULL if there is no thread candidate to run.
1307 *---------------------------------------------------------------------------*/
OS_SelectThread(void)1308 OSThread *OS_SelectThread(void)
1309 {
1310 OSThread *t = OSi_ThreadInfo.list;
1311
1312 while (t && !OS_IsThreadRunnable(t))
1313 {
1314 t = t->next;
1315 }
1316
1317 return t;
1318 }
1319
1320 /*---------------------------------------------------------------------------*
1321 Name: OS_RescheduleThread
1322
1323 Description: Switch to the runnable thread with the highest priority.
1324
1325 Arguments: None.
1326
1327 Returns: None or Never return.
1328 *---------------------------------------------------------------------------*/
OS_RescheduleThread(void)1329 void OS_RescheduleThread(void)
1330 {
1331 OSIntrMode bak_intr = OS_DisableInterrupts();
1332 OSi_RescheduleThread();
1333 (void)OS_RestoreInterrupts(bak_intr);
1334 }
1335
1336 /*---------------------------------------------------------------------------*
1337 Name: OS_YieldThread
1338
1339 Description: Does thread rescheduling. Current thread relinquish CPU
1340 to give chance of running to other threads which has same
1341 priority.
1342
1343 Arguments: None.
1344
1345 Returns: None.
1346 *---------------------------------------------------------------------------*/
OS_YieldThread(void)1347 void OS_YieldThread(void)
1348 {
1349 OSThread *current = OS_GetCurrentThread();
1350 OSThread *pre = NULL;
1351 OSThread *lastThread = NULL;
1352 int samePriorityThread = 0;
1353 OSIntrMode enable = OS_DisableInterrupts();
1354
1355 {
1356 OSThread *t = OSi_ThreadInfo.list;
1357 OSThread *tPre = NULL;
1358
1359 while (t)
1360 {
1361 if (t == current)
1362 {
1363 pre = tPre;
1364 }
1365
1366 if (current->priority == t->priority)
1367 {
1368 lastThread = t;
1369 samePriorityThread++;
1370 }
1371
1372 tPre = t;
1373 t = t->next;
1374 }
1375 }
1376
1377 //---- no thread with the same priority as the current one or do not need to arrange list
1378 if (samePriorityThread <= 1 || lastThread == current)
1379 {
1380 (void)OS_RestoreInterrupts(enable);
1381 return;
1382 }
1383
1384 //---- remove thread from list
1385 if (!pre)
1386 {
1387 OSi_ThreadInfo.list = current->next;
1388 }
1389 else
1390 {
1391 pre->next = current->next;
1392 }
1393
1394 //---- insert thread after 'lastThread'
1395 current->next = lastThread->next;
1396 lastThread->next = current;
1397
1398 //---- re-schedule
1399 OSi_RescheduleThread();
1400
1401 (void)OS_RestoreInterrupts(enable);
1402 }
1403
1404
1405 /*---------------------------------------------------------------------------*
1406 Name: OS_DumpThreadList
1407
1408 Description: Dump the thread list.
1409
1410 Arguments: None.
1411
1412 Returns: None.
1413 *---------------------------------------------------------------------------*/
OS_DumpThreadList(void)1414 void OS_DumpThreadList(void)
1415 {
1416 #ifndef SDK_FINALROM
1417 #ifndef SDK_THREAD_INFINITY
1418 int i;
1419 #endif
1420
1421 OS_Printf("thread list top %08x\n", OSi_ThreadInfo.list);
1422
1423 #ifndef SDK_THREAD_INFINITY
1424 OS_Printf("No: address prio next\n");
1425 for (i = 0; i < OS_THREAD_MAX_NUM; i++)
1426 {
1427 OSThread *thread = OSi_ThreadInfo.entry[i];
1428 OS_Printf("%02d: %08x %5d %08x\n", i, thread, (thread) ? thread->priority : 0,
1429 (thread) ? thread->next : 0);
1430 }
1431 #else
1432 // OS_Printf("Id: address prio next\n");
1433 OS_Printf("Id: address prio next st queue.h queue.t link.p link.n\n");
1434 {
1435 OSThread *thread = OSi_ThreadInfo.list;
1436 while (thread)
1437 {
1438 // OS_Printf("%02d: %08x %5d %08x\n", thread->id, thread, thread->priority, thread->next );
1439 OS_Printf("%02d: %08x %5d %08x %d %8x %8x %8x %8x\n", thread->id, thread,
1440 thread->priority, thread->next, thread->state,
1441 (thread->queue) ? thread->queue->head : (OSThread *)1,
1442 (thread->queue) ? thread->queue->tail : (OSThread *)1, thread->link.prev,
1443 thread->link.next);
1444 thread = thread->next;
1445
1446 }
1447 }
1448 #endif
1449 #endif
1450 }
1451
1452 /*---------------------------------------------------------------------------*
1453 Name: OS_GetNumberOfThread
1454
1455 Description: Get the number of threads that exist in the system.
1456
1457 Arguments: None.
1458
1459 Returns: number of thread which exists in system
1460 *---------------------------------------------------------------------------*/
OS_GetNumberOfThread(void)1461 int OS_GetNumberOfThread(void)
1462 {
1463 OSIntrMode enabled = OS_DisableInterrupts();
1464 int threads = 0;
1465
1466 #ifndef SDK_THREAD_INFINITY
1467 int i;
1468
1469 for (i = 0; i < OS_THREAD_MAX_NUM; i++)
1470 {
1471 if (OSi_ThreadInfo.entry[i])
1472 {
1473 threads++;
1474 }
1475 }
1476 #else
1477 OSThread *thread = OSi_ThreadInfo.list;
1478 while (thread)
1479 {
1480 threads++;
1481 thread = thread->next;
1482 }
1483 #endif
1484
1485 (void)OS_RestoreInterrupts(enabled);
1486 return threads;
1487 }
1488
1489 /*---------------------------------------------------------------------------*
1490 Name: OS_GetStackStatus
1491
1492 Description: Checks thread stack. Check each CheckNUM.
1493 Return result.
1494
1495 Arguments: thread: thread checked
1496
1497 Returns: 0 (OS_STACK_NO_ERROR): no error
1498 OS_STACK_OVERFLOW: overflow
1499 OS_STACK_ABOUT_TO_OVERFLOW: about to overflow
1500 OS_STACK_UNDERFLOW: underflow
1501 *---------------------------------------------------------------------------*/
OS_GetStackStatus(const OSThread * thread)1502 OSStackStatus OS_GetStackStatus(const OSThread *thread)
1503 {
1504 //---- Check if overflow
1505 if (*(u32 *)(thread->stackTop) != OSi_STACK_CHECKNUM_TOP)
1506 {
1507 return OS_STACK_OVERFLOW;
1508 }
1509 //---- Check if about to overflow
1510 else if (thread->stackWarningOffset
1511 && *(u32 *)(thread->stackTop + thread->stackWarningOffset) != OSi_STACK_CHECKNUM_WARN)
1512 {
1513 return OS_STACK_ABOUT_TO_OVERFLOW;
1514 }
1515 //---- Check if underFlow
1516 else if (*(u32 *)(thread->stackBottom - sizeof(u32)*2) != OSi_STACK_CHECKNUM_BOTTOM)
1517 {
1518 return OS_STACK_UNDERFLOW;
1519 }
1520 //---- No Error, return.
1521 else
1522 {
1523 return OS_STACK_NO_ERROR;
1524 }
1525 }
1526
1527 /*---------------------------------------------------------------------------*
1528 Name: OSi_CheckStack
1529
1530 Description: Checks thread stack. Check each CheckNUM.
1531 If changed, display warning and halt.
1532
1533 Arguments: file: Filename displayed when stack overflows.
1534 line: Line number displayed when stack overflows.
1535 thread: thread checked
1536
1537 Returns: None.
1538 ( if error occurred, never return )
1539 *---------------------------------------------------------------------------*/
1540 static char *OSi_CheckStack_mesg[] = {
1541 "overflow", "about to overflow", "underflow"
1542 };
1543
1544 #ifndef SDK_FINALROM
1545 #ifndef SDK_NO_MESSAGE
OSi_CheckStack(const char * file,int line,const OSThread * thread)1546 void OSi_CheckStack(const char *file, int line, const OSThread *thread)
1547 {
1548 OSStackStatus st;
1549
1550 if ((st = OS_GetStackStatus(thread)) == OS_STACK_NO_ERROR)
1551 {
1552 return;
1553 }
1554
1555 OSi_Panic(file, line, " stack %x(id:%d) %s.\nstack area: %08x-%08x, warning offset: %x",
1556 thread,
1557 thread->id,
1558 OSi_CheckStack_mesg[(int)st - 1],
1559 thread->stackTop, thread->stackBottom, thread->stackWarningOffset);
1560 // Never return
1561 }
1562 #endif
1563 #endif
1564
1565 /*---------------------------------------------------------------------------*
1566 Name: OSi_GetSystemStackPointer
1567
1568 Description: Get the system mode stack pointer at svc/irq mode.
1569
1570 Arguments: None.
1571
1572 Returns: Stack Pointer
1573 *---------------------------------------------------------------------------*/
1574 static u32 OSi_SystemStackBuffer;
1575
1576 #include <nitro/code32.h>
OSi_GetSystemStackPointer(void)1577 asm u32 OSi_GetSystemStackPointer( void )
1578 {
1579 ldr r0, =OSi_SystemStackBuffer
1580 stmia r0, { sp }^
1581 ldr r0, [ r0 ]
1582 bx lr
1583 }
1584 #include <nitro/codereset.h>
1585
1586 /*---------------------------------------------------------------------------*
1587 Name: OSi_GetCurrentStackPointer
1588
1589 Description: Get the current mode stack pointer.
1590
1591 Arguments: None.
1592
1593 Returns: Stack Pointer
1594 *---------------------------------------------------------------------------*/
OSi_GetCurrentStackPointer(void)1595 asm u32 OSi_GetCurrentStackPointer( void )
1596 {
1597 mov r0, sp
1598 bx lr
1599 }
1600
1601 /*---------------------------------------------------------------------------*
1602 Name: OS_SetThreadStackWarningOffset
1603
1604 Description: Sets warning level for stack checker.
1605
1606 Arguments: thread: thread to set
1607 offset: offset from stack top. Must be multiple of 4
1608
1609 Returns: None.
1610 *---------------------------------------------------------------------------*/
OS_SetThreadStackWarningOffset(OSThread * thread,u32 offset)1611 void OS_SetThreadStackWarningOffset(OSThread *thread, u32 offset)
1612 {
1613 SDK_ASSERTMSG((offset & 3) == 0, "Offset must be aligned by 4");
1614 SDK_ASSERTMSG(OS_GetThreadContext(thread)->sp > thread->stackTop + offset,
1615 "Cannot set warning level below current sp.");
1616
1617 //---- remember warning offset
1618 thread->stackWarningOffset = offset;
1619
1620 //---- set Stack CheckNum
1621 if (offset != 0)
1622 {
1623 *(u32 *)(thread->stackTop + offset) = OSi_STACK_CHECKNUM_WARN;
1624 }
1625 }
1626
1627 /*---------------------------------------------------------------------------*
1628 Name: OS_SetThreadPriority
1629
1630 Description: Changes priority of thread.
1631
1632 Arguments: thread: thread to set priority
1633 prio: new priority to be set
1634
1635 Returns: TRUE if success
1636 *---------------------------------------------------------------------------*/
OS_SetThreadPriority(OSThread * thread,u32 prio)1637 BOOL OS_SetThreadPriority(OSThread *thread, u32 prio)
1638 {
1639 OSThread *t = OSi_ThreadInfo.list;
1640 OSThread *pre = NULL;
1641 OSIntrMode enable;
1642
1643 SDK_ASSERTMSG(OS_THREAD_PRIORITY_MIN <= prio
1644 && prio <= OS_THREAD_PRIORITY_MAX, "invalid priority");
1645 SDK_ASSERTMSG(thread != &OSi_IdleThread, "cannot change idle thread priority.");
1646
1647 enable = OS_DisableInterrupts();
1648
1649 while (t && t != thread)
1650 {
1651 pre = t;
1652 t = t->next;
1653 }
1654
1655 //---- thread not found or thread is idle
1656 if (!t || t == &OSi_IdleThread)
1657 {
1658 (void)OS_RestoreInterrupts(enable);
1659 return FALSE;
1660 }
1661
1662 if (t->priority != prio)
1663 {
1664 //---- remove thread from list
1665 if (!pre)
1666 {
1667 OSi_ThreadInfo.list = thread->next;
1668 }
1669 else
1670 {
1671 pre->next = thread->next;
1672 }
1673
1674 //---- set priority and insert proper position
1675 thread->priority = prio;
1676 OSi_InsertThreadToList(thread);
1677
1678 //---- re-schedule
1679 OSi_RescheduleThread();
1680 }
1681
1682 (void)OS_RestoreInterrupts(enable);
1683
1684 return TRUE;
1685 }
1686
1687 /*---------------------------------------------------------------------------*
1688 Name: OS_GetThreadPriority
1689
1690 Description: Gets priority of thread.
1691
1692 Arguments: thread: thread to get priority
1693
1694 Returns: priority
1695 *---------------------------------------------------------------------------*/
OS_GetThreadPriority(const OSThread * thread)1696 u32 OS_GetThreadPriority(const OSThread *thread)
1697 {
1698 SDK_ASSERTMSG(thread, "OS_GetThreadPriority: bad thread");
1699
1700 return thread->priority;
1701 }
1702
1703
1704 /*---------------------------------------------------------------------------*
1705 Name: OS_Sleep
1706
1707 Description: Sleep specified period.
1708
1709 Arguments: msec: sleeping period. ( milliseconds )
1710
1711 Returns: None.
1712 *---------------------------------------------------------------------------*/
OS_Sleep(u32 msec)1713 void OS_Sleep(u32 msec)
1714 {
1715 OSAlarm alarm;
1716
1717 SDK_ASSERTMSG(OS_IsTickAvailable()
1718 && OS_IsAlarmAvailable(), "OS_Sleep: need to start Tick and Alarm beforehand.");
1719 SDK_ASSERTMSG(OSi_IsThreadInitialized, "OS_Sleep: thread system not initialized.");
1720
1721 OS_CreateAlarm(&alarm);
1722 {
1723 OSThread *volatile p_thread = OSi_GetCurrentThread();
1724 OSIntrMode bak_cpsr = OS_DisableInterrupts();
1725
1726 // ---- remember alarm
1727 p_thread->alarmForSleep = &alarm;
1728
1729 OS_SetAlarm(&alarm, OS_MilliSecondsToTicks(msec), &OSi_SleepAlarmCallback,
1730 (void *)&p_thread);
1731 while (p_thread != NULL)
1732 {
1733 OS_SleepThread(NULL);
1734 }
1735 (void)OS_RestoreInterrupts(bak_cpsr);
1736 }
1737 }
1738
1739 //---------------- callback to wakeup sleeping thread
OSi_SleepAlarmCallback(void * arg)1740 static void OSi_SleepAlarmCallback(void *arg)
1741 {
1742 OSThread **pp_thread = (OSThread **)arg;
1743 OSThread *p_thread = *pp_thread;
1744 *pp_thread = NULL;
1745
1746 //---- clear remembrance of alarm
1747 p_thread->alarmForSleep = NULL;
1748
1749 OS_WakeupThreadDirect(p_thread);
1750 }
1751
1752
1753 /*---------------------------------------------------------------------------*
1754 Name: OS_SetSwitchThreadCallback
1755
1756 Description: Sets callback called at switching thread.
1757
1758 Arguments: callback: callback function
1759
1760 Returns: Previous callback function before set callback now
1761 *---------------------------------------------------------------------------*/
OS_SetSwitchThreadCallback(OSSwitchThreadCallback callback)1762 OSSwitchThreadCallback OS_SetSwitchThreadCallback(OSSwitchThreadCallback callback)
1763 {
1764 OSSwitchThreadCallback prev;
1765 OSIntrMode enabled;
1766
1767 enabled = OS_DisableInterrupts();
1768 prev = OSi_ThreadInfo.switchCallback;
1769 OSi_ThreadInfo.switchCallback = callback;
1770
1771 (void)OS_RestoreInterrupts(enabled);
1772 return prev;
1773 }
1774
1775 /*---------------------------------------------------------------------------*
1776 Name: OSi_IdleThreadProc
1777
1778 Description: Procedure of idle thread that system creates.
1779
1780 Arguments: None.
1781
1782 Returns: None (never return)
1783 *---------------------------------------------------------------------------*/
OSi_IdleThreadProc(void *)1784 static void OSi_IdleThreadProc(void *)
1785 {
1786 (void)OS_EnableInterrupts();
1787 while (1)
1788 {
1789 OS_Halt();
1790 }
1791 // Never return
1792 }
1793
1794 /*---------------------------------------------------------------------------*
1795 Name: OSi_GetIdleThread
1796
1797 Description: Get a pointer to the idle thread structure.
1798
1799 Arguments: None.
1800
1801 Returns: Pointer to the idle thread structure.
1802 *---------------------------------------------------------------------------*/
OSi_GetIdleThread(void)1803 OSThread *OSi_GetIdleThread(void)
1804 {
1805 OSThread *t = NULL;
1806 if (OSi_IsThreadInitialized)
1807 {
1808 t = &OSi_IdleThread;
1809 }
1810 return t;
1811 }
1812
1813 /*---------------------------------------------------------------------------*
1814 Name: OS_DisableScheduler
1815
1816 Description: Disables scheduler.
1817
1818 Arguments: None.
1819
1820 Returns: Previous scheduler suspend count.
1821 Suspended if value >= 0.
1822 *---------------------------------------------------------------------------*/
OS_DisableScheduler(void)1823 u32 OS_DisableScheduler(void)
1824 {
1825 OSIntrMode enabled = OS_DisableInterrupts();
1826 u32 count;
1827
1828 if (OSi_RescheduleCount < (u32)(0 - 1) /* u32 max value -1 */ )
1829 {
1830 count = OSi_RescheduleCount++;
1831 }
1832 (void)OS_RestoreInterrupts(enabled);
1833
1834 return count;
1835 }
1836
1837 /*---------------------------------------------------------------------------*
1838 Name: OS_EnableScheduler
1839
1840 Description: Enables scheduler.
1841
1842 Arguments: None.
1843
1844 Returns: Previous scheduler suspend count.
1845 Suspended if value >= 0.
1846 *---------------------------------------------------------------------------*/
OS_EnableScheduler(void)1847 u32 OS_EnableScheduler(void)
1848 {
1849 OSIntrMode enabled = OS_DisableInterrupts();
1850 u32 count = 0;
1851
1852 if (OSi_RescheduleCount > 0)
1853 {
1854 count = OSi_RescheduleCount--;
1855 }
1856 (void)OS_RestoreInterrupts(enabled);
1857
1858 return count;
1859 }
1860
1861 #ifdef SDK_THREAD_INFINITY
1862 /*---------------------------------------------------------------------------*
1863 Name: OS_GetThread
1864
1865 Description: Gets pointer to thread whose id is specified.
1866
1867 Arguments: id: thread id to get thread
1868
1869 Returns: pointer to thread which id is specified
1870 *---------------------------------------------------------------------------*/
OS_GetThread(u32 id)1871 OSThread *OS_GetThread(u32 id)
1872 {
1873 OSThread *retval = NULL;
1874 OSThread *t = OSi_ThreadInfo.list;
1875
1876 while (t)
1877 {
1878 if (t->id == id)
1879 {
1880 retval = t;
1881 break;
1882 }
1883
1884 t = t->next;
1885 }
1886
1887 return retval;
1888 }
1889 #endif
1890
1891
1892 #ifdef SDK_THREAD_INFINITY
1893 /*---------------------------------------------------------------------------*
1894 Name: OS_SetThreadDestructor
1895
1896 Description: Sets thread destructor, which is called when that thread exits.
1897
1898 Arguments: thread : thread pointer
1899 dtor : destructor function
1900
1901 Returns: None.
1902 *---------------------------------------------------------------------------*/
OS_SetThreadDestructor(OSThread * thread,OSThreadDestructor dtor)1903 void OS_SetThreadDestructor(OSThread *thread, OSThreadDestructor dtor)
1904 {
1905 SDK_ASSERT(thread);
1906 thread->destructor = dtor;
1907 }
1908
1909 /*---------------------------------------------------------------------------*
1910 Name: OS_GetThreadDestructor
1911
1912 Description: Gets thread destructor which is set.
1913
1914 Arguments: thread : thread pointer
1915
1916 Returns: destructor function
1917 *---------------------------------------------------------------------------*/
OS_GetThreadDestructor(const OSThread * thread)1918 OSThreadDestructor OS_GetThreadDestructor(const OSThread *thread)
1919 {
1920 SDK_ASSERT(thread);
1921 return thread->destructor;
1922 }
1923
1924 /*---------------------------------------------------------------------------*
1925 Name: OS_SetThreadParameter
1926
1927 Description: Sets user parameter which is allowed to use freely.
1928
1929 Arguments: thread : thread pointer
1930 parameter : user parameter
1931
1932 Returns: None.
1933 *---------------------------------------------------------------------------*/
OS_SetThreadParameter(OSThread * thread,void * parameter)1934 void OS_SetThreadParameter(OSThread *thread, void *parameter)
1935 {
1936 SDK_ASSERT(thread);
1937 thread->userParameter = parameter;
1938 }
1939
1940 /*---------------------------------------------------------------------------*
1941 Name: OS_GetThreadParameter
1942
1943 Description: Gets user parameter which is set.
1944
1945 Arguments: thread : thread pointer
1946
1947 Returns: user parameter that is set
1948 *---------------------------------------------------------------------------*/
OS_GetThreadParameter(const OSThread * thread)1949 void *OS_GetThreadParameter(const OSThread *thread)
1950 {
1951 SDK_ASSERT(thread);
1952 return thread->userParameter;
1953 }
1954
1955
1956
1957 /*---------------------------------------------------------------------------*
1958 Name: OSi_SetSystemErrno
1959
1960 Description: Sets system error number.
1961
1962 Arguments: thread : thread to set error number
1963 errno : error number to set
1964
1965 Returns: None.
1966 *---------------------------------------------------------------------------*/
OSi_SetSystemErrno(OSThread * thread,int errno)1967 void OSi_SetSystemErrno(OSThread *thread, int errno)
1968 {
1969 SDK_ASSERT(thread);
1970 thread->systemErrno = errno;
1971 }
1972
1973 /*---------------------------------------------------------------------------*
1974 Name: OSi_GetSystemErrno
1975
1976 Description: Gets system error number.
1977
1978 Arguments: thread : thread to set error number
1979
1980 Returns: error number
1981 *---------------------------------------------------------------------------*/
OSi_GetSystemErrno(const OSThread * thread)1982 int OSi_GetSystemErrno(const OSThread *thread)
1983 {
1984 SDK_ASSERT(thread);
1985 return thread->systemErrno;
1986 }
1987
1988 /*---------------------------------------------------------------------------*
1989 Name: OS_GetErrno
1990
1991 Description: Gets system error number.
1992
1993 Arguments: None.
1994
1995 Returns: error number
1996 *---------------------------------------------------------------------------*/
OS_GetErrno(void)1997 int OS_GetErrno(void)
1998 {
1999 OSThread *thread = OSi_GetCurrentThread();
2000 return OSi_GetSystemErrno(thread);
2001 }
2002 #endif
2003
2004 /*---------------------------------------------------------------------------*
2005 Name: OS_IsThreadInList
2006
2007 Description: Checks if the specified thread is in the thread list.
2008
2009 Arguments: thread : thread
2010
2011 Returns: TRUE if thread is in the thread list
2012 *---------------------------------------------------------------------------*/
OS_IsThreadInList(const OSThread * thread)2013 BOOL OS_IsThreadInList(const OSThread *thread)
2014 {
2015 BOOL r = FALSE;
2016 OSThread *t = OSi_ThreadInfo.list;
2017 OSIntrMode enabled = OS_DisableInterrupts();
2018
2019 while (t)
2020 {
2021 if (t == thread)
2022 {
2023 r = TRUE;
2024 break;
2025 }
2026
2027 t = t->next;
2028 }
2029
2030 (void)OS_RestoreInterrupts(enabled);
2031 return r;
2032 }
2033
2034 /*---------------------------------------------------------------------------*
2035 Name: OS_SetThreadDestructorStack
2036
2037 Description: Specifies stack area to call thread destructor.
2038
2039 Arguments: stack: stack bottom address
2040 stackSize: stack size (byte. must be aligned by 4)
2041
2042 Returns: None.
2043 *---------------------------------------------------------------------------*/
OS_SetThreadDestructorStack(void * stack)2044 void OS_SetThreadDestructorStack(void *stack)
2045 {
2046 SDK_ASSERT(stack);
2047 SDK_ASSERT((u32)stack % STACK_ALIGN == 0);
2048
2049 OSi_StackForDestructor = stack;
2050 }
2051
2052 //================================================================================
2053 // for DEBUG
2054 //================================================================================
2055 /*---------------------------------------------------------------------------*
2056 Name: OS_GetThreadResource
2057
2058 Description: Stores thread resources to specified pointer.
2059
2060 Arguments: resource Pointer storing thread resources
2061
2062 Returns: TRUE ... success (always return this now)
2063 FALSE ... fail
2064 *---------------------------------------------------------------------------*/
OS_GetThreadResource(OSThreadResource * resource)2065 BOOL OS_GetThreadResource(OSThreadResource *resource)
2066 {
2067 resource->num = OS_GetNumberOfThread();
2068
2069 return TRUE;
2070 }
2071
2072
2073 #if defined(SDK_TCM_APPLY) && defined(SDK_ARM9)
2074 #include <nitro/itcm_end.h>
2075 #endif
2076