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);
48 if( Os_IrqAnyDisabled() ) {
52 #warning Dont I have to check this at terminate task also?
55 ERRORHOOK(E_OS_MISSINGEND);
62 * Start an basic task.
66 void Os_TaskStartBasic( void ) {
71 pcb = Os_TaskGetCurrent();
72 Os_ResourceGetInternal();
73 Os_TaskMakeRunning(pcb);
79 if( Os_IrqAnyDisabled() ) {
84 ERRORHOOK(E_OS_MISSINGEND);
91 static void Os_StackSetup( OsPcbType *pcbPtr ) {
94 /* Find bottom of the stack so that we can place the
97 * stack bottom = high address. stack top = low address
99 bottom = (uint8_t *)pcbPtr->stack.top + pcbPtr->stack.size;
100 pcbPtr->stack.curr = bottom;
101 // TODO: alignments here..
102 // TODO :use function os_arch_get_call_size() ??
104 // Make some space for back-chain.
106 // Set the current stack so that it points to the context
107 pcbPtr->stack.curr = bottom - Os_ArchGetScSize();
109 Os_StackSetEndmark(pcbPtr);
113 * Fill the stack with a predefined pattern
115 * @param pcbPtr Pointer to the pcb to fill with pattern
117 static void Os_StackFill(OsPcbType *pcbPtr) {
118 uint8_t *p = pcbPtr->stack.curr;
120 assert(pcbPtr->stack.curr > pcbPtr->stack.top);
122 while (p > (uint8_t *) pcbPtr->stack.top) {
133 static void Os_TaskSetEntry(OsPcbType *pcbPtr ) {
140 * Setup the context for a pcb. The context differs for different arch's
141 * so we call the arch dependent functions also.
142 * The context at setup is always a small context.
144 * @param pcb Ptr to the pcb to setup context for.
146 void Os_ContextInit( OsPcbType *pcb ) {
148 if( pcb->autostart ) {
149 Os_TaskMakeReady(pcb);
151 pcb->state = ST_SUSPENDED;
156 OsArch_SetTaskEntry(pcb);
158 Os_ArchSetupContext(pcb);
165 void Os_ContextReInit( OsPcbType *pcbPtr ) {
166 Os_StackSetup(pcbPtr);
170 * Search for a specific task in the pcb list.
172 * @param tid The task id to search for
173 * @return Ptr to the found pcb or NULL
175 OsPcbType *os_find_task( TaskType tid ) {
178 /* TODO: Implement this as an array */
179 TAILQ_FOREACH(i_pcb,& os_sys.pcb_head,pcb_list) {
180 if(i_pcb->pid == tid ) {
189 * Adds a pcb to the list of pcb's
192 TaskType Os_AddTask( OsPcbType *pcb ) {
195 Irq_Save(msr); // Save irq status and disable interrupts
197 pcb->pid = os_sys.task_cnt;
198 // Add to list of PCB's
199 TAILQ_INSERT_TAIL(& os_sys.pcb_head,pcb,pcb_list);
202 Irq_Restore(msr); // Restore interrupts
207 #define PRIO_ILLEGAL -100
208 // TODO: we can't have O(n) search here.. hash on prio instead
211 * Find the top priority task. Even the running task is included.
216 OsPcbType *Os_TaskGetTop( void ){
218 OsPcbType *top_prio_pcb = NULL;
219 OsPriorityType top_prio = PRIO_ILLEGAL;
221 os_isr_printf(D_TASK,"os_find_top_prio_proc\n");
223 TAILQ_FOREACH(i_pcb,& os_sys.ready_head,ready_list) {
224 // all ready task are canidates
225 if( i_pcb->state & (ST_READY|ST_RUNNING)) {
226 if( top_prio != PRIO_ILLEGAL ) {
227 if( i_pcb->prio > top_prio ) {
228 top_prio = i_pcb->prio;
229 top_prio_pcb = i_pcb;
232 top_prio = i_pcb->prio;
233 top_prio_pcb = i_pcb;
240 assert(top_prio_pcb!=NULL);
242 os_isr_printf(D_TASK,"Found %s\n",top_prio_pcb->name);
248 #define USE_DEBUG_PRINT
253 // old_pcb -> WAITING
254 // new_pcb -> READY(RUNNING)
257 // new_pcb -> READY/RUNNING
262 * - remove from ready queue
263 * - set state == ST_RUNNING
266 * * leave in ready queue
267 * * set state == ST_RUNNING
268 * - ready queue and ST_READY not the same
269 * + No need to remove the running process from ready queue
272 OsPcbType *Os_FindTopPrioTask( void ) {
286 * @param force Force a re-scheduling
289 void Os_Dispatch( _Bool force ) {
291 OsPcbType *currPcbPtr;
293 assert(os_sys.int_nest_cnt == 0);
294 assert(os_sys.scheduler_lock == 0 );
296 pcbPtr = Os_TaskGetTop();
297 currPcbPtr = Os_TaskGetCurrent();
298 /* Swap if we found any process or are forced (multiple activations)*/
299 if( pcbPtr != currPcbPtr ) {
300 /* Add us to the ready list */
301 if( currPcbPtr->state & ST_RUNNING ) {
302 Os_TaskRunningToReady(currPcbPtr);
310 assert(pcbPtr!=NULL);
312 Os_ResourceReleaseInternal();
314 #if (OS_STACK_MONITORING == 1)
315 if( !Os_StackIsEndmarkOk(currPcbPtr) ) {
316 #if ( OS_SC1 == 1) || ( OS_SC2 == 1)
318 ShutdownOS(E_OS_STACKFAULT);
320 #error SC3 or SC4 not supported. Protection hook should be called here
326 // Make a simple stack check for prio procs...
327 // See OS068, Autosar SWS
329 uint32_t stackp = (uint32_t)Os_ArchGetStackPtr();
330 uint32_t smallc_size = Os_ArchGetScSize();
332 // enough size to place a small context on the stack
333 // top( low address ) + small context > current stackpointer
334 if( (uint32_t)(currPcbPtr->stack.top + smallc_size) > stackp ) {
335 ShutdownOS(E_OS_STACKFAULT);
341 * 1. Re-Activate the same basic task again -> Os_ArchSwapContextToW()
342 * 2. Swap out a terminated task -> Os_ArchSwapContextToW()
343 * 3. Normal swap -> Os_ArchSwapContext()
347 /* Force is ONLY used from TerminateTask() */
349 Os_StackSetup(pcbPtr);
350 OsArch_SetTaskEntry(pcbPtr);
351 // TODO: This really need to be done
352 Os_ArchSetupContext(pcbPtr);
353 // Os_ArchSetSpAndCall(pcbPtr->stack.curr,Os_TaskStartBasic);
357 Os_ArchSwapContext(currPcbPtr,pcbPtr);
359 pcbPtr = Os_TaskGetCurrent();
360 Os_TaskMakeRunning(pcbPtr);
362 Os_ResourceGetInternal();
367 Os_StackSetup(pcbPtr);
368 Os_ArchSetSpAndCall(pcbPtr->stack.curr,Os_TaskStartBasic);
370 /* We haven't removed ourselves from the ready list? */
371 assert(currPcbPtr->state != ST_WAITING);
372 /* We have terminated and found us in the ready list? */
373 assert(currPcbPtr->state != ST_SUSPENDED);
382 * Called when a task is to be run for the first time.
384 void Os_TaskSwapContextTo(OsPcbType *old_pcb, OsPcbType *new_pcb ) {
387 Os_ArchSwapContextTo(old_pcb,new_pcb);
388 /* TODO: When do we return here ?? */
392 void Os_Arc_GetStackInfo( TaskType task, StackInfoType *s) {
393 OsPcbType *pcb = os_get_pcb(task);
395 s->curr = Os_ArchGetStackPtr();
396 s->top = pcb->stack.top;
397 s->at_swap = pcb->stack.curr;
398 s->size = pcb->stack.size;
399 s->usage = (void *)Os_StackGetUsage(pcb);
404 OsPcbType *os_find_higher_priority_task( OsPriorityType prio ) {
406 OsPcbType *h_prio_pcb = NULL;
407 OsPriorityType t_prio = prio;
409 TAILQ_FOREACH(i_pcb,& os_sys.ready_head,ready_list) {
410 if( i_pcb->prio > t_prio ) {
411 t_prio = i_pcb->prio;
420 StatusType GetTaskState(TaskType TaskId, TaskStateRefType State) {
\r
421 state_t curr_state = os_pcb_get_state(os_get_pcb(TaskId));
\r
422 StatusType rv = E_OK;
\r
424 // TODO: Lazy impl. for now */
\r
425 switch(curr_state) {
\r
426 case ST_RUNNING: *State = TASK_STATE_RUNNING; break;
\r
427 case ST_WAITING: *State = TASK_STATE_WAITING; break;
\r
428 case ST_SUSPENDED: *State = TASK_STATE_SUSPENDED; break;
\r
429 case ST_READY: *State = TASK_STATE_READY; break;
\r
432 // Prevent label warning. Remove when proper error handling is implemented.
\r
435 OS_STD_END_2(OSServiceId_GetTaskState,TaskId, State);
\r
438 StatusType GetTaskID( TaskRefType task_id ) {
\r
439 *task_id = os_sys.curr_pcb->pid;
\r
443 ISRType GetISRID( void ) {
446 if(os_sys.int_nest_cnt == 0 ) {
451 return (ISRType)Os_TaskGetCurrent()->pid;
454 #define TASK_CHECK_ID(x) \
455 if( (x) > Oil_GetTaskCnt()) { \
462 * The task <TaskID> is transferred from the suspended state into
\r
463 * the ready state. The operating system ensures that the task
\r
464 * code is being executed from the first statement.
\r
466 * The service may be called from interrupt level and from task
\r
467 * level (see Figure 12-1).
\r
468 * Rescheduling after the call to ActivateTask depends on the
\r
469 * place it is called from (ISR, non preemptable task, preemptable
\r
472 * If E_OS_LIMIT is returned the activation is ignored.
\r
473 * When an extended task is transferred from suspended state
\r
474 * into ready state all its events are cleared.
\r
477 * ActivateTask will not immediately change the state of the task
478 * in case of multiple activation requests. If the task is not
479 * suspended, the activation will only be recorded and performed later.
485 StatusType ActivateTask( TaskType TaskID ) {
\r
487 OsPcbType *pcb = os_get_pcb(TaskID);
\r
488 StatusType rv = E_OK;
\r
490 os_isr_printf(D_TASK,"ActivateTask %s\n",pcb->name);
\r
492 #if (OS_STATUS_EXTENDED == STD_ON )
493 TASK_CHECK_ID(TaskID);
495 /* @req OS093 ActivateTask */
496 if( Os_IrqAnyDisabled() ) {
497 rv = E_OS_DISABLEDINT;
504 if( os_pcb_get_state(pcb) == ST_SUSPENDED ) {
506 if (pcb->proc_type == PROC_EXTENDED) {
507 /** @req OSEK ActivateTask Cleanup events
508 * OSEK,ActivateTask, When an extended task is transferred from suspended
509 * state into ready state all its events are cleared.*/
514 OsArch_SetTaskEntry(pcb);
515 Os_ArchSetupContext(pcb);
516 Os_TaskMakeReady(pcb);
519 if( pcb->proc_type == PROC_EXTENDED ) {
520 /** @req OSEK Activate task.
521 * An extended task be activated once. See Chapter 4.3 in OSEK
527 /** @req OSEK_? Too many task activations */
528 if( pcb->activations == pcb->activationLimit ) {
538 /* Preempt only if higher prio than us */
\r
539 if( (pcb->scheduling == FULL) &&
540 (os_sys.int_nest_cnt == 0) && (pcb->prio > Os_TaskGetCurrent()->prio) )
545 OS_STD_END_1(OSServiceId_ActivateTask,TaskID);
\r
549 * This service causes the termination of the calling task. The
550 * calling task is transferred from the running state into the
553 * An internal resource assigned to the calling task is automatically
554 * released. Other resources occupied by the task shall have been
555 * released before the call to TerminateTask. If a resource is still
556 * occupied in standard status the behaviour is undefined.
558 * If the call was successful, TerminateTask does not return to the
559 * call level and the status can not be evaluated.
561 * If the version with extended status is used, the service returns
562 * in case of error, and provides a status which can be evaluated
563 * in the application.
565 * If the service TerminateTask is called successfully, it enforces a
568 * [ Ending a task function without call to TerminateTask
569 * or ChainTask is strictly forbidden and may leave the system in an
572 * [] is an OSEK requirement and is overridden by OS052
577 StatusType TerminateTask( void ) {
\r
578 OsPcbType *curr_pcb = Os_TaskGetCurrent();
\r
579 StatusType rv = E_OK;
582 os_std_printf(D_TASK,"TerminateTask %s\n",curr_pcb->name);
\r
584 #if (OS_STATUS_EXTENDED == STD_ON )
587 if( os_sys.int_nest_cnt != 0 ) {
593 if( Os_ResourceCheckAndRelease(curr_pcb) == 1 ) {
605 --curr_pcb->activations;
608 // assert(curr_pcb->activations>=0);
610 /*@req OSEK TerminateTask
611 * In case of tasks with multiple activation requests,
612 * terminating the current instance of the task automatically puts the next
613 * instance of the same task into the ready state
615 if( curr_pcb->activations <= 0 ) {
616 curr_pcb->activations = 0;
617 Os_TaskMakeSuspended(curr_pcb);
619 /* We need to add ourselves to the ready list again,
620 * with a startup context. */
623 // Os_ContextReInit(curr_pcb);
625 /* Force the dispatcher to find something, even if its us */
628 Irq_Restore(flags);
\r
629 // It must find something here...otherwise something is very wrong..
\r
636 OS_STD_END(OSServiceId_TerminateTask);
\r
639 StatusType ChainTask( TaskType TaskId ) {
\r
643 #if (OS_STATUS_EXTENDED == STD_ON )
644 TASK_CHECK_ID(TaskId);
646 if( os_sys.int_nest_cnt != 0 ) {
653 rv = ActivateTask(TaskId);
\r
654 /* TODO: more more here..*/
\r
656 Irq_Restore(flags);
\r
658 if (rv != E_OK) goto err;
\r
660 OS_STD_END_1(OSServiceId_ChainTask,TaskId);
\r
664 * If a higher-priority task is ready, the internal resource of the task
\r
665 * is released, the current task is put into the ready state, its
\r
666 * context is saved and the higher-priority task is executed.
\r
667 * Otherwise the calling task is continued.
\r
669 * TODO: The OSEK spec says a lot of strange things under "particulareties"
\r
670 * that I don't understand
672 * See OSEK/VDX 13.2.3.4
\r
675 StatusType Schedule( void ) {
\r
677 // OsPcbType *curr_pcb = get_curr_pcb();
\r
678 StatusType rv = E_OK;
681 /* We need to figure out if we have an internal resource,
682 * otherwise no re-scheduling.
683 * NON - Have internal resource prio OS_RES_SCHEDULER_PRIO (32+)
684 * FULL - Assigned internal resource OR
685 * No assigned internal resource.
687 if( Os_TaskGetCurrent()->scheduling != NON ) {
692 if( os_get_resource_int_p() == NULL ) {
698 /* Check that we are not calling from interrupt context */
699 if( os_sys.int_nest_cnt != 0 ) {
706 Irq_Restore(flags);
\r
708 // Prevent label warning. Remove this when proper error handling is implemented.
\r
711 OS_STD_END(OSServiceId_Schedule);
\r