summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpixel <pixel>2006-02-09 17:08:24 +0000
committerpixel <pixel>2006-02-09 17:08:24 +0000
commit1f97ba72e51f52f351137550239e9dae7f743fc7 (patch)
tree6d3108a06b884e5092fcce5c6d287af547e5daef
parent038c92026a1222d204dcf1b85e5f349eb24f34d5 (diff)
In general: better thread handling. Added locks everywhere it should. Added/fixed thread spawning stuff.
Also, added Lua's methods: -) copy -) setgcthreshold -) getgcthreshold -) getgccount
-rw-r--r--include/BLua.h35
-rw-r--r--lib/BLua.cc344
2 files changed, 302 insertions, 77 deletions
diff --git a/include/BLua.h b/include/BLua.h
index 77c3a9d..9fa4248 100644
--- a/include/BLua.h
+++ b/include/BLua.h
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/* $Id: BLua.h,v 1.27 2006-01-31 17:02:38 pixel Exp $ */
+/* $Id: BLua.h,v 1.28 2006-02-09 17:08:24 pixel Exp $ */
#ifndef __BLUA_H__
#define __BLUA_H__
@@ -33,6 +33,7 @@ extern "C" {
#define lua_unlock(L) do_lua_unlock(L)
#include <lua.h>
+#include <lauxlib.h>
#include <map>
#include <Exceptions.h>
#include <Handle.h>
@@ -66,6 +67,7 @@ class Lua : public Base {
void push(void *);
void push(lua_CFunction, int = 0);
void pop(int = 1);
+ void copy(int = -1);
void newtable();
void * newuser(size_t);
void settable(int = -3, bool raw = false);
@@ -94,11 +96,16 @@ class Lua : public Base {
Lua * tothread(int = -1);
String escape_string(const String &);
void load(Handle *, bool docall = true) throw (GeneralException);
+ void load(const String &, bool docall = true) throw (GeneralException);
void dump(Handle *, bool strip = true);
void dumpvars(Handle *, const String &, int = -1);
- Lua * thread();
- int yield(int nargs = 0);
- int resume(int nresults = 0);
+ Lua * thread(bool saveit = true);
+ Lua * thread(const String &, int nargs = 0, bool saveit = true);
+ Lua * thread(Handle *, int nargs = 0, bool saveit = true);
+ int yield(int nresults = 0);
+ void resume(int nargs = 0) throw (GeneralException);
+ void resume(const String &, int nargs = 0);
+ void resume(Handle *, int nargs = 0);
static Lua * find(lua_State *) throw (GeneralException);
void showerror();
int getmetatable(int = -1);
@@ -107,16 +114,28 @@ class Lua : public Base {
void do_break();
- virtual void lock() {}
- virtual void unlock() {}
+ virtual void lock();
+ virtual void unlock();
bool is_protected();
- private:
+ void openlib(const String & libname, const struct luaL_reg *l, int nup);
+
+ void setgcthreshold(int = 0);
+ int getgcthreshold();
+ int getgccount();
+
+ protected:
+ virtual Lua * spawn_from_thread(lua_State *);
Lua(lua_State *);
+
+ private:
+ void setup_state(lua_State *);
lua_State * L;
static std::map<lua_State *, Lua *> lualist;
- bool _protected;
+ bool _protected, _is_thread;
void dumpvars_r(Handle *, int, int = 0) throw (GeneralException);
+
+ friend class LuaStatics;
};
class LuaObject : public Base {
diff --git a/lib/BLua.cc b/lib/BLua.cc
index 061a1f6..d86740d 100644
--- a/lib/BLua.cc
+++ b/lib/BLua.cc
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/* $Id: BLua.cc,v 1.35 2006-02-02 14:09:48 pixel Exp $ */
+/* $Id: BLua.cc,v 1.36 2006-02-09 17:08:24 pixel Exp $ */
#include <stdlib.h>
#include "BLua.h"
@@ -60,6 +60,8 @@ class LuaStatics : public Base {
static int trueluapanic(lua_State *) throw(GeneralException);
static int luaerror(lua_State *);
static int callwrap(lua_State *, lua_CFunction);
+ static void createhook(lua_State *, lua_State *);
+ static void destroyhook(lua_State *, lua_State *);
static int collector(lua_State *);
static int destructor(lua_State *);
@@ -75,14 +77,18 @@ class LuaStatics : public Base {
static int dumpvars(lua_State *);
static int iconv(lua_State *);
+
+ static int globalindex(lua_State *);
};
std::map<lua_State *, Lua *> Lua::lualist;
int LuaStatics::luaerror(lua_State * __L) {
Lua * L = Lua::find(__L);
+ L->lock();
L->push_lua_context();
L->showerror();
+ L->unlock();
return 0;
}
@@ -94,9 +100,11 @@ int LuaStatics::trueluapanic(lua_State * __L) throw (GeneralException) {
Lua * L = Lua::find(__L);
if (L->is_protected())
return 0; // luaerror will get it for us...
+ L->lock();
L->push_lua_context();
L->showerror();
- throw LuaException("Unprotected error running Lua code, bailing out; except unstable lua environment.");
+ L->unlock();
+ throw LuaException("Unprotected error running Lua code, bailing out; expect unstable lua environment.");
}
int LuaStatics::andB(lua_State * __L) {
@@ -236,8 +244,10 @@ int LuaStatics::getglobal(lua_State * _L) {
Buffer b;
b << "return " + L->tostring();
+ L->lock();
L->load(&b, false);
L->call(0, 1);
+ L->unlock();
return 1;
}
@@ -289,11 +299,79 @@ int LuaStatics::iconv(lua_State * _L) {
return 1;
}
-Lua::Lua() : L(lua_open()) {
+int LuaStatics::callwrap(lua_State * __L, lua_CFunction func) {
+ Lua * L = Lua::find(__L);
+ int n;
+
+ try {
+ n = func(__L);
+ }
+ catch (LuaException e) {
+ L->error(String("LuaException: ") + e.GetMsg());
+ }
+ catch (GeneralException e) {
+ L->error(String("GeneralException: ") + e.GetMsg());
+ }
+
+ return n;
+}
+
+int LuaStatics::collector(lua_State * __L) {
+ Lua * L = Lua::find(__L);
+ void ** u = (void **) L->touserdata();
+ bool * obj = (bool *) (u + 1);
+// printm(M_INFO, "From LUA: collecting object\n");
+ if (*obj) {
+// printm(M_INFO, "Is object at %p\n", *u);
+ Base * b = (Base *) *u;
+ delete b;
+ } else {
+// printm(M_INFO, "Is struct at %p\n", *u);
+ free(*u);
+ }
+ *u = 0;
+ return 0;
+}
+
+int LuaStatics::destructor(lua_State * __L) {
+ Lua * L = Lua::find(__L);
+ Base * b = (Base *) LuaObject::getme(L);
+ delete b;
+ L->push("__obj");
+ L->gettable(-2, true);
+ void ** u = (void **) L->touserdata();
+ bool * obj = (bool *) (u + 1);
+ if (*obj) {
+ Base * b = (Base *) *u;
+ delete b;
+ } else {
+ free(*u);
+ }
+ *u = 0;
+ L->pop();
+ return 0;
+}
+
+void LuaStatics::createhook(lua_State * __L, lua_State * L1) {
+ Lua * L = Lua::find(__L);
+ L->spawn_from_thread(L1);
+}
+
+void LuaStatics::destroyhook(lua_State * __L, lua_State * L1) {
+ Lua * L = Lua::find(L1);
+ delete L;
+}
+
+void Lua::setup_state(lua_State *) {
lualist[L] = this;
lua_atpanic(L, LuaStatics::luapanic);
lua_setcallwrap(L, LuaStatics::callwrap);
+ lua_setcreatehook(L, LuaStatics::createhook);
+ lua_setdestroyhook(L, LuaStatics::destroyhook);
+}
+Lua::Lua() : L(lua_open()), _protected(false), _is_thread(false) {
+ setup_state(L);
declarefunc("andB", LuaStatics::andB);
declarefunc("orB", LuaStatics::orB);
declarefunc("xorB", LuaStatics::xorB);
@@ -303,16 +381,31 @@ Lua::Lua() : L(lua_open()) {
declarefunc("hex", LuaStatics::hex);
declarefunc("getglobal", LuaStatics::getglobal);
declarefunc("dumpvars", LuaStatics::dumpvars);
+ push("BLUA_THREADS");
+ newtable();
+ settable(LUA_REGISTRYINDEX);
}
-Lua::Lua(lua_State * __L) : L(__L), _protected(false) {
- lualist[L] = this;
- lua_atpanic(L, LuaStatics::luapanic);
+Lua::Lua(lua_State * __L) : L(__L), _protected(false), _is_thread(true) {
+ setup_state(L);
+
+ // **TODO**
+ // do we need to define global functions as well.. ?
+ // I don't think so. Environment should be duplicated.
+
+}
+
+Lua * Lua::spawn_from_thread(lua_State * __L) {
+ return new Lua(__L);
}
Lua::~Lua() {
- lua_setgcthreshold(L, 0);
- lua_close(L);
+ if (!_is_thread) {
+ lua_setgcthreshold(L, 0);
+ lua_close(L);
+ }
+
+ L = 0;
}
bool Lua::is_protected() {
@@ -324,65 +417,85 @@ Lua::Lua(const Lua & l) throw (GeneralException) {
}
void Lua::open_base() {
+ lock();
luaopen_base(L);
lua_pop(L, 1);
+ unlock();
}
void Lua::open_table() {
+ lock();
luaopen_table(L);
lua_pop(L, 1);
+ unlock();
}
void Lua::open_io() {
+ lock();
luaopen_io(L);
lua_pop(L, 1);
+ unlock();
}
void Lua::open_string() {
+ lock();
luaopen_string(L);
push("iconv");
push(LuaStatics::iconv);
settable();
lua_pop(L, 1);
+ unlock();
}
void Lua::open_math() {
+ lock();
luaopen_math(L);
lua_pop(L, 1);
+ unlock();
}
void Lua::open_debug() {
+ lock();
luaopen_debug(L);
lua_pop(L, 1);
+ unlock();
}
void Lua::open_dir() {
+ lock();
luaopen_dir(L);
lua_pop(L, 1);
+ unlock();
}
void Lua::declarefunc(const String & name, lua_CFunction f, int i) {
+ lock();
lua_pushstring(L, name.to_charp());
lua_pushcfunction(L, f);
lua_settable(L, i);
+ unlock();
}
void Lua::call(const String & f, int i, int nargs, int nresults) {
+ lock();
lua_pushstring(L, f.to_charp());
lua_gettable(L, i);
lua_insert(L, -1 - nargs - nresults);
call(nargs, nresults);
+ unlock();
}
void Lua::call(int nargs, int nresults) throw(GeneralException) {
int r;
+ lock();
lua_pushcfunction(L, LuaStatics::luaerror);
lua_insert(L, 1);
_protected = true;
r = lua_pcall(L, nargs, nresults, 1);
_protected = false;
lua_remove(L, 1);
+ unlock();
switch(r) {
case 0:
@@ -434,6 +547,10 @@ void Lua::pop(int n) {
lua_pop(L, n);
}
+void Lua::copy(int n) {
+ lua_pushvalue(L, n);
+}
+
void Lua::newtable() {
lua_newtable(L);
}
@@ -471,8 +588,10 @@ void Lua::getglobal(const String & name) throw (GeneralException) {
b << "return " + name;
try {
+ lock();
load(&b, false);
call(0, 1);
+ unlock();
}
catch (LuaException &) {
throw LuaException("Error finding global variable `" + name + "'");
@@ -547,6 +666,7 @@ bool Lua::islightuserdata(int i) {
bool Lua::isobject(int i) {
bool r = false;
+ lock();
if (istable(i)) {
push("__obj");
gettable(i);
@@ -555,6 +675,7 @@ bool Lua::isobject(int i) {
} else {
r = isnil(i);
}
+ unlock();
return r;
}
@@ -615,8 +736,25 @@ int LuaStatics::putF(lua_State * L, const void * p, size_t size, void * ud) {
}
String Lua::escape_string(const String & s) {
- /* TODO */
- return s;
+ String r = "";
+ int i;
+ for (i = 0; i < s.strlen(); i++) {
+ switch(s[i]) {
+ case '"': case '\\':
+ r += '\\';
+ r += s[i];
+ break;
+ case '\n':
+ r += "\n";
+ break;
+ case '\0':
+ r += "\\000";
+ break;
+ default:
+ r += s[i];
+ }
+ }
+ return r;
}
void Lua::load(Handle * h, bool docall) throw (GeneralException) {
@@ -625,6 +763,8 @@ void Lua::load(Handle * h, bool docall) throw (GeneralException) {
lf.f = h;
+ if (docall)
+ lock();
status = lua_load(L, LuaStatics::getF, &lf, h->GetName().to_charp());
if (status) {
@@ -633,8 +773,31 @@ void Lua::load(Handle * h, bool docall) throw (GeneralException) {
throw LuaException("Error loading lua chunk from Handle `" + h->GetName() + "'");
}
+ if (docall) {
+ call();
+ unlock();
+ }
+}
+
+void Lua::load(const String & s, bool docall) throw (GeneralException) {
+ const char * buf = s.to_charp();
+ int status;
+
if (docall)
+ lock();
+
+ status = luaL_loadbuffer(L, buf, s.strlen(), buf);
+
+ if (status) {
+ push_lua_context();
+ showerror();
+ throw LuaException("Error loading lua string `" + s + "'");
+ }
+
+ if (docall) {
call();
+ unlock();
+ }
}
extern "C" void luacmain(lua_State * L, int stripping, lua_Chunkwriter w, void * uD);
@@ -754,16 +917,80 @@ void Lua::dumpvars_r(Handle * h, int i, int depth) throw (GeneralException) {
}
}
-Lua * Lua::thread() {
- return new Lua(lua_newthread(L));
+Lua * Lua::thread(bool saveit) {
+ lua_State * L1 = lua_newthread(L);
+ Lua * Lt = find(L1);
+ if (saveit) {
+ push("BLUA_THREADS"); // -2 = thread, -1 = "BLUA_THREADS"
+ copy(); // -3 = thread, -2 = "BLUA_THREADS", -1 = "BLUA_THREADS"
+ gettable(LUA_REGISTRYINDEX); // -3 = thread, -2 = "BLUA_THREADS", -1 = BLUA_THREADS
+ push((lua_Number) (int) (void *) Lt); // -4 = thread, -3 = "BLUA_THREADS", -2 = BLUA_THREADS, -1 = key-Lt
+ copy(-4); // -5 = thread, -4 = "BLUA_THREADS", -3 = BLUA_THREADS, -2 = key-Lt, -1 = thread
+ settable(); // -3 = thread, -2 = "BLUA_THREADS", -1 = BLUA_THREADS
+ settable(LUA_REGISTRYINDEX); // -1 = thread
+ }
+ return Lt;
}
-int Lua::yield(int nargs) {
- return lua_yield(L, nargs);
+Lua * Lua::thread(const String & code, int nargs, bool saveit) {
+ Lua * L1;
+ L1 = thread(saveit);
+ L1->resume(code, nargs);
+ return L1;
}
-int Lua::resume(int nresults) {
- return lua_resume(L, nresults);
+Lua * Lua::thread(Handle * h, int nargs, bool saveit) {
+ Lua * L1;
+ L1 = thread(saveit);
+ L1->resume(h, nargs);
+ return L1;
+}
+
+int Lua::yield(int nresults) {
+ return lua_yield(L, nresults);
+}
+
+void Lua::resume(int nargs) throw (GeneralException) {
+ int r;
+
+ lock();
+ _protected = true;
+ r = lua_resume(L, nargs);
+ _protected = false;
+
+ if (r != 0) {
+ push_lua_context();
+ showerror();
+ }
+
+ unlock();
+
+ switch(r) {
+ case 0:
+ return;
+ case LUA_ERRRUN:
+ throw LuaException("Runtime error while running LUA code.");
+ case LUA_ERRMEM:
+ throw LuaException("Memory allocation error while running LUA code.");
+ case LUA_ERRERR:
+ throw LuaException("Error in Error function.");
+ default:
+ throw LuaException("Unknow error while running LUA code.");
+ }
+}
+
+void Lua::resume(Handle * h, int nargs) {
+ lock();
+ load(h, false);
+ resume(nargs);
+ unlock();
+}
+
+void Lua::resume(const String & s, int nargs) {
+ lock();
+ load(s, false);
+ resume(nargs);
+ unlock();
}
Lua * Lua::find(lua_State * __L) throw (GeneralException) {
@@ -835,24 +1062,50 @@ void Lua::do_break() {
lua_break(L);
}
+void Lua::lock() {
+}
+
+void Lua::unlock() {
+}
+
+void Lua::openlib(const String & libname, const luaL_reg *l, int nup) {
+ luaL_openlib(L, libname.to_charp(), l, nup);
+}
+
+void Lua::setgcthreshold(int newthreshold) {
+ lua_setgcthreshold(L, newthreshold);
+}
+
+int Lua::getgcthreshold() {
+ return lua_getgcthreshold(L);
+}
+
+int Lua::getgccount() {
+ return lua_getgccount(L);
+}
+
void LuaObject::push(Lua * L) throw (GeneralException) {
if (pushed && wantdestruct) {
throw GeneralException("Error: object is owned by the LUA script and can not be pushed.");
}
+ L->lock();
L->newtable();
pushmembers(L);
+ L->unlock();
pushed = true;
}
void LuaObject::pushme(Lua * L, void * o, bool obj) {
void ** u;
bool * b;
+ L->lock();
L->push("__obj");
u = (void **) L->newuser(sizeof(o) + sizeof(bool));
*u = o;
b = (bool *) (u + 1);
*b = obj;
L->settable(-3, true);
+ L->unlock();
}
void * LuaObject::getme(Lua * L, int i) {
@@ -876,12 +1129,15 @@ void * LuaObject::getme(Lua * L, int i) {
}
void LuaObject::pushit(Lua * L, const String & s, lua_CFunction f) {
+ L->lock();
L->push(s);
L->push(f);
L->settable(-3, true);
+ L->unlock();
}
void LuaObject::pushmeta(Lua * L, const String & s, lua_CFunction f) {
+ L->lock();
if (!L->getmetatable()) {
L->newtable();
}
@@ -889,71 +1145,21 @@ void LuaObject::pushmeta(Lua * L, const String & s, lua_CFunction f) {
L->push(f);
L->settable();
L->setmetatable();
-}
-
-int LuaStatics::callwrap(lua_State * __L, lua_CFunction func) {
- Lua * L = Lua::find(__L);
- int n;
-
- try {
- n = func(__L);
- }
- catch (LuaException e) {
- L->error(String("LuaException: ") + e.GetMsg());
- }
- catch (GeneralException e) {
- L->error(String("GeneralException: ") + e.GetMsg());
- }
-
- return n;
-}
-
-int LuaStatics::collector(lua_State * __L) {
- Lua * L = Lua::find(__L);
- void ** u = (void **) L->touserdata();
- bool * obj = (bool *) (u + 1);
-// printm(M_INFO, "From LUA: collecting object\n");
- if (*obj) {
-// printm(M_INFO, "Is object at %p\n", *u);
- Base * b = (Base *) *u;
- delete b;
- } else {
-// printm(M_INFO, "Is struct at %p\n", *u);
- free(*u);
- }
- *u = 0;
- return 0;
-}
-
-int LuaStatics::destructor(lua_State * __L) {
- Lua * L = Lua::find(__L);
- Base * b = (Base *) LuaObject::getme(L);
- delete b;
- L->push("__obj");
- L->gettable(-2, true);
- void ** u = (void **) L->touserdata();
- bool * obj = (bool *) (u + 1);
- if (*obj) {
- Base * b = (Base *) *u;
- delete b;
- } else {
- free(*u);
- }
- *u = 0;
- L->pop();
- return 0;
+ L->unlock();
}
void LuaObject::pushdestruct(Lua * L) throw (GeneralException) {
if (pushed) {
throw GeneralException("Error: can't push destructor, object already pushed");
}
+ L->lock();
push(L);
L->push("__obj");
L->gettable(-2, true);
pushmeta(L, "__gc", LuaStatics::collector);
L->pop();
pushit(L, "destroy", LuaStatics::destructor);
+ L->unlock();
wantdestruct = true;
}