implement lua_thread_abort, add lua_thread_yield_state func, and fix lua_thread_resume_state to use protected mode
authorTero Marttila <terom@fixme.fi>
Thu, 21 May 2009 16:56:42 +0300
changeset 210 05abca972db0
parent 209 d240da5dbeb5
child 211 b460d958a685
implement lua_thread_abort, add lua_thread_yield_state func, and fix lua_thread_resume_state to use protected mode
src/lua_thread.c
src/lua_thread.h
--- 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