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(&currentThread->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(&currentThread->joinQueue); // possible to never return
820 #else
821     OS_WakeupThread(&currentThread->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