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(&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_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(&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     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