ISIX-RTOS - small operating system for ARM microcontrollers 1.2

port_scheduler.c

Go to the documentation of this file.
00001 #include <isix/config.h>
00002 #include <isix/printk.h>
00003 #include <isix/types.h>
00004 #include <prv/scheduler.h>
00005 /* Unix utilities */
00006 #include <ucontext.h>
00007 #include <sys/types.h>
00008 #include <sys/time.h>
00009 #include <signal.h>
00010 #include <unistd.h>
00011 #include <stdlib.h>
00012 #include <stdio.h>
00013 
00014 /*-----------------------------------------------------------------------*/
00015 //On the pc stack size is alwas assumed as 256k
00016 #define STACK_SIZE (256*1024)
00017 
00018 /*-----------------------------------------------------------------------*/
00019 static ucontext_t signal_context;  /* The interrupt context */
00020 static void *signal_stack;
00021 static sigset_t sigblock_mask;
00022 /*-----------------------------------------------------------------------*/
00023 //Create of stack context
00024 unsigned long* isixp_task_init_stack(unsigned long *sp, task_func_ptr_t pfun, void *param)
00025 {
00026     ucontext_t* uc = calloc(1,sizeof(ucontext_t));
00027     if( uc == NULL )
00028     {
00029         perror("malloc");
00030         exit(1);
00031     }
00032     void *stack = malloc(STACK_SIZE);
00033     if (stack == NULL)
00034     {
00035         perror("malloc");
00036         exit(1);
00037     }
00038     getcontext( uc );
00039     /*  and a sigmask */
00040     uc->uc_stack.ss_sp = stack;
00041     uc->uc_stack.ss_size = STACK_SIZE;
00042     uc->uc_stack.ss_flags = 0;
00043     sigemptyset(&uc->uc_sigmask);
00044     /* setup the function we're going to, and n-1 arguments. */
00045     makecontext(uc, (void (*)(void))pfun, 1, param );
00046     printf("Init stack %p\n",uc);
00047     return (unsigned long*)uc;
00048 }
00049 
00050 /* ----------------------------------------------------------------------*/
00051 static void unused_func(void ) {}
00052 void isix_systime_handler(void) __attribute__ ((weak, alias("unused_func")));
00053 
00054 /*-----------------------------------------------------------------------*/
00055 //Cyclic schedule time interrupt
00056 
00057 static void schedule_time(void)
00058 {
00059        //Increment system ticks
00060            isixp_enter_critical();
00061        //Call isix system time handler if used
00062        isix_systime_handler();
00063        isixp_schedule_time();
00064        //Clear interrupt mask
00065            isixp_exit_critical();
00066        //Yeld
00067        port_yield();
00068 }
00069 
00070 /*-----------------------------------------------------------------------*/
00071 //Set interrupt mask
00072 void port_set_interrupt_mask(void)
00073 {
00074     if(sigprocmask(SIG_BLOCK,&sigblock_mask, NULL)==-1)
00075     {
00076             perror("Sigblock"); exit(1);
00077     }
00078 }
00079 
00080 /*-----------------------------------------------------------------------*/
00081 //Clear interrupt mask
00082 void port_clear_interrupt_mask(void)
00083 {
00084     if(sigprocmask(SIG_UNBLOCK,&sigblock_mask, NULL)==-1)
00085     {
00086             perror("Sigblock"); exit(1);
00087     }
00088 }
00089 
00090 /*-----------------------------------------------------------------------*/
00091 //Yield to another task
00092 void port_yield( void )
00093 {
00094     isixp_schedule();
00095     setcontext( (ucontext_t*)isix_current_task->top_stack );
00096 }
00097 
00098 /*-----------------------------------------------------------------------*/
00099 
00100 /*
00101  *   Timer interrupt handler.
00102  *   Creates a new context to run the scheduler in, masks signals, then swaps
00103  *   contexts saving the previously executing thread and jumping to the
00104  *   scheduler.
00105  *         */
00106 static void timer_interrupt(int j, siginfo_t *si, void *old_context)
00107 {
00108         //printf("Context switch\n");
00109         /* Create new scheduler context */
00110         getcontext(&signal_context);
00111         signal_context.uc_stack.ss_sp = signal_stack;
00112         signal_context.uc_stack.ss_size = STACK_SIZE;
00113         signal_context.uc_stack.ss_flags = 0;
00114         sigemptyset(&signal_context.uc_sigmask);
00115         makecontext(&signal_context, schedule_time, 0);
00116 
00117 #ifdef ISIX_CONFIG_USE_PREEMPTION
00118     /* Set a PendSV to request a context switch. */
00119      if(isix_scheduler_running)
00120      {
00121         /* save running thread, jump to scheduler */
00122         swapcontext((ucontext_t*)isix_current_task->top_stack ,&signal_context);
00123      }
00124 #endif
00125 }
00126 /*-----------------------------------------------------------------------*/
00127 
00128 /* Set up SIGALRM signal handler */
00129 static void setup_signals(void)
00130 {
00131     struct sigaction act;
00132     act.sa_sigaction = timer_interrupt;
00133     sigemptyset(&act.sa_mask);
00134     act.sa_flags = SA_RESTART | SA_SIGINFO;
00135     if(sigaction(SIGALRM, &act, NULL) != 0) 
00136     {
00137         perror("Signal handler");
00138     }
00139 }
00140 
00141 /*-----------------------------------------------------------------------*/
00142 //Start first task by svc call
00143 void port_start_first_task( void )
00144 {
00145     //Setup sigblock_mask;
00146     if(sigemptyset(&sigblock_mask) == -1 || sigaddset(&sigblock_mask,SIGALRM) == -1 )
00147     {
00148         perror("Sigblock");
00149     }
00150     struct itimerval it;
00151     signal_stack = malloc(STACK_SIZE);
00152     if (signal_stack == NULL)
00153     {
00154       perror("malloc");
00155       exit(1);
00156     }
00157     //Setup signals
00158     setup_signals();
00159     it.it_interval.tv_sec = 0;
00160     it.it_interval.tv_usec = 1000;
00161     it.it_value = it.it_interval;
00162     if( setitimer(ITIMER_REAL, &it, NULL) )
00163     {
00164         perror("itimer");
00165     }
00166     isixp_schedule();
00167     printf("first task uccontext %p\n",isix_current_task->top_stack);
00168     setcontext( (ucontext_t*)isix_current_task->top_stack  );
00169 }
00170 
00171 /*-----------------------------------------------------------------------*/
00172 //Cleanup task dealocate the memory
00173 void port_cleanup_task( void *sp )
00174 {
00175     ucontext_t *uc = (ucontext_t*)(sp);
00176     free( signal_context.uc_stack.ss_sp );
00177     free(uc);
00178 }  
00179 /*-----------------------------------------------------------------------*/
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines