19 } |
19 } |
20 |
20 |
21 /** |
21 /** |
22 * Thread completed, cleanup and call user callback with given error (NULL for success). |
22 * Thread completed, cleanup and call user callback with given error (NULL for success). |
23 */ |
23 */ |
24 static void lua_thread_done (lua_State *L, struct lua_thread *thread, error_t *err) |
24 static void lua_thread_done (struct lua_thread *thread, error_t *err) |
25 { |
25 { |
26 // remove from registry so thread can be GC'd |
26 // remove from registry so thread can be GC'd |
27 lua_pushthread(L); |
27 // XXX: unsafe |
28 lua_pushnil(L); |
28 lua_pushthread(thread->L); |
29 lua_settable(L, LUA_REGISTRYINDEX); |
29 lua_pushnil(thread->L); |
|
30 lua_settable(thread->L, LUA_REGISTRYINDEX); |
30 |
31 |
31 // drop our ref |
32 // drop our ref |
32 thread->L = NULL; |
33 thread->L = NULL; |
33 |
34 |
34 // call |
35 // call |
145 return lua_yield(L, 0); |
146 return lua_yield(L, 0); |
146 } |
147 } |
147 |
148 |
148 static int _lua_thread_resume_state (lua_State *L) |
149 static int _lua_thread_resume_state (lua_State *L) |
149 { |
150 { |
150 struct lua_thread *thread; |
151 struct lua_thread *thread, **thread_ptr; |
151 error_t err; |
152 |
152 int ret; |
153 // read the ctx argument off the stack |
153 |
154 if ((thread_ptr = lua_touserdata(L, 1)) == NULL) |
154 // pop irrelevant context arg |
155 return luaL_error(L, "lua_touserdata"); |
155 lua_pop(L, 1); |
156 else |
|
157 lua_pop(L, 1); |
156 |
158 |
157 // lookup the thread's context |
159 // lookup the thread's context |
158 lua_pushthread(L); |
160 lua_pushthread(L); |
159 lua_gettable(L, LUA_REGISTRYINDEX); |
161 lua_gettable(L, LUA_REGISTRYINDEX); |
160 |
162 |
169 if ((thread = lua_touserdata(L, -1)) == NULL) |
171 if ((thread = lua_touserdata(L, -1)) == NULL) |
170 return luaL_error(L, "lua_touserdata"); |
172 return luaL_error(L, "lua_touserdata"); |
171 else |
173 else |
172 lua_pop(L, 1); |
174 lua_pop(L, 1); |
173 |
175 |
|
176 // store it |
|
177 *thread_ptr = thread; |
|
178 |
|
179 // ok |
|
180 return 0; |
|
181 } |
|
182 |
|
183 void lua_thread_resume_state (lua_State *L) |
|
184 { |
|
185 struct lua_thread *thread = NULL; |
|
186 error_t err; |
|
187 int ret; |
|
188 |
|
189 // execute in protected mode |
|
190 if (nexus_lua_error(L, lua_cpcall(L, _lua_thread_resume_state, &thread), &err)) |
|
191 return log_warn_error(&err, "%p", L); |
|
192 |
174 // handle the resume |
193 // handle the resume |
175 if ((ret = lua_thread_resume(L, thread, &err)) < 0) |
194 if ((ret = lua_thread_resume(L, thread, &err)) < 0) |
176 // notify user |
195 // notify user |
177 lua_thread_done(thread->L, thread, &err); |
196 lua_thread_done(thread, &err); |
178 |
197 |
179 // finished? |
198 // finished? |
180 else if (ret == 0) |
199 else if (ret == 0) |
181 lua_thread_done(thread->L, thread, NULL); |
200 lua_thread_done(thread, NULL); |
182 |
201 |
183 // ok |
|
184 return 0; |
|
185 } |
|
186 |
|
187 void lua_thread_resume_state (lua_State *L) |
|
188 { |
|
189 error_t err; |
|
190 |
|
191 // execute in protected mode |
|
192 if (nexus_lua_error(L, lua_cpcall(L, _lua_thread_resume_state, NULL), &err)) |
|
193 log_warn_error(&err, "%p", L); |
|
194 } |
202 } |
195 |
203 |
196 static int _lua_thread_abort (lua_State *L) |
204 static int _lua_thread_abort (lua_State *L) |
197 { |
205 { |
198 struct lua_thread *thread; |
206 struct lua_thread *thread; |