00001
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <sys/tm.h>
00032
00033 #ifdef CONF_TM
00034
00035 #include <sys/critsec.h>
00036 #include <sys/mm.h>
00037 #include <sys/time.h>
00038 #include <sys/irq.h>
00039 #include <sys/bitops.h>
00040 #include <stdlib.h>
00041 #include <unistd.h>
00042
00043 #ifdef CONF_VIS
00044 # include <sys/lcd.h>
00045 # include <conio.h>
00046 # include <sys/battery.h>
00047 #endif
00048
00049 #define fatal(a)
00050
00051
00053
00054
00055
00057
00058 pchain_t *priority_head;
00059
00060 tdata_t td_single;
00061 tdata_t *ctid;
00062
00063 volatile unsigned int nb_tasks;
00064 volatile unsigned int nb_system_tasks;
00065
00067
00068
00069
00071
00072 #if 0
00073 void integrity_check(void) {
00074 pchain_t *prio=priority_head;
00075 tdata_t *td;
00076
00077 if(prio->prev!=NULL) { fatal("ERR10"); }
00078
00079 do {
00080 if(prio->next) {
00081 if(prio->next->prev!=prio) { fatal("ERR11"); }
00082 if(prio->next->priority>prio->priority) { fatal("ERR12"); }
00083 }
00084 td=prio->ctid;
00085 do {
00086 if(td==NULL) { fatal("ERR13"); }
00087 if(td->priority!=prio) { fatal("ERR14"); }
00088 if(td->next->prev != td) { fatal("ERR15"); }
00089 if(td->prev->next != td) { fatal("ERR16"); }
00090
00091 td=td->next;
00092 } while(td!=prio->ctid);
00093
00094 prio=prio->next;
00095 } while(prio);
00096 }
00097 #endif
00098
00099
00101
00104 void tm_switcher(void);
00105 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00106 __asm__("\n\
00107 .text\n\
00108 .align 1\n\
00109 .globl _tm_switcher\n\
00110 _tm_switcher:\n\
00111 ; r6 saved by ROM\n\
00112 ; r0 saved by system timer handler\n\
00113 \n\
00114 mov.w r1,@-r7 ; save registers\n\
00115 mov.w r2,@-r7 \n\
00116 mov.w r3,@-r7 \n\
00117 mov.w r4,@-r7 \n\
00118 mov.w r5,@-r7 \n\
00119 \n\
00120 mov.w r7,r0 ; pass sp\n\
00121 \n\
00122 jsr _tm_scheduler ; call scheduler\n\
00123 \n\
00124 _tm_switcher_return: \n\
00125 mov.w r0,r7 ; set new sp\n\
00126 \n\
00127 mov.w @r7+,r5\n\
00128 mov.w @r7+,r4\n\
00129 mov.w @r7+,r3\n\
00130 mov.w @r7+,r2\n\
00131 mov.w @r7+,r1\n\
00132 \n\
00133 ; r0 will be restored by system timer handler\n\
00134 ; r6 will be restored by ROM\n\
00135 \n\
00136 rts ; return to new task\n\
00137 ");
00138 #endif // DOXYGEN_SHOULD_SKIP_THIS
00139
00140
00142
00147 size_t *tm_scheduler(size_t *old_sp) {
00148 tdata_t *next;
00149 pchain_t *priority;
00150 wakeup_t tmp;
00151
00152 priority=ctid->priority;
00153 switch(ctid->tstate) {
00154 case T_ZOMBIE:
00155 if(ctid->next!=ctid) {
00156
00157
00158
00159 priority->ctid =ctid->prev;
00160 ctid->next->prev=ctid->prev;
00161 ctid->prev->next=ctid->next;
00162 } else {
00163
00164
00165
00166 if(priority->next)
00167 priority->next->prev = priority->prev;
00168 if(priority->prev)
00169 priority->prev->next = priority->next;
00170 else
00171 priority_head = priority->next;
00172 free(priority);
00173 }
00174
00175
00176
00177
00178 free(ctid->stack_base);
00179 free(ctid);
00180
00181
00182
00183
00184
00185 if ((ctid->tflags & T_KERNEL)==T_KERNEL)
00186 --nb_system_tasks;
00187
00188 switch(--nb_tasks) {
00189 case 1:
00190 #ifdef CONF_TM_DEBUG
00191 if((priority_head->ctid->tflags & T_IDLE)==0) {
00192
00193 fatal("ERR00");
00194 }
00195 #endif // CONF_TM_DEBUG
00196
00197 *((priority_head->ctid->sp_save) + SP_RETURN_OFFSET ) = (size_t) &exit;
00198 priority_head->ctid->tstate=T_SLEEPING;
00199 break;
00200
00201 case 0:
00202
00203
00204
00205 systime_set_switcher(&rom_dummy_handler);
00206 ctid=&td_single;
00207
00208 return ctid->sp_save;
00209 }
00210 break;
00211
00212 case T_RUNNING:
00213 ctid->tstate=T_SLEEPING;
00214
00215
00216 case T_WAITING:
00217 ctid->sp_save=old_sp;
00218 }
00219
00220
00221
00222
00223 priority=priority_head;
00224 next=priority->ctid->next;
00225 while (1) {
00226 if (next->tstate==T_SLEEPING)
00227 break;
00228
00229 if (next->tstate==T_WAITING) {
00230 if ((next->tflags & T_SHUTDOWN) != 0) {
00231 next->wakeup_data = 0;
00232 break;
00233 }
00234 ctid = next;
00235 tmp = next->wakeup(next->wakeup_data);
00236 if (tmp != 0) {
00237 next->wakeup_data = tmp;
00238 break;
00239 }
00240 }
00241
00242 if(next == priority->ctid) {
00243
00244
00245
00246 if(priority->next != NULL)
00247 priority = priority->next;
00248 #ifdef CONF_TM_DEBUG
00249 else {
00250
00251
00252 fatal("ERR01");
00253 }
00254 #else
00255 else
00256 priority = priority_head;
00257 #endif
00258 next=priority->ctid->next;
00259 } else
00260 next=next->next;
00261 }
00262 ctid=next->priority->ctid=next;
00263 ctid->tstate=T_RUNNING;
00264
00265 return ctid->sp_save;
00266 }
00267
00269
00271 extern void yield(void);
00272 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00273 __asm__("\n\
00274 .text\n\
00275 .globl _yield\n\
00276 .align 1\n\
00277 _yield:\n\
00278 stc ccr,r0h ; to fake an IRQ, we have to\n\
00279 push r0 ; store the registers\n\
00280 orc #0x80,ccr ; disable interrupts\n\
00281 \n\
00282 push r6 ; store r6\n\
00283 \n\
00284 mov.w #0x04d4,r0 ; store rom return addr\n\
00285 push r0\n\
00286 \n\
00287 push r0 ; store r0 (destroyed by call.)\n\
00288 \n\
00289 mov.w #_systime_tm_return,r0 ; store systime return addr\n\
00290 push r0\n\
00291 \n\
00292 jmp @_tm_switcher ; call task switcher\n\
00293 ");
00294 #endif // DOXYGEN_SHOULD_SKIP_THIS
00295
00297
00299 extern int tm_idle_task(int argc,char **argv) __attribute__ ((noreturn));
00300 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00301 __asm__("\n\
00302 .text\n\
00303 .align 1\n\
00304 _tm_idle_task:\n\
00305 sleep\n\
00306 bra _tm_idle_task\n\
00307 ");
00308 #endif // DOXYGEN_SHOULD_SKIP_THIS
00309
00310 #ifdef CONF_VIS
00311
00312
00314 int tm_man_task(int argc, char **argv)
00315 {
00316 int state=0;
00317
00318 while (!shutdown_requested()) {
00319 if(nb_tasks > nb_system_tasks) state ^= 1; else state=0;
00320 lcd_show(state == 0 ? man_stand : man_run);
00321 #ifndef CONF_LCD_REFRESH
00322 lcd_refresh();
00323 #endif // CONF_LCD_REFRESH
00324 msleep(500);
00325 }
00326 return 0;
00327 }
00328
00329 #ifdef CONF_BATTERY_INDICATOR
00330
00331
00333 int tm_battery_task(int argc, char **argv) {
00334 int bmv;
00335
00336 while (!shutdown_requested()) {
00337 bmv=get_battery_mv();
00338
00339 if(bmv>BATTERY_NORMAL_THRESHOLD_MV)
00340 dlcd_hide(LCD_BATTERY_X);
00341 else if(bmv<BATTERY_LOW_THRESHOLD_MV)
00342 dlcd_show(LCD_BATTERY_X);
00343
00344 msleep(2000);
00345 }
00346 return 0;
00347 }
00348 #endif // CONF_BATTERY_INDICATOR
00349 #endif // CONF_VIS
00350
00352
00355 void tm_init(void) {
00356 tdata_t* td_idle;
00357
00358
00359
00360 nb_tasks=0;
00361 nb_system_tasks=0;
00362 priority_head=NULL;
00363 INITIALIZE_KERNEL_CRITICAL_SECTION();
00364
00365
00366
00367 td_single.tstate=T_RUNNING;
00368 ctid=&td_single;
00369
00370
00371
00372 td_idle=(tdata_t*)execi(&tm_idle_task,0,NULL,0,IDLE_STACK_SIZE);
00373 td_idle->tflags |= T_IDLE;
00374
00375 #ifdef CONF_VIS
00376 execi(&tm_man_task, 0, NULL, 1, IDLE_STACK_SIZE);
00377
00378 #ifdef CONF_BATTERY_INDICATOR
00379 execi(&tm_battery_task, 0, NULL, 1, IDLE_STACK_SIZE);
00380 #endif // CONF_BATTERY_INDICATOR
00381 #endif // CONF_VIS
00382
00383 systime_set_timeslice(TM_DEFAULT_SLICE);
00384 }
00385
00386
00388
00390 void tm_start(void) {
00391 disable_irqs();
00392
00393 systime_set_switcher(&tm_switcher);
00394 yield();
00395
00396 enable_irqs();
00397
00398 }
00399
00401
00410 tid_t execi(int (*code_start)(int,char**),int argc, char **argv,
00411 priority_t priority,size_t stack_size) {
00412 pchain_t *pchain, *ppchain;
00413 int freepchain=0;
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423 tdata_t *td=malloc(sizeof(tdata_t));
00424 size_t *sp=malloc(stack_size);
00425
00426
00427 pchain_t *newpchain=malloc(sizeof(pchain_t));
00428
00429 if (td == NULL || sp == NULL || newpchain == NULL)
00430 {
00431 free(td);
00432 free(sp);
00433 free(newpchain);
00434 return -1;
00435 }
00436
00437 td->tflags = 0;
00438 if ((size_t)code_start < (size_t)&mm_start)
00439 {
00440 td->tflags |= T_KERNEL;
00441 nb_system_tasks++;
00442 }
00443 else
00444 td->tflags |= T_USER;
00445
00446 td->stack_base=sp;
00447
00448 sp+=(stack_size>>1);
00449
00450
00451
00452
00453
00454 *(--sp)=(size_t) &exit;
00455
00456
00457
00458
00459
00460 *(--sp)=(size_t) code_start;
00461 *(--sp)=0;
00462 *(--sp)=0;
00463 *(--sp)=(size_t)
00464 &rom_ocia_return;
00465
00466 *(--sp)=(size_t) argc;
00467 *(--sp)=(size_t)
00468 &systime_tm_return;
00469
00470 *(--sp)=(size_t) argv;
00471 *(--sp)=0;
00472 *(--sp)=0;
00473 *(--sp)=0;
00474 *(--sp)=0;
00475
00476 td->sp_save=sp;
00477 td->tstate=T_SLEEPING;
00478 td->parent=ctid;
00479
00480 ENTER_KERNEL_CRITICAL_SECTION();
00481
00482 ppchain=NULL;
00483 for( pchain = priority_head;
00484 pchain != NULL && (pchain->priority) > priority;
00485 ppchain = pchain, pchain = pchain->next
00486 );
00487 if(pchain==NULL || pchain->priority!=priority) {
00488
00489
00490 newpchain->priority=priority;
00491 newpchain->ctid=td;
00492
00493 newpchain->next=pchain;
00494 if(pchain)
00495 pchain->prev =newpchain;
00496 newpchain->prev=ppchain;
00497 if(ppchain)
00498 ppchain->next=newpchain;
00499 else
00500 priority_head=newpchain;
00501
00502
00503
00504 td->prev=td->next=td;
00505 td->priority=newpchain;
00506 } else {
00507
00508
00509 td->priority=pchain;
00510 td->prev=pchain->ctid->prev;
00511 td->next=pchain->ctid;
00512 td->next->prev=td->prev->next=td;
00513 freepchain=1;
00514 }
00515 nb_tasks++;
00516
00517 LEAVE_KERNEL_CRITICAL_SECTION();
00518
00519 if(freepchain)
00520 free(newpchain);
00521
00522 return (tid_t) td;
00523 }
00524
00526
00531 void exit(int code) {
00532 enable_irqs();
00533 if (!(ctid->tflags & T_KERNEL))
00534 mm_reaper();
00535 ctid->tstate=T_ZOMBIE;
00536
00537 while(1)
00538 yield();
00539 }
00540
00542
00546 wakeup_t wait_event(wakeup_t (*wakeup)(wakeup_t),wakeup_t data) {
00547 ctid->wakeup =wakeup;
00548 ctid->wakeup_data=data;
00549 ctid->tstate =T_WAITING;
00550
00551 yield();
00552
00553 return ctid->wakeup_data;
00554 }
00555
00557
00559 static wakeup_t tm_sleep_wakeup(wakeup_t data) {
00560 time_t remaining = ((time_t)data) - get_system_up_time();
00561
00562 if (((time_t)data) <= get_system_up_time())
00563 {
00564 tm_timeslice = TM_DEFAULT_SLICE;
00565 return -1;
00566 }
00567
00568 if (remaining < tm_timeslice)
00569 tm_timeslice = remaining;
00570
00571 return 0;
00572 }
00573
00575
00578 unsigned int msleep(unsigned int msec)
00579 {
00580 #if defined(CONF_TIME) && defined(CONF_TM)
00581 if (wait_event(&tm_sleep_wakeup, get_system_up_time() + MSECS_TO_TICKS(msec)) == 0)
00582 return (MSECS_TO_TICKS(msec) - get_system_up_time());
00583 #else
00584 delay(msec);
00585 #endif
00586 return 0;
00587 }
00588
00590
00593 unsigned int sleep(unsigned int sec)
00594 {
00595 return msleep(1000*sec)/1000;
00596 }
00597
00599
00601 void shutdown_task(tid_t tid) {
00602 tdata_t *td=(tdata_t*) tid;
00603 td->tflags |= T_SHUTDOWN;
00604 }
00605
00607
00609 void shutdown_tasks(tflags_t flags) {
00610 pchain_t* pchain;
00611 tdata_t* td;
00612
00613 ENTER_KERNEL_CRITICAL_SECTION();
00614
00615 pchain = priority_head;
00616 while (pchain != NULL) {
00617 td = pchain->ctid;
00618 do {
00619 if ((td->tflags & flags) != 0) {
00620
00621
00622 td->tflags |= T_SHUTDOWN;
00623 }
00624 td = td->next;
00625 } while (td != pchain->ctid);
00626 pchain = pchain->next;
00627 }
00628
00629 LEAVE_KERNEL_CRITICAL_SECTION();
00630 }
00631
00633
00635 void kill(tid_t tid) {
00636 tdata_t *td=(tdata_t*) tid;
00637 if(td==ctid)
00638 exit(-1);
00639 else {
00640
00641
00642
00643 ENTER_KERNEL_CRITICAL_SECTION();
00644
00645 *( (td->sp_save) + SP_RETURN_OFFSET )=(size_t) &exit;
00646 td->tstate=T_SLEEPING;
00647
00648 LEAVE_KERNEL_CRITICAL_SECTION();
00649 }
00650 }
00651
00653
00655 void killall(priority_t prio) {
00656 pchain_t *pchain;
00657 tdata_t *td;
00658 tflags_t flags = T_KERNEL | T_IDLE;
00659
00660 if (prio == PRIO_HIGHEST)
00661 flags = T_IDLE;
00662
00663 ENTER_KERNEL_CRITICAL_SECTION();
00664
00665
00666
00667 pchain=priority_head;
00668 while(pchain!=NULL && prio<pchain->priority)
00669 pchain=pchain->next;
00670
00671 while(pchain!=NULL) {
00672 td=pchain->ctid;
00673 do {
00674 if((td!=ctid) && ((td->tflags & flags) == 0)) {
00675
00676
00677 *( (td->sp_save) + SP_RETURN_OFFSET )=(size_t) &exit;
00678 td->tstate=T_SLEEPING;
00679 }
00680 td=td->next;
00681 } while(td!=pchain->ctid);
00682 pchain=pchain->next;
00683 }
00684
00685 LEAVE_KERNEL_CRITICAL_SECTION();
00686 }
00687
00688 #endif // CONF_TM
00689