1 /* -------------------------------- Arctic Core ------------------------------
2 * Arctic Core - the open source AUTOSAR platform http://arccore.com
4 * Copyright (C) 2009 ArcCore AB <contact@arccore.com>
6 * This source code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by the
8 * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * -------------------------------- Arctic Core ------------------------------*/
24 _Bool os_pcb_pid_valid( OsPcbType *restrict pcb ) {
25 return ( pcb->pid > Oil_GetTaskCnt() ) ? 0 : 1;
28 * Start an extended task.
30 * - Grab the internal resource for the process
31 * - Set it running state.
32 * - Start to execute the process
35 void Os_TaskStartExtended( void ) {
40 pcb = Os_TaskGetCurrent();
41 Os_ResourceGetInternal();
42 Os_TaskMakeRunning(pcb);
47 Os_ResourceCheckAndRelease(pcb);
51 if( Os_IrqAnyDisabled() ) {
56 ERRORHOOK(E_OS_MISSINGEND);
63 * Start an basic task.
67 void Os_TaskStartBasic( void ) {
72 pcb = Os_TaskGetCurrent();
73 Os_ResourceGetInternal();
74 Os_TaskMakeRunning(pcb);
78 Os_ResourceCheckAndRelease(pcb);
82 if( Os_IrqAnyDisabled() ) {
87 ERRORHOOK(E_OS_MISSINGEND);
94 static void Os_StackSetup( OsPcbType *pcbPtr ) {
97 /* Find bottom of the stack so that we can place the
100 * stack bottom = high address. stack top = low address
102 bottom = (uint8_t *)pcbPtr->stack.top + pcbPtr->stack.size;
103 pcbPtr->stack.curr = bottom;
104 // TODO: alignments here..
105 // TODO :use function os_arch_get_call_size() ??
107 // Make some space for back-chain.
109 // Set the current stack so that it points to the context
110 pcbPtr->stack.curr = bottom - Os_ArchGetScSize();
112 Os_StackSetEndmark(pcbPtr);
116 * Fill the stack with a predefined pattern
118 * @param pcbPtr Pointer to the pcb to fill with pattern
120 static void Os_StackFill(OsPcbType *pcbPtr) {
121 uint8_t *p = pcbPtr->stack.curr;
123 assert(pcbPtr->stack.curr > pcbPtr->stack.top);
125 while (p > (uint8_t *) pcbPtr->stack.top) {
136 static void Os_TaskSetEntry(OsPcbType *pcbPtr ) {
143 * Setup the context for a pcb. The context differs for different arch's
144 * so we call the arch dependent functions also.
145 * The context at setup is always a small context.
147 * @param pcb Ptr to the pcb to setup context for.
149 void Os_ContextInit( OsPcbType *pcb ) {
151 if( pcb->autostart ) {
152 Os_TaskMakeReady(pcb);
154 pcb->state = ST_SUSPENDED;
159 OsArch_SetTaskEntry(pcb);
161 os_arch_setup_context(pcb);
168 void Os_ContextReInit( OsPcbType *pcbPtr ) {
169 Os_StackSetup(pcbPtr);
170 OsArch_SetTaskEntry(pcbPtr);
171 // TODO: This really need to be done
172 os_arch_setup_context(pcbPtr);
176 * Search for a specific task in the pcb list.
178 * @param tid The task id to search for
179 * @return Ptr to the found pcb or NULL
181 OsPcbType *os_find_task( TaskType tid ) {
184 /* TODO: Implement this as an array */
185 TAILQ_FOREACH(i_pcb,& os_sys.pcb_head,pcb_list) {
186 if(i_pcb->pid == tid ) {
195 * Adds a pcb to the list of pcb's
198 TaskType Os_AddTask( OsPcbType *pcb ) {
201 Irq_Save(msr); // Save irq status and disable interrupts
203 pcb->pid = os_sys.task_cnt;
204 // Add to list of PCB's
205 TAILQ_INSERT_TAIL(& os_sys.pcb_head,pcb,pcb_list);
208 Irq_Restore(msr); // Restore interrupts
213 #define PRIO_ILLEGAL -100
214 // TODO: we can't have O(n) search here.. hash on prio instead
217 * Find the top priority task. Even the running task is included.
222 OsPcbType *Os_TaskGetTop( void ){
224 OsPcbType *top_prio_pcb = NULL;
225 OsPriorityType top_prio = PRIO_ILLEGAL;
227 os_isr_printf(D_TASK,"os_find_top_prio_proc\n");
229 TAILQ_FOREACH(i_pcb,& os_sys.ready_head,ready_list) {
230 // all ready task are canidates
231 if( i_pcb->state & (ST_READY|ST_RUNNING)) {
232 if( top_prio != PRIO_ILLEGAL ) {
233 if( i_pcb->prio > top_prio ) {
234 top_prio = i_pcb->prio;
235 top_prio_pcb = i_pcb;
238 top_prio = i_pcb->prio;
239 top_prio_pcb = i_pcb;
246 assert(top_prio_pcb!=NULL);
248 os_isr_printf(D_TASK,"Found %s\n",top_prio_pcb->name);
259 // old_pcb -> WAITING
260 // new_pcb -> READY(RUNNING)
263 // new_pcb -> READY/RUNNING
268 * - remove from ready queue
269 * - set state == ST_RUNNING
272 * * leave in ready queue
273 * * set state == ST_RUNNING
274 * - ready queue and ST_READY not the same
275 * + No need to remove the running process from ready queue
278 OsPcbType *Os_FindTopPrioTask( void ) {
292 * @param force Force a re-scheduling
295 void Os_Dispatch( _Bool force ) {
297 OsPcbType *currPcbPtr;
299 assert(os_sys.int_nest_cnt == 0);
300 assert(os_sys.scheduler_lock == 0 );
302 pcbPtr = Os_TaskGetTop();
303 currPcbPtr = Os_TaskGetCurrent();
304 /* Swap if we found any process or are forced (multiple activations)*/
305 if( pcbPtr != currPcbPtr || force ) {
306 /* Add us to the ready list */
307 if( currPcbPtr->state & ST_RUNNING ) {
308 Os_TaskRunningToReady(currPcbPtr);
316 assert(pcbPtr!=NULL);
318 Os_ResourceReleaseInternal();
320 #if (OS_STACK_MONITORING == 1)
321 if( !Os_StackIsEndmarkOk(currPcbPtr) ) {
322 #if ( OS_SC1 == 1) || ( OS_SC2 == 1)
324 ShutdownOS(E_OS_STACKFAULT);
326 #error SC3 or SC4 not supported. Protection hook should be called here
332 // Make a simple stack check for prio procs...
333 // See OS068, Autosar SWS
335 uint32_t stackp = (uint32_t)Os_ArchGetStackPtr();
336 uint32_t smallc_size = Os_ArchGetScSize();
338 // enough size to place a small context on the stack
339 // top( low address ) + small context > current stackpointer
340 if( (uint32_t)(currPcbPtr->stack.top + smallc_size) > stackp ) {
341 ShutdownOS(E_OS_STACKFAULT);
347 * 1. Re-Activate the same basic task again -> Os_ArchSwapContextToW()
348 * 2. Swap out a terminated task -> Os_ArchSwapContextToW()
349 * 3. Normal swap -> Os_ArchSwapContext()
352 /* Force is ONLY used from TerminateTask() */
354 Os_ArchSwapContextToW(currPcbPtr ,pcbPtr, pcbPtr->stack.curr );
357 Os_ArchSwapContext(currPcbPtr,pcbPtr);
359 pcbPtr = Os_TaskGetCurrent();
360 Os_TaskMakeRunning(pcbPtr);
362 Os_ResourceGetInternal();
367 /* We haven't removed ourselves from the ready list? */
368 assert(currPcbPtr->state != ST_WAITING);
369 /* We have terminated and found us in the ready list? */
370 assert(currPcbPtr->state != ST_SUSPENDED);
378 * Called when a task is to be run for the first time.
380 void Os_TaskSwapContextTo(OsPcbType *old_pcb, OsPcbType *new_pcb ) {
383 Os_ArchSwapContextTo(old_pcb,new_pcb);
384 /* TODO: When do we return here ?? */
388 void Os_Arc_GetStackInfo( TaskType task, StackInfoType *s) {
389 OsPcbType *pcb = os_get_pcb(task);
391 s->curr = Os_ArchGetStackPtr();
392 s->top = pcb->stack.top;
393 s->at_swap = pcb->stack.curr;
394 s->size = pcb->stack.size;
395 s->usage = (void *)Os_StackGetUsage(pcb);
400 OsPcbType *os_find_higher_priority_task( OsPriorityType prio ) {
402 OsPcbType *h_prio_pcb = NULL;
403 OsPriorityType t_prio = prio;
405 TAILQ_FOREACH(i_pcb,& os_sys.ready_head,ready_list) {
406 if( i_pcb->prio > t_prio ) {
407 t_prio = i_pcb->prio;
416 StatusType GetTaskState(TaskType TaskId, TaskStateRefType State) {
\r
417 state_t curr_state = os_pcb_get_state(os_get_pcb(TaskId));
\r
418 StatusType rv = E_OK;
\r
420 // TODO: Lazy impl. for now */
\r
421 switch(curr_state) {
\r
422 case ST_RUNNING: *State = TASK_STATE_RUNNING; break;
\r
423 case ST_WAITING: *State = TASK_STATE_WAITING; break;
\r
424 case ST_SUSPENDED: *State = TASK_STATE_SUSPENDED; break;
\r
425 case ST_READY: *State = TASK_STATE_READY; break;
\r
428 // Prevent label warning. Remove when proper error handling is implemented.
\r
431 OS_STD_END_2(OSServiceId_GetTaskState,TaskId, State);
\r
434 StatusType GetTaskID( TaskRefType task_id ) {
\r
435 *task_id = os_sys.curr_pcb->pid;
\r
439 ISRType GetISRID( void ) {
443 if(os_sys.int_nest_cnt == 0 ) {
448 return (ISRType)Os_TaskGetCurrent()->pid;
452 * The task <TaskID> is transferred from the suspended state into
\r
453 * the ready state. The operating system ensures that the task
\r
454 * code is being executed from the first statement.
\r
456 * The service may be called from interrupt level and from task
\r
457 * level (see Figure 12-1).
\r
458 * Rescheduling after the call to ActivateTask depends on the
\r
459 * place it is called from (ISR, non preemptable task, preemptable
\r
462 * If E_OS_LIMIT is returned the activation is ignored.
\r
463 * When an extended task is transferred from suspended state
\r
464 * into ready state all its events are cleared.
\r
467 * ActivateTask will not immediately change the state of the task
468 * in case of multiple activation requests. If the task is not
469 * suspended, the activation will only be recorded and performed later.
475 StatusType ActivateTask( TaskType TaskID ) {
\r
477 OsPcbType *pcb = os_get_pcb(TaskID);
\r
478 StatusType rv = E_OK;
\r
480 os_isr_printf(D_TASK,"ActivateTask %s\n",pcb->name);
\r
482 if( !os_pcb_pid_valid(pcb) ) {
\r
487 /* @req OS093 ActivateTask */
488 if( Os_IrqAnyDisabled() ) {
489 rv = E_OS_DISABLEDINT;
495 if( os_pcb_get_state(pcb) == ST_SUSPENDED ) {
497 if (pcb->proc_type == PROC_EXTENDED) {
498 /** @req OSEK ActivateTask Cleanup events
499 * OSEK,ActivateTask, When an extended task is transferred from suspended
500 * state into ready state all its events are cleared.*/
504 Os_TaskMakeReady(pcb);
507 if( pcb->proc_type == PROC_EXTENDED ) {
508 /** @req OSEK Activate task.
509 * An extended task be activated once. See Chapter 4.3 in OSEK
515 /** @req OSEK_? Too many task activations */
516 if( pcb->activations == pcb->activationLimit ) {
526 /* Preempt only if higher prio than us */
\r
527 if( (pcb->scheduling == FULL) &&
528 (os_sys.int_nest_cnt == 0) )
533 OS_STD_END_1(OSServiceId_ActivateTask,TaskID);
\r
537 * This service causes the termination of the calling task. The
538 * calling task is transferred from the running state into the
541 * An internal resource assigned to the calling task is automatically
542 * released. Other resources occupied by the task shall have been
543 * released before the call to TerminateTask. If a resource is still
544 * occupied in standard status the behaviour is undefined.
546 * If the call was successful, TerminateTask does not return to the
547 * call level and the status can not be evaluated.
549 * If the version with extended status is used, the service returns
550 * in case of error, and provides a status which can be evaluated
551 * in the application.
553 * If the service TerminateTask is called successfully, it enforces a
556 * [ Ending a task function without call to TerminateTask
557 * or ChainTask is strictly forbidden and may leave the system in an
560 * [] is an OSEK requirement and is overridden by OS052
565 StatusType TerminateTask( void ) {
\r
566 OsPcbType *curr_pcb = Os_TaskGetCurrent();
\r
567 StatusType rv = E_OK;
570 os_std_printf(D_TASK,"TerminateTask %s\n",curr_pcb->name);
\r
572 if( os_sys.int_nest_cnt != 0 ) {
579 --curr_pcb->activations;
580 assert(curr_pcb->activations>=0);
582 /*@req OSEK TerminateTask
583 * In case of tasks with multiple activation requests,
584 * terminating the current instance of the task automatically puts the next
585 * instance of the same task into the ready state
587 if( curr_pcb->activations == 0 ) {
588 Os_TaskMakeSuspended(curr_pcb);
590 /* We need to add ourselves to the ready list again,
591 * with a startup context. */
595 /* We're manipulating the current stack here.
596 * Os_ArchSwapContext(old,new) saves on current stack.
597 * 1. We add an argument to Os_ArchSwapContext() to set the stack.
598 * 2. We could call ActivateTask here...
600 Os_ContextReInit(curr_pcb);
602 /* Force the dispatcher to find something, even if its us */
605 Irq_Restore(flags);
\r
606 // It must find something here...otherwise something is very wrong..
\r
613 OS_STD_END(OSServiceId_TerminateTask);
\r
616 StatusType ChainTask( TaskType TaskId ) {
\r
620 if( os_sys.int_nest_cnt != 0 ) {
626 rv = ActivateTask(TaskId);
\r
627 /* TODO: more more here..*/
\r
629 Irq_Restore(flags);
\r
631 if (rv != E_OK) goto err;
\r
633 OS_STD_END_1(OSServiceId_ChainTask,TaskId);
\r
637 * If a higher-priority task is ready, the internal resource of the task
\r
638 * is released, the current task is put into the ready state, its
\r
639 * context is saved and the higher-priority task is executed.
\r
640 * Otherwise the calling task is continued.
\r
642 * TODO: The OSEK spec says a lot of strange things under "particulareties"
\r
643 * that I don't understand
645 * See OSEK/VDX 13.2.3.4
\r
648 StatusType Schedule( void ) {
\r
650 // OsPcbType *curr_pcb = get_curr_pcb();
\r
651 StatusType rv = E_OK;
654 /* We need to figure out if we have an internal resource,
655 * otherwise no re-scheduling.
656 * NON - Have internal resource prio OS_RES_SCHEDULER_PRIO (32+)
657 * FULL - Assigned internal resource OR
658 * No assigned internal resource.
660 if( Os_TaskGetCurrent()->scheduling != NON ) {
665 if( os_get_resource_int_p() == NULL ) {
671 /* Check that we are not calling from interrupt context */
672 if( os_sys.int_nest_cnt != 0 ) {
679 Irq_Restore(flags);
\r
681 // Prevent label warning. Remove this when proper error handling is implemented.
\r
684 OS_STD_END(OSServiceId_Schedule);
\r