-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcoroutine.c
73 lines (66 loc) · 2.21 KB
/
coroutine.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include "coroutine.h"
#include <assert.h>
#include <stdlib.h>
coroutine* current_coroutine;
coroutine* root_coroutine;
int context_switch(context* cfrom, context* cto);
void coroutine_entry(coroutine_func f, void* arg){
f(arg);
current_coroutine->state=1; //tag finished
coroutine_yield(); //as a normal yield.
}
void coroutine_start(coroutine* c, coroutine_func entry, void* arg){
c->caller=0;
c->stack=malloc(STACK_SIZE);
c->state=0;
memset(&c->c_context, 0, sizeof(context));
c->c_context.rsp=c->stack+STACK_SIZE;
// return rip does not matter.
c->c_context.rdi=entry;
c->c_context.rsi=arg;
//*(uint64_t)(c->c_context.rsp+8)=entry; //the entry.
//*(uint64_t)(c->c_context.rsp+16)=arg; //the arg.
c->c_context.rbp=c->stack+STACK_SIZE;
c->c_context.rip=&coroutine_entry;
// everything is ready now, and only requires a trigger.
//printf("%d %d\n", c, c->stack);
}
void coroutine_yield(){
assert(current_coroutine!=root_coroutine); // root coroutine should not be yielded.
context* current_context=¤t_coroutine->c_context;
context* parent_context=¤t_coroutine->caller->c_context;
coroutine* parent=current_coroutine->caller;
current_coroutine->caller=0;
current_coroutine=parent;
context_switch(current_context, parent_context);
}
int coroutine_await(coroutine* target){
assert(target->caller==0);
assert(target->state==0);
context* current_context=¤t_coroutine->c_context;
target->caller=current_coroutine;
current_coroutine=target;
context* new_context=¤t_coroutine->c_context;
context_switch(current_context, new_context);
// After some hard work we gain control again.
// now we just free the coroutine.
if(target->state==0){
return 0;
}else{
coroutine_destroy(target);
return 1;
}
}
void coroutine_init(){
// In fact nothing is done.
// root_coroutine is the place to store registers.
root_coroutine=(coroutine*)malloc(sizeof(coroutine));
current_coroutine=root_coroutine;
}
void coroutine_destroy(coroutine* co){
assert(co->state==1);
//printf("%d %d\n", co, co->stack);
free(co->stack);
//printf("stack\n");
free(co);
}