数据结构如下图所示:
Coroutine就是协程的相应属性,status表示协程的运行状态。sleep与wait两颗红黑树,ready使用的队列,比如某协程调用sleep函数,加入睡眠树(sleep_tree),status |= S即可。比如某协程在等待树(wait_tree)中,而IO准备就绪放入ready队列中,只需要移出等待树(wait_tree),状态更改status &= ~W即可。有一个前提条件就是不管何种运行状态的协程,都在就绪队列中,只是同时包含有其他的运行状态。
按照前面几章的描述,定义一个协程结构体需要多少域,我们描述了每一个协程有自己的上下文环境,需要保存CPU的寄存器ctx;需要有子过程的回调函数func;需要有子过程回调函数的参数 arg;需要定义自己的栈空间 stack;需要有自己栈空间的大小 stack_size;需要定义协程的创建时间 birth;需要定义协程当前的运行状态 status;需要定当前运行状态的结点(ready_next, wait_node, sleep_node);需要定义协程id;需要定义调度器的全局对象 sched。
协程的核心结构体如下:
typedef struct _nty_coroutine {
nty_cpu_ctx ctx;
proc_coroutine func;
void *arg;
size_t stack_size;
nty_coroutine_status status;
nty_schedule *sched;
uint64_t birth;
uint64_t id;
void *stack;
RB_ENTRY(_nty_coroutine) sleep_node;
RB_ENTRY(_nty_coroutine) wait_node;
TAILQ_ENTRY(_nty_coroutine) ready_next;
TAILQ_ENTRY(_nty_coroutine) defer_next;
} nty_coroutine;
调度器是管理所有协程运行的组件,协程与调度器的运行关系。
调度器的属性,需要有保存CPU的寄存器上下文 ctx,可以从协程运行状态yield到调度器运行的。从协程到调度器用yield,从调度器到协程用resume。
以下为协程的定义。
typedef struct _nty_coroutine_queue nty_coroutine_queue;
typedef struct _nty_coroutine_rbtree_sleep nty_coroutine_rbtree_sleep;
typedef struct _nty_coroutine_rbtree_wait nty_coroutine_rbtree_wait;
typedef struct _nty_schedule {
uint64_t birth;
nty_cpu_ctx ctx;
struct _nty_coroutine *curr_thread;
int page_size;
int poller_fd;
int eventfd;
struct epoll_event eventlist[NTY_CO_MAX_EVENTS];
int nevents;
int num_new_events;
nty_coroutine_queue ready;
nty_coroutine_rbtree_sleep sleeping;
nty_coroutine_rbtree_wait waiting;
} nty_schedule;