📄 task.c
字号:
/* * FILENAME: task.c * * Copyright 1999- 2004 By InterNiche Technologies Inc. All rights reserved * Portions Copyright 1984 by the Massachusetts Institute of Technology * * * MODULE: MISCLIB * * ROUTINES: port_prep(), tk_block(), tk_del(), tk_ev_block(), * ROUTINES: tk_ev_wake(), tk_exit(), tk_init(), tk_kill(), * ROUTINES: tk_new(), tk_sleep(), tk_stats(), tk_wake(), * * PORTABLE: yes */#include "license.h"#include "ipport.h"#include "task.h"int(*port_prep)(int already_found) = NULL;task * tk_cur; /* a pointer to the current task */unsigned TDEBUG = 0; /* DEBUG flag */u_long tk_wakeups = 0; /* count fo task switches */static task * tk_died = NULL;static int tid = 0;void tk_del(task * tk); /* remove tasks resources *//* FUNCTION: tk_init() * * tk_init() - Initialize the tasking system. Create the first task, * and set its stack pointer to the main program stack. The first * task always uses the main system startup stack for compatability * with compiler provided "startup" files. The circular list of tasks * contains only the original task, so originally set its next task * pointer to point to itself. This routine returns to the caller * with a pointer to the first task, or error it returns NULL. * * PARAM1: stack_t * st_base * PARAM2: int st_size * * RETURNS: */task *tk_init(stack_t * st_base, int st_size){ task *tk; /* pointer to the first task */ stack_t * sp; printf("in tk_init()\n"); /* create the first task */ tk = (task*)TK_ALLOC(sizeof(struct task)); tk_cur = tk; /* It is the currently running task */ /* Task is running thus does not need to be awakened. */ tk->tk_flags = TF_MAIN; /* mark it as using system stack */ tk->tk_name = "Main"; tk->tk_next = tk; /* task is only one in list */ tk->tk_count = 0; tk->tk_tid = tid++; tk->tk_size = st_size; tk->tk_stack = st_base; /* fill the system stack with the guardword */ sp = tk_getsp();#ifdef STK_TOPDOWN /* Intel x86 "top down" stack */ while (sp > st_base) { sp--; /* stop when sp == base */ *sp = GUARDWORD; }#elif STK_BOTTOMUP /* stack moves from bottom up */ { stack_t * stacktop = st_base + st_size/sizeof(stack_t); while (sp < stacktop) { sp++; *sp = GUARDWORD; } }#else#error You must define a stack type! (STK_TOPDOWN or STK_BOTTOMUP)#endif tk->tk_guard = sp; /* set address for stack check */#ifdef DEBUG if (TDEBUG) dprintf("tk_init: Initial stack size = %d\n", tk->tk_size);#endif return(tk);}/* FUNCTION: tk_new() * * Create a new task with stksiz bytes of stack, and place * it in the circular list of tasks after prev_tk. Awaken it so that * it will run, and set it up so that when it does run, it will start * runing routine start. This routine does not affect the execution * of the currently running task. Returns a pointer to the new task, * or NULL if there isn't enough memory for the new task * * * PARAM1: task * prev_tk * PARAM2: task code routine * PARAM3: size of stack * PARAM4: name for new task * PARAM5: arg for task (deprecated) * * RETURNS: */task * tk_new(task * prev_tk, /* predecessor (sp?) to the new task */ int (*start)(int), /* Where the new task starts execution. */ int stksiz, /* The size in bytes of the stack of the new task. */ char * name, /* The task's name as a string */ int arg) /* argument to the task */{ task * tk; /* a pointer to the new task */ stack_t * sp; /* pointer to task stack area for fill */ /* create the new task */ tk = (task *)TK_ALLOC(sizeof(task)); if (tk == NULL) { return NULL; /* if no memory left, return null */ } tk->tk_size = stksiz; tk->tk_stack = (stack_t *)STK_ALLOC(stksiz); if (tk->tk_stack == NULL) { TK_FREE(tk); return NULL; } /* set it up to run */ tk->tk_fp = tk_frame (tk, start, arg); /* fill stack with guardword */ sp = tk->tk_fp;#ifdef STK_TOPDOWN /* Intel x86 "top down" stack */ sp--; while (sp > tk->tk_stack) { sp--; *sp = GUARDWORD; }#else /* stack moves from bottom up */ dtrap(); /* untested */ x = stksiz - (sp - tk->tk_stack); /* bytes to fill */ x = x/(sizeof(stack_t)); x++; sp++; while (x++ > 0) *sp++ = GUARDWORD; #endif tk->tk_guard = sp; tk->tk_flags |= TF_AWAKE; /* Schedule the task to run. */ tk->tk_next = prev_tk->tk_next; /* Fit it in after prev_tk. */ prev_tk->tk_next = tk; tk->tk_name = name; /* Set its name */ tk->tk_count = 0; /* init the count */ tk->tk_tid = tid++; return (tk);}/* FUNCTION: tk_block () * * Block the currently running task and run the next task in the * circular list of tasks that is awake. Before returning, see if any * cleanup has to be done for another task. * * * PARAM1: * * RETURNS: */voidtk_block () { task * tk = tk_cur; /* the next task to run */ /* check if the guard word is still intact */ if (*(tk->tk_guard) != GUARDWORD) { panic("tk_block stack"); return; }#ifdef NPDEBUG if (TDEBUG) dprintf("TASK: Task %s blocking.\n", tk->tk_name);#endif IN_PROFILER(PF_IDLE, PF_ENTRY); /* measure time in the idle loop */ /* find the next ready to run task */ do { tk = tk->tk_next; /* see if a sleeping task is ready to wake */ if (tk->tk_waketick && tk->tk_waketick < cticks) { tk->tk_waketick = 0; /* clear wakeup tick flag */ break; /* go run this task */ } } while ((tk->tk_flags & TF_AWAKE) == 0); IN_PROFILER(PF_IDLE, PF_EXIT); tk->tk_flags &= ~TF_AWAKE; /* clear wake flag before it runs */ tk_switch (tk); /* Run the next task. */#ifdef NPDEBUG if (TDEBUG) dprintf("TASK: Task %s running\n", tk_cur->tk_name);#endif if (tk_died) { tk_del(tk_died); /* delete dead task */ tk_died = NULL; /* clear pointer/flag */ }}/* FUNCTION: tk_exit() * * tk_exit() : destroy the current task. Accomplished by setting a * flag indicating that an exit has occured and then entering the * scheduler loop. When tk_block() returns for some other task and * finds this flag set, it deallocates the task which exited. This is * necessary because we still need a stack to run on. The task * removes itself from the circular list of tasks in the system so * that it cannot be awoken after it has exited. Otherwise, the exit * might be done in the context of the task itself, which would prove * disastrous. This routine never returns. * * * PARAM1: void * * RETURNS: no */voidtk_exit() { tk_kill(tk_cur); /* kill current task, save in tk_to_die */ tk_block(); /* this should delete tk_to_die */ panic("tk_exit"); /* should never return from block */}/* FUNCTION: tk_kill() * * tk_kill(task) - kill a task. A special case is if you're killing * yourself, you die the instant your task blocks. * * * PARAM1: task * tk - task to die * * RETURNS: void */voidtk_kill(task * tk_to_die){ task *tk; if(tk_died) /* Is another task in the process of dying? */ { tk_yield(); /* this should allow it to finish */ if(tk_died) /* Other task still dying? */ { dtrap(); /* system bug */ } } /* hunt for the task which tk_to_die is the successor of */ for (tk = tk_cur; tk->tk_next != tk_to_die; tk = tk->tk_next) ; /* now patch around tk_to_die */ tk->tk_next = tk_to_die->tk_next; /* If I'm killing myself, die the next time I block */ if (tk_cur == tk_to_die) { tk_died = tk_cur; } else tk_del(tk_to_die);}/* FUNCTION: tk_stats() * * tk_stats() - print out tasking system status * * PARAM1: void * pio * * RETURNS: */inttk_stats(void * pio) {#ifdef NET_STATS task *tk; char * state; ns_printf(pio, "tasking status:"); ns_printf(pio, "task wakeups: %D\n", tk_wakeups); ns_printf(pio, " name \tstate \tstack\tused\twakes\n"); tk = tk_cur; do /* measure stack usage using guardword pattern */ { stack_t * up; int i; /* number of unused words in stack area */ up = tk->tk_guard;#ifdef STK_TOPDOWN for (i = tk->tk_size/sizeof(stack_t) -1; i; i--) if (*up++ != GUARDWORD) break;#else /* BOTTOMUP */ for (i = tk->tk_size/sizeof(stack_t) -1; i; i--) if (*up-- != GUARDWORD) break;#endif if (tk == tk_cur) state = "running "; else if(tk->tk_event) state = "event_wt"; else if(tk->tk_waketick) state = "sleeping"; else if(tk->tk_flags & TF_AWAKE) state = "ready "; else state = "blocked "; ns_printf(pio, "%d) %-18s\t%s\t%u\t%u\t%lu\n", tk->tk_tid, tk->tk_name, state, tk->tk_size, i*sizeof(stack_t), tk->tk_count); tk = tk->tk_next; } while (tk != tk_cur);#else USE_ARG(pio);#endif return 0;}/* FUNCTION: tk_del() * * PARAM1: task * tk * * RETURNS: */voidtk_del(task * tk){ if (tk_cur == tk) /* don't delete running task! */ panic("tk_del"); /* free stack if it's not system stack */ if ((tk->tk_flags & TF_MAIN) == 0) STK_FREE(tk->tk_stack); TK_FREE(tk);}/* FUNCTION: tk_wake() * * PARAM1: task * tk * * RETURNS: */voidtk_wake(task * tk){ tk->tk_flags |= TF_AWAKE; tk_wakeups++; tk->tk_count++;}/* FUNCTION: tk_sleep() * * tk_sleep()- put current task to sleep for passed tick count. * * * PARAM1: long ticks * * RETURNS: */voidtk_sleep(long ticks){ tk_cur->tk_flags &= ~TF_AWAKE; /* put task to sleep */ tk_cur->tk_waketick = cticks + ticks; /* set wake time */ tk_block(); tk_wakeups++; tk_cur->tk_count++;}/* FUNCTION: tk_ev_block() * * tk_ev_block() - block current task until an event occurs. The * event is signaled by calling tk_ev_wake() with a pointer match the * one passed here. * * * PARAM1: void * event * * RETURNS: */voidtk_ev_block(void * event){ tk_cur->tk_flags &= ~TF_AWAKE; /* put task to sleep */ tk_cur->tk_event = event; /* set wake event */ tk_block(); /* wait for tk_ev_wake() */ tk_wakeups++; tk_cur->tk_count++;}/* FUNCTION: tk_ev_wake() * * tk_ev_wake() - wake any tasks sleeping on the passed event. This * does not wake up tk_cur. * * * PARAM1: void * event * * RETURNS: */voidtk_ev_wake(void * event){ task * tk; /* look though task list - skip tk_cur */ for (tk = tk_cur->tk_next; tk != tk_cur; tk = tk->tk_next) { if (tk->tk_event == event) /* is task wait for this event */ { tk->tk_event = NULL; /* clear the event */ tk->tk_flags |= TF_AWAKE; /* wake the task */ } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -