Cleanup child Lua State after joining the child thread.

master
Robert G. Jakabosky 14 years ago
parent 010f18486e
commit 2a68693f07

@ -126,6 +126,7 @@ typedef void (*dyn_caster_t)(void **obj, obj_type **type);
#define OBJ_TYPE_FLAG_WEAK_REF (1<<0) #define OBJ_TYPE_FLAG_WEAK_REF (1<<0)
#define OBJ_TYPE_SIMPLE (1<<1) #define OBJ_TYPE_SIMPLE (1<<1)
#define OBJ_TYPE_IMPORT (1<<2)
struct obj_type { struct obj_type {
dyn_caster_t dcaster; /**< caster to support casting to sub-objects. */ dyn_caster_t dcaster; /**< caster to support casting to sub-objects. */
int32_t id; /**< type's id. */ int32_t id; /**< type's id. */
@ -180,6 +181,11 @@ typedef enum {
REG_META, REG_META,
} module_reg_type; } module_reg_type;
typedef struct reg_impl {
const char *if_name;
const void *impl;
} reg_impl;
typedef struct reg_sub_module { typedef struct reg_sub_module {
obj_type *type; obj_type *type;
module_reg_type req_type; module_reg_type req_type;
@ -189,6 +195,7 @@ typedef struct reg_sub_module {
const obj_base *bases; const obj_base *bases;
const obj_field *fields; const obj_field *fields;
const obj_const *constants; const obj_const *constants;
const reg_impl *implements;
int bidirectional_consts; int bidirectional_consts;
} reg_sub_module; } reg_sub_module;
@ -295,6 +302,7 @@ static const char *nobj_lua_Reader(lua_State *L, void *data, size_t *size) {
nobj_reader_state *state = (nobj_reader_state *)data; nobj_reader_state *state = (nobj_reader_state *)data;
const char *ptr; const char *ptr;
(void)L;
ptr = state->ffi_init_code[state->offset]; ptr = state->ffi_init_code[state->offset];
if(ptr != NULL) { if(ptr != NULL) {
*size = strlen(ptr); *size = strlen(ptr);
@ -338,6 +346,183 @@ static int nobj_try_loading_ffi(lua_State *L, const char *ffi_mod_name,
} }
#endif #endif
typedef struct {
void *impl;
void *obj;
} obj_implement;
static FUNC_UNUSED void *obj_implement_luaoptional(lua_State *L, int _index, void **impl, char *if_name) {
void *ud;
if(lua_isnoneornil(L, _index)) {
return NULL;
}
/* get the implements table for this interface. */
lua_pushlightuserdata(L, if_name);
lua_rawget(L, LUA_REGISTRYINDEX);
/* get pointer to userdata value & check if it is a userdata value. */
ud = (obj_implement *)lua_touserdata(L, _index);
if(ud != NULL) {
/* get the userdata's metatable */
if(lua_getmetatable(L, _index)) {
/* lookup metatable in interface table for this object's implementation of the interface. */
lua_gettable(L, -2);
} else {
/* no metatable. */
goto no_interface;
}
#if LUAJIT_FFI
} else if(nobj_ffi_support_enabled_hint) { /* handle cdata. */
/* get cdata interface check function from interface table. */
lua_getfield(L, -1, "cdata");
if(lua_isfunction(L, -1)) {
/* pass cdata to function, return value should be an implmentation. */
lua_pushvalue(L, _index);
lua_call(L, 1, 1);
/* get pointer to cdata. */
ud = (void *)lua_topointer(L, _index);
} else {
lua_pop(L, 1); /* pop non-function. */
goto no_interface;
}
#endif
} else {
goto no_interface;
}
if(!lua_isnil(L, -1)) {
*impl = lua_touserdata(L, -1);
lua_pop(L, 2); /* pop interface table & implementation. */
/* object implements interface. */
return ud;
} else {
lua_pop(L, 1); /* pop nil. */
}
no_interface:
lua_pop(L, 1); /* pop interface table. */
return NULL;
}
static FUNC_UNUSED void *obj_implement_luacheck(lua_State *L, int _index, void **impl, char *type) {
void *ud = obj_implement_luaoptional(L, _index, impl, type);
if(ud == NULL) {
#define ERROR_BUFFER_SIZE 256
char buf[ERROR_BUFFER_SIZE];
snprintf(buf, ERROR_BUFFER_SIZE-1,"Expected object with %s interface", type);
/* value doesn't implement this interface. */
luaL_argerror(L, _index, buf);
}
return ud;
}
/* use static pointer as key to interfaces table. (version 1.0) */
static char obj_interfaces_table_key[] = "obj_interfaces<1.0>_table_key";
static void obj_get_global_interfaces_table(lua_State *L) {
/* get global interfaces table. */
lua_getfield(L, LUA_REGISTRYINDEX, obj_interfaces_table_key);
if(lua_isnil(L, -1)) {
/* Need to create global interfaces table. */
lua_pop(L, 1); /* pop nil */
lua_createtable(L, 0, 4); /* 0 size array part, small hash part. */
lua_pushvalue(L, -1); /* dup table. */
/* store interfaces table in Lua registery. */
lua_setfield(L, LUA_REGISTRYINDEX, obj_interfaces_table_key);
}
}
static void obj_get_interface(lua_State *L, const char *name, int global_if_tab) {
/* get a interface's implementation table */
lua_getfield(L, global_if_tab, name);
if(lua_isnil(L, -1)) {
lua_pop(L, 1); /* pop nil */
/* new interface. (i.e. no object implement it yet.)
*
* create an empty table for this interface that will be used when an
* implementation is registered for this interface.
*/
lua_createtable(L, 0, 2); /* 0 size array part, small hash part. */
lua_pushvalue(L, -1); /* dup table. */
lua_setfield(L, global_if_tab, name); /* store interface in global interfaces table. */
}
}
static int obj_get_userdata_interface(lua_State *L) {
/* get the userdata's metatable */
if(lua_getmetatable(L, 2)) {
/* lookup metatable in interface table for the userdata's implementation of the interface. */
lua_gettable(L, 1);
if(!lua_isnil(L, -1)) {
/* return the implementation. */
return 1;
}
}
/* no metatable or no implementation. */
return 0;
}
static void obj_interface_register(lua_State *L, char *name, int global_if_tab) {
/* get the table of implementations for this interface. */
obj_get_interface(L, name, global_if_tab);
/* check for 'userdata' function. */
lua_getfield(L, -1, "userdata");
if(lua_isnil(L, -1)) {
lua_pop(L, 1); /* pop nil. */
/* add C function for getting a userdata's implementation. */
lua_pushcfunction(L, obj_get_userdata_interface);
lua_setfield(L, -2, "userdata");
} else {
/* already have function. */
lua_pop(L, 1); /* pop C function. */
}
/* we are going to use a lightuserdata pointer for fast lookup of the interface's impl. table. */
lua_pushlightuserdata(L, name);
lua_insert(L, -2);
lua_settable(L, LUA_REGISTRYINDEX);
}
static void obj_register_interfaces(lua_State *L, char *interfaces[]) {
int i;
int if_tab;
/* get global interfaces table. */
obj_get_global_interfaces_table(L);
if_tab = lua_gettop(L);
for(i = 0; interfaces[i] != NULL ; i++) {
obj_interface_register(L, interfaces[i], if_tab);
}
lua_pop(L, 1); /* pop global interfaces table. */
}
static void obj_type_register_implement(lua_State *L, const reg_impl *impl, int global_if_tab, int mt_tab) {
/* get the table of implementations for this interface. */
obj_get_interface(L, impl->if_name, global_if_tab);
/* register object's implement in the interface table. */
lua_pushvalue(L, mt_tab);
lua_pushlightuserdata(L, (void *)impl->impl);
lua_settable(L, -3);
lua_pop(L, 1); /* pop inteface table. */
}
static void obj_type_register_implements(lua_State *L, const reg_impl *impls) {
int if_tab;
int mt_tab;
/* get absolute position of object's metatable. */
mt_tab = lua_gettop(L);
/* get global interfaces table. */
obj_get_global_interfaces_table(L);
if_tab = lua_gettop(L);
for(; impls->if_name != NULL ; impls++) {
obj_type_register_implement(L, impls, if_tab, mt_tab);
}
lua_pop(L, 1); /* pop global interfaces table. */
}
#ifndef REG_PACKAGE_IS_CONSTRUCTOR #ifndef REG_PACKAGE_IS_CONSTRUCTOR
#define REG_PACKAGE_IS_CONSTRUCTOR 1 #define REG_PACKAGE_IS_CONSTRUCTOR 1
#endif #endif
@ -354,6 +539,48 @@ static int nobj_try_loading_ffi(lua_State *L, const char *ffi_mod_name,
#define OBJ_DATA_HIDDEN_METATABLE 1 #define OBJ_DATA_HIDDEN_METATABLE 1
#endif #endif
static FUNC_UNUSED int obj_import_external_type(lua_State *L, obj_type *type) {
/* find the external type's metatable using it's name. */
lua_pushstring(L, type->name);
lua_rawget(L, LUA_REGISTRYINDEX); /* external type's metatable. */
if(!lua_isnil(L, -1)) {
/* found it. Now we will map our 'type' pointer to the metatable. */
/* REGISTERY[lightuserdata<type>] = REGISTERY[type->name] */
lua_pushlightuserdata(L, type); /* use our 'type' pointer as lookup key. */
lua_pushvalue(L, -2); /* dup. type's metatable. */
lua_rawset(L, LUA_REGISTRYINDEX); /* save external type's metatable. */
/* NOTE: top of Lua stack still has the type's metatable. */
return 1;
} else {
lua_pop(L, 1); /* pop nil. */
}
return 0;
}
static FUNC_UNUSED int obj_import_external_ffi_type(lua_State *L, obj_type *type) {
/* find the external type's metatable using it's name. */
lua_pushstring(L, type->name);
lua_rawget(L, LUA_REGISTRYINDEX); /* external type's metatable. */
if(!lua_isnil(L, -1)) {
/* found it. Now we will map our 'type' pointer to the C check function. */
/* _priv_table[lightuserdata<type>] = REGISTERY[type->name].c_check */
lua_getfield(L, -1, "c_check");
lua_remove(L, -2); /* remove metatable. */
if(lua_isfunction(L, -1)) {
lua_pushlightuserdata(L, type); /* use our 'type' pointer as lookup key. */
lua_pushvalue(L, -2); /* dup. check function */
lua_rawset(L, -4); /* save check function to module's private table. */
/* NOTE: top of Lua stack still has the type's C check function. */
return 1;
} else {
lua_pop(L, 1); /* pop non function value. */
}
} else {
lua_pop(L, 1); /* pop nil. */
}
return 0;
}
static FUNC_UNUSED obj_udata *obj_udata_toobj(lua_State *L, int _index) { static FUNC_UNUSED obj_udata *obj_udata_toobj(lua_State *L, int _index) {
obj_udata *ud; obj_udata *ud;
size_t len; size_t len;
@ -377,10 +604,23 @@ static FUNC_UNUSED int obj_udata_is_compatible(lua_State *L, obj_udata *ud, void
obj_type *ud_type; obj_type *ud_type;
lua_pushlightuserdata(L, type); lua_pushlightuserdata(L, type);
lua_rawget(L, LUA_REGISTRYINDEX); /* type's metatable. */ lua_rawget(L, LUA_REGISTRYINDEX); /* type's metatable. */
recheck_metatable:
if(lua_rawequal(L, -1, -2)) { if(lua_rawequal(L, -1, -2)) {
*obj = ud->obj; *obj = ud->obj;
/* same type no casting needed. */ /* same type no casting needed. */
return 1; return 1;
} else if(lua_isnil(L, -1)) {
lua_pop(L, 1); /* pop nil. */
if((type->flags & OBJ_TYPE_IMPORT) == 0) {
/* can't resolve internal type. */
luaL_error(L, "Unknown object type(id=%d, name=%s)", type->id, type->name);
}
/* try to import external type. */
if(obj_import_external_type(L, type)) {
/* imported type, re-try metatable check. */
goto recheck_metatable;
}
/* External type not yet available, so the object can't be compatible. */
} else { } else {
/* Different types see if we can cast to the required type. */ /* Different types see if we can cast to the required type. */
lua_rawgeti(L, -2, type->id); lua_rawgeti(L, -2, type->id);
@ -433,7 +673,7 @@ static FUNC_UNUSED obj_udata *obj_udata_luacheck_internal(lua_State *L, int _ind
return ud; return ud;
} }
} }
} else { } else if(!lua_isnoneornil(L, _index)) {
/* handle cdata. */ /* handle cdata. */
/* get private table. */ /* get private table. */
lua_pushlightuserdata(L, obj_udata_private_key); lua_pushlightuserdata(L, obj_udata_private_key);
@ -442,16 +682,30 @@ static FUNC_UNUSED obj_udata *obj_udata_luacheck_internal(lua_State *L, int _ind
lua_pushlightuserdata(L, type); lua_pushlightuserdata(L, type);
lua_rawget(L, -2); lua_rawget(L, -2);
/* pass cdata value to type checking function. */ /* check for function. */
lua_pushvalue(L, _index);
lua_call(L, 1, 1);
if(!lua_isnil(L, -1)) { if(!lua_isnil(L, -1)) {
/* valid type get pointer from cdata. */ got_check_func:
/* pass cdata value to type checking function. */
lua_pushvalue(L, _index);
lua_call(L, 1, 1);
if(!lua_isnil(L, -1)) {
/* valid type get pointer from cdata. */
lua_pop(L, 2);
*obj = *(void **)lua_topointer(L, _index);
return ud;
}
lua_pop(L, 2); lua_pop(L, 2);
*obj = *(void **)lua_topointer(L, _index); } else {
return ud; lua_pop(L, 1); /* pop nil. */
if(type->flags & OBJ_TYPE_IMPORT) {
/* try to import external ffi type. */
if(obj_import_external_ffi_type(L, type)) {
/* imported type. */
goto got_check_func;
}
/* External type not yet available, so the object can't be compatible. */
}
} }
lua_pop(L, 2);
} }
if(not_delete) { if(not_delete) {
luaL_typerror(L, _index, type->name); /* is not a userdata value. */ luaL_typerror(L, _index, type->name); /* is not a userdata value. */
@ -467,7 +721,7 @@ static FUNC_UNUSED void *obj_udata_luacheck(lua_State *L, int _index, obj_type *
static FUNC_UNUSED void *obj_udata_luaoptional(lua_State *L, int _index, obj_type *type) { static FUNC_UNUSED void *obj_udata_luaoptional(lua_State *L, int _index, obj_type *type) {
void *obj = NULL; void *obj = NULL;
if(lua_isnil(L, _index)) { if(lua_isnoneornil(L, _index)) {
return obj; return obj;
} }
obj_udata_luacheck_internal(L, _index, &(obj), type, 1); obj_udata_luacheck_internal(L, _index, &(obj), type, 1);
@ -482,6 +736,9 @@ static FUNC_UNUSED void *obj_udata_luadelete(lua_State *L, int _index, obj_type
/* null userdata. */ /* null userdata. */
ud->obj = NULL; ud->obj = NULL;
ud->flags = 0; ud->flags = 0;
/* clear the metatable in invalidate userdata. */
lua_pushnil(L);
lua_setmetatable(L, _index);
return obj; return obj;
} }
@ -529,6 +786,9 @@ static FUNC_UNUSED void *obj_udata_luadelete_weak(lua_State *L, int _index, obj_
/* null userdata. */ /* null userdata. */
ud->obj = NULL; ud->obj = NULL;
ud->flags = 0; ud->flags = 0;
/* clear the metatable in invalidate userdata. */
lua_pushnil(L);
lua_setmetatable(L, _index);
/* get objects weak table. */ /* get objects weak table. */
lua_pushlightuserdata(L, obj_udata_weak_ref_key); lua_pushlightuserdata(L, obj_udata_weak_ref_key);
lua_rawget(L, LUA_REGISTRYINDEX); /* weak ref table. */ lua_rawget(L, LUA_REGISTRYINDEX); /* weak ref table. */
@ -646,12 +906,26 @@ static FUNC_UNUSED void * obj_simple_udata_luacheck(lua_State *L, int _index, ob
if(lua_getmetatable(L, _index)) { if(lua_getmetatable(L, _index)) {
lua_pushlightuserdata(L, type); lua_pushlightuserdata(L, type);
lua_rawget(L, LUA_REGISTRYINDEX); /* type's metatable. */ lua_rawget(L, LUA_REGISTRYINDEX); /* type's metatable. */
recheck_metatable:
if(lua_rawequal(L, -1, -2)) { if(lua_rawequal(L, -1, -2)) {
lua_pop(L, 2); /* pop both metatables. */ lua_pop(L, 2); /* pop both metatables. */
return ud; return ud;
} else if(lua_isnil(L, -1)) {
lua_pop(L, 1); /* pop nil. */
if((type->flags & OBJ_TYPE_IMPORT) == 0) {
/* can't resolve internal type. */
luaL_error(L, "Unknown object type(id=%d, name=%s)", type->id, type->name);
}
/* try to import external type. */
if(obj_import_external_type(L, type)) {
/* imported type, re-try metatable check. */
goto recheck_metatable;
}
/* External type not yet available, so the object can't be compatible. */
return 0;
} }
} }
} else { } else if(!lua_isnoneornil(L, _index)) {
/* handle cdata. */ /* handle cdata. */
/* get private table. */ /* get private table. */
lua_pushlightuserdata(L, obj_udata_private_key); lua_pushlightuserdata(L, obj_udata_private_key);
@ -660,22 +934,34 @@ static FUNC_UNUSED void * obj_simple_udata_luacheck(lua_State *L, int _index, ob
lua_pushlightuserdata(L, type); lua_pushlightuserdata(L, type);
lua_rawget(L, -2); lua_rawget(L, -2);
/* pass cdata value to type checking function. */ /* check for function. */
lua_pushvalue(L, _index);
lua_call(L, 1, 1);
if(!lua_isnil(L, -1)) { if(!lua_isnil(L, -1)) {
/* valid type get pointer from cdata. */ got_check_func:
lua_pop(L, 2); /* pass cdata value to type checking function. */
return (void *)lua_topointer(L, _index); lua_pushvalue(L, _index);
lua_call(L, 1, 1);
if(!lua_isnil(L, -1)) {
/* valid type get pointer from cdata. */
lua_pop(L, 2);
return (void *)lua_topointer(L, _index);
}
} else {
if(type->flags & OBJ_TYPE_IMPORT) {
/* try to import external ffi type. */
if(obj_import_external_ffi_type(L, type)) {
/* imported type. */
goto got_check_func;
}
/* External type not yet available, so the object can't be compatible. */
}
} }
lua_pop(L, 2);
} }
luaL_typerror(L, _index, type->name); /* is not a userdata value. */ luaL_typerror(L, _index, type->name); /* is not a userdata value. */
return NULL; return NULL;
} }
static FUNC_UNUSED void * obj_simple_udata_luaoptional(lua_State *L, int _index, obj_type *type) { static FUNC_UNUSED void * obj_simple_udata_luaoptional(lua_State *L, int _index, obj_type *type) {
if(lua_isnil(L, _index)) { if(lua_isnoneornil(L, _index)) {
return NULL; return NULL;
} }
return obj_simple_udata_luacheck(L, _index, type); return obj_simple_udata_luacheck(L, _index, type);
@ -916,6 +1202,8 @@ static void obj_type_register(lua_State *L, const reg_sub_module *type_reg, int
obj_type_register_constants(L, type_reg->constants, -2, type_reg->bidirectional_consts); obj_type_register_constants(L, type_reg->constants, -2, type_reg->bidirectional_consts);
obj_type_register_implements(L, type_reg->implements);
lua_pushliteral(L, "__index"); lua_pushliteral(L, "__index");
lua_pushvalue(L, -3); /* dup methods table */ lua_pushvalue(L, -3); /* dup methods table */
lua_rawset(L, -3); /* metatable.__index = methods */ lua_rawset(L, -3); /* metatable.__index = methods */
@ -934,6 +1222,80 @@ static FUNC_UNUSED int lua_checktype_ref(lua_State *L, int _index, int _type) {
return luaL_ref(L, LUA_REGISTRYINDEX); return luaL_ref(L, LUA_REGISTRYINDEX);
} }
/* use static pointer as key to weak callback_state table. */
static char obj_callback_state_weak_ref_key[] = "obj_callback_state_weak_ref_key";
static FUNC_UNUSED void *nobj_get_callback_state(lua_State *L, int owner_idx, int size) {
void *cb_state;
lua_pushlightuserdata(L, obj_callback_state_weak_ref_key); /* key for weak table. */
lua_rawget(L, LUA_REGISTRYINDEX); /* check if weak table exists already. */
if(lua_isnil(L, -1)) {
lua_pop(L, 1); /* pop nil. */
/* create weak table for callback_state */
lua_newtable(L); /* weak table. */
lua_newtable(L); /* metatable for weak table. */
lua_pushliteral(L, "__mode");
lua_pushliteral(L, "k");
lua_rawset(L, -3); /* metatable.__mode = 'k' weak keys. */
lua_setmetatable(L, -2); /* add metatable to weak table. */
lua_pushlightuserdata(L, obj_callback_state_weak_ref_key); /* key for weak table. */
lua_pushvalue(L, -2); /* dup weak table. */
lua_rawset(L, LUA_REGISTRYINDEX); /* add weak table to registry. */
}
/* check weak table for callback_state. */
lua_pushvalue(L, owner_idx); /* dup. owner as lookup key. */
lua_rawget(L, -2);
if(lua_isnil(L, -1)) {
lua_pop(L, 1); /* pop nil. */
lua_pushvalue(L, owner_idx); /* dup. owner as lookup key. */
/* create new callback state. */
cb_state = lua_newuserdata(L, size);
lua_rawset(L, -3);
lua_pop(L, 1); /* pop <weak table> */
} else {
/* got existing callback state. */
cb_state = lua_touserdata(L, -1);
lua_pop(L, 2); /* pop <weak table>, <callback_state> */
}
return cb_state;
}
static FUNC_UNUSED void *nobj_delete_callback_state(lua_State *L, int owner_idx) {
void *cb_state = NULL;
lua_pushlightuserdata(L, obj_callback_state_weak_ref_key); /* key for weak table. */
lua_rawget(L, LUA_REGISTRYINDEX); /* check if weak table exists already. */
if(lua_isnil(L, -1)) {
lua_pop(L, 1); /* pop nil. no weak table, so there is no callback state. */
return NULL;
}
/* get callback state. */
lua_pushvalue(L, owner_idx); /* dup. owner */
lua_rawget(L, -2);
if(lua_isnil(L, -1)) {
lua_pop(L, 2); /* pop <weak table>, nil. No callback state for the owner. */
} else {
cb_state = lua_touserdata(L, -1);
lua_pop(L, 1); /* pop <state> */
/* remove callback state. */
lua_pushvalue(L, owner_idx); /* dup. owner */
lua_pushnil(L);
lua_rawset(L, -3);
lua_pop(L, 1); /* pop <weak table> */
}
return cb_state;
}
static char *obj_interfaces[] = {
NULL,
};
#define obj_type_Lua_LLThread_check(L, _index) \ #define obj_type_Lua_LLThread_check(L, _index) \
@ -1056,13 +1418,19 @@ static Lua_LLThread *llthread_new() {
return this; return this;
} }
static void llthread_cleanup_child(Lua_LLThread *this) {
if(this->child) {
llthread_child_destroy(this->child);
this->child = NULL;
}
}
static void llthread_destroy(Lua_LLThread *this) { static void llthread_destroy(Lua_LLThread *this) {
/* We still own the child thread object iff the thread was not started or /* We still own the child thread object iff the thread was not started or
* we have joined the thread. * we have joined the thread.
*/ */
if((this->state & TSTATE_JOINED) == TSTATE_JOINED || this->state == TSTATE_NONE) { if((this->state & TSTATE_JOINED) == TSTATE_JOINED || this->state == TSTATE_NONE) {
if(this->child) llthread_child_destroy(this->child); llthread_cleanup_child(this);
this->child = NULL;
} }
free(this); free(this);
} }
@ -1116,6 +1484,7 @@ static int llthread_start(Lua_LLThread *this, int start_detached) {
this->state = TSTATE_STARTED; this->state = TSTATE_STARTED;
if(start_detached) { if(start_detached) {
this->state |= TSTATE_DETACHED; this->state |= TSTATE_DETACHED;
this->child = NULL;
} }
} }
#else #else
@ -1124,6 +1493,7 @@ static int llthread_start(Lua_LLThread *this, int start_detached) {
this->state = TSTATE_STARTED; this->state = TSTATE_STARTED;
if(start_detached) { if(start_detached) {
this->state |= TSTATE_DETACHED; this->state |= TSTATE_DETACHED;
this->child = NULL;
rc = pthread_detach(this->thread); rc = pthread_detach(this->thread);
} }
} }
@ -1137,17 +1507,16 @@ static int llthread_join(Lua_LLThread *this) {
/* Destroy the thread object. */ /* Destroy the thread object. */
CloseHandle( this->thread ); CloseHandle( this->thread );
this->state |= TSTATE_JOINED;
return 0; return 0;
#else #else
Lua_LLThread_child *child;
int rc; int rc;
/* then join the thread. */ /* then join the thread. */
rc = pthread_join(this->thread, (void **)&(child)); rc = pthread_join(this->thread, NULL);
if(rc == 0) { if(rc == 0) {
this->state |= TSTATE_JOINED; this->state |= TSTATE_JOINED;
/* if the child thread returns NULL, then it freed the child object. */
this->child = child;
} }
return rc; return rc;
#endif #endif
@ -1341,9 +1710,10 @@ static Lua_LLThread *llthread_create(lua_State *L, const char *code, size_t code
/* method: _priv */ /* method: _priv */
static int Lua_LLThread__delete__meth(lua_State *L) { static int Lua_LLThread__delete__meth(lua_State *L) {
int this_flags_idx1 = 0; int this_flags_idx1 = 0;
Lua_LLThread * this_idx1 = obj_type_Lua_LLThread_delete(L,1,&(this_flags_idx1)); Lua_LLThread * this_idx1;
Lua_LLThread_child *child; Lua_LLThread_child *child;
this_idx1 = obj_type_Lua_LLThread_delete(L,1,&(this_flags_idx1));
if(!(this_flags_idx1 & OBJ_UDATA_FLAG_OWN)) { return 0; } if(!(this_flags_idx1 & OBJ_UDATA_FLAG_OWN)) { return 0; }
/* if the thread has been started and has not been detached/joined. */ /* if the thread has been started and has not been detached/joined. */
if((this_idx1->state & TSTATE_STARTED) == TSTATE_STARTED && if((this_idx1->state & TSTATE_STARTED) == TSTATE_STARTED &&
@ -1364,12 +1734,14 @@ static int Lua_LLThread__delete__meth(lua_State *L) {
/* method: start */ /* method: start */
static int Lua_LLThread__start__meth(lua_State *L) { static int Lua_LLThread__start__meth(lua_State *L) {
Lua_LLThread * this_idx1 = obj_type_Lua_LLThread_check(L,1); Lua_LLThread * this_idx1;
bool start_detached_idx2 = lua_toboolean(L,2); bool start_detached_idx2;
bool res_idx1 = 0; bool res_idx1 = 0;
char buf[ERROR_LEN]; char buf[ERROR_LEN];
int rc; int rc;
this_idx1 = obj_type_Lua_LLThread_check(L,1);
start_detached_idx2 = lua_toboolean(L,2);
if(this_idx1->state != TSTATE_NONE) { if(this_idx1->state != TSTATE_NONE) {
lua_pushboolean(L, 0); /* false */ lua_pushboolean(L, 0); /* false */
lua_pushliteral(L, "Thread already started."); lua_pushliteral(L, "Thread already started.");
@ -1389,7 +1761,7 @@ static int Lua_LLThread__start__meth(lua_State *L) {
/* method: join */ /* method: join */
static int Lua_LLThread__join__meth(lua_State *L) { static int Lua_LLThread__join__meth(lua_State *L) {
Lua_LLThread * this_idx1 = obj_type_Lua_LLThread_check(L,1); Lua_LLThread * this_idx1;
bool res_idx1 = 0; bool res_idx1 = 0;
const char * err_msg_idx2 = NULL; const char * err_msg_idx2 = NULL;
Lua_LLThread_child *child; Lua_LLThread_child *child;
@ -1397,6 +1769,7 @@ static int Lua_LLThread__join__meth(lua_State *L) {
int top; int top;
int rc; int rc;
this_idx1 = obj_type_Lua_LLThread_check(L,1);
if((this_idx1->state & TSTATE_STARTED) == 0) { if((this_idx1->state & TSTATE_STARTED) == 0) {
lua_pushboolean(L, 0); /* false */ lua_pushboolean(L, 0); /* false */
lua_pushliteral(L, "Can't join a thread that hasn't be started."); lua_pushliteral(L, "Can't join a thread that hasn't be started.");
@ -1422,19 +1795,21 @@ static int Lua_LLThread__join__meth(lua_State *L) {
const char *err_msg = lua_tostring(child->L, -1); const char *err_msg = lua_tostring(child->L, -1);
lua_pushboolean(L, 0); lua_pushboolean(L, 0);
lua_pushfstring(L, "Error from child thread: %s", err_msg); lua_pushfstring(L, "Error from child thread: %s", err_msg);
return 2; top = 2;
} else { } else {
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
top = lua_gettop(child->L);
/* return results to parent thread. */
llthread_push_results(L, child, 2, top);
} }
top = lua_gettop(child->L); llthread_cleanup_child(this_idx1);
/* return results to parent thread. */
llthread_push_results(L, child, 2, top);
return top; return top;
} else { } else {
res_idx1 = false; res_idx1 = false;
err_msg_idx2 = buf; err_msg_idx2 = buf;
strerror_r(errno, buf, ERROR_LEN); strerror_r(errno, buf, ERROR_LEN);
} }
llthread_cleanup_child(this_idx1);
lua_pushboolean(L, res_idx1); lua_pushboolean(L, res_idx1);
lua_pushstring(L, err_msg_idx2); lua_pushstring(L, err_msg_idx2);
@ -1444,9 +1819,10 @@ static int Lua_LLThread__join__meth(lua_State *L) {
/* method: new */ /* method: new */
static int llthreads__new__func(lua_State *L) { static int llthreads__new__func(lua_State *L) {
size_t lua_code_len_idx1; size_t lua_code_len_idx1;
const char * lua_code_idx1 = luaL_checklstring(L,1,&(lua_code_len_idx1)); const char * lua_code_idx1;
int this_flags_idx1 = OBJ_UDATA_FLAG_OWN; int this_flags_idx1 = OBJ_UDATA_FLAG_OWN;
Lua_LLThread * this_idx1; Lua_LLThread * this_idx1;
lua_code_idx1 = luaL_checklstring(L,1,&(lua_code_len_idx1));
this_idx1 = llthread_create(L, lua_code_idx1, lua_code_len_idx1); this_idx1 = llthread_create(L, lua_code_idx1, lua_code_len_idx1);
obj_type_Lua_LLThread_push(L, this_idx1, this_flags_idx1); obj_type_Lua_LLThread_push(L, this_idx1, this_flags_idx1);
@ -1484,6 +1860,10 @@ static const obj_const obj_Lua_LLThread_constants[] = {
{NULL, NULL, 0.0 , 0} {NULL, NULL, 0.0 , 0}
}; };
static const reg_impl obj_Lua_LLThread_implements[] = {
{NULL, NULL}
};
static const luaL_reg llthreads_function[] = { static const luaL_reg llthreads_function[] = {
{"new", llthreads__new__func}, {"new", llthreads__new__func},
{NULL, NULL} {NULL, NULL}
@ -1496,8 +1876,8 @@ static const obj_const llthreads_constants[] = {
static const reg_sub_module reg_sub_modules[] = { static const reg_sub_module reg_sub_modules[] = {
{ &(obj_type_Lua_LLThread), REG_OBJECT, obj_Lua_LLThread_pub_funcs, obj_Lua_LLThread_methods, obj_Lua_LLThread_metas, obj_Lua_LLThread_bases, obj_Lua_LLThread_fields, obj_Lua_LLThread_constants, 0}, { &(obj_type_Lua_LLThread), REG_OBJECT, obj_Lua_LLThread_pub_funcs, obj_Lua_LLThread_methods, obj_Lua_LLThread_metas, obj_Lua_LLThread_bases, obj_Lua_LLThread_fields, obj_Lua_LLThread_constants, obj_Lua_LLThread_implements, 0},
{NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0} {NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0}
}; };
@ -1543,6 +1923,9 @@ LUA_NOBJ_API int luaopen_llthreads(lua_State *L) {
const luaL_Reg *submodules = submodule_libs; const luaL_Reg *submodules = submodule_libs;
int priv_table = -1; int priv_table = -1;
/* register interfaces */
obj_register_interfaces(L, obj_interfaces);
/* private table to hold reference to object metatables. */ /* private table to hold reference to object metatables. */
lua_newtable(L); lua_newtable(L);
priv_table = lua_gettop(L); priv_table = lua_gettop(L);
@ -1584,7 +1967,7 @@ LUA_NOBJ_API int luaopen_llthreads(lua_State *L) {
#if LUAJIT_FFI #if LUAJIT_FFI
if(nobj_check_ffi_support(L)) { if(nobj_check_ffi_support(L)) {
nobj_try_loading_ffi(L, "llthreads", llthreads_ffi_lua_code, nobj_try_loading_ffi(L, "llthreads.nobj.ffi.lua", llthreads_ffi_lua_code,
llthreads_ffi_export, priv_table); llthreads_ffi_export, priv_table);
} }
#endif #endif

@ -129,13 +129,19 @@ static Lua_LLThread *llthread_new() {
return this; return this;
} }
static void llthread_cleanup_child(Lua_LLThread *this) {
if(this->child) {
llthread_child_destroy(this->child);
this->child = NULL;
}
}
static void llthread_destroy(Lua_LLThread *this) { static void llthread_destroy(Lua_LLThread *this) {
/* We still own the child thread object iff the thread was not started or /* We still own the child thread object iff the thread was not started or
* we have joined the thread. * we have joined the thread.
*/ */
if((this->state & TSTATE_JOINED) == TSTATE_JOINED || this->state == TSTATE_NONE) { if((this->state & TSTATE_JOINED) == TSTATE_JOINED || this->state == TSTATE_NONE) {
if(this->child) llthread_child_destroy(this->child); llthread_cleanup_child(this);
this->child = NULL;
} }
free(this); free(this);
} }
@ -189,6 +195,7 @@ static int llthread_start(Lua_LLThread *this, int start_detached) {
this->state = TSTATE_STARTED; this->state = TSTATE_STARTED;
if(start_detached) { if(start_detached) {
this->state |= TSTATE_DETACHED; this->state |= TSTATE_DETACHED;
this->child = NULL;
} }
} }
#else #else
@ -197,6 +204,7 @@ static int llthread_start(Lua_LLThread *this, int start_detached) {
this->state = TSTATE_STARTED; this->state = TSTATE_STARTED;
if(start_detached) { if(start_detached) {
this->state |= TSTATE_DETACHED; this->state |= TSTATE_DETACHED;
this->child = NULL;
rc = pthread_detach(this->thread); rc = pthread_detach(this->thread);
} }
} }
@ -210,17 +218,16 @@ static int llthread_join(Lua_LLThread *this) {
/* Destroy the thread object. */ /* Destroy the thread object. */
CloseHandle( this->thread ); CloseHandle( this->thread );
this->state |= TSTATE_JOINED;
return 0; return 0;
#else #else
Lua_LLThread_child *child;
int rc; int rc;
/* then join the thread. */ /* then join the thread. */
rc = pthread_join(this->thread, (void **)&(child)); rc = pthread_join(this->thread, NULL);
if(rc == 0) { if(rc == 0) {
this->state |= TSTATE_JOINED; this->state |= TSTATE_JOINED;
/* if the child thread returns NULL, then it freed the child object. */
this->child = child;
} }
return rc; return rc;
#endif #endif
@ -486,19 +493,21 @@ static Lua_LLThread *llthread_create(lua_State *L, const char *code, size_t code
const char *err_msg = lua_tostring(child->L, -1); const char *err_msg = lua_tostring(child->L, -1);
lua_pushboolean(L, 0); lua_pushboolean(L, 0);
lua_pushfstring(L, "Error from child thread: %s", err_msg); lua_pushfstring(L, "Error from child thread: %s", err_msg);
return 2; top = 2;
} else { } else {
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
top = lua_gettop(child->L);
/* return results to parent thread. */
llthread_push_results(L, child, 2, top);
} }
top = lua_gettop(child->L); llthread_cleanup_child(${this});
/* return results to parent thread. */
llthread_push_results(L, child, 2, top);
return top; return top;
} else { } else {
${res} = false; ${res} = false;
${err_msg} = buf; ${err_msg} = buf;
strerror_r(errno, buf, ERROR_LEN); strerror_r(errno, buf, ERROR_LEN);
} }
llthread_cleanup_child(${this});
]] ]]
}, },
} }

Loading…
Cancel
Save