]> rtime.felk.cvut.cz Git - arc.git/blobdiff - system/kernel/task.c
merge with osek-ctest
[arc.git] / system / kernel / task.c
index c77d2a201546574ac278235d4960aed1b7f105d5..2c0c3faaca59454fe5c33b70690ebe9720660d3a 100644 (file)
-/* -------------------------------- Arctic Core ------------------------------
- * Arctic Core - the open source AUTOSAR platform http://arccore.com
- *
- * Copyright (C) 2009  ArcCore AB <contact@arccore.com>
- *
- * This source code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by the
- * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- * -------------------------------- Arctic Core ------------------------------*/
-
+/* -------------------------------- Arctic Core ------------------------------\r
+ * Arctic Core - the open source AUTOSAR platform http://arccore.com\r
+ *\r
+ * Copyright (C) 2009  ArcCore AB <contact@arccore.com>\r
+ *\r
+ * This source code is free software; you can redistribute it and/or modify it\r
+ * under the terms of the GNU General Public License version 2 as published by the\r
+ * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.\r
+ *\r
+ * This program is distributed in the hope that it will be useful, but\r
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
+ * for more details.\r
+ * -------------------------------- Arctic Core ------------------------------*/\r
+\r
 #include <stdlib.h>\r
-#include "Os.h"
-
-#include "internal.h"
-#include "arc.h"
-#include "arch.h"
-
-/** @req OS067 */
-
-_Bool os_pcb_pid_valid( OsPcbType *restrict pcb ) {
-       return ( pcb->pid > Os_CfgGetTaskCnt() ) ? 0 : 1;
-}
-/**
- * Start an extended task.
- * Tasks done:
- * - Grab the internal resource for the process
- * - Set it running state.
- * - Start to execute the process
- *
- */
-void Os_TaskStartExtended( void ) {
-       OsPcbType *pcb;
-
-       PRETASKHOOK();
-
-       pcb = Os_TaskGetCurrent();
-       Os_ResourceGetInternal();
-       Os_TaskMakeRunning(pcb);
-
-       Os_ArchFirstCall();
-
-       /** @req OS239 */
-       Irq_Disable();
-       if( Os_IrqAnyDisabled() ) {
-               Os_IrqClearAll();
-       }
-
-// TODO:Dont I have to check this at terminate task also?
-
-       /** @req OS069 */
-       ERRORHOOK(E_OS_MISSINGEND);
-
-       /** @req OS052 */
-       TerminateTask();
-}
-
-/**
- * Start an basic task.
- * See extended task.
- */
-
-void Os_TaskStartBasic( void ) {
-       OsPcbType *pcb;
-
-       PRETASKHOOK();
-
-       pcb = Os_TaskGetCurrent();
-       Os_ResourceGetInternal();
-       Os_TaskMakeRunning(pcb);
-       Os_ArchFirstCall();
-
-
-       /** @req OS239 */
-       Irq_Disable();
-       if( Os_IrqAnyDisabled() ) {
-               Os_IrqClearAll();
-       }
-
-       /** @req OS069 */
-       ERRORHOOK(E_OS_MISSINGEND);
-
-       /** @req OS052 */
-       TerminateTask();
-}
-
-
-static void Os_StackSetup( OsPcbType *pcbPtr ) {
-       uint8_t *bottom;
-
-       /* Find bottom of the stack so that we can place the
-        * context there.
-        *
-        * stack bottom = high address. stack top = low address
-        */
-       bottom = (uint8_t *)pcbPtr->stack.top + pcbPtr->stack.size;
-       pcbPtr->stack.curr = bottom;
-       // TODO: alignments here..
-       // TODO :use function os_arch_get_call_size() ??
-
-       // Make some space for back-chain.
-       bottom -= 16;
-       // Set the current stack so that it points to the context
-       pcbPtr->stack.curr = bottom - Os_ArchGetScSize();
-
-       Os_StackSetEndmark(pcbPtr);
-}
-
-/**
- * Fill the stack with a predefined pattern
- *
- * @param pcbPtr Pointer to the pcb to fill with pattern
- */
-static void Os_StackFill(OsPcbType *pcbPtr) {
-       uint8_t *p = pcbPtr->stack.curr;
-
-       assert(pcbPtr->stack.curr > pcbPtr->stack.top);
-
-       while (p > (uint8_t *) pcbPtr->stack.top) {
-               --p;
-               *p = STACK_PATTERN;
-       }
-}
-
-#if 0
-/**
- *
- * @param pcbPtr
- */
-static void Os_TaskSetEntry(OsPcbType *pcbPtr ) {
-
-}
-#endif
-
-
-/**
- * Setup the context for a pcb. The context differs for different arch's
- * so we call the arch dependent functions also.
- * The context at setup is always a small context.
- *
- * @param pcb Ptr to the pcb to setup context for.
- */
-void Os_ContextInit( OsPcbType *pcb ) {
-
-       if( pcb->autostart ) {
-               Os_TaskMakeReady(pcb);
-       } else {
-               pcb->state = ST_SUSPENDED;
-       }
-
-       Os_StackSetup(pcb);
-       Os_StackFill(pcb);
-       Os_ArchSetTaskEntry(pcb);
-
-       Os_ArchSetupContext(pcb);
-}
-
-/**
- *
- * @param pcb
- */
-void Os_ContextReInit( OsPcbType *pcbPtr ) {
-       Os_StackSetup(pcbPtr);
-}
-
-/**
- * Search for a specific task in the pcb list.
- *
- * @param tid The task id to search for
- * @return Ptr to the found pcb or NULL
- */
-OsPcbType *os_find_task( TaskType tid ) {
-       OsPcbType *i_pcb;
-
-       /* TODO: Implement this as an array */
-       TAILQ_FOREACH(i_pcb,& os_sys.pcb_head,pcb_list) {
-               if(i_pcb->pid == tid ) {
-                       return i_pcb;
-               }
-       }
-       assert(0);
-       return NULL;
-}
-
-/**
- * Adds a pcb to the list of pcb's
- * @param pcb
- */
-TaskType Os_AddTask( OsPcbType *pcb ) {
-       long msr;
-
-       Irq_Save(msr);  // Save irq status and disable interrupts
-
-       pcb->pid = os_sys.task_cnt;
-       // Add to list of PCB's
-       TAILQ_INSERT_TAIL(& os_sys.pcb_head,pcb,pcb_list);
-       os_sys.task_cnt++;
-
-       Irq_Restore(msr);  // Restore interrupts
-       return pcb->pid;
-}
-
-
-#define PRIO_ILLEGAL   -100
-
-/**
- * Find the top priority task. Even the running task is included.
- * TODO: There should be a priority queue (using a heap?) here instead.
- *        giving O(log n) for instertions and (1) for getting the top
- *        prio task. The curerent implementation is ehhhh bad.
- * @return
- */
-
-OsPcbType *Os_TaskGetTop( void ){
-       OsPcbType *i_pcb;
-       OsPcbType *top_prio_pcb = NULL;
-       OsPriorityType top_prio = PRIO_ILLEGAL;
-
-       OS_DEBUG(D_TASK,"os_find_top_prio_proc\n");
-
-       TAILQ_FOREACH(i_pcb,& os_sys.ready_head,ready_list) {
-               // all ready task are canidates
-               if( i_pcb->state & (ST_READY|ST_RUNNING)) {
-                       if( top_prio != PRIO_ILLEGAL ) {
-                               if( i_pcb->prio > top_prio ) {
-                                       top_prio = i_pcb->prio;
-                                       top_prio_pcb = i_pcb;
-                               }
-                       } else {
-                               top_prio = i_pcb->prio;
-                               top_prio_pcb = i_pcb;
-                       }
-               } else {
-                       assert(0);
-               }
-       }
-
-       assert(top_prio_pcb!=NULL);
-
-       OS_DEBUG(D_TASK,"Found %s\n",top_prio_pcb->name);
-
-       return top_prio_pcb;
-}
-
-
-#define USE_LDEBUG_PRINTF
-#include "debug.h"
-
-// we come here from
-// - WaitEvent()
-//   old_pcb -> WAITING
-//   new_pcb -> READY(RUNNING)
-// - Schedule(),
-//   old_pcb -> READY
-//   new_pcb -> READY/RUNNING
-
-/*
- * two strategies
- * 1. When running ->
- *    - remove from ready queue
- *    - set state == ST_RUNNING
- *
- * 2. When running ->
- *    * leave in ready queue
- *    * set state == ST_RUNNING
- *    - ready queue and ST_READY not the same
- *    + No need to remove the running process from ready queue
- */
-
-OsPcbType *Os_FindTopPrioTask( void ) {
-
-
-       return NULL;
-}
-
-/**
- * Tries to Dispatch.
- *
- * Used by:
- *   ActivateTask()
- *   WaitEvent()
- *   TerminateTask()
- *
- * @param force Force a re-scheduling
- *
- */
-void Os_Dispatch( _Bool force ) {
-       OsPcbType *pcbPtr;
-       OsPcbType *currPcbPtr;
-       (void)force;
-
-       assert(os_sys.int_nest_cnt == 0);
-       assert(os_sys.scheduler_lock == 0 );
-
-       pcbPtr = Os_TaskGetTop();
-       currPcbPtr = Os_TaskGetCurrent();
-       /* Swap if we found any process or are forced (multiple activations)*/
-       if( pcbPtr != currPcbPtr ) {
-               /* Add us to the ready list */
-               if( currPcbPtr->state & ST_RUNNING ) {
-                       Os_TaskRunningToReady(currPcbPtr);
-               }
-
-               /*
-                * Swap context
-                */
-               /** @req OS052 */
-               POSTTASKHOOK();
-               assert(pcbPtr!=NULL);
-
-               Os_ResourceReleaseInternal();
-
-#if (OS_STACK_MONITORING == 1)
-               if( !Os_StackIsEndmarkOk(currPcbPtr) ) {
-#if (  OS_SC1 == 1) || (  OS_SC2 == 1)
-                       /** @req OS068 */
-                       ShutdownOS(E_OS_STACKFAULT);
-#else
-#error SC3 or SC4 not supported. Protection hook should be called here
-#endif
-               }
-#endif
-
-               Os_ArchSwapContext(currPcbPtr,pcbPtr);
-
-               pcbPtr = Os_TaskGetCurrent();
-               Os_TaskMakeRunning(pcbPtr);
-
-               Os_ResourceGetInternal();
-
-               PRETASKHOOK();
-
-       } else {
-               if( Os_GetOp() != OP_SET_EVENT ) {
-
-                       /* We want to run the same task, again. This only happens
-                        * when we have multiple activation of a basic task (
-                        * extended tasks have an activation limit of 1)
-                        */
-
-                       /* Setup the stack again, and just call the basic task */
-                       Os_StackSetup(pcbPtr);
-                       Os_ArchSetSpAndCall(pcbPtr->stack.curr,Os_TaskStartBasic);
-               } else {
-                       /* Two cases:
-                        * 1. SetEvent() on itself
-                        * 2. SetEvent()
-                        *
-                        *
-                        * */
-
-               }
-       }
-}
-
-// We come here from
-// - os_init
-
-volatile static int a1, b1, c1;
-volatile static OsPcbType *o1;
-volatile static OsPcbType *n1;
-
-void hej(int a, int b, int c, OsPcbType *o, OsPcbType *n) {
-       a1 = a;
-       b1 = b;
-       c1 = c;
-       o1 = o;
-       n1 = n;
-}
-
-/**
- * Called when a task is to be run for the first time.
- */
-void Os_TaskSwapContextTo(OsPcbType *old_pcb, OsPcbType *new_pcb ) {
-
-       hej(1, 2, 3, old_pcb, new_pcb);
-
-       Os_ArchSwapContextTo(old_pcb,new_pcb);
-       /* TODO: When do we return here ?? */
-}
-
-
-void Os_Arc_GetStackInfo( TaskType task, StackInfoType *s) {
-       OsPcbType *pcb  = os_get_pcb(task);
-
-       s->curr         = Os_ArchGetStackPtr();
-       s->top          = pcb->stack.top;
-       s->at_swap      = pcb->stack.curr;
-       s->size         = pcb->stack.size;
-       s->usage        = (void *)Os_StackGetUsage(pcb);
-}
-
-
-/**
- * Returns the state of a task (running, ready, waiting, suspended)
- * at the time of calling GetTaskState.
- *
- * @param TaskId  Task reference
- * @param State   Reference to the state of the task
- */
-
+#include "Os.h"\r
+\r
+#include "internal.h"\r
+#include "arc.h"\r
+#include "arch.h"\r
+\r
+/** @req OS067 */\r
+\r
+_Bool os_pcb_pid_valid( OsPcbType *restrict pcb ) {\r
+       return ( pcb->pid > Os_CfgGetTaskCnt() ) ? 0 : 1;\r
+}\r
+/**\r
+ * Start an extended task.\r
+ * Tasks done:\r
+ * - Grab the internal resource for the process\r
+ * - Set it running state.\r
+ * - Start to execute the process\r
+ *\r
+ */\r
+void Os_TaskStartExtended( void ) {\r
+       OsPcbType *pcb;\r
+\r
+       pcb = Os_TaskGetCurrent();\r
+       Os_ResourceGetInternal();\r
+       Os_TaskMakeRunning(pcb);\r
+\r
+       PRETASKHOOK();\r
+\r
+       Os_ArchFirstCall();\r
+\r
+       /** @req OS239 */\r
+       Irq_Disable();\r
+       if( Os_IrqAnyDisabled() ) {\r
+               Os_IrqClearAll();\r
+       }\r
+\r
+// TODO:Dont I have to check this at terminate task also?\r
+\r
+       /** @req OS069 */\r
+       ERRORHOOK(E_OS_MISSINGEND);\r
+\r
+       /** @req OS052 */\r
+       TerminateTask();\r
+}\r
+\r
+/**\r
+ * Start an basic task.\r
+ * See extended task.\r
+ */\r
+\r
+void Os_TaskStartBasic( void ) {\r
+       OsPcbType *pcb;\r
+\r
+       pcb = Os_TaskGetCurrent();\r
+       Os_ResourceGetInternal();\r
+       Os_TaskMakeRunning(pcb);\r
+\r
+       PRETASKHOOK();\r
+\r
+       Os_ArchFirstCall();\r
+\r
+\r
+       /** @req OS239 */\r
+       Irq_Disable();\r
+       if( Os_IrqAnyDisabled() ) {\r
+               Os_IrqClearAll();\r
+       }\r
+\r
+       /** @req OS069 */\r
+       ERRORHOOK(E_OS_MISSINGEND);\r
+\r
+       /** @req OS052 */\r
+       TerminateTask();\r
+}\r
+\r
+\r
+static void Os_StackSetup( OsPcbType *pcbPtr ) {\r
+       uint8_t *bottom;\r
+\r
+       /* Find bottom of the stack so that we can place the\r
+        * context there.\r
+        *\r
+        * stack bottom = high address. stack top = low address\r
+        */\r
+       bottom = (uint8_t *)pcbPtr->stack.top + pcbPtr->stack.size;\r
+       pcbPtr->stack.curr = bottom;\r
+       // TODO: alignments here..\r
+       // TODO :use function os_arch_get_call_size() ??\r
+\r
+       // Make some space for back-chain.\r
+       bottom -= 16;\r
+       // Set the current stack so that it points to the context\r
+       pcbPtr->stack.curr = bottom - Os_ArchGetScSize();\r
+\r
+       Os_StackSetEndmark(pcbPtr);\r
+}\r
+\r
+/**\r
+ * Fill the stack with a predefined pattern\r
+ *\r
+ * @param pcbPtr Pointer to the pcb to fill with pattern\r
+ */\r
+static void Os_StackFill(OsPcbType *pcbPtr) {\r
+       uint8_t *p = pcbPtr->stack.curr;\r
+\r
+       assert(pcbPtr->stack.curr > pcbPtr->stack.top);\r
+\r
+       while (p > (uint8_t *) pcbPtr->stack.top) {\r
+               --p;\r
+               *p = STACK_PATTERN;\r
+       }\r
+}\r
+\r
+#if 0\r
+/**\r
+ *\r
+ * @param pcbPtr\r
+ */\r
+static void Os_TaskSetEntry(OsPcbType *pcbPtr ) {\r
+\r
+}\r
+#endif\r
+\r
+\r
+/**\r
+ * Setup the context for a pcb. The context differs for different arch's\r
+ * so we call the arch dependent functions also.\r
+ * The context at setup is always a small context.\r
+ *\r
+ * @param pcb Ptr to the pcb to setup context for.\r
+ */\r
+void Os_ContextInit( OsPcbType *pcb ) {\r
+\r
+       if( pcb->autostart ) {\r
+               Os_TaskMakeReady(pcb);\r
+       } else {\r
+               pcb->state = ST_SUSPENDED;\r
+       }\r
+\r
+       Os_StackSetup(pcb);\r
+       Os_StackFill(pcb);\r
+       Os_ArchSetTaskEntry(pcb);\r
+\r
+       Os_ArchSetupContext(pcb);\r
+}\r
+\r
+/**\r
+ *\r
+ * @param pcb\r
+ */\r
+void Os_ContextReInit( OsPcbType *pcbPtr ) {\r
+       Os_StackSetup(pcbPtr);\r
+}\r
+\r
+/**\r
+ * Search for a specific task in the pcb list.\r
+ *\r
+ * @param tid The task id to search for\r
+ * @return Ptr to the found pcb or NULL\r
+ */\r
+OsPcbType *os_find_task( TaskType tid ) {\r
+       OsPcbType *i_pcb;\r
+\r
+       /* TODO: Implement this as an array */\r
+       TAILQ_FOREACH(i_pcb,& os_sys.pcb_head,pcb_list) {\r
+               if(i_pcb->pid == tid ) {\r
+                       return i_pcb;\r
+               }\r
+       }\r
+       assert(0);\r
+       return NULL;\r
+}\r
+\r
+/**\r
+ * Adds a pcb to the list of pcb's\r
+ * @param pcb\r
+ */\r
+TaskType Os_AddTask( OsPcbType *pcb ) {\r
+       long msr;\r
+\r
+       Irq_Save(msr);  // Save irq status and disable interrupts\r
+\r
+       pcb->pid = os_sys.task_cnt;\r
+       // Add to list of PCB's\r
+       TAILQ_INSERT_TAIL(& os_sys.pcb_head,pcb,pcb_list);\r
+       os_sys.task_cnt++;\r
+\r
+       Irq_Restore(msr);  // Restore interrupts\r
+       return pcb->pid;\r
+}\r
+\r
+\r
+#define PRIO_ILLEGAL   -100\r
+\r
+/**\r
+ * Find the top priority task. Even the running task is included.\r
+ * TODO: There should be a priority queue (using a heap?) here instead.\r
+ *        giving O(log n) for instertions and (1) for getting the top\r
+ *        prio task. The curerent implementation is ehhhh bad.\r
+ * @return\r
+ */\r
+\r
+OsPcbType *Os_TaskGetTop( void ){\r
+       OsPcbType *i_pcb;\r
+       OsPcbType *top_prio_pcb = NULL;\r
+       OsPriorityType top_prio = PRIO_ILLEGAL;\r
+\r
+       OS_DEBUG(D_TASK,"os_find_top_prio_proc\n");\r
+\r
+       TAILQ_FOREACH(i_pcb,& os_sys.ready_head,ready_list) {\r
+               // all ready task are canidates\r
+               if( i_pcb->state & (ST_READY|ST_RUNNING)) {\r
+                       if( top_prio != PRIO_ILLEGAL ) {\r
+                               if( i_pcb->prio > top_prio ) {\r
+                                       top_prio = i_pcb->prio;\r
+                                       top_prio_pcb = i_pcb;\r
+                               }\r
+                       } else {\r
+                               top_prio = i_pcb->prio;\r
+                               top_prio_pcb = i_pcb;\r
+                       }\r
+               } else {\r
+                       assert(0);\r
+               }\r
+       }\r
+\r
+       assert(top_prio_pcb!=NULL);\r
+\r
+       OS_DEBUG(D_TASK,"Found %s\n",top_prio_pcb->name);\r
+\r
+       return top_prio_pcb;\r
+}\r
+\r
+\r
+#define USE_LDEBUG_PRINTF\r
+#include "debug.h"\r
+\r
+// we come here from\r
+// - WaitEvent()\r
+//   old_pcb -> WAITING\r
+//   new_pcb -> READY(RUNNING)\r
+// - Schedule(),\r
+//   old_pcb -> READY\r
+//   new_pcb -> READY/RUNNING\r
+\r
+/*\r
+ * two strategies\r
+ * 1. When running ->\r
+ *    - remove from ready queue\r
+ *    - set state == ST_RUNNING\r
+ *\r
+ * 2. When running ->\r
+ *    * leave in ready queue\r
+ *    * set state == ST_RUNNING\r
+ *    - ready queue and ST_READY not the same\r
+ *    + No need to remove the running process from ready queue\r
+ */\r
+\r
+OsPcbType *Os_FindTopPrioTask( void ) {\r
+\r
+\r
+       return NULL;\r
+}\r
+\r
+/**\r
+ * Tries to Dispatch.\r
+ *\r
+ * Used by:\r
+ *   ActivateTask()\r
+ *   WaitEvent()\r
+ *   TerminateTask()\r
+ *   ChainTask()\r
+ *\r
+ * @param force Force a re-scheduling\r
+ *\r
+ */\r
+void Os_Dispatch( _Bool force ) {\r
+       OsPcbType *pcbPtr;\r
+       OsPcbType *currPcbPtr;\r
+       (void)force;\r
+\r
+       assert(os_sys.int_nest_cnt == 0);\r
+       assert(os_sys.scheduler_lock == 0 );\r
+\r
+       pcbPtr = Os_TaskGetTop();\r
+       currPcbPtr = Os_TaskGetCurrent();\r
+       /* Swap if we found any process or are forced (multiple activations)*/\r
+       if( pcbPtr != currPcbPtr ) {\r
+\r
+               /* Add us to the ready list */\r
+               if( currPcbPtr->state & ST_RUNNING ) {\r
+                       /** @req OS052 */\r
+                       POSTTASKHOOK();\r
+                       Os_TaskRunningToReady(currPcbPtr);\r
+               }\r
+\r
+               /*\r
+                * Swap context\r
+                */\r
+               assert(pcbPtr!=NULL);\r
+\r
+               Os_ResourceReleaseInternal();\r
+\r
+#if (OS_STACK_MONITORING == 1)\r
+               if( !Os_StackIsEndmarkOk(currPcbPtr) ) {\r
+#if (  OS_SC1 == 1) || (  OS_SC2 == 1)\r
+                       /** @req OS068 */\r
+                       ShutdownOS(E_OS_STACKFAULT);\r
+#else\r
+#error SC3 or SC4 not supported. Protection hook should be called here\r
+#endif\r
+               }\r
+#endif\r
+\r
+               Os_ArchSwapContext(currPcbPtr,pcbPtr);\r
+\r
+               pcbPtr = Os_TaskGetCurrent();\r
+               Os_TaskMakeRunning(pcbPtr);\r
+\r
+               Os_ResourceGetInternal();\r
+\r
+               PRETASKHOOK();\r
+\r
+       } else {\r
+               if( Os_GetOp() != OP_SET_EVENT ) {\r
+\r
+                       /* We want to run the same task, again. This only happens\r
+                        * when we have multiple activation of a basic task (\r
+                        * extended tasks have an activation limit of 1)\r
+                        */\r
+\r
+                       /* Setup the stack again, and just call the basic task */\r
+                       Os_StackSetup(pcbPtr);\r
+                       Os_ArchSetSpAndCall(pcbPtr->stack.curr,Os_TaskStartBasic);\r
+               } else {\r
+                       /* Two cases:\r
+                        * 1. SetEvent() on itself\r
+                        * 2. SetEvent()\r
+                        *\r
+                        *\r
+                        * */\r
+\r
+               }\r
+       }\r
+}\r
+\r
+// We come here from\r
+// - os_init\r
+\r
+/**\r
+ * Called when a task is to be run for the first time.\r
+ */\r
+void Os_TaskSwapContextTo(OsPcbType *old_pcb, OsPcbType *new_pcb ) {\r
+\r
+       Os_ArchSwapContextTo(old_pcb,new_pcb);\r
+       /* TODO: When do we return here ?? */\r
+}\r
+\r
+\r
+void Os_Arc_GetStackInfo( TaskType task, StackInfoType *s) {\r
+       OsPcbType *pcb  = os_get_pcb(task);\r
+\r
+       s->curr         = Os_ArchGetStackPtr();\r
+       s->top          = pcb->stack.top;\r
+       s->at_swap      = pcb->stack.curr;\r
+       s->size         = pcb->stack.size;\r
+       s->usage        = (void *)Os_StackGetUsage(pcb);\r
+}\r
+\r
+\r
+/**\r
+ * Returns the state of a task (running, ready, waiting, suspended)\r
+ * at the time of calling GetTaskState.\r
+ *\r
+ * @param TaskId  Task reference\r
+ * @param State   Reference to the state of the task\r
+ */\r
+\r
 StatusType GetTaskState(TaskType TaskId, TaskStateRefType State) {\r
        state_t curr_state = os_pcb_get_state(os_get_pcb(TaskId));\r
        StatusType rv = E_OK;\r
@@ -420,38 +409,50 @@ StatusType GetTaskState(TaskType TaskId, TaskStateRefType State) {
 \r
        OS_STD_END_2(OSServiceId_GetTaskState,TaskId, State);\r
 }\r
-
-
-/**
- * GetTaskID returns the information about the TaskID of the task
- * which is currently running.
- *
- * @param task_id Reference to the task which is currently running
- * @return
+\r
+\r
+/**\r
+ * GetTaskID returns the information about the TaskID of the task\r
+ * which is currently running.\r
+ *\r
+ * @param task_id Reference to the task which is currently running\r
+ * @return\r
  */\r
 StatusType GetTaskID( TaskRefType task_id ) {\r
        *task_id = os_sys.curr_pcb->pid;\r
        return E_OK;\r
 }\r
-
-
-ISRType GetISRID( void ) {
-
-       /** @req OS264 */
-       if(os_sys.int_nest_cnt == 0 ) {
-               return INVALID_ISR;
-       }
-
-       /** @req OS263 */
-       return (ISRType)Os_TaskGetCurrent()->pid;
-}
-
-#define TASK_CHECK_ID(x)                               \
-       if( (x) > Os_CfgGetTaskCnt()) { \
-               rv = E_OS_ID;                                   \
-               goto err;                                               \
-       }
-
+\r
+\r
+ISRType GetISRID( void ) {\r
+\r
+       /** @req OS264 */\r
+       if(os_sys.int_nest_cnt == 0 ) {\r
+               return INVALID_ISR;\r
+       }\r
+\r
+       /** @req OS263 */\r
+       return (ISRType)Os_TaskGetCurrent()->pid;\r
+}\r
+\r
+#define TASK_CHECK_ID(x)                               \\r
+       if( (x) > Os_CfgGetTaskCnt()) { \\r
+               rv = E_OS_ID;                                   \\r
+               goto err;                                               \\r
+       }\r
+\r
+static inline void Os_Arc_SetCleanContext( OsPcbType *pcb ) {\r
+       if (pcb->proc_type == PROC_EXTENDED) {\r
+               /** @req OSEK ActivateTask Cleanup events\r
+                * OSEK,ActivateTask, When an extended task is transferred from suspended\r
+                * state into ready state all its events are cleared.*/\r
+               pcb->ev_set = 0;\r
+               pcb->ev_wait = 0;\r
+       }\r
+       Os_StackSetup(pcb);\r
+       Os_ArchSetTaskEntry(pcb);\r
+       Os_ArchSetupContext(pcb);\r
+}\r
 \r
 /**\r
  * The task <TaskID> is transferred from the suspended state into\r
@@ -467,14 +468,14 @@ ISRType GetISRID( void ) {
  * If E_OS_LIMIT is returned the activation is ignored.\r
  * When an extended task is transferred from suspended state\r
  * into ready state all its events are cleared.\r
- *
- * Note!
- * ActivateTask will not immediately change the state of the task
- * in case of multiple activation requests. If the task is not
- * suspended, the activation will only be recorded and performed later.
- *
- * @param pid
- * @return
+ *\r
+ * Note!\r
+ * ActivateTask will not immediately change the state of the task\r
+ * in case of multiple activation requests. If the task is not\r
+ * suspended, the activation will only be recorded and performed later.\r
+ *\r
+ * @param pid\r
+ * @return\r
  */\r
 \r
 StatusType ActivateTask( TaskType TaskID ) {\r
@@ -483,143 +484,146 @@ StatusType ActivateTask( TaskType TaskID ) {
        StatusType rv = E_OK;\r
 \r
        OS_DEBUG(D_TASK,"ActivateTask %s\n",pcb->name);\r
-
-#if (OS_STATUS_EXTENDED == STD_ON )
-       TASK_CHECK_ID(TaskID);
-
-       /* @req OS093 ActivateTask */
-       if( Os_IrqAnyDisabled() ) {
-               rv = E_OS_DISABLEDINT;
-               goto err;
-       }
-#endif
-
-       Irq_Save(msr);
-
-       if( os_pcb_get_state(pcb) == ST_SUSPENDED ) {
-               pcb->activations++;
-               if (pcb->proc_type == PROC_EXTENDED) {
-                       /** @req OSEK ActivateTask Cleanup events
-                        * OSEK,ActivateTask, When an extended task is transferred from suspended
-                        * state into ready state all its events are cleared.*/
-                       pcb->ev_set = 0;
-                       pcb->ev_wait = 0;
-               }
-               Os_StackSetup(pcb);
-               Os_ArchSetTaskEntry(pcb);
-               Os_ArchSetupContext(pcb);
-               Os_TaskMakeReady(pcb);
-       } else {
-
-               if( pcb->proc_type == PROC_EXTENDED ) {
-                       /** @req OSEK Activate task.
-                        * An extended task be activated once. See Chapter 4.3 in OSEK
-                        */
-                       rv = E_OS_LIMIT;
-                       goto err;
-               }
-
-               /** @req OSEK_? Too many task activations */
-               if( pcb->activations == pcb->activationLimit ) {
-                       rv=E_OS_LIMIT;
-                       goto err;
-               } else {
-                       pcb->activations++;
-               }
-       }
-
-
-       /* Preempt only if higher prio than us */\r
-       if(     (pcb->scheduling == FULL) &&
-               (os_sys.int_nest_cnt == 0) && (pcb->prio > Os_TaskGetCurrent()->prio) )
+\r
+#if (OS_STATUS_EXTENDED == STD_ON )\r
+       TASK_CHECK_ID(TaskID);\r
+\r
+       /* @req OS093 ActivateTask */\r
+       if( Os_IrqAnyDisabled() ) {\r
+               rv = E_OS_DISABLEDINT;\r
+               goto err;\r
+       }\r
+#endif\r
+\r
+       Irq_Save(msr);\r
+\r
+       if( os_pcb_get_state(pcb) == ST_SUSPENDED ) {\r
+               pcb->activations++;\r
+               Os_Arc_SetCleanContext(pcb);\r
+               Os_TaskMakeReady(pcb);\r
+       } else {\r
+\r
+               if( pcb->proc_type == PROC_EXTENDED ) {\r
+                       /** @req OSEK Activate task.\r
+                        * An extended task be activated once. See Chapter 4.3 in OSEK\r
+                        */\r
+                       rv = E_OS_LIMIT;\r
+                       goto err;\r
+               }\r
+\r
+               /** @req OSEK_? Too many task activations */\r
+               if( pcb->activations == pcb->activationLimit ) {\r
+                       rv=E_OS_LIMIT;\r
+                       goto err;\r
+               } else {\r
+                       pcb->activations++;\r
+               }\r
+       }\r
+\r
+\r
+       /* Preempt only if we are preemptable and target has higher prio than us */\r
+       if(     (Os_TaskGetCurrent()->scheduling == FULL) &&\r
+               (os_sys.int_nest_cnt == 0) &&\r
+               (pcb->prio > Os_TaskGetCurrent()->prio) &&\r
+               (Os_SchedulerResourceIsFree()))\r
        {\r
                Os_Dispatch(0);\r
-       }
-
+       }\r
+\r
        Irq_Restore(msr);\r
 \r
        OS_STD_END_1(OSServiceId_ActivateTask,TaskID);\r
 }\r
-
-/**
- * This  service  causes  the  termination  of  the  calling  task.  The
- * calling  task  is  transferred  from  the  running  state  into  the
- * suspended state.
- *
- * An internal resource assigned to the calling task is automatically
- * released. Other resources occupied by the task shall have been
- * released before the call to TerminateTask. If a resource is still
- * occupied in standard status the behaviour is undefined.
- *
- *   If the call was successful, TerminateTask does not return to the
- * call level and the status can not be evaluated.
- *
- *   If the version with extended status is used, the service returns
- * in case of error, and provides a status which can be evaluated
- * in the application.
- *
- *   If the service TerminateTask is called successfully, it enforces a
- * rescheduling.
- *
- *  [ Ending   a   task   function   without   call   to   TerminateTask
- *    or ChainTask is strictly forbidden and may leave the system in an
- *    undefined state. ]
- *
- * [] is an OSEK requirement and is overridden by OS052
- *
- * @return
- */
+\r
+/**\r
+ * This  service  causes  the  termination  of  the  calling  task.  The\r
+ * calling  task  is  transferred  from  the  running  state  into  the\r
+ * suspended state.\r
+ *\r
+ * An internal resource assigned to the calling task is automatically\r
+ * released. Other resources occupied by the task shall have been\r
+ * released before the call to TerminateTask. If a resource is still\r
+ * occupied in standard status the behaviour is undefined.\r
+ *\r
+ *   If the call was successful, TerminateTask does not return to the\r
+ * call level and the status can not be evaluated.\r
+ *\r
+ *   If the version with extended status is used, the service returns\r
+ * in case of error, and provides a status which can be evaluated\r
+ * in the application.\r
+ *\r
+ *   If the service TerminateTask is called successfully, it enforces a\r
+ * rescheduling.\r
+ *\r
+ *  [ Ending   a   task   function   without   call   to   TerminateTask\r
+ *    or ChainTask is strictly forbidden and may leave the system in an\r
+ *    undefined state. ]\r
+ *\r
+ * [] is an OSEK requirement and is overridden by OS052\r
+ *\r
+ * @return\r
+ */\r
 \r
 StatusType TerminateTask( void ) {\r
        OsPcbType *curr_pcb = Os_TaskGetCurrent();\r
-       StatusType rv = E_OK;
+       StatusType rv = E_OK;\r
        uint32_t flags;\r
 \r
        OS_DEBUG(D_TASK,"TerminateTask %s\n",curr_pcb->name);\r
-
-#if (OS_STATUS_EXTENDED == STD_ON )
-
-
-       if( os_sys.int_nest_cnt != 0 ) {
-               rv =  E_OS_CALLEVEL;
-               goto err;
-       }
-
-       /** @req OS070 */
-       if( Os_ResourceCheckAndRelease(curr_pcb) == 1 ) {
-               rv =  E_OS_RESOURCE;
-               goto err;
-
-       }
-
-
-#endif
-
-
-       Irq_Save(flags);
-
-       --curr_pcb->activations;
-
-
-//     assert(curr_pcb->activations>=0);
-
-       /*@req OSEK TerminateTask
-        * In case of tasks with multiple activation requests,
-        * terminating the current instance of the task automatically puts the next
-        * instance of the same task into the ready state
-        */
-       if( curr_pcb->activations <= 0 ) {
-               curr_pcb->activations = 0;
-               Os_TaskMakeSuspended(curr_pcb);
-       } else {
-               /* We need to add ourselves to the ready list again,
-                * with a startup context. */
-       }
-
-//     Os_ContextReInit(curr_pcb);
-
-       /* Force the dispatcher to find something, even if its us */
-       Os_Dispatch(1);
+\r
+#if (OS_STATUS_EXTENDED == STD_ON )\r
+\r
+\r
+       if( os_sys.int_nest_cnt != 0 ) {\r
+               rv =  E_OS_CALLEVEL;\r
+               goto err;\r
+       }\r
+\r
+       if ( Os_SchedulerResourceIsOccupied() ) {\r
+               rv =  E_OS_RESOURCE;\r
+               goto err;\r
+       }\r
+\r
+       /** @req OS070 */\r
+       if( Os_ResourceCheckAndRelease(curr_pcb) == 1 ) {\r
+               rv =  E_OS_RESOURCE;\r
+               goto err;\r
+\r
+       }\r
+\r
+\r
+#endif\r
+\r
+\r
+       Irq_Save(flags);\r
+\r
+       --curr_pcb->activations;\r
+\r
+\r
+//     assert(curr_pcb->activations>=0);\r
+\r
+       /*@req OSEK TerminateTask\r
+        * In case of tasks with multiple activation requests,\r
+        * terminating the current instance of the task automatically puts the next\r
+        * instance of the same task into the ready state\r
+        */\r
+       if( curr_pcb->activations <= 0 ) {\r
+               curr_pcb->activations = 0;\r
+               POSTTASKHOOK();\r
+               Os_TaskMakeSuspended(curr_pcb);\r
+       } else {\r
+               /* We need to add ourselves to the ready list again,\r
+                * with a startup context. */\r
+\r
+               /* We are already in ready list..\r
+                * This should give us a clean start /tojo */\r
+               Os_Arc_SetCleanContext(curr_pcb);\r
+       }\r
+\r
+//     Os_ContextReInit(curr_pcb);\r
+\r
+       /* Force the dispatcher to find something, even if its us */\r
+       Os_Dispatch(1);\r
 \r
        Irq_Restore(flags);\r
        // It must find something here...otherwise something is very wrong..\r
@@ -633,22 +637,74 @@ StatusType TerminateTask( void ) {
 }\r
 \r
 StatusType ChainTask( TaskType TaskId ) {\r
-       StatusType rv;
-       uint32_t flags;
-
-#if (OS_STATUS_EXTENDED == STD_ON )
-       TASK_CHECK_ID(TaskId);
-
-       if( os_sys.int_nest_cnt != 0 ) {
-               rv =  E_OS_CALLEVEL;
-               goto err;
-       }
-#endif
+       OsPcbType *curr_pcb = Os_TaskGetCurrent();\r
+       StatusType rv = E_OK;\r
+       uint32_t flags;\r
+\r
+#if (OS_STATUS_EXTENDED == STD_ON )\r
+       TASK_CHECK_ID(TaskId);\r
+\r
+       if( os_sys.int_nest_cnt != 0 ) {\r
+               rv =  E_OS_CALLEVEL;\r
+               goto err;\r
+       }\r
+\r
+       if ( Os_SchedulerResourceIsOccupied() ) {\r
+               rv =  E_OS_RESOURCE;\r
+               goto err;\r
+       }\r
+\r
+       if( Os_ResourceCheckAndRelease(curr_pcb) == 1 ) {\r
+               rv =  E_OS_RESOURCE;\r
+               goto err;\r
+       }\r
+#endif\r
+       OsPcbType *pcb = os_get_pcb(TaskId);\r
 \r
        Irq_Save(flags);\r
-       rv = ActivateTask(TaskId);\r
-       /* TODO: more more here..*/\r
-       TerminateTask();\r
+\r
+       if (curr_pcb == pcb) {\r
+               /* If we are chaining same task just make a clean start */\r
+               /* TODO: Is it allowed to chain same task if extended? */\r
+               Os_Arc_SetCleanContext(curr_pcb);\r
+\r
+               /* Force the dispatcher to find something, even if its us */\r
+               Os_Dispatch(1);\r
+\r
+               Irq_Restore(flags);\r
+               /* It must find something here...otherwise something is very wrong.. */\r
+               assert(0);\r
+\r
+       } else {\r
+               /* We are chaining another task\r
+                * We need to make sure it is in valid state */\r
+               if( os_pcb_get_state(pcb) != ST_SUSPENDED ) {\r
+                       if( pcb->proc_type == PROC_EXTENDED ) {\r
+                               /** @req OSEK Activate task.\r
+                                * An extended task be activated once. See Chapter 4.3 in OSEK */\r
+                               rv = E_OS_LIMIT;\r
+                               goto err;\r
+                       }\r
+\r
+                       /** @req OSEK_? Too many task activations */\r
+                       if( pcb->activations == pcb->activationLimit ) {\r
+                               rv=E_OS_LIMIT;\r
+                               goto err;\r
+                       }\r
+               }\r
+\r
+               // Terminate current task\r
+               --curr_pcb->activations;\r
+               if( curr_pcb->activations <= 0 ) {\r
+                       curr_pcb->activations = 0;\r
+                       POSTTASKHOOK();\r
+                       Os_TaskMakeSuspended(curr_pcb);\r
+               }\r
+\r
+               rv = ActivateTask(TaskId);\r
+               // we return here only if something is wrong\r
+       }\r
+\r
        Irq_Restore(flags);\r
 \r
        if (rv != E_OK) goto err;\r
@@ -663,43 +719,47 @@ StatusType ChainTask( TaskType TaskId ) {
  * Otherwise the calling task is continued.\r
  *\r
  * TODO: The OSEK spec says a lot of strange things under "particulareties"\r
- * that I don't understand
- *
+ * that I don't understand\r
+ *\r
  * See OSEK/VDX 13.2.3.4\r
- *
+ *\r
  */\r
 StatusType Schedule( void ) {\r
 //     OsPcbType *pcb;\r
 //     OsPcbType *curr_pcb = get_curr_pcb();\r
-       StatusType rv = E_OK;
+       StatusType rv = E_OK;\r
        uint32_t flags;\r
-
-       /* We need to figure out if we have an internal resource,
-        * otherwise no re-scheduling.
-        * NON  - Have internal resource prio OS_RES_SCHEDULER_PRIO (32+)
-        * FULL - Assigned internal resource OR
-        *        No assigned internal resource.
-        * */
-       if( Os_TaskGetCurrent()->scheduling != NON ) {
-               return E_OK;
-       }
-
-#if 0
-       if( os_get_resource_int_p() == NULL ) {
-               /* We do nothing */
-               return E_OK;
-       }
-#endif
-
-       /* Check that we are not calling from interrupt context */
-       if( os_sys.int_nest_cnt != 0 ) {
-               rv =  E_OS_CALLEVEL;
-               goto err;
-       }
-\r
-       Irq_Save(flags);
-       Os_Dispatch(0);\r
-       Irq_Restore(flags);\r
+\r
+       /* Check that we are not calling from interrupt context */\r
+       if( os_sys.int_nest_cnt != 0 ) {\r
+               rv =  E_OS_CALLEVEL;\r
+               goto err;\r
+       }\r
+\r
+       /* We need to figure out if we have an internal resource,\r
+        * otherwise no re-scheduling.\r
+        * NON  - Have internal resource prio OS_RES_SCHEDULER_PRIO (32+)\r
+        * FULL - Assigned internal resource OR\r
+        *        No assigned internal resource.\r
+        * */\r
+       if( Os_TaskGetCurrent()->scheduling != NON ) {\r
+               return E_OK;\r
+       }\r
+\r
+#if 0\r
+       if( os_get_resource_int_p() == NULL ) {\r
+               /* We do nothing */\r
+               return E_OK;\r
+       }\r
+#endif\r
+\r
+       OsPcbType* top_pcb = Os_TaskGetTop();\r
+       /* only dispatch if some other ready task has higher prio */\r
+       if (top_pcb->prio > Os_TaskGetCurrent()->prio) {\r
+               Irq_Save(flags);\r
+               Os_Dispatch(0);\r
+               Irq_Restore(flags);\r
+       }\r
 \r
        // Prevent label warning. Remove this when proper error handling is implemented.\r
        if (0) goto err;\r