ISIX-RTOS - small operating system for ARM microcontrollers 1.2
|
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 /*-----------------------------------------------------------------------*/