]> rtime.felk.cvut.cz Git - arc.git/blob - system/kernel/task.c
Fixed ramlog when using SELECT_OS_CONSOLE.
[arc.git] / system / kernel / task.c
1 /* -------------------------------- Arctic Core ------------------------------\r
2  * Arctic Core - the open source AUTOSAR platform http://arccore.com\r
3  *\r
4  * Copyright (C) 2009  ArcCore AB <contact@arccore.com>\r
5  *\r
6  * This source code is free software; you can redistribute it and/or modify it\r
7  * under the terms of the GNU General Public License version 2 as published by the\r
8  * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.\r
9  *\r
10  * This program is distributed in the hope that it will be useful, but\r
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
13  * for more details.\r
14  * -------------------------------- Arctic Core ------------------------------*/\r
15 \r
16 /* ----------------------------[includes]------------------------------------*/\r
17 \r
18 #include <stdlib.h>\r
19 #include "Os.h"\r
20 \r
21 #include "application.h"\r
22 #include "internal.h"\r
23 #include "task_i.h"\r
24 #include "sys.h"\r
25 #include "arc.h"\r
26 #include "arch.h"\r
27 \r
28 /* ----------------------------[private define]------------------------------*/\r
29 /* ----------------------------[private macro]-------------------------------*/\r
30 /* ----------------------------[private typedef]-----------------------------*/\r
31 /* ----------------------------[private function prototypes]-----------------*/\r
32 /* ----------------------------[private variables]---------------------------*/\r
33 #if OS_TASK_CNT!=0\r
34 OsTaskVarType Os_TaskVarList[OS_TASK_CNT];\r
35 #endif\r
36 \r
37 /* ----------------------------[private functions]---------------------------*/\r
38 // schedule()\r
39 static inline void Os_TaskRunningToReady( OsTaskVarType *pcb ) {\r
40         assert(pcb->state == ST_RUNNING );\r
41         pcb->state = ST_READY;\r
42 }\r
43 \r
44 \r
45 // ActivateTask(pid)\r
46 // SetEvent(pid)\r
47 void Os_TaskMakeReady( OsTaskVarType *pcb ) {\r
48         if( !( pcb->state & ( ST_READY | ST_RUNNING )) ) {\r
49                 pcb->state = ST_READY;\r
50                 TAILQ_INSERT_TAIL(& Os_Sys.ready_head,pcb,ready_list);\r
51                 OS_DEBUG(D_TASK,"Added %s to ready list\n",pcb->constPtr->name);\r
52         }\r
53 }\r
54 \r
55 // WaitEvent\r
56 void Os_TaskMakeWaiting( OsTaskVarType *pcb )\r
57 {\r
58         assert( pcb->state & (ST_READY|ST_RUNNING) );\r
59 \r
60         pcb->state = ST_WAITING;\r
61         TAILQ_REMOVE(&Os_Sys.ready_head,pcb,ready_list);\r
62         OS_DEBUG(D_TASK,"Removed %s from ready list\n",pcb->constPtr->name);\r
63 }\r
64 \r
65 // Sleeping\r
66 #if defined(USE_KERNEL_EXTRA)\r
67 static inline void Os_TaskMakeSleeping( OsTaskVarType *pcb )\r
68 {\r
69         assert( pcb->state & (ST_READY|ST_RUNNING) );\r
70 \r
71         pcb->state = ST_WAITING | ST_SLEEPING;\r
72         TAILQ_REMOVE(&Os_Sys.ready_head,pcb,ready_list);\r
73         OS_DEBUG(D_TASK,"Removed %s from ready list\n",pcb->constPtr->name);\r
74 }\r
75 \r
76 \r
77 static inline void Os_TaskMakeWaitingOnSem( OsTaskVarType *pcb )\r
78 {\r
79         assert( pcb->state & (ST_READY|ST_RUNNING) );\r
80 \r
81         pcb->state = ST_WAITING_SEM;\r
82         TAILQ_REMOVE(&Os_Sys.ready_head,pcb,ready_list);\r
83         OS_DEBUG(D_TASK,"Removed %s from ready list\n",pcb->constPtr->name);\r
84 }\r
85 \r
86 \r
87 #endif\r
88 \r
89 // Terminate task\r
90 static inline void Os_TaskMakeSuspended( OsTaskVarType *pcb )\r
91         {\r
92         assert( pcb->state & (ST_READY|ST_RUNNING) );\r
93         pcb->state = ST_SUSPENDED;\r
94         TAILQ_REMOVE(&Os_Sys.ready_head,pcb,ready_list);\r
95         OS_DEBUG(D_TASK,"Removed %s from ready list\n",pcb->constPtr->name);\r
96 }\r
97 \r
98 \r
99 /* ----------------------------[public functions]----------------------------*/\r
100 \r
101 \r
102 \r
103 /** @req OS067 */\r
104 \r
105 _Bool os_pcb_pid_valid( OsTaskVarType *restrict pcb ) {\r
106         return ( pcb->constPtr->pid > OS_TASK_CNT ) ? 0 : 1;\r
107 }\r
108 /**\r
109  * Start an extended task.\r
110  * Tasks done:\r
111  * - Grab the internal resource for the process\r
112  * - Set it running state.\r
113  * - Start to execute the process\r
114  *\r
115  */\r
116 void Os_TaskStartExtended( void ) {\r
117 \r
118         OsTaskVarType *pcb;\r
119 \r
120         pcb = Os_SysTaskGetCurr();\r
121 #if 0\r
122         Os_ResourceGetInternal();\r
123         Os_TaskMakeRunning(pcb);\r
124 #endif\r
125 \r
126 //      PRETASKHOOK();\r
127 \r
128         Os_ArchFirstCall();\r
129 \r
130         /* We got back without any TerminateTask() or ChainTask()\r
131          *\r
132          * OSEK:\r
133          *    Each task shall terminate itself at the end of its code.\r
134          *    Ending the task without a call to TerminateTask or ChainTask\r
135          *    is strictly forbidden and causes undefined behaviour.\r
136          *\r
137          * Autosar:\r
138          *    OS052, OS069, OS070 and OS239\r
139          * */\r
140 \r
141         /** @req OS239 */\r
142         Irq_Disable();\r
143         if( Os_SysIntAnyDisabled() ) {\r
144                 Os_SysIntClearAll();\r
145         }\r
146 \r
147         /** @req OS070 */\r
148         if( Os_TaskOccupiesResources(pcb) ) {\r
149                 Os_TaskResourceFreeAll(pcb);\r
150         }\r
151 \r
152         /** @req OS069 */\r
153         ERRORHOOK(E_OS_MISSINGEND);\r
154 \r
155         /** @req OS052 */\r
156         TerminateTask();\r
157 }\r
158 \r
159 /**\r
160  * Start an basic task.\r
161  * See extended task.\r
162  */\r
163 \r
164 void Os_TaskStartBasic( void ) {\r
165 \r
166         OsTaskVarType *pcb;\r
167 \r
168         pcb = Os_SysTaskGetCurr();\r
169 #if 0\r
170         Os_ResourceGetInternal();\r
171         Os_TaskMakeRunning(pcb);\r
172 #endif\r
173 \r
174 //      PRETASKHOOK();\r
175 \r
176         Os_ArchFirstCall();\r
177 \r
178         /** @req OS239 */\r
179         Irq_Disable();\r
180         if( Os_SysIntAnyDisabled() ) {\r
181                 Os_SysIntClearAll();\r
182         }\r
183 \r
184         /** @req OS070 */\r
185         if( Os_TaskOccupiesResources(pcb) ) {\r
186                 Os_TaskResourceFreeAll(pcb);\r
187         }\r
188 \r
189         /** @req OS069 */\r
190         ERRORHOOK(E_OS_MISSINGEND);\r
191 \r
192         /** @req OS052 */\r
193         TerminateTask();\r
194 }\r
195 \r
196 \r
197 static void Os_StackSetup( OsTaskVarType *pcbPtr ) {\r
198         uint8_t *bottom;\r
199 \r
200         /* Find bottom of the stack so that we can place the\r
201          * context there.\r
202          *\r
203          * stack bottom = high address. stack top = low address\r
204          */\r
205         bottom = (uint8_t *)pcbPtr->stack.top + pcbPtr->stack.size;\r
206         pcbPtr->stack.curr = bottom;\r
207         // TODO: alignments here..\r
208         // TODO :use function os_arch_get_call_size() ??\r
209 \r
210         // Make some space for back-chain.\r
211         bottom -= 16;\r
212         // Set the current stack so that it points to the context\r
213         pcbPtr->stack.curr = bottom - Os_ArchGetScSize();\r
214 \r
215         Os_StackSetEndmark(pcbPtr);\r
216 }\r
217 \r
218 /**\r
219  * Fill the stack with a predefined pattern\r
220  *\r
221  * @param pcbPtr Pointer to the pcb to fill with pattern\r
222  */\r
223 static void Os_StackFill(OsTaskVarType *pcbPtr) {\r
224         uint8_t *p = pcbPtr->stack.curr;\r
225 \r
226         assert(pcbPtr->stack.curr > pcbPtr->stack.top);\r
227 \r
228         while (p > (uint8_t *) pcbPtr->stack.top) {\r
229                 --p;\r
230                 *p = STACK_PATTERN;\r
231         }\r
232 }\r
233 \r
234 #if 0\r
235 /**\r
236  *\r
237  * @param pcbPtr\r
238  */\r
239 static void Os_TaskSetEntry(OsTaskVarType *pcbPtr ) {\r
240 \r
241 }\r
242 #endif\r
243 \r
244 \r
245 /**\r
246  * Setup the context for a pcb. The context differs for different arch's\r
247  * so we call the arch dependent functions also.\r
248  * The context at setup is always a small context.\r
249  *\r
250  * @param pcb Ptr to the pcb to setup context for.\r
251  */\r
252 void Os_TaskContextInit( OsTaskVarType *pcb ) {\r
253 \r
254         if( pcb->constPtr->autostart ) {\r
255                 Os_TaskMakeReady(pcb);\r
256         } else {\r
257                 pcb->state = ST_SUSPENDED;\r
258         }\r
259 \r
260         Os_StackSetup(pcb);\r
261         Os_StackFill(pcb);\r
262         Os_ArchSetTaskEntry(pcb);\r
263 \r
264         Os_ArchSetupContext(pcb);\r
265 }\r
266 \r
267 /**\r
268  *\r
269  * @param pcb\r
270  */\r
271 void Os_ContextReInit( OsTaskVarType *pcbPtr ) {\r
272         Os_StackSetup(pcbPtr);\r
273 }\r
274 \r
275 #if 0\r
276 /**\r
277  * Search for a specific task in the pcb list.\r
278  *\r
279  * @param tid The task id to search for\r
280  * @return Ptr to the found pcb or NULL\r
281  */\r
282 OsTaskVarType *Os_TaskGet( TaskType tid ) {\r
283         OsTaskVarType *i_pcb;\r
284         TAILQ_FOREACH(i_pcb,& Os_Sys.pcb_head,pcb_list) {\r
285                 if(i_pcb->constPtr->pid == tid ) {\r
286                         return i_pcb;\r
287                 }\r
288         }\r
289 \r
290         assert(0);\r
291         return NULL;\r
292 }\r
293 #endif\r
294 \r
295 #if 0\r
296 /**\r
297  * Adds a pcb to the list of pcb's\r
298  * @param pcb\r
299  */\r
300 TaskType Os_AddTask( OsTaskVarType *pcb ) {\r
301         long msr;\r
302 \r
303         Irq_Save(msr);  // Save irq status and disable interrupts\r
304 \r
305         pcb->pid = Os_Sys.task_cnt;\r
306         // Add to list of PCB's\r
307         TAILQ_INSERT_TAIL(& Os_Sys.pcb_head,pcb,pcb_list);\r
308         Os_Sys.task_cnt++;\r
309         Os_Sys.isrCnt++;\r
310 \r
311         Irq_Restore(msr);  // Restore interrupts\r
312         return pcb->pid;\r
313 }\r
314 #endif\r
315 \r
316 \r
317 #define PRIO_ILLEGAL    -100\r
318 \r
319 /**\r
320  * Find the top priority task. Even the running task is included.\r
321  * TODO: There should be a priority queue (using a heap?) here instead.\r
322  *        giving O(log n) for instertions and (1) for getting the top\r
323  *        prio task. The curerent implementation is ehhhh bad.\r
324  * @return\r
325  */\r
326 \r
327 OsTaskVarType *Os_TaskGetTop( void ){\r
328         OsTaskVarType *i_pcb;\r
329         OsTaskVarType *top_prio_pcb = NULL;\r
330         OsPriorityType top_prio = PRIO_ILLEGAL;\r
331 \r
332 //      OS_DEBUG(D_TASK,"os_find_top_prio_proc\n");\r
333 \r
334         TAILQ_FOREACH(i_pcb,& Os_Sys.ready_head,ready_list) {\r
335                 // all ready task are canidates\r
336                 if( i_pcb->state & (ST_READY|ST_RUNNING)) {\r
337                         if( top_prio != PRIO_ILLEGAL ) {\r
338                                 if( i_pcb->activePriority > top_prio ) {\r
339                                         top_prio = i_pcb->activePriority;\r
340                                         top_prio_pcb = i_pcb;\r
341                                 }\r
342                         } else {\r
343                                 top_prio = i_pcb->activePriority;\r
344                                 top_prio_pcb = i_pcb;\r
345                         }\r
346                 } else {\r
347                         assert(0);\r
348                 }\r
349         }\r
350 \r
351         assert(top_prio_pcb!=NULL);\r
352 \r
353         OS_DEBUG(D_TASK,"Found %s\n",top_prio_pcb->constPtr->name);\r
354 \r
355         return top_prio_pcb;\r
356 }\r
357 \r
358 \r
359 #define USE_LDEBUG_PRINTF\r
360 #include "debug.h"\r
361 \r
362 // we come here from\r
363 // - WaitEvent()\r
364 //   old_pcb -> WAITING\r
365 //   new_pcb -> READY(RUNNING)\r
366 // - Schedule(),\r
367 //   old_pcb -> READY\r
368 //   new_pcb -> READY/RUNNING\r
369 \r
370 /*\r
371  * two strategies\r
372  * 1. When running ->\r
373  *    - remove from ready queue\r
374  *    - set state == ST_RUNNING\r
375  *\r
376  * 2. When running ->\r
377  *    * leave in ready queue\r
378  *    * set state == ST_RUNNING\r
379  *    - ready queue and ST_READY not the same\r
380  *    + No need to remove the running process from ready queue\r
381  */\r
382 \r
383 OsTaskVarType *Os_FindTopPrioTask( void ) {\r
384 \r
385 \r
386         return NULL;\r
387 }\r
388 \r
389 /**\r
390  * Tries to Dispatch.\r
391  *\r
392  * Used by:\r
393  *   ActivateTask()\r
394  *   WaitEvent()\r
395  *   TerminateTask()\r
396  *   ChainTask()\r
397  *\r
398  * @param force Force a re-scheduling\r
399  *\r
400  */\r
401 void Os_Dispatch( uint32_t op ) {\r
402         OsTaskVarType *pcbPtr;\r
403         OsTaskVarType *currPcbPtr = Os_SysTaskGetCurr();\r
404 \r
405         assert(Os_Sys.intNestCnt == 0);\r
406         assert(Os_SchedulerResourceIsFree());\r
407 \r
408         /* When calling post hook we must still be in ST_RUNNING */\r
409         assert( currPcbPtr->state & ST_RUNNING );\r
410         POSTTASKHOOK();\r
411 \r
412         /* Go the correct state for running task */\r
413         if( op  & ( OP_SET_EVENT | OP_SCHEDULE | OP_RELEASE_RESOURCE )) {\r
414                 Os_TaskRunningToReady(currPcbPtr);\r
415         } else if( op & (OP_WAIT_EVENT) ) {\r
416                 Os_TaskMakeWaiting(currPcbPtr);\r
417 #if defined(USE_KERNEL_EXTRA)\r
418         } else if( op & OP_WAIT_SEMAPHORE) {\r
419                 Os_TaskMakeWaitingOnSem(currPcbPtr);\r
420         } else if( op & OP_SIGNAL_SEMAPHORE) {\r
421                 Os_TaskRunningToReady(currPcbPtr);\r
422 \r
423         } else if( op & (OP_SLEEP )) {\r
424                 Os_TaskMakeSleeping(currPcbPtr);\r
425 #endif\r
426         } else if( op & OP_ACTIVATE_TASK ) {\r
427                 Os_TaskMakeReady(currPcbPtr);\r
428         } else if( op & OP_CHAIN_TASK ) {\r
429                 assert( Os_Sys.chainedPcbPtr != NULL );\r
430 \r
431                 /*  #  from chain  top\r
432                  * ----------------------------------------------------------\r
433                  *  1    1     1     1    1->RUNNING\r
434                  *  2    1     1     2    1->READY,            2->RUNNING\r
435                  *  3    1     2     2    1->SUSPENDED/READY*, 2->RUNNING\r
436                  *  4    1     2     3    1->SUSPENDED/READY*, 2->READY  , 3-RUNNING\r
437                  *\r
438                  *  *) Depends on the number of activations.\r
439                  *\r
440                  *  - Chained task is always READY when coming from ChainTask()\r
441                  */\r
442                 if( currPcbPtr != Os_Sys.chainedPcbPtr ) {\r
443                         /* #3 and #4 */\r
444                         --currPcbPtr->activations;\r
445                         if( currPcbPtr->activations <= 0 ) {\r
446                                 currPcbPtr->activations = 0;\r
447                                 Os_TaskMakeSuspended(currPcbPtr);\r
448                         } else {\r
449                                 Os_TaskRunningToReady(currPcbPtr);\r
450                         }\r
451                         /* Chained task is already in READY */\r
452                 }\r
453                 Os_Sys.chainedPcbPtr = NULL;\r
454 \r
455         } else if( op & OP_TERMINATE_TASK ) {\r
456                 /*@req OSEK TerminateTask\r
457                  * In case of tasks with multiple activation requests,\r
458                  * terminating the current instance of the task automatically puts the next\r
459                  * instance of the same task into the ready state\r
460                  */\r
461                 --currPcbPtr->activations;\r
462 \r
463                 if( currPcbPtr->activations <= 0 ) {\r
464                         currPcbPtr->activations = 0;\r
465                         Os_TaskMakeSuspended(currPcbPtr);\r
466                 }\r
467         } else {\r
468                 assert(0);\r
469         }\r
470 \r
471         pcbPtr = Os_TaskGetTop();\r
472 \r
473 \r
474 \r
475         /* Swap if we found any process or are forced (multiple activations)*/\r
476         if( pcbPtr != currPcbPtr ) {\r
477 \r
478                 if( (op & OP_CHAIN_TASK) && ( currPcbPtr == Os_Sys.chainedPcbPtr ) ) {\r
479                         /* #2 */\r
480                         Os_TaskRunningToReady(currPcbPtr);\r
481                 }\r
482                 /*\r
483                  * Swap context\r
484                  */\r
485                 assert(pcbPtr!=NULL);\r
486 \r
487                 Os_ResourceReleaseInternal();\r
488 \r
489 #if (OS_STACK_MONITORING == 1)\r
490                 if( !Os_StackIsEndmarkOk(currPcbPtr) ) {\r
491 #if (  OS_SC1 == STD_ON) || (  OS_SC2 == STD_ON )\r
492                         /** @req OS068 */\r
493                         ShutdownOS(E_OS_STACKFAULT);\r
494 #else\r
495                         /** @req OS396\r
496                          * If a stack fault is detected by stack monitoring AND the configured scalability\r
497                          * class is 3 or 4, the Operating System module shall call the ProtectionHook() with\r
498                          * the status E_OS_STACKFAULT.\r
499                          * */\r
500                         PROTECTIONHOOK(E_OS_STACKFAULT);\r
501 #endif\r
502                 }\r
503 #endif\r
504                 OS_DEBUG(D_TASK,"Swapping to: %s\n",pcbPtr->constPtr->name);\r
505                 Os_TaskSwapContext(currPcbPtr,pcbPtr);\r
506         } else {\r
507                 OS_DEBUG(D_TASK,"Continuing task %s\n",pcbPtr->constPtr->name);\r
508                 /* Setup the stack again, and just call the basic task */\r
509                 Os_StackSetup(pcbPtr);\r
510                 /* TODO: release and get the internal resource ? */\r
511                 Os_TaskMakeRunning(pcbPtr);\r
512                 PRETASKHOOK();\r
513                 Os_ArchSetSpAndCall(pcbPtr->stack.curr,Os_TaskStartBasic);\r
514                 assert(0);\r
515         }\r
516 }\r
517 \r
518 \r
519 /*\r
520  * Thoughts on task switching and memory protection\r
521  *\r
522  * If we would have had memory protection:\r
523  * - Applications have their own MMU settings.\r
524  * - Swapping between tasks in same Application does NOT involve the MMU.\r
525  * - When running a non-trusted Application I need will have to:\r
526  *   - Run kernel in supervisor mode.\r
527  *   - Trap the start of each task\r
528  *   - All calls to the kernel will have a trap interface, i.e.  Os_ResourceGetInternal(ActivateTask(TASK_ID_foo);\r
529  *   - An ISR2:\r
530  *     - The interupt is taken, the kernel runs in supervisor mode\r
531  *     - If the ISR2 activates\r
532  *\r
533  * Stack design:\r
534  * ALT1: 1 kernel stack...\r
535  * ALT2:\r
536  *\r
537  *  Do we need virtual memory??\r
538  */\r
539 \r
540 void Os_TaskSwapContext(OsTaskVarType *old_pcb, OsTaskVarType *new_pcb ) {\r
541         Os_SysTaskSetCurr(new_pcb);\r
542 #if     (OS_USE_APPLICATIONS == STD_ON)\r
543         Os_Sys.currApplId = new_pcb->constPtr->applOwnerId;\r
544 #endif\r
545         Os_ResourceGetInternal();\r
546         Os_TaskMakeRunning(new_pcb);\r
547         /* TODO: The pretask hook is not called with the right stack\r
548          * (it's called on the old task stack, not the new ) */\r
549         PRETASKHOOK();\r
550         Os_ArchSwapContext(old_pcb,new_pcb);\r
551 }\r
552 \r
553 void Os_TaskSwapContextTo(OsTaskVarType *old_pcb, OsTaskVarType *new_pcb ) {\r
554         Os_SysTaskSetCurr(new_pcb);\r
555 #if     (OS_USE_APPLICATIONS == STD_ON)\r
556         Os_Sys.currApplId = new_pcb->constPtr->applOwnerId;\r
557 #endif\r
558         Os_ResourceGetInternal();\r
559         Os_TaskMakeRunning(new_pcb);\r
560         PRETASKHOOK();\r
561         Os_ArchSwapContextTo(old_pcb,new_pcb);\r
562         assert(0);\r
563 }\r
564 \r
565 \r
566 void Os_Arc_GetStackInfo( TaskType task, StackInfoType *s) {\r
567         OsTaskVarType *pcb      = Os_TaskGet(task);\r
568 \r
569         s->curr         = Os_ArchGetStackPtr();\r
570         s->top          = pcb->stack.top;\r
571         s->at_swap      = pcb->stack.curr;\r
572         s->size         = pcb->stack.size;\r
573         s->usage        = (void *)Os_StackGetUsage(pcb);\r
574 }\r
575 \r
576 \r
577 #define TASK_CHECK_ID(x)                                \\r
578         if( (x) > OS_TASK_CNT) { \\r
579                 rv = E_OS_ID;                                   \\r
580                 goto err;                                               \\r
581         }\r
582 \r
583 \r
584 /**\r
585  * Returns the state of a task (running, ready, waiting, suspended)\r
586  * at the time of calling GetTaskState.\r
587  *\r
588  * @param TaskId  Task reference\r
589  * @param State   Reference to the state of the task\r
590  */\r
591 \r
592 StatusType GetTaskState(TaskType TaskId, TaskStateRefType State) {\r
593         state_t curr_state;\r
594         StatusType rv = E_OK;\r
595 \r
596         TASK_CHECK_ID(TaskId);\r
597 \r
598         curr_state = os_pcb_get_state(Os_TaskGet(TaskId));\r
599 \r
600         // TODO: Lazy impl. for now */\r
601         switch(curr_state) {\r
602         case ST_RUNNING:        *State = TASK_STATE_RUNNING;    break;\r
603         case ST_WAITING:        *State = TASK_STATE_WAITING;    break;\r
604         case ST_SUSPENDED:      *State = TASK_STATE_SUSPENDED;  break;\r
605         case ST_READY:          *State = TASK_STATE_READY;      break;\r
606         }\r
607 \r
608         // Prevent label warning. Remove when proper error handling is implemented.\r
609         if (0) goto err;\r
610 \r
611         OS_STD_END_2(OSServiceId_GetTaskState,TaskId, State);\r
612 }\r
613 \r
614 \r
615 /**\r
616  * GetTaskID returns the information about the TaskID of the task\r
617  * which is currently running.\r
618  *\r
619  * @param task_id Reference to the task which is currently running\r
620  * @return\r
621  */\r
622 StatusType GetTaskID( TaskRefType TaskID ) {\r
623         StatusType rv = E_OK;\r
624         *TaskID = INVALID_TASK;\r
625 \r
626         /* Test specification say return CALLEVEL if in ISR\r
627          * but impl. spec says otherwise */\r
628         if( Os_Sys.intNestCnt == 0 ) {\r
629                 if( Os_Sys.currTaskPtr->state & ST_RUNNING ) {\r
630                         *TaskID = Os_Sys.currTaskPtr->constPtr->pid;\r
631                 } else {\r
632                         /* This is not a real error since this could\r
633                          * be the case when called from ErrorHook */\r
634                 }\r
635         }\r
636 \r
637     return rv;\r
638 }\r
639 \r
640 \r
641 /**\r
642  * This service returns the identifier of the currently executing ISR\r
643  *\r
644  * If its caller is not a category 2 ISR (or Hook routines called\r
645  * inside a category 2 ISR), GetISRID() shall return INVALID_ISR.\r
646  *\r
647  * @return\r
648  */\r
649 ISRType GetISRID( void ) {\r
650 \r
651         /** @req OS264 */\r
652         if(Os_Sys.intNestCnt == 0 ) {\r
653                 return INVALID_ISR;\r
654         }\r
655 \r
656         /** @req OS263 */\r
657         return (ISRType)Os_SysTaskGetCurr()->constPtr->pid;\r
658 }\r
659 \r
660 static inline void Os_Arc_SetCleanContext( OsTaskVarType *pcb ) {\r
661         if (pcb->constPtr->proc_type == PROC_EXTENDED) {\r
662                 /** @req OSEK ActivateTask Cleanup events\r
663                  * OSEK,ActivateTask, When an extended task is transferred from suspended\r
664                  * state into ready state all its events are cleared.*/\r
665                 pcb->ev_set = 0;\r
666                 pcb->ev_wait = 0;\r
667         }\r
668         Os_StackSetup(pcb);\r
669         Os_ArchSetTaskEntry(pcb);\r
670         Os_ArchSetupContext(pcb);\r
671 }\r
672 \r
673 /**\r
674  * The task <TaskID> is transferred from the suspended state into\r
675  * the  ready state. The operating system ensures that the task\r
676  * code is being executed from the first statement.\r
677  *\r
678  * The service may be called from interrupt  level and from task\r
679  * level (see Figure 12-1).\r
680  * Rescheduling after the call to  ActivateTask depends on the\r
681  * place it is called from (ISR, non preemptable task, preemptable\r
682  * task).\r
683  *\r
684  * If E_OS_LIMIT is returned the activation is ignored.\r
685  * When an extended task is transferred from suspended state\r
686  * into ready state all its events are cleared.\r
687  *\r
688  * Note!\r
689  * ActivateTask will not immediately change the state of the task\r
690  * in case of multiple activation requests. If the task is not\r
691  * suspended, the activation will only be recorded and performed later.\r
692  *\r
693  * @param pid\r
694  * @return\r
695  */\r
696 \r
697 \r
698 StatusType ActivateTask( TaskType TaskID ) {\r
699         long msr;\r
700         OsTaskVarType *pcb = Os_TaskGet(TaskID);\r
701         StatusType rv = E_OK;\r
702 \r
703         OS_DEBUG(D_TASK,"# ActivateTask %s\n",pcb->constPtr->name);\r
704 \r
705 #if (OS_STATUS_EXTENDED == STD_ON )\r
706         /* extended */\r
707         TASK_CHECK_ID(TaskID);\r
708 #endif\r
709 \r
710         Irq_Save(msr);\r
711 \r
712 #if     (OS_APPLICATION_CNT > 1)\r
713 \r
714         rv = Os_ApplHaveAccess( pcb->constPtr->accessingApplMask );\r
715         if( rv != E_OK ) {\r
716                 goto err;\r
717         }\r
718 \r
719 #endif\r
720 \r
721         /* @req OS093 ActivateTask */\r
722         if( Os_SysIntAnyDisabled() ) {\r
723                 /* Standard */\r
724                 rv = E_OS_DISABLEDINT;\r
725                 goto err;\r
726         }\r
727 \r
728         pcb->activations++;\r
729         if( os_pcb_get_state(pcb) != ST_SUSPENDED ) {\r
730                 /** @req OSEK_? Too many task activations */\r
731                 if( pcb->activations >= (pcb->constPtr->activationLimit + 1) ) {\r
732                         /* Standard */\r
733                         rv=E_OS_LIMIT;\r
734                         Irq_Restore(msr);\r
735                         --pcb->activations;\r
736                         goto err;\r
737                 }\r
738         } else {\r
739                 /* We have a suspended task, make it ready for use */\r
740                 assert( pcb->activations == 1 );\r
741                 Os_Arc_SetCleanContext(pcb);\r
742                 Os_TaskMakeReady(pcb);\r
743         }\r
744 \r
745         /* Preempt only if we are preemptable and target has higher prio than us */\r
746         if(     (Os_SysTaskGetCurr()->constPtr->scheduling == FULL) &&\r
747                 (Os_Sys.intNestCnt == 0) &&\r
748                 (pcb->activePriority > Os_SysTaskGetCurr()->activePriority) &&\r
749                 (Os_SchedulerResourceIsFree()))\r
750         {\r
751                 Os_Dispatch(OP_ACTIVATE_TASK);\r
752         }\r
753 \r
754         Irq_Restore(msr);\r
755 \r
756         OS_STD_END_1(OSServiceId_ActivateTask,TaskID);\r
757 }\r
758 \r
759 /**\r
760  * This  service  causes  the  termination  of  the  calling  task.  The\r
761  * calling  task  is  transferred  from  the  running  state  into  the\r
762  * suspended state.\r
763  *\r
764  * An internal resource assigned to the calling task is automatically\r
765  * released. Other resources occupied by the task shall have been\r
766  * released before the call to TerminateTask. If a resource is still\r
767  * occupied in standard status the behaviour is undefined.\r
768  *\r
769  *   If the call was successful, TerminateTask does not return to the\r
770  * call level and the status can not be evaluated.\r
771  *\r
772  *   If the version with extended status is used, the service returns\r
773  * in case of error, and provides a status which can be evaluated\r
774  * in the application.\r
775  *\r
776  *   If the service TerminateTask is called successfully, it enforces a\r
777  * rescheduling.\r
778  *\r
779  *  [ Ending   a   task   function   without   call   to   TerminateTask\r
780  *    or ChainTask is strictly forbidden and may leave the system in an\r
781  *    undefined state. ]\r
782  *\r
783  * [] is an OSEK requirement and is overridden by OS052\r
784  *\r
785  * @return\r
786  */\r
787 \r
788 StatusType TerminateTask( void ) {\r
789         OsTaskVarType *curr_pcb = Os_SysTaskGetCurr();\r
790         StatusType rv = E_OK;\r
791         uint32_t flags;\r
792 \r
793         OS_DEBUG(D_TASK,"# TerminateTask %s\n",curr_pcb->constPtr->name);\r
794 \r
795 #if (OS_STATUS_EXTENDED == STD_ON )\r
796 \r
797 \r
798         if( Os_Sys.intNestCnt != 0 ) {\r
799                 rv =  E_OS_CALLEVEL;\r
800                 goto err;\r
801         }\r
802 \r
803 #if 0\r
804         if ( Os_SchedulerResourceIsOccupied() ) {\r
805                 rv =  E_OS_RESOURCE;\r
806                 goto err;\r
807         }\r
808 #endif\r
809 \r
810         if( Os_TaskOccupiesResources(curr_pcb) ) {\r
811                 /* Note! Do NOT release the resource here */\r
812                 rv =  E_OS_RESOURCE;\r
813                 goto err;\r
814         }\r
815 \r
816 #endif\r
817         Irq_Save(flags);\r
818 \r
819         /* Force the dispatcher to find something, even if its us */\r
820         Os_Dispatch(OP_TERMINATE_TASK);\r
821 \r
822         assert(0);\r
823 \r
824         OS_STD_END(OSServiceId_TerminateTask);\r
825 }\r
826 \r
827 StatusType ChainTask( TaskType TaskId ) {\r
828         OsTaskVarType *curr_pcb = Os_SysTaskGetCurr();\r
829         StatusType rv = E_OK;\r
830         uint32_t flags;\r
831         OsTaskVarType *pcb = Os_TaskGet(TaskId);\r
832 \r
833 \r
834         OS_DEBUG(D_TASK,"# ChainTask %s\n",curr_pcb->constPtr->name);\r
835 \r
836 #if (OS_STATUS_EXTENDED == STD_ON )\r
837         /* extended */\r
838         TASK_CHECK_ID(TaskId);\r
839 \r
840         if( Os_Sys.intNestCnt != 0 ) {\r
841                 /* extended */\r
842                 rv = E_OS_CALLEVEL;\r
843                 goto err;\r
844         }\r
845 \r
846 #endif\r
847 \r
848         Irq_Save(flags);\r
849 \r
850 #if (OS_STATUS_EXTENDED == STD_ON )\r
851 #if 0\r
852         if ( Os_SchedulerResourceIsOccupied() ) {\r
853                 /* extended */\r
854                 rv = E_OS_RESOURCE;\r
855                 Irq_Restore(flags);\r
856                 goto err;\r
857         }\r
858 #endif\r
859 \r
860         if( Os_TaskOccupiesResources(curr_pcb) ) {\r
861                 /* extended */\r
862                 rv = E_OS_RESOURCE;\r
863                 Irq_Restore(flags);\r
864                 goto err;\r
865         }\r
866 #endif\r
867 \r
868 //      if( os_pcb_get_state(pcb) != ST_SUSPENDED ) {\r
869         if (curr_pcb != pcb) {\r
870                 /** @req OSEK_? Too many task activations */\r
871                 if( (pcb->activations + 1) >  pcb->constPtr->activationLimit ) {\r
872                         /* standard */\r
873                         rv = E_OS_LIMIT;\r
874                         Irq_Restore(flags);\r
875                         goto err;\r
876                 }\r
877 \r
878                 if( os_pcb_get_state(pcb) == ST_SUSPENDED ) {\r
879                         assert( pcb->activations == 0 );\r
880                         Os_Arc_SetCleanContext(pcb);\r
881                         Os_TaskMakeReady(pcb);\r
882                 }\r
883 \r
884                 pcb->activations++;\r
885 \r
886         }\r
887 \r
888         Os_Sys.chainedPcbPtr = pcb;\r
889 \r
890         Os_Dispatch(OP_CHAIN_TASK);\r
891 \r
892         assert( 0 );\r
893 \r
894         OS_STD_END_1(OSServiceId_ChainTask,TaskId);\r
895 }\r
896 \r
897 /**\r
898  * If a higher-priority task is ready, the internal resource of the task\r
899  * is released, the current task is put into the  ready state, its\r
900  * context is saved and the higher-priority task is executed.\r
901  * Otherwise the calling task is continued.\r
902  *\r
903  * TODO: The OSEK spec says a lot of strange things under "particulareties"\r
904  * that I don't understand\r
905  *\r
906  * See OSEK/VDX 13.2.3.4\r
907  *\r
908  */\r
909 StatusType Schedule( void ) {\r
910         StatusType rv = E_OK;\r
911         uint32_t flags;\r
912         OsTaskVarType *curr_pcb = Os_SysTaskGetCurr();\r
913 \r
914         OS_DEBUG(D_TASK,"# Schedule %s\n",curr_pcb->constPtr->name);\r
915 \r
916         /* Check that we are not calling from interrupt context */\r
917         if( Os_Sys.intNestCnt != 0 ) {\r
918                 rv =  E_OS_CALLEVEL;\r
919                 goto err;\r
920         }\r
921 \r
922         if ( Os_TaskOccupiesResources(curr_pcb) ) {\r
923                 rv = E_OS_RESOURCE;\r
924                 goto err;\r
925         }\r
926 \r
927         assert( Os_SysTaskGetCurr()->state & ST_RUNNING );\r
928 \r
929         /* We need to figure out if we have an internal resource,\r
930          * otherwise no re-scheduling.\r
931          * NON  - Have internal resource prio OS_RES_SCHEDULER_PRIO (32+)\r
932          * FULL - Assigned internal resource OR\r
933          *        No assigned internal resource.\r
934          * */\r
935         if( Os_SysTaskGetCurr()->constPtr->scheduling != NON ) {\r
936                 return E_OK;\r
937         }\r
938 \r
939         Irq_Save(flags);\r
940         OsTaskVarType* top_pcb = Os_TaskGetTop();\r
941         /* only dispatch if some other ready task has higher prio */\r
942         if (top_pcb->activePriority > Os_SysTaskGetCurr()->activePriority) {\r
943                 Os_Dispatch(OP_SCHEDULE);\r
944         }\r
945 \r
946         Irq_Restore(flags);\r
947         // Prevent label warning. Remove this when proper error handling is implemented.\r
948         if (0) goto err;\r
949 \r
950         OS_STD_END(OSServiceId_Schedule);\r
951 }\r
952 \r