implement lua_thread_abort, add lua_thread_yield_state func, and fix lua_thread_resume_state to use protected mode
--- a/src/lua_thread.c Thu May 21 16:55:56 2009 +0300
+++ b/src/lua_thread.c Thu May 21 16:56:42 2009 +0300
@@ -1,4 +1,5 @@
#include "lua_thread.h"
+#include "log.h"
#include <string.h>
#include <assert.h>
@@ -164,27 +165,94 @@
return (thread->L != NULL);
}
-void lua_thread_resume_state (lua_State *L)
+int lua_thread_yield_state (lua_State *L)
+{
+ return lua_yield(L, 0);
+}
+
+static int _lua_thread_resume_state (lua_State *L)
{
struct lua_thread *thread;
error_t err;
int ret;
+ // pop irrelevant context arg
+ lua_pop(L, 1);
+
// lookup the thread's context
lua_pushthread(L);
lua_gettable(L, LUA_REGISTRYINDEX);
+
+ // not registered?
+ if (lua_isnil(L, -1))
+ return luaL_error(L, "not a registered lua_thread state");
+
+ else if (lua_isboolean(L, -1) && !lua_toboolean(L, -1))
+ return luaL_error(L, "lua_thread was aborted");
// get it as a pointer
if ((thread = lua_touserdata(L, -1)) == NULL)
- luaL_error(L, "lua_thread_resume_state: lua_touserdata");
+ return luaL_error(L, "lua_touserdata");
+ else
+ lua_pop(L, 1);
// handle the resume
if ((ret = lua_thread_resume(L, thread, &err)) < 0)
// notify user
- return lua_thread_done(thread->L, thread, &err);
+ lua_thread_done(thread->L, thread, &err);
// finished?
- if (ret == 0)
- return lua_thread_done(thread->L, thread, NULL);
+ else if (ret == 0)
+ lua_thread_done(thread->L, thread, NULL);
+
+ // ok
+ return 0;
}
+void lua_thread_resume_state (lua_State *L)
+{
+ error_t err;
+
+ // execute in protected mode
+ if (nexus_lua_error(L, lua_cpcall(L, _lua_thread_resume_state, NULL), &err))
+ log_warn_error(&err, "%p", L);
+}
+
+static int _lua_thread_abort (lua_State *L)
+{
+ struct lua_thread *thread;
+
+ // get context arg
+ if ((thread = lua_touserdata(L, -1)) == NULL)
+ luaL_error(L, "lua_thread_resume_state: lua_touserdata");
+ else
+ lua_pop(L, 1);
+
+ // no mechanism to actually abort the underlying wait yet
+ (void) thread;
+
+ // invalidate in registry for later lua_thread_resume_state
+ lua_pushthread(L);
+ lua_pushboolean(L, false);
+ lua_settable(L, LUA_REGISTRYINDEX);
+
+ // not much else we can do
+ return 0;
+}
+
+void lua_thread_abort (struct lua_thread *thread)
+{
+ error_t err;
+
+ if (!thread->L)
+ // no thread executing
+ return;
+
+ // use protected mode
+ if (nexus_lua_error(thread->L, lua_cpcall(thread->L, _lua_thread_abort, thread), &err))
+ log_warn_error(&err, "_lua_thread_abort");
+
+ // unset
+ thread->L = NULL;
+}
+
--- a/src/lua_thread.h Thu May 21 16:55:56 2009 +0300
+++ b/src/lua_thread.h Thu May 21 16:56:42 2009 +0300
@@ -62,9 +62,24 @@
int lua_thread_start (struct lua_thread *thread, const char *chunk, error_t *err);
/**
- * Protected-mode function to resume execution of the given lua_State, which must be a lua_State created with
+ * Protected-mode function to yield execution of the given lua_State, which must be a luaState created with
* lua_thread_start.
+ *
+ * This should be called the same way as lua_yield, except no results are supported yet.
+ */
+int lua_thread_yield_state (lua_State *L);
+
+/**
+ * Resume execution of the given lua_State, which must be a lua_State created with lua_thread_start.
*/
void lua_thread_resume_state (lua_State *L);
+/**
+ * Abort execution of the given thread, if it's running.
+ *
+ * Currently, there is no mechanism to actually abort a running thread, so this will instead release the lua_thread for
+ * new use, and then cause the lua_thread_resume to do nothing.
+ */
+void lua_thread_abort (struct lua_thread *thread);
+
#endif