ISIX-RTOS - small operating system for ARM microcontrollers 1.2

task.c

Go to the documentation of this file.
00001 #include <isix/config.h>
00002 #include <isix/types.h>
00003 #include <prv/scheduler.h>
00004 #include <isix/task.h>
00005 #include <isix/memory.h>
00006 #include <prv/semaphore.h>
00007 #include <prv/multiple_objects.h>
00008 #include <string.h>
00009 
00010 #ifndef ISIX_DEBUG_TASK
00011 #define ISIX_DEBUG_TASK ISIX_DBG_OFF
00012 #endif
00013 
00014 
00015 #if ISIX_DEBUG_TASK == ISIX_DBG_ON
00016 #include <isix/printk.h>
00017 #else
00018 #define isix_printk(...)
00019 #endif
00020 
00021 /*-----------------------------------------------------------------------*/
00022 //Align Mask
00023 #define ALIGN_MASK 0x03
00024 //Align Bytes
00025 #define ALIGN_BYTES 4
00026 //Magic value for stack checking
00027 #define MAGIC_FILL_VALUE 0x55
00028 /*-----------------------------------------------------------------------*/
00029 /* Create task function */
00030 task_t* isix_task_create(task_func_ptr_t task_func, void *func_param, unsigned long  stack_depth, prio_t priority)
00031 {
00032         isix_printk("TaskCreate: Create task with prio %d",priority);
00033     if(isix_get_min_priority()< priority )
00034     {
00035         return NULL;
00036     }
00037         //If stack length is small error
00038     if(stack_depth<ISIX_PORT_SCHED_MIN_STACK_DEPTH) return NULL;
00039     //Alignement
00040     if(stack_depth & ALIGN_MASK)
00041     {
00042         stack_depth += ALIGN_BYTES - (stack_depth & ALIGN_MASK);
00043     }
00044     //Allocate task_t structure
00045     task_t *task = (task_t*)isix_alloc(sizeof(task_t));
00046     isix_printk("Alloc task struct %08x",task);
00047     //No free memory
00048     if(task==NULL) return NULL;
00049     //Zero task structure
00050     memset(task,0,sizeof(task_t));
00051     //Try Allocate stack for task
00052     task->init_stack = isix_alloc(stack_depth);
00053     isix_printk("Alloc stack mem %08x",task->init_stack);
00054     if(task->init_stack==NULL)
00055     {
00056         //Free allocated stack memory
00057         isix_free(task);
00058         return NULL;
00059     }
00060 #ifdef ISIX_CONFIG_STACK_GROWTH
00061      task->top_stack = (unsigned long*)(((char*)task->init_stack) + stack_depth - sizeof(long));
00062 #else
00063      task->top_stack = task->init_stack;
00064 #endif
00065 #if ISIX_CONFIG_TASK_STACK_CHECK==ISIX_ON
00066     memset(task->init_stack,MAGIC_FILL_VALUE,stack_depth);
00067 #endif
00068     isix_printk("Top stack SP=%08x",task->top_stack);
00069     //Assign task priority
00070     task->prio = priority;
00071     //Task is ready
00072     task->state = TASK_READY;
00073     //Create initial task stack context
00074     task->top_stack = isixp_task_init_stack(task->top_stack,task_func,func_param);
00075     //Lock scheduler
00076     isixp_enter_critical();
00077     //Add task to ready list
00078     if(isixp_add_task_to_ready_list(task)<0)
00079     {
00080         //Free allocated innode
00081         isix_printk("Add task to ready list failed.");
00082         isix_free(task->top_stack);
00083         isix_free(task);
00084             isixp_exit_critical();
00085             return NULL;
00086     }
00087     if(isix_scheduler_running==false)
00088     {
00089         //Scheduler not running assign task
00090         if(isix_current_task==NULL) isix_current_task = task;
00091         else if(isix_current_task->prio>task->prio) isix_current_task = task;
00092     }
00093     isixp_exit_critical();
00094     if(isix_current_task->prio>task->prio && isix_scheduler_running==true)
00095     {
00096         //New task have higer priority then current task
00097             isix_printk("Call scheduler new prio %d > old prio %d",task->prio,isix_current_task->prio);
00098         isix_yield();
00099     }
00100     return task;
00101 }
00102 
00103 /*-----------------------------------------------------------------------*/
00104 /*Change task priority function
00105  * task - task pointer structure if NULL current prio change
00106  * new_prio - new priority                                  */
00107 int isixp_task_change_prio(task_t *task,prio_t new_prio,bool yield)
00108 {
00109         if(isix_get_min_priority()< new_prio )
00110         {
00111            return ISIX_ENOPRIO;
00112         }
00113         isixp_enter_critical();
00114     task_t *taskc = task?task:isix_current_task;
00115     //Save task prio
00116     prio_t prio = taskc->prio;
00117     if(prio==new_prio)
00118     {
00119         isixp_exit_critical();
00120         return ISIX_EOK;
00121     }
00122     bool yield_req = false;
00123     if(taskc->state & TASK_READY)
00124     {
00125         isix_printk("Change prio of ready task");
00126         isixp_delete_task_from_ready_list(taskc);
00127         //Assign new prio
00128         taskc->prio = new_prio;
00129         //Add task to ready list
00130         if(isixp_add_task_to_ready_list(taskc)<0)
00131         {
00132             isixp_exit_critical();
00133             return ISIX_ENOMEM;
00134         }
00135         if(new_prio<prio && !(isix_current_task->state&TASK_RUNNING) ) yield_req = true;
00136     }
00137     else if(taskc->state & TASK_WAITING)
00138     {
00139         isix_printk("Change prio of task waiting on sem");
00140         list_delete(&taskc->inode_sem);
00141         //Assign new prio
00142         taskc->prio = new_prio;
00143         isixp_add_task_to_sem_list(&taskc->sem->sem_task,taskc);
00144     }
00145     isixp_exit_critical();
00146     //Yield processor
00147     if(yield_req && yield)
00148     {
00149         isix_printk("CPUYield request");
00150         isix_yield();
00151     }
00152     isix_printk("New prio %d\n",new_prio);
00153     return ISIX_EOK;
00154 }
00155 
00156 /*-----------------------------------------------------------------------*/
00157 //Delete task pointed by struct task
00158 int isix_task_delete(task_t *task)
00159 {
00160     isixp_enter_critical();
00161     task_t *taskd = task?task:isix_current_task;
00162     isix_printk("Task: %08x(SP %08x) to delete",task,taskd->init_stack);
00163     if(taskd->state & TASK_READY)
00164     {
00165        //Task is ready remove from read
00166         isixp_delete_task_from_ready_list(taskd);
00167         isix_printk("Remove from ready list\n");
00168     }
00169     else if(taskd->state & TASK_SLEEPING)
00170     {
00171         //Task sleeping remove from sleeping
00172         list_delete(&taskd->inode);
00173         isix_printk("Remove from sleeping list");
00174     }
00175     //Task waiting for sem remove from waiting list
00176     if(taskd->state & TASK_WAITING)
00177     {
00178        list_delete(&taskd->inode_sem);
00179        taskd->sem = NULL;
00180        isix_printk("Remove from sem list");
00181     }
00182 #if ISIX_CONFIG_USE_MULTIOBJECTS
00183     if( taskd->state & TASK_WAITING_MULTIPLE )
00184     {
00185         isixp_delete_from_multiple_wait_list( taskd );
00186         isix_printk("Remove item from multiple list");
00187     }
00188 #endif
00189     //Add task to delete list
00190     taskd->state = TASK_DEAD;
00191     isixp_add_task_to_delete_list(taskd);
00192     if(task==NULL || task==isix_current_task)
00193     {
00194         isixp_exit_critical();
00195         isix_printk("Current task yield req");
00196         isix_yield();
00197         return ISIX_EOK;
00198     }
00199     else
00200     {
00201         isixp_exit_critical();
00202         return ISIX_EOK;
00203     }
00204 }
00205 
00206 /*-----------------------------------------------------------------------*/
00207 //Get current thread handler
00208 task_t * isix_task_self(void)
00209 {
00210     task_t *t = isix_current_task;
00211     return t;
00212 }
00213 
00214 /*-----------------------------------------------------------------------*/
00215 //Stack check for fill value
00216 #if ISIX_CONFIG_TASK_STACK_CHECK == ISIX_ON
00217 
00218 #ifndef ISIX_CONFIG_STACK_GROWTH
00219 #error isix_free_stack_space() for grown stack not implemented yet
00220 #endif
00221 
00222 size_t isix_free_stack_space(const task_t *task)
00223 {
00224         size_t usage=0;
00225         unsigned char *bStack = (unsigned char*)task->init_stack;
00226         while(*bStack==MAGIC_FILL_VALUE)
00227         {
00228                 bStack++;
00229                 usage++;
00230         }
00231         return usage;
00232 }
00233 #endif
00234 /*-----------------------------------------------------------------------*/
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines