文章归档

Libtask: c和linux/unix下的协程库

实现协程核心的文件只有几个,其中*-ucontext.h是特定平台上下文切换功能的实现,是几个用户态的API。以386平台为例:

extern    int         swapcontext(ucontext_t*, const ucontext_t*);
extern    void        makecontext(ucontext_t*, void(*)(), int, ...);
extern    int         getmcontext(mcontext_t*);
extern    void        setmcontext(const mcontext_t*);

task.c/task.h是调度器的实现。其实明白上面这几个API,基本上就可以知道协程是怎么干活的了。下面主要分析task.c代码。

使用libtask构建程序不需要显式地使用main函数,只需一个taskmain即可,因为main函数是在task.c里实现的,也就是libtask的调度。

----- task.c ------
int main(int argc, char **argv) {
	....
	taskcreate(taskmainstart, nil, mainstacksize);
	taskscheduler();
	....
}

taskcreate创建了第一个协程,这个协程就是用户的taskmain函数,将其加入调度队列,然后进入调度函数taskscheduler(),taskscheduler()不会返回

static void taskscheduler(void) {
	int i;
	Task *t;

	for(;;){
		if(taskcount == 0)
			exit(taskexitval);
		t = taskrunqueue.head;
		if(t == nil){
			fprint(2, "no runnable tasks! %d tasks stalled\n", taskcount);
			exit(1);
		}
		deltask(&taskrunqueue, t);
		t->ready = 0;
		taskrunning = t;
		tasknswitch++;
		contextswitch(&taskschedcontext, &t->context);
		taskrunning = nil;
		if(t->exiting){
			if(!t->system)
				taskcount--;
			i = t->alltaskslot;
			alltask[i] = alltask[--nalltask];
			alltask[i]->alltaskslot = i;
			free(t);
		}
	}
}

contextswitch切换到到协程t去执行了,从t返回的情况有两种,要么是协程执行完毕了,要么是用户主动的yield,然后等待下次继续被执行。

<busying, todo...>

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>