-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathlcororep.cpp
More file actions
168 lines (151 loc) · 4.53 KB
/
lcororep.cpp
File metadata and controls
168 lines (151 loc) · 4.53 KB
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include "common.h"
#include "context_lua.h"
static int32_t coresume_continue(lua_State *L, int status, lua_KContext ctx);
static int auxresume (lua_State *L, lua_State *co, int narg) {
int status, stacks;
int ismain = lua_pushthread(L);
lua_pop(L, 1);
if (ismain) {
lua_pushliteral(L, "cannot call resume in main thread");
return -1; /* error flag */
}
if (!lua_checkstack(co, narg)) {
lua_pushliteral(L, "too many arguments to resume");
return -1; /* error flag */
}
if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) {
lua_pushliteral(L, "cannot resume dead coroutine");
return -1; /* error flag */
}
lua_xmove(L, co, narg);
context_lua_t *lctx = context_lua_t::lua_get_context(L);
while (((status = lua_resume(co, L, narg)) == LUA_YIELD) && lctx->yielding_up()) { /* can happen only when status == LUA_YIELD */
if ((stacks = lua_checkstack(L, LUA_MINSTACK)) && lua_yieldable(L)) { /* reserve LUA_MINSTACK stack for resume result */
return lua_yieldk(L, 0, 0, coresume_continue); /* yield again! n(0) result to yield and ctx(0) is not allowed */
} else { /* lua_gettop(co) must be 0 since context_lua_t::lua_yield_send yield 0 result */
int yieldup_status = stacks ? NL_EYIELD : NL_ESTACKLESS;
lctx->yielding_finalize(NULL, yieldup_status);
lua_pushboolean(co, 0); /* stack on co must be enough since we have checked it at last yield */
lua_pushinteger(co, yieldup_status);
lua_pushnil(co);
lua_pushnil(co);
narg = 4;
}
}
if (status == LUA_OK || status == LUA_YIELD) {
int nres = lua_gettop(co);
if (!lua_checkstack(L, nres + 1)) {
lua_pop(co, nres); /* remove results anyway */
lua_pushliteral(L, "too many results to resume");
return -1; /* error flag */
}
lua_xmove(co, L, nres); /* move yielded values */
return nres;
} else {
lua_xmove(co, L, 1); /* move error message */
return -1; /* error flag */
}
}
static int lua_coresume (lua_State *L) {
lua_State *co = lua_tothread(L, 1);
int r;
luaL_argcheck(L, co, 1, "coroutine expected");
r = auxresume(L, co, lua_gettop(L) - 1);
if (r < 0) {
lua_pushboolean(L, 0);
lua_insert(L, -2);
return 2; /* return false + error message */
}
else {
lua_pushboolean(L, 1);
lua_insert(L, -(r + 1));
return r + 1; /* return true + `resume' returns */
}
}
static int32_t coresume_continue(lua_State *L, int status, lua_KContext ctx)
{
return lua_coresume(L);
}
static int lua_auxwrap (lua_State *L) {
lua_State *co = lua_tothread(L, lua_upvalueindex(1));
int r = auxresume(L, co, lua_gettop(L));
if (r < 0) {
if (lua_isstring(L, -1)) { /* error object is a string? */
luaL_where(L, 1); /* add extra info */
lua_insert(L, -2);
lua_concat(L, 2);
}
return lua_error(L); /* propagate error */
}
return r;
}
static int lua_cocreate (lua_State *L) {
lua_State *NL;
luaL_checktype(L, 1, LUA_TFUNCTION);
NL = lua_newthread(L);
lua_pushvalue(L, 1); /* move function to top */
lua_xmove(L, NL, 1); /* move function from L to NL */
return 1;
}
static int lua_cowrap (lua_State *L) {
lua_cocreate(L);
lua_pushcclosure(L, lua_auxwrap, 1);
return 1;
}
static int lua_coyield (lua_State *L) {
lua_pushlightuserdata(L, &context_lua_t::m_root_coro_table_key);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pushthread(L);
lua_rawget(L, -2);
int ret = lua_toboolean(L, -1);
lua_pop(L, 2);
if (!ret) {
return lua_yield(L, lua_gettop(L));
} else { /* is root coroutine */
return luaL_error(L, "attempt to yield from root coroutine");
}
}
static int lua_costatus (lua_State *L) {
lua_State *co = lua_tothread(L, 1);
luaL_argcheck(L, co, 1, "coroutine expected");
if (L == co) lua_pushliteral(L, "running");
else {
switch (lua_status(co)) {
case LUA_YIELD:
lua_pushliteral(L, "suspended");
break;
case LUA_OK: {
lua_Debug ar;
if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */
lua_pushliteral(L, "normal"); /* it is running */
else if (lua_gettop(co) == 0)
lua_pushliteral(L, "dead");
else
lua_pushliteral(L, "suspended"); /* initial state */
break;
}
default: /* some error occurred */
lua_pushliteral(L, "dead");
break;
}
}
return 1;
}
static int lua_corunning (lua_State *L) {
int ismain = lua_pushthread(L);
lua_pushboolean(L, ismain);
return 2;
}
static const luaL_Reg co_funcs[] = {
{"create", lua_cocreate},
{"resume", lua_coresume},
{"running", lua_corunning},
{"status", lua_costatus},
{"wrap", lua_cowrap},
{"yield", lua_coyield},
{NULL, NULL}
};
LUAMOD_API int luaopen_my_coroutine (lua_State *L) {
luaL_newlib(L, co_funcs);
return 1;
}