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:: 2009-12-17#$
14 $Rev: 11257 $
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_TASSERTMSG(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_TASSERTMSG(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_TASSERTMSG(OSi_GetCurrentThread(), "thread system were not initialized");
627 SDK_TASSERTMSG(OS_THREAD_PRIORITY_MIN <= prio
628 && prio <= OS_THREAD_PRIORITY_MAX, "invalid priority");
629 SDK_TASSERTMSG(stackSize % STACK_ALIGN == 0, "stack size must be aligned by %d", STACK_ALIGN);
630 SDK_TASSERTMSG((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_TASSERTMSG(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 SDK_ASSERT( OS_GetProcMode() != OS_PROCMODE_IRQ );
1182
1183 enable = OS_DisableInterrupts();
1184 #ifndef SDK_THREAD_INFINITY
1185 {
1186 currentThread = OSi_GetCurrentThread();
1187 SDK_ASSERT(currentThread);
1188
1189 if (queue)
1190 {
1191 *queue |= (OSThreadQueue)(1UL << currentThread->id);
1192 }
1193
1194 currentThread->state = OS_THREAD_STATE_WAITING;
1195 OSi_RescheduleThread();
1196 }
1197 #else
1198 {
1199 currentThread = OSi_GetCurrentThread();
1200 SDK_ASSERT(currentThread);
1201
1202 if (queue)
1203 {
1204 currentThread->queue = queue;
1205 OSi_InsertLinkToQueue(queue, currentThread);
1206 }
1207
1208 currentThread->state = OS_THREAD_STATE_WAITING;
1209 OSi_RescheduleThread();
1210 }
1211 #endif
1212 (void)OS_RestoreInterrupts(enable);
1213 }
1214
1215 /*---------------------------------------------------------------------------*
1216 Name: OS_WakeupThread
1217
1218 Description: Gets threads out of sleep status.
1219
1220 Arguments: None.
1221
1222 Returns: None.
1223 *---------------------------------------------------------------------------*/
OS_WakeupThread(OSThreadQueue * queue)1224 void OS_WakeupThread(OSThreadQueue *queue)
1225 {
1226 OSIntrMode enable;
1227 #ifndef SDK_THREAD_INFINITY
1228 u32 mask;
1229 #else
1230 BOOL isNeedRescheduling = FALSE;
1231 #endif
1232 SDK_ASSERT(queue);
1233 enable = OS_DisableInterrupts();
1234
1235 #ifndef SDK_THREAD_INFINITY
1236 mask = (u32)*queue;
1237 if (mask)
1238 {
1239 //---- wakeup threads
1240 OSThread *t = OSi_ThreadInfo.list;
1241 while (t)
1242 {
1243 if (mask & (1UL << t->id))
1244 {
1245 t->state = OS_THREAD_STATE_READY;
1246 }
1247
1248 t = t->next;
1249 }
1250
1251 OS_InitThreadQueue(queue);
1252 OSi_RescheduleThread();
1253 }
1254 #else
1255 if (queue->head)
1256 {
1257 while (queue->head)
1258 {
1259 OSThread *thread = OSi_RemoveLinkFromQueue(queue);
1260
1261 thread->state = OS_THREAD_STATE_READY;
1262 thread->queue = NULL;
1263 thread->link.prev = thread->link.next = NULL;
1264 }
1265
1266 OS_InitThreadQueue(queue);
1267 OSi_RescheduleThread();
1268 }
1269 #endif
1270
1271 (void)OS_RestoreInterrupts(enable);
1272 }
1273
1274
1275 /*---------------------------------------------------------------------------*
1276 Name: OS_WakeupThreadDirect
1277
1278 Description: Gets threads out of sleep status directly.
1279
1280 Arguments: None.
1281
1282 Returns: None.
1283 *---------------------------------------------------------------------------*/
OS_WakeupThreadDirect(OSThread * thread)1284 void OS_WakeupThreadDirect(OSThread *thread)
1285 {
1286 OSIntrMode enable;
1287
1288 SDK_ASSERT(thread);
1289 SDK_ASSERT(thread->state != OS_THREAD_STATE_TERMINATED);
1290 enable = OS_DisableInterrupts();
1291 {
1292 thread->state = OS_THREAD_STATE_READY;
1293 OSi_RescheduleThread();
1294
1295 }
1296 (void)OS_RestoreInterrupts(enable);
1297 }
1298
1299
1300 /*---------------------------------------------------------------------------*
1301 Name: OS_SelectThread
1302
1303 Description: Select the runnable thread with the highest priority.
1304
1305 Arguments: None.
1306
1307 Returns: Pointer to the thread that must run.
1308 NULL if there is no thread candidate to run.
1309 *---------------------------------------------------------------------------*/
OS_SelectThread(void)1310 OSThread *OS_SelectThread(void)
1311 {
1312 OSThread *t = OSi_ThreadInfo.list;
1313
1314 while (t && !OS_IsThreadRunnable(t))
1315 {
1316 t = t->next;
1317 }
1318
1319 return t;
1320 }
1321
1322 /*---------------------------------------------------------------------------*
1323 Name: OS_RescheduleThread
1324
1325 Description: Switch to the runnable thread with the highest priority.
1326
1327 Arguments: None.
1328
1329 Returns: None or Never return.
1330 *---------------------------------------------------------------------------*/
OS_RescheduleThread(void)1331 void OS_RescheduleThread(void)
1332 {
1333 OSIntrMode bak_intr = OS_DisableInterrupts();
1334 OSi_RescheduleThread();
1335 (void)OS_RestoreInterrupts(bak_intr);
1336 }
1337
1338 /*---------------------------------------------------------------------------*
1339 Name: OS_YieldThread
1340
1341 Description: Does thread rescheduling. Current thread relinquish CPU
1342 to give chance of running to other threads which has same
1343 priority.
1344
1345 Arguments: None.
1346
1347 Returns: None.
1348 *---------------------------------------------------------------------------*/
OS_YieldThread(void)1349 void OS_YieldThread(void)
1350 {
1351 OSThread *current = OS_GetCurrentThread();
1352 OSThread *pre = NULL;
1353 OSThread *lastThread = NULL;
1354 int samePriorityThread = 0;
1355 OSIntrMode enable = OS_DisableInterrupts();
1356
1357 {
1358 OSThread *t = OSi_ThreadInfo.list;
1359 OSThread *tPre = NULL;
1360
1361 while (t)
1362 {
1363 if (t == current)
1364 {
1365 pre = tPre;
1366 }
1367
1368 if (current->priority == t->priority)
1369 {
1370 lastThread = t;
1371 samePriorityThread++;
1372 }
1373
1374 tPre = t;
1375 t = t->next;
1376 }
1377 }
1378
1379 //---- no thread with the same priority as the current one or do not need to arrange list
1380 if (samePriorityThread <= 1 || lastThread == current)
1381 {
1382 (void)OS_RestoreInterrupts(enable);
1383 return;
1384 }
1385
1386 //---- remove thread from list
1387 if (!pre)
1388 {
1389 OSi_ThreadInfo.list = current->next;
1390 }
1391 else
1392 {
1393 pre->next = current->next;
1394 }
1395
1396 //---- insert thread after 'lastThread'
1397 current->next = lastThread->next;
1398 lastThread->next = current;
1399
1400 //---- re-schedule
1401 OSi_RescheduleThread();
1402
1403 (void)OS_RestoreInterrupts(enable);
1404 }
1405
1406
1407 /*---------------------------------------------------------------------------*
1408 Name: OS_DumpThreadList
1409
1410 Description: Dump the thread list.
1411
1412 Arguments: None.
1413
1414 Returns: None.
1415 *---------------------------------------------------------------------------*/
OS_DumpThreadList(void)1416 void OS_DumpThreadList(void)
1417 {
1418 #ifndef SDK_FINALROM
1419 #ifndef SDK_THREAD_INFINITY
1420 int i;
1421 #endif
1422
1423 OS_TPrintf("thread list top %08x\n", OSi_ThreadInfo.list);
1424
1425 #ifndef SDK_THREAD_INFINITY
1426 OS_TPrintf("No: address prio next\n");
1427 for (i = 0; i < OS_THREAD_MAX_NUM; i++)
1428 {
1429 OSThread *thread = OSi_ThreadInfo.entry[i];
1430 OS_TPrintf("%02d: %08x %5d %08x\n", i, thread, (thread) ? thread->priority : 0,
1431 (thread) ? thread->next : 0);
1432 }
1433 #else
1434 // OS_TPrintf("Id: address prio next\n");
1435 OS_TPrintf("Id: address prio next st queue.h queue.t link.p link.n\n");
1436 {
1437 OSThread *thread = OSi_ThreadInfo.list;
1438 while (thread)
1439 {
1440 // OS_TPrintf("%02d: %08x %5d %08x\n", thread->id, thread, thread->priority, thread->next );
1441 OS_TPrintf("%02d: %08x %5d %08x %d %8x %8x %8x %8x\n", thread->id, thread,
1442 thread->priority, thread->next, thread->state,
1443 (thread->queue) ? thread->queue->head : (OSThread *)1,
1444 (thread->queue) ? thread->queue->tail : (OSThread *)1, thread->link.prev,
1445 thread->link.next);
1446 thread = thread->next;
1447
1448 }
1449 }
1450 #endif
1451 #endif
1452 }
1453
1454 /*---------------------------------------------------------------------------*
1455 Name: OS_GetNumberOfThread
1456
1457 Description: Get the number of threads that exist in the system.
1458
1459 Arguments: None.
1460
1461 Returns: number of thread which exists in system
1462 *---------------------------------------------------------------------------*/
OS_GetNumberOfThread(void)1463 int OS_GetNumberOfThread(void)
1464 {
1465 OSIntrMode enabled = OS_DisableInterrupts();
1466 int threads = 0;
1467
1468 #ifndef SDK_THREAD_INFINITY
1469 int i;
1470
1471 for (i = 0; i < OS_THREAD_MAX_NUM; i++)
1472 {
1473 if (OSi_ThreadInfo.entry[i])
1474 {
1475 threads++;
1476 }
1477 }
1478 #else
1479 OSThread *thread = OSi_ThreadInfo.list;
1480 while (thread)
1481 {
1482 threads++;
1483 thread = thread->next;
1484 }
1485 #endif
1486
1487 (void)OS_RestoreInterrupts(enabled);
1488 return threads;
1489 }
1490
1491 /*---------------------------------------------------------------------------*
1492 Name: OS_GetStackStatus
1493
1494 Description: Checks thread stack. Check each CheckNUM.
1495 Return result.
1496
1497 Arguments: thread: thread checked
1498
1499 Returns: 0 (OS_STACK_NO_ERROR): no error
1500 OS_STACK_OVERFLOW: overflow
1501 OS_STACK_ABOUT_TO_OVERFLOW: about to overflow
1502 OS_STACK_UNDERFLOW: underflow
1503 *---------------------------------------------------------------------------*/
OS_GetStackStatus(const OSThread * thread)1504 OSStackStatus OS_GetStackStatus(const OSThread *thread)
1505 {
1506 //---- Check if overflow
1507 if (*(u32 *)(thread->stackTop) != OSi_STACK_CHECKNUM_TOP)
1508 {
1509 return OS_STACK_OVERFLOW;
1510 }
1511 //---- Check if about to overflow
1512 else if (thread->stackWarningOffset
1513 && *(u32 *)(thread->stackTop + thread->stackWarningOffset) != OSi_STACK_CHECKNUM_WARN)
1514 {
1515 return OS_STACK_ABOUT_TO_OVERFLOW;
1516 }
1517 //---- Check if underFlow
1518 else if (*(u32 *)(thread->stackBottom - sizeof(u32)*2) != OSi_STACK_CHECKNUM_BOTTOM)
1519 {
1520 return OS_STACK_UNDERFLOW;
1521 }
1522 //---- No Error, return.
1523 else
1524 {
1525 return OS_STACK_NO_ERROR;
1526 }
1527 }
1528
1529 /*---------------------------------------------------------------------------*
1530 Name: OSi_CheckStack
1531
1532 Description: Checks thread stack. Check each CheckNUM.
1533 If changed, display warning and halt.
1534
1535 Arguments: file: Filename displayed when stack overflows.
1536 line: Line number displayed when stack overflows.
1537 thread: thread checked
1538
1539 Returns: None.
1540 ( if error occurred, never return )
1541 *---------------------------------------------------------------------------*/
1542 static char *OSi_CheckStack_mesg[] = {
1543 "overflow", "about to overflow", "underflow"
1544 };
1545
1546 #ifndef SDK_FINALROM
1547 #ifndef SDK_NO_MESSAGE
OSi_CheckStack(const char * file,int line,const OSThread * thread)1548 void OSi_CheckStack(const char *file, int line, const OSThread *thread)
1549 {
1550 OSStackStatus st;
1551
1552 if ((st = OS_GetStackStatus(thread)) == OS_STACK_NO_ERROR)
1553 {
1554 return;
1555 }
1556
1557 OSi_Panic(file, line, " stack %x(id:%d) %s.\nstack area: %08x-%08x, warning offset: %x",
1558 thread,
1559 thread->id,
1560 OSi_CheckStack_mesg[(int)st - 1],
1561 thread->stackTop, thread->stackBottom, thread->stackWarningOffset);
1562 // Never return
1563 }
1564 #endif
1565 #endif
1566
1567 /*---------------------------------------------------------------------------*
1568 Name: OSi_GetSystemStackPointer
1569
1570 Description: Get the system mode stack pointer at svc/irq mode.
1571
1572 Arguments: None.
1573
1574 Returns: Stack Pointer
1575 *---------------------------------------------------------------------------*/
1576 static u32 OSi_SystemStackBuffer;
1577
1578 #include <nitro/code32.h>
OSi_GetSystemStackPointer(void)1579 asm u32 OSi_GetSystemStackPointer( void )
1580 {
1581 ldr r0, =OSi_SystemStackBuffer
1582 stmia r0, { sp }^
1583 ldr r0, [ r0 ]
1584 bx lr
1585 }
1586 #include <nitro/codereset.h>
1587
1588 /*---------------------------------------------------------------------------*
1589 Name: OSi_GetCurrentStackPointer
1590
1591 Description: Get the current mode stack pointer.
1592
1593 Arguments: None.
1594
1595 Returns: Stack Pointer
1596 *---------------------------------------------------------------------------*/
OSi_GetCurrentStackPointer(void)1597 asm u32 OSi_GetCurrentStackPointer( void )
1598 {
1599 mov r0, sp
1600 bx lr
1601 }
1602
1603 /*---------------------------------------------------------------------------*
1604 Name: OS_SetThreadStackWarningOffset
1605
1606 Description: Sets warning level for stack checker.
1607
1608 Arguments: thread: thread to set
1609 offset: offset from stack top. Must be multiple of 4
1610
1611 Returns: None.
1612 *---------------------------------------------------------------------------*/
OS_SetThreadStackWarningOffset(OSThread * thread,u32 offset)1613 void OS_SetThreadStackWarningOffset(OSThread *thread, u32 offset)
1614 {
1615 SDK_TASSERTMSG((offset & 3) == 0, "Offset must be aligned by 4");
1616 SDK_TASSERTMSG(OS_GetThreadContext(thread)->sp > thread->stackTop + offset,
1617 "Cannot set warning level below current sp.");
1618
1619 //---- remember warning offset
1620 thread->stackWarningOffset = offset;
1621
1622 //---- set Stack CheckNum
1623 if (offset != 0)
1624 {
1625 *(u32 *)(thread->stackTop + offset) = OSi_STACK_CHECKNUM_WARN;
1626 }
1627 }
1628
1629 /*---------------------------------------------------------------------------*
1630 Name: OS_SetThreadPriority
1631
1632 Description: Changes priority of thread.
1633
1634 Arguments: thread: thread to set priority
1635 prio: new priority to be set
1636
1637 Returns: TRUE if success
1638 *---------------------------------------------------------------------------*/
OS_SetThreadPriority(OSThread * thread,u32 prio)1639 BOOL OS_SetThreadPriority(OSThread *thread, u32 prio)
1640 {
1641 OSThread *t = OSi_ThreadInfo.list;
1642 OSThread *pre = NULL;
1643 OSIntrMode enable;
1644
1645 SDK_TASSERTMSG(OS_THREAD_PRIORITY_MIN <= prio
1646 && prio <= OS_THREAD_PRIORITY_MAX, "invalid priority");
1647 SDK_TASSERTMSG(thread != &OSi_IdleThread, "cannot change idle thread priority.");
1648
1649 enable = OS_DisableInterrupts();
1650
1651 while (t && t != thread)
1652 {
1653 pre = t;
1654 t = t->next;
1655 }
1656
1657 //---- thread not found or thread is idle
1658 if (!t || t == &OSi_IdleThread)
1659 {
1660 (void)OS_RestoreInterrupts(enable);
1661 return FALSE;
1662 }
1663
1664 if (t->priority != prio)
1665 {
1666 //---- remove thread from list
1667 if (!pre)
1668 {
1669 OSi_ThreadInfo.list = thread->next;
1670 }
1671 else
1672 {
1673 pre->next = thread->next;
1674 }
1675
1676 //---- set priority and insert proper position
1677 thread->priority = prio;
1678 OSi_InsertThreadToList(thread);
1679
1680 //---- re-schedule
1681 OSi_RescheduleThread();
1682 }
1683
1684 (void)OS_RestoreInterrupts(enable);
1685
1686 return TRUE;
1687 }
1688
1689 /*---------------------------------------------------------------------------*
1690 Name: OS_GetThreadPriority
1691
1692 Description: Gets priority of thread.
1693
1694 Arguments: thread: thread to get priority
1695
1696 Returns: priority
1697 *---------------------------------------------------------------------------*/
OS_GetThreadPriority(const OSThread * thread)1698 u32 OS_GetThreadPriority(const OSThread *thread)
1699 {
1700 SDK_TASSERTMSG(thread, "OS_GetThreadPriority: bad thread");
1701
1702 return thread->priority;
1703 }
1704
1705
1706 /*---------------------------------------------------------------------------*
1707 Name: OS_Sleep
1708
1709 Description: Sleep specified period.
1710
1711 Arguments: msec: sleeping period. ( milliseconds )
1712
1713 Returns: None.
1714 *---------------------------------------------------------------------------*/
OS_Sleep(u32 msec)1715 void OS_Sleep(u32 msec)
1716 {
1717 OSAlarm alarm;
1718
1719 SDK_TASSERTMSG(OS_IsTickAvailable()
1720 && OS_IsAlarmAvailable(), "OS_Sleep: need to start Tick and Alarm beforehand.");
1721 SDK_TASSERTMSG(OSi_IsThreadInitialized, "OS_Sleep: thread system not initialized.");
1722
1723 OS_CreateAlarm(&alarm);
1724 {
1725 OSThread *volatile p_thread = OSi_GetCurrentThread();
1726 OSIntrMode bak_cpsr = OS_DisableInterrupts();
1727
1728 // ---- remember alarm
1729 p_thread->alarmForSleep = &alarm;
1730
1731 OS_SetAlarm(&alarm, OS_MilliSecondsToTicks(msec), &OSi_SleepAlarmCallback,
1732 (void *)&p_thread);
1733 while (p_thread != NULL)
1734 {
1735 OS_SleepThread(NULL);
1736 }
1737 (void)OS_RestoreInterrupts(bak_cpsr);
1738 }
1739 }
1740
1741 //---------------- callback to wakeup sleeping thread
OSi_SleepAlarmCallback(void * arg)1742 static void OSi_SleepAlarmCallback(void *arg)
1743 {
1744 OSThread **pp_thread = (OSThread **)arg;
1745 OSThread *p_thread = *pp_thread;
1746 *pp_thread = NULL;
1747
1748 //---- clear remembrance of alarm
1749 p_thread->alarmForSleep = NULL;
1750
1751 OS_WakeupThreadDirect(p_thread);
1752 }
1753
1754
1755 /*---------------------------------------------------------------------------*
1756 Name: OS_SetSwitchThreadCallback
1757
1758 Description: Sets callback called at switching thread.
1759
1760 Arguments: callback: callback function
1761
1762 Returns: Previous callback function before set callback now
1763 *---------------------------------------------------------------------------*/
OS_SetSwitchThreadCallback(OSSwitchThreadCallback callback)1764 OSSwitchThreadCallback OS_SetSwitchThreadCallback(OSSwitchThreadCallback callback)
1765 {
1766 OSSwitchThreadCallback prev;
1767 OSIntrMode enabled;
1768
1769 enabled = OS_DisableInterrupts();
1770 prev = OSi_ThreadInfo.switchCallback;
1771 OSi_ThreadInfo.switchCallback = callback;
1772
1773 (void)OS_RestoreInterrupts(enabled);
1774 return prev;
1775 }
1776
1777 /*---------------------------------------------------------------------------*
1778 Name: OSi_IdleThreadProc
1779
1780 Description: Procedure of idle thread that system creates.
1781
1782 Arguments: None.
1783
1784 Returns: None (never return)
1785 *---------------------------------------------------------------------------*/
OSi_IdleThreadProc(void *)1786 static void OSi_IdleThreadProc(void *)
1787 {
1788 (void)OS_EnableInterrupts();
1789 while (1)
1790 {
1791 OS_Halt();
1792 }
1793 // Never return
1794 }
1795
1796 /*---------------------------------------------------------------------------*
1797 Name: OSi_GetIdleThread
1798
1799 Description: Get a pointer to the idle thread structure.
1800
1801 Arguments: None.
1802
1803 Returns: Pointer to the idle thread structure.
1804 *---------------------------------------------------------------------------*/
OSi_GetIdleThread(void)1805 OSThread *OSi_GetIdleThread(void)
1806 {
1807 OSThread *t = NULL;
1808 if (OSi_IsThreadInitialized)
1809 {
1810 t = &OSi_IdleThread;
1811 }
1812 return t;
1813 }
1814
1815 /*---------------------------------------------------------------------------*
1816 Name: OS_DisableScheduler
1817
1818 Description: Disables scheduler.
1819
1820 Arguments: None.
1821
1822 Returns: Previous scheduler suspend count.
1823 Suspended if value >= 0.
1824 *---------------------------------------------------------------------------*/
OS_DisableScheduler(void)1825 u32 OS_DisableScheduler(void)
1826 {
1827 OSIntrMode enabled = OS_DisableInterrupts();
1828 u32 count;
1829
1830 if (OSi_RescheduleCount < (u32)(0 - 1) /* u32 max value -1 */ )
1831 {
1832 count = OSi_RescheduleCount++;
1833 }
1834 (void)OS_RestoreInterrupts(enabled);
1835
1836 return count;
1837 }
1838
1839 /*---------------------------------------------------------------------------*
1840 Name: OS_EnableScheduler
1841
1842 Description: Enables scheduler.
1843
1844 Arguments: None.
1845
1846 Returns: Previous scheduler suspend count.
1847 Suspended if value >= 0.
1848 *---------------------------------------------------------------------------*/
OS_EnableScheduler(void)1849 u32 OS_EnableScheduler(void)
1850 {
1851 OSIntrMode enabled = OS_DisableInterrupts();
1852 u32 count = 0;
1853
1854 if (OSi_RescheduleCount > 0)
1855 {
1856 count = OSi_RescheduleCount--;
1857 }
1858 (void)OS_RestoreInterrupts(enabled);
1859
1860 return count;
1861 }
1862
1863 #ifdef SDK_THREAD_INFINITY
1864 /*---------------------------------------------------------------------------*
1865 Name: OS_GetThread
1866
1867 Description: Gets pointer to thread whose id is specified.
1868
1869 Arguments: id: thread id to get thread
1870
1871 Returns: pointer to thread which id is specified
1872 *---------------------------------------------------------------------------*/
OS_GetThread(u32 id)1873 OSThread *OS_GetThread(u32 id)
1874 {
1875 OSThread *retval = NULL;
1876 OSThread *t = OSi_ThreadInfo.list;
1877
1878 while (t)
1879 {
1880 if (t->id == id)
1881 {
1882 retval = t;
1883 break;
1884 }
1885
1886 t = t->next;
1887 }
1888
1889 return retval;
1890 }
1891 #endif
1892
1893
1894 #ifdef SDK_THREAD_INFINITY
1895 /*---------------------------------------------------------------------------*
1896 Name: OS_SetThreadDestructor
1897
1898 Description: Sets thread destructor, which is called when that thread exits.
1899
1900 Arguments: thread : thread pointer
1901 dtor : destructor function
1902
1903 Returns: None.
1904 *---------------------------------------------------------------------------*/
OS_SetThreadDestructor(OSThread * thread,OSThreadDestructor dtor)1905 void OS_SetThreadDestructor(OSThread *thread, OSThreadDestructor dtor)
1906 {
1907 SDK_ASSERT(thread);
1908 thread->destructor = dtor;
1909 }
1910
1911 /*---------------------------------------------------------------------------*
1912 Name: OS_GetThreadDestructor
1913
1914 Description: Gets thread destructor which is set.
1915
1916 Arguments: thread : thread pointer
1917
1918 Returns: destructor function
1919 *---------------------------------------------------------------------------*/
OS_GetThreadDestructor(const OSThread * thread)1920 OSThreadDestructor OS_GetThreadDestructor(const OSThread *thread)
1921 {
1922 SDK_ASSERT(thread);
1923 return thread->destructor;
1924 }
1925
1926 /*---------------------------------------------------------------------------*
1927 Name: OS_SetThreadParameter
1928
1929 Description: Sets user parameter which is allowed to use freely.
1930
1931 Arguments: thread : thread pointer
1932 parameter : user parameter
1933
1934 Returns: None.
1935 *---------------------------------------------------------------------------*/
OS_SetThreadParameter(OSThread * thread,void * parameter)1936 void OS_SetThreadParameter(OSThread *thread, void *parameter)
1937 {
1938 SDK_ASSERT(thread);
1939 thread->userParameter = parameter;
1940 }
1941
1942 /*---------------------------------------------------------------------------*
1943 Name: OS_GetThreadParameter
1944
1945 Description: Gets user parameter which is set.
1946
1947 Arguments: thread : thread pointer
1948
1949 Returns: user parameter that is set
1950 *---------------------------------------------------------------------------*/
OS_GetThreadParameter(const OSThread * thread)1951 void *OS_GetThreadParameter(const OSThread *thread)
1952 {
1953 SDK_ASSERT(thread);
1954 return thread->userParameter;
1955 }
1956
1957
1958
1959 /*---------------------------------------------------------------------------*
1960 Name: OSi_SetSystemErrno
1961
1962 Description: Sets system error number.
1963
1964 Arguments: thread : thread to set error number
1965 errno : error number to set
1966
1967 Returns: None.
1968 *---------------------------------------------------------------------------*/
OSi_SetSystemErrno(OSThread * thread,int errno)1969 void OSi_SetSystemErrno(OSThread *thread, int errno)
1970 {
1971 SDK_ASSERT(thread);
1972 thread->systemErrno = errno;
1973 }
1974
1975 /*---------------------------------------------------------------------------*
1976 Name: OSi_GetSystemErrno
1977
1978 Description: Gets system error number.
1979
1980 Arguments: thread : thread to set error number
1981
1982 Returns: error number
1983 *---------------------------------------------------------------------------*/
OSi_GetSystemErrno(const OSThread * thread)1984 int OSi_GetSystemErrno(const OSThread *thread)
1985 {
1986 SDK_ASSERT(thread);
1987 return thread->systemErrno;
1988 }
1989
1990 /*---------------------------------------------------------------------------*
1991 Name: OS_GetErrno
1992
1993 Description: Gets system error number.
1994
1995 Arguments: None.
1996
1997 Returns: error number
1998 *---------------------------------------------------------------------------*/
OS_GetErrno(void)1999 int OS_GetErrno(void)
2000 {
2001 OSThread *thread = OSi_GetCurrentThread();
2002 return OSi_GetSystemErrno(thread);
2003 }
2004 #endif
2005
2006 /*---------------------------------------------------------------------------*
2007 Name: OS_IsThreadInList
2008
2009 Description: Checks if the specified thread is in the thread list.
2010
2011 Arguments: thread : thread
2012
2013 Returns: TRUE if thread is in the thread list
2014 *---------------------------------------------------------------------------*/
OS_IsThreadInList(const OSThread * thread)2015 BOOL OS_IsThreadInList(const OSThread *thread)
2016 {
2017 BOOL r = FALSE;
2018 OSThread *t = OSi_ThreadInfo.list;
2019 OSIntrMode enabled = OS_DisableInterrupts();
2020
2021 while (t)
2022 {
2023 if (t == thread)
2024 {
2025 r = TRUE;
2026 break;
2027 }
2028
2029 t = t->next;
2030 }
2031
2032 (void)OS_RestoreInterrupts(enabled);
2033 return r;
2034 }
2035
2036 /*---------------------------------------------------------------------------*
2037 Name: OS_SetThreadDestructorStack
2038
2039 Description: Specifies stack area to call thread destructor.
2040
2041 Arguments: stack: stack bottom address
2042 stackSize: stack size (byte. must be aligned by 4)
2043
2044 Returns: None.
2045 *---------------------------------------------------------------------------*/
OS_SetThreadDestructorStack(void * stack)2046 void OS_SetThreadDestructorStack(void *stack)
2047 {
2048 SDK_ASSERT(stack);
2049 SDK_ASSERT((u32)stack % STACK_ALIGN == 0);
2050
2051 OSi_StackForDestructor = stack;
2052 }
2053
2054 //================================================================================
2055 // for DEBUG
2056 //================================================================================
2057 /*---------------------------------------------------------------------------*
2058 Name: OS_GetThreadResource
2059
2060 Description: Stores thread resources to specified pointer.
2061
2062 Arguments: resource Pointer storing thread resources
2063
2064 Returns: TRUE ... success (always return this now)
2065 FALSE ... fail
2066 *---------------------------------------------------------------------------*/
OS_GetThreadResource(OSThreadResource * resource)2067 BOOL OS_GetThreadResource(OSThreadResource *resource)
2068 {
2069 resource->num = OS_GetNumberOfThread();
2070
2071 return TRUE;
2072 }
2073
2074
2075 #if defined(SDK_TCM_APPLY) && defined(SDK_ARM9)
2076 #include <nitro/itcm_end.h>
2077 #endif
2078