📄 task.c
字号:
/* Copyright (c) 2005 Russ Cox, MIT; see COPYRIGHT */#include "taskimpl.h"#include <fcntl.h>typedef struct Tasklist Tasklist;struct Tasklist{ Task *head; Task *tail;};int taskdebuglevel;int taskcount;int tasknswitch;int taskexitval;Task *taskrunning;Context taskschedcontext;Tasklist taskrunqueue;static char *argv0;static void addtask(Tasklist*, Task*);static void deltask(Tasklist*, Task*);static void contextswitch(Context *from, Context *to);static voidtaskdebug(char *fmt, ...){ va_list arg; char buf[128]; Task *t; char *p; static int fd = -1;return; va_start(arg, fmt); vfprint(1, fmt, arg); va_end(arg);return; if(fd < 0){ p = strrchr(argv0, '/'); if(p) p++; else p = argv0; snprint(buf, sizeof buf, "/tmp/%s.tlog", p); if((fd = open(buf, O_CREAT|O_WRONLY, 0666)) < 0) fd = open("/dev/null", O_WRONLY); } va_start(arg, fmt); vsnprint(buf, sizeof buf, fmt, arg); va_end(arg); t = taskrunning; if(t) fprint(fd, "%d.%d: %s\n", getpid(), t->id, buf); else fprint(fd, "%d._: %s\n", getpid(), buf);}static voidtaskstart(uint y, uint x){ Task *t; ulong z; z = x<<16; /* hide undefined 32-bit shift from 32-bit compilers */ z <<= 16; z |= y; t = (Task*)z;//print("taskstart %p\n", v); t->startfn(t->startarg);//print("taskexits %p\n", v); taskexit(0);//print("not reacehd\n");}static int taskidgen;static Task*taskalloc(void (*fn)(void*), void *arg, uint stack){ Task *t; sigset_t zero; uint x, y; ulong z; /* allocate the task and stack together */ t = malloc(sizeof *t+stack); if(t == nil){ fprint(2, "taskalloc malloc: %r\n"); abort(); } memset(t, 0, sizeof *t); t->stk = (uchar*)(t+1); t->stksize = stack; t->id = ++taskidgen; t->startfn = fn; t->startarg = arg; /* do a reasonable initialization */ memset(&t->context.uc, 0, sizeof t->context.uc); sigemptyset(&zero); sigprocmask(SIG_BLOCK, &zero, &t->context.uc.uc_sigmask); /* must initialize with current context */ if(getcontext(&t->context.uc) < 0){ fprint(2, "getcontext: %r\n"); abort(); } /* call makecontext to do the real work. */ /* leave a few words open on both ends */ t->context.uc.uc_stack.ss_sp = t->stk+8; t->context.uc.uc_stack.ss_size = t->stksize-64;#ifdef __sun__ /* sigh */ /* can avoid this with __MAKECONTEXT_V2_SOURCE but only on SunOS 5.9 */ t->context.uc.uc_stack.ss_sp = (char*)t->context.uc.uc_stack.ss_sp +t->context.uc.uc_stack.ss_size;#endif /* * All this magic is because you have to pass makecontext a * function that takes some number of word-sized variables, * and on 64-bit machines pointers are bigger than words. */ z = (ulong)t; y = z; z >>= 16; /* hide undefined 32-bit shift from 32-bit compilers */ x = z>>16; makecontext(&t->context.uc, (void(*)())taskstart, 2, y, x); return t;}inttaskcreate(void (*fn)(void*), void *arg, uint stack){ int id; Task *t; t = taskalloc(fn, arg, stack); taskcount++; id = t->id; taskready(t); return id;}voidtaskswitch(void){ needstack(0); contextswitch(&taskrunning->context, &taskschedcontext);}voidtaskready(Task *t){ addtask(&taskrunqueue, t);}inttaskyield(void){ int n; n = tasknswitch; taskready(taskrunning); taskswitch(); return tasknswitch - n;}intanyready(void){ return taskrunqueue.head != nil;}voidtaskexitall(int val){ exit(val);}voidtaskexit(int val){ taskexitval = val; taskrunning->exiting = 1; taskswitch();}static voidcontextswitch(Context *from, Context *to){ if(swapcontext(&from->uc, &to->uc) < 0){ fprint(2, "swapcontext failed: %r\n"); assert(0); }}static voidtaskscheduler(void){ Task *t; taskdebug("scheduler enter"); for(;;){ t = taskrunqueue.head; if(t == nil){ if(taskcount == 0) exit(taskexitval); fprint(2, "no runnable tasks! %d tasks stalled\n", taskcount); exit(1); } deltask(&taskrunqueue, t); taskrunning = t; tasknswitch++; taskdebug("run %d (%s)", t->id, t->name); contextswitch(&taskschedcontext, &t->context);//print("back in scheduler\n"); taskrunning = nil; if(t->exiting){ taskcount--; free(t); } }}void**taskdata(void){ return &taskrunning->udata;}/* * debugging */voidtasksetname(char *fmt, ...){ va_list arg; Task *t; t = taskrunning; va_start(arg, fmt); vsnprint(t->name, sizeof t->name, fmt, arg); va_end(arg);}char*taskgetname(void){ return taskrunning->name;}voidtasksetstate(char *fmt, ...){ va_list arg; Task *t; t = taskrunning; va_start(arg, fmt); vsnprint(t->state, sizeof t->name, fmt, arg); va_end(arg);}voidneedstack(int n){ Task *t; t = taskrunning; if((char*)&t <= (char*)t->stk || (char*)&t - (char*)t->stk < 256+n){ fprint(2, "task stack overflow: &t=%p tstk=%p n=%d\n", &t, t->stk, 256+n); abort(); }}/* * startup */static int taskargc;static char **taskargv;int mainstacksize;static voidtaskmainstart(void *v){ taskmain(taskargc, taskargv);}intmain(int argc, char **argv){ argv0 = argv[0]; taskargc = argc; taskargv = argv; if(mainstacksize == 0) mainstacksize = 256*1024; taskcreate(taskmainstart, nil, mainstacksize); taskscheduler(); fprint(2, "taskscheduler returned in main!\n"); abort(); return 0;}/* * hooray for linked lists */static voidaddtask(Tasklist *l, Task *t){ if(l->tail){ l->tail->next = t; t->prev = l->tail; }else{ l->head = t; t->prev = nil; } l->tail = t; t->next = nil;}static voiddeltask(Tasklist *l, Task *t){ if(t->prev) t->prev->next = t->next; else l->head = t->next; if(t->next) t->next->prev = t->prev; else l->tail = t->prev;}unsigned inttaskid(void){ return taskrunning->id;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -