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() ) {
55 #warning Dont I have to check this at terminate task also?
58 ERRORHOOK(E_OS_MISSINGEND);
65 * Start an basic task.
69 void Os_TaskStartBasic( void ) {
74 pcb = Os_TaskGetCurrent();
75 Os_ResourceGetInternal();
76 Os_TaskMakeRunning(pcb);
80 Os_ResourceCheckAndRelease(pcb);
84 if( Os_IrqAnyDisabled() ) {
89 ERRORHOOK(E_OS_MISSINGEND);
96 static void Os_StackSetup( OsPcbType *pcbPtr ) {
99 /* Find bottom of the stack so that we can place the
102 * stack bottom = high address. stack top = low address
104 bottom = (uint8_t *)pcbPtr->stack.top + pcbPtr->stack.size;
105 pcbPtr->stack.curr = bottom;
106 // TODO: alignments here..
107 // TODO :use function os_arch_get_call_size() ??
109 // Make some space for back-chain.
111 // Set the current stack so that it points to the context
112 pcbPtr->stack.curr = bottom - Os_ArchGetScSize();
114 Os_StackSetEndmark(pcbPtr);
118 * Fill the stack with a predefined pattern
120 * @param pcbPtr Pointer to the pcb to fill with pattern
122 static void Os_StackFill(OsPcbType *pcbPtr) {
123 uint8_t *p = pcbPtr->stack.curr;
125 assert(pcbPtr->stack.curr > pcbPtr->stack.top);
127 while (p > (uint8_t *) pcbPtr->stack.top) {
138 static void Os_TaskSetEntry(OsPcbType *pcbPtr ) {
145 * Setup the context for a pcb. The context differs for different arch's
146 * so we call the arch dependent functions also.
147 * The context at setup is always a small context.
149 * @param pcb Ptr to the pcb to setup context for.
151 void Os_ContextInit( OsPcbType *pcb ) {
153 if( pcb->autostart ) {
154 Os_TaskMakeReady(pcb);
156 pcb->state = ST_SUSPENDED;
161 OsArch_SetTaskEntry(pcb);
163 Os_ArchSetupContext(pcb);
170 void Os_ContextReInit( OsPcbType *pcbPtr ) {
171 Os_StackSetup(pcbPtr);
175 * Search for a specific task in the pcb list.
177 * @param tid The task id to search for
178 * @return Ptr to the found pcb or NULL
180 OsPcbType *os_find_task( TaskType tid ) {
183 /* TODO: Implement this as an array */
184 TAILQ_FOREACH(i_pcb,& os_sys.pcb_head,pcb_list) {
185 if(i_pcb->pid == tid ) {
194 * Adds a pcb to the list of pcb's
197 TaskType Os_AddTask( OsPcbType *pcb ) {
200 Irq_Save(msr); // Save irq status and disable interrupts
202 pcb->pid = os_sys.task_cnt;
203 // Add to list of PCB's
204 TAILQ_INSERT_TAIL(& os_sys.pcb_head,pcb,pcb_list);
207 Irq_Restore(msr); // Restore interrupts
212 #define PRIO_ILLEGAL -100
213 // TODO: we can't have O(n) search here.. hash on prio instead
216 * Find the top priority task. Even the running task is included.
221 OsPcbType *Os_TaskGetTop( void ){
223 OsPcbType *top_prio_pcb = NULL;
224 OsPriorityType top_prio = PRIO_ILLEGAL;
226 os_isr_printf(D_TASK,"os_find_top_prio_proc\n");
228 TAILQ_FOREACH(i_pcb,& os_sys.ready_head,ready_list) {
229 // all ready task are canidates
230 if( i_pcb->state & (ST_READY|ST_RUNNING)) {
231 if( top_prio != PRIO_ILLEGAL ) {
232 if( i_pcb->prio > top_prio ) {
233 top_prio = i_pcb->prio;
234 top_prio_pcb = i_pcb;
237 top_prio = i_pcb->prio;
238 top_prio_pcb = i_pcb;
245 assert(top_prio_pcb!=NULL);
247 os_isr_printf(D_TASK,"Found %s\n",top_prio_pcb->name);
258 // old_pcb -> WAITING
259 // new_pcb -> READY(RUNNING)
262 // new_pcb -> READY/RUNNING
267 * - remove from ready queue
268 * - set state == ST_RUNNING
271 * * leave in ready queue
272 * * set state == ST_RUNNING
273 * - ready queue and ST_READY not the same
274 * + No need to remove the running process from ready queue
277 OsPcbType *Os_FindTopPrioTask( void ) {
291 * @param force Force a re-scheduling
294 void Os_Dispatch( _Bool force ) {
296 OsPcbType *currPcbPtr;
298 assert(os_sys.int_nest_cnt == 0);
299 assert(os_sys.scheduler_lock == 0 );
301 pcbPtr = Os_TaskGetTop();
302 currPcbPtr = Os_TaskGetCurrent();
303 /* Swap if we found any process or are forced (multiple activations)*/
304 if( pcbPtr != currPcbPtr ) {
305 /* Add us to the ready list */
306 if( currPcbPtr->state & ST_RUNNING ) {
307 Os_TaskRunningToReady(currPcbPtr);
315 assert(pcbPtr!=NULL);
317 Os_ResourceReleaseInternal();
319 #if (OS_STACK_MONITORING == 1)
320 if( !Os_StackIsEndmarkOk(currPcbPtr) ) {
321 #if ( OS_SC1 == 1) || ( OS_SC2 == 1)
323 ShutdownOS(E_OS_STACKFAULT);
325 #error SC3 or SC4 not supported. Protection hook should be called here
331 // Make a simple stack check for prio procs...
332 // See OS068, Autosar SWS
334 uint32_t stackp = (uint32_t)Os_ArchGetStackPtr();
335 uint32_t smallc_size = Os_ArchGetScSize();
337 // enough size to place a small context on the stack
338 // top( low address ) + small context > current stackpointer
339 if( (uint32_t)(currPcbPtr->stack.top + smallc_size) > stackp ) {
340 ShutdownOS(E_OS_STACKFAULT);
346 * 1. Re-Activate the same basic task again -> Os_ArchSwapContextToW()
347 * 2. Swap out a terminated task -> Os_ArchSwapContextToW()
348 * 3. Normal swap -> Os_ArchSwapContext()
352 /* Force is ONLY used from TerminateTask() */
354 Os_StackSetup(pcbPtr);
355 OsArch_SetTaskEntry(pcbPtr);
356 // TODO: This really need to be done
357 Os_ArchSetupContext(pcbPtr);
358 // Os_ArchSetSpAndCall(pcbPtr->stack.curr,Os_TaskStartBasic);
362 Os_ArchSwapContext(currPcbPtr,pcbPtr);
364 pcbPtr = Os_TaskGetCurrent();
365 Os_TaskMakeRunning(pcbPtr);
367 Os_ResourceGetInternal();
372 Os_StackSetup(pcbPtr);
373 Os_ArchSetSpAndCall(pcbPtr->stack.curr,Os_TaskStartBasic);
375 /* We haven't removed ourselves from the ready list? */
376 assert(currPcbPtr->state != ST_WAITING);
377 /* We have terminated and found us in the ready list? */
378 assert(currPcbPtr->state != ST_SUSPENDED);
387 * Called when a task is to be run for the first time.
389 void Os_TaskSwapContextTo(OsPcbType *old_pcb, OsPcbType *new_pcb ) {
392 Os_ArchSwapContextTo(old_pcb,new_pcb);
393 /* TODO: When do we return here ?? */
397 void Os_Arc_GetStackInfo( TaskType task, StackInfoType *s) {
398 OsPcbType *pcb = os_get_pcb(task);
400 s->curr = Os_ArchGetStackPtr();
401 s->top = pcb->stack.top;
402 s->at_swap = pcb->stack.curr;
403 s->size = pcb->stack.size;
404 s->usage = (void *)Os_StackGetUsage(pcb);
409 OsPcbType *os_find_higher_priority_task( OsPriorityType prio ) {
411 OsPcbType *h_prio_pcb = NULL;
412 OsPriorityType t_prio = prio;
414 TAILQ_FOREACH(i_pcb,& os_sys.ready_head,ready_list) {
415 if( i_pcb->prio > t_prio ) {
416 t_prio = i_pcb->prio;
425 StatusType GetTaskState(TaskType TaskId, TaskStateRefType State) {
\r
426 state_t curr_state = os_pcb_get_state(os_get_pcb(TaskId));
\r
427 StatusType rv = E_OK;
\r
429 // TODO: Lazy impl. for now */
\r
430 switch(curr_state) {
\r
431 case ST_RUNNING: *State = TASK_STATE_RUNNING; break;
\r
432 case ST_WAITING: *State = TASK_STATE_WAITING; break;
\r
433 case ST_SUSPENDED: *State = TASK_STATE_SUSPENDED; break;
\r
434 case ST_READY: *State = TASK_STATE_READY; break;
\r
437 // Prevent label warning. Remove when proper error handling is implemented.
\r
440 OS_STD_END_2(OSServiceId_GetTaskState,TaskId, State);
\r
443 StatusType GetTaskID( TaskRefType task_id ) {
\r
444 *task_id = os_sys.curr_pcb->pid;
\r
448 ISRType GetISRID( void ) {
451 if(os_sys.int_nest_cnt == 0 ) {
456 return (ISRType)Os_TaskGetCurrent()->pid;
459 #define TASK_CHECK_ID(x) \
460 if( (x) > Oil_GetTaskCnt()) { \
467 * The task <TaskID> is transferred from the suspended state into
\r
468 * the ready state. The operating system ensures that the task
\r
469 * code is being executed from the first statement.
\r
471 * The service may be called from interrupt level and from task
\r
472 * level (see Figure 12-1).
\r
473 * Rescheduling after the call to ActivateTask depends on the
\r
474 * place it is called from (ISR, non preemptable task, preemptable
\r
477 * If E_OS_LIMIT is returned the activation is ignored.
\r
478 * When an extended task is transferred from suspended state
\r
479 * into ready state all its events are cleared.
\r
482 * ActivateTask will not immediately change the state of the task
483 * in case of multiple activation requests. If the task is not
484 * suspended, the activation will only be recorded and performed later.
490 StatusType ActivateTask( TaskType TaskID ) {
\r
492 OsPcbType *pcb = os_get_pcb(TaskID);
\r
493 StatusType rv = E_OK;
\r
495 os_isr_printf(D_TASK,"ActivateTask %s\n",pcb->name);
\r
497 #if (OS_STATUS_EXTENDED == STD_ON )
498 TASK_CHECK_ID(TaskID);
500 /* @req OS093 ActivateTask */
501 if( Os_IrqAnyDisabled() ) {
502 rv = E_OS_DISABLEDINT;
509 if( os_pcb_get_state(pcb) == ST_SUSPENDED ) {
511 if (pcb->proc_type == PROC_EXTENDED) {
512 /** @req OSEK ActivateTask Cleanup events
513 * OSEK,ActivateTask, When an extended task is transferred from suspended
514 * state into ready state all its events are cleared.*/
519 OsArch_SetTaskEntry(pcb);
520 Os_ArchSetupContext(pcb);
522 Os_TaskMakeReady(pcb);
525 if( pcb->proc_type == PROC_EXTENDED ) {
526 /** @req OSEK Activate task.
527 * An extended task be activated once. See Chapter 4.3 in OSEK
533 /** @req OSEK_? Too many task activations */
534 if( pcb->activations == pcb->activationLimit ) {
544 /* Preempt only if higher prio than us */
\r
545 if( (pcb->scheduling == FULL) &&
546 (os_sys.int_nest_cnt == 0) && (pcb->prio > Os_TaskGetCurrent()->prio) )
551 OS_STD_END_1(OSServiceId_ActivateTask,TaskID);
\r
555 * This service causes the termination of the calling task. The
556 * calling task is transferred from the running state into the
559 * An internal resource assigned to the calling task is automatically
560 * released. Other resources occupied by the task shall have been
561 * released before the call to TerminateTask. If a resource is still
562 * occupied in standard status the behaviour is undefined.
564 * If the call was successful, TerminateTask does not return to the
565 * call level and the status can not be evaluated.
567 * If the version with extended status is used, the service returns
568 * in case of error, and provides a status which can be evaluated
569 * in the application.
571 * If the service TerminateTask is called successfully, it enforces a
574 * [ Ending a task function without call to TerminateTask
575 * or ChainTask is strictly forbidden and may leave the system in an
578 * [] is an OSEK requirement and is overridden by OS052
583 StatusType TerminateTask( void ) {
\r
584 OsPcbType *curr_pcb = Os_TaskGetCurrent();
\r
585 StatusType rv = E_OK;
588 os_std_printf(D_TASK,"TerminateTask %s\n",curr_pcb->name);
\r
590 #if (OS_STATUS_EXTENDED == STD_ON )
591 if( os_sys.int_nest_cnt != 0 ) {
599 --curr_pcb->activations;
600 // assert(curr_pcb->activations>=0);
602 /*@req OSEK TerminateTask
603 * In case of tasks with multiple activation requests,
604 * terminating the current instance of the task automatically puts the next
605 * instance of the same task into the ready state
607 if( curr_pcb->activations == 0 ) {
608 Os_TaskMakeSuspended(curr_pcb);
610 /* We need to add ourselves to the ready list again,
611 * with a startup context. */
614 // Os_ContextReInit(curr_pcb);
616 /* Force the dispatcher to find something, even if its us */
619 Irq_Restore(flags);
\r
620 // It must find something here...otherwise something is very wrong..
\r
627 OS_STD_END(OSServiceId_TerminateTask);
\r
630 StatusType ChainTask( TaskType TaskId ) {
\r
634 #if (OS_STATUS_EXTENDED == STD_ON )
635 TASK_CHECK_ID(TaskId);
637 if( os_sys.int_nest_cnt != 0 ) {
644 rv = ActivateTask(TaskId);
\r
645 /* TODO: more more here..*/
\r
647 Irq_Restore(flags);
\r
649 if (rv != E_OK) goto err;
\r
651 OS_STD_END_1(OSServiceId_ChainTask,TaskId);
\r
655 * If a higher-priority task is ready, the internal resource of the task
\r
656 * is released, the current task is put into the ready state, its
\r
657 * context is saved and the higher-priority task is executed.
\r
658 * Otherwise the calling task is continued.
\r
660 * TODO: The OSEK spec says a lot of strange things under "particulareties"
\r
661 * that I don't understand
663 * See OSEK/VDX 13.2.3.4
\r
666 StatusType Schedule( void ) {
\r
668 // OsPcbType *curr_pcb = get_curr_pcb();
\r
669 StatusType rv = E_OK;
672 /* We need to figure out if we have an internal resource,
673 * otherwise no re-scheduling.
674 * NON - Have internal resource prio OS_RES_SCHEDULER_PRIO (32+)
675 * FULL - Assigned internal resource OR
676 * No assigned internal resource.
678 if( Os_TaskGetCurrent()->scheduling != NON ) {
683 if( os_get_resource_int_p() == NULL ) {
689 /* Check that we are not calling from interrupt context */
690 if( os_sys.int_nest_cnt != 0 ) {
697 Irq_Restore(flags);
\r
699 // Prevent label warning. Remove this when proper error handling is implemented.
\r
702 OS_STD_END(OSServiceId_Schedule);
\r