lthreadlib.c 3.2 KB
Newer Older
1 2 3
#include <lua.h>
#include <lauxlib.h>

4 5 6 7 8 9
#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM == 501
#include "compat-5.2.h"
#endif

#include "openbuslua.h"

10

11 12
#if defined(_WIN32)

13 14 15
#include <errno.h>
#include <process.h>

16
static int newthread(void (__cdecl *func) (void *), void *data) {
17 18 19 20 21
  uintptr_t res = _beginthread(func, 0, data);
  if (res == -1L) return errno;
	return 0;
}

22
static const char *geterrmsg(int code) {
23 24 25 26 27 28 29 30
  switch (code) {
    case EAGAIN: return "too many threads";
    case EINVAL: return "stack size is incorrect";
    case EACCES: return "insufficient resources";    
  }
	return "unexpected error";
}

31
static void luathread (void *data)
32 33 34 35 36
{
	lua_State *L = (lua_State *)data;
	int status = openbuslua_call(L, 1, 0);
	openbuslua_report(L, status);
}
37 38 39 40 41 42 43

#else

#include <pthread.h>
#include <errno.h>
#include <string.h>

44
static int newthread(void *(*func) (void *), void *data) {
45 46 47 48 49 50
	pthread_t thread;
	int res = pthread_create(&thread, NULL, func, data);
	if (res) return errno;
	return 0;
}

51
static const char *geterrmsg(int code) {
52 53 54
	return strerror(code);
}

55
static void *luathread (void *data)
56 57 58 59 60 61 62
{
	lua_State *L = (lua_State *)data;
	int status = openbuslua_call(L, 1, 0);
	openbuslua_report(L, status);
	pthread_exit(NULL);
}

63 64 65
#endif


66
static void copypreload (lua_State *from, lua_State *to)
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
{
	/* table is in the stack at index 't' */
#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM > 501
	luaL_getsubtable(from, LUA_REGISTRYINDEX, "_PRELOAD");
	luaL_getsubtable(to, LUA_REGISTRYINDEX, "_PRELOAD");
#else
	luaL_findtable(from, LUA_GLOBALSINDEX, "package.preload", 1);
	luaL_findtable(to, LUA_GLOBALSINDEX, "package.preload", 1);
#endif
	lua_pushnil(from);  /* first key */
	while (lua_next(from, -2) != 0) {
		const char *name = lua_tostring(from, -2);
		lua_CFunction func = lua_tocfunction(from, -1);
		lua_getfield(to, -1, name);
		if (lua_isnil(to, -1) && name != NULL && func != NULL) {
			lua_pushcfunction(to, func);
			lua_setfield(to, -3, name);
		}
		lua_pop(from, 1);  /* pop value and leave key for next iteration */
		lua_pop(to, 1);  /* pop value of '_PRELOAD[modname]' */
	}
	lua_pop(from, 1);  /* pop '_PRELOAD' table */
	lua_pop(to, 1);  /* pop '_PRELOAD' table */
}

static int l_spawn (lua_State *L)
{
	int status = LUA_OK;
	size_t codelen;
	const char *code = luaL_checklstring(L, 1, &codelen);
	lua_State *newL = luaL_newstate();  /* create state */
	if (newL == NULL) luaL_error(L, "not enough memory");
	lua_getfield(L, LUA_REGISTRYINDEX, "OPENBUS_DEBUG");
	status = openbuslua_init(newL, 0, !lua_isnil(L, -1));
	if (status == LUA_OK) {
102
		copypreload(L, newL);
103 104
		status = luaL_loadbuffer(newL, code, codelen, code);
		if (status == LUA_OK) {
105
			int res = newthread(luathread, newL);
106
			if (res) {
107
				const char *errmsg = geterrmsg(errno);
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
				lua_close(newL);
				luaL_error(L, "unable to start thread (error=%s)", errmsg);
			}
		}
	}
	if (status != LUA_OK && !lua_isnil(newL, -1)) {
		const char *msg = lua_tostring(newL, -1);
		if (msg == NULL) msg = "(error object is not a string)";
		lua_pushstring(L, msg);
		lua_close(newL);
		lua_error(L);
	}
	return 0;
}

static const luaL_Reg funcs[] = {
  {"spawn", l_spawn},
  {NULL, NULL}
};


LUAMOD_API int luaopen_openbus_util_thread (lua_State *L) {
	luaL_newlib(L, funcs);
	return 1;
}