Esempio n. 1
0
/*
 * Returns: [thread_ludata]
 */
static int
thread_init (lua_State *L)
{
    struct sys_thread *td;

    /* TLS Index */
    if (g_TLSIndex == INVALID_TLS_INDEX) {
#ifndef _WIN32
	const int res = pthread_key_create(&g_TLSIndex, NULL);
	if (res) {
	    errno = res;
	    goto err;
	}
#else
	if ((g_TLSIndex = TlsAlloc()) == INVALID_TLS_INDEX)
	    goto err;
#endif
    }
    /* VM Mutex */
    td = sys_get_thread();
    if (!td) {
	if (vmthread_new(L, (void *) &td))
	    goto err;

	thread_settable(L, L, td->tid);
	sys_set_thread(td);
	sys_vm2_enter(td);
    }
    lua_pushlightuserdata(L, td->vmtd);
    return 1;
 err:
    return sys_seterror(L, 0);
}
Esempio n. 2
0
void
sys_vm_leave (void)
{
    if (g_TLSIndex == INVALID_TLS_INDEX)
	return;

    sys_vm2_leave(sys_get_thread());
}
Esempio n. 3
0
/*
 * Arguments: dpool_udata, data_items (any) ...
 */
static int
dpool_put (lua_State *L)
{
    struct sys_thread *td = sys_get_thread();
    struct data_pool *dp = checkudata(L, 1, DPOOL_TYPENAME);
    int nput = lua_gettop(L) - 1;

    if (!td) luaL_argerror(L, 0, "Threading not initialized");
    if (!nput) luaL_argerror(L, 2, "data expected");

    lua_getfenv(L, 1);  /* storage */
    lua_insert(L, 1);

    if (dp->n >= dp->max) {
	if (dp->flags & DPOOL_PUTONFULL) {
	    lua_pushlightuserdata(L, (void *) DPOOL_PUTONFULL);
	    lua_rawget(L, 1);
	    lua_insert(L, 2);
	    lua_call(L, 1 + nput, LUA_MULTRET);
	    nput = lua_gettop(L) - 1;
	    if (!nput) return 0;
	} else do {
	    if (thread_event_wait(&dp->tev, TIMEOUT_INFINITE))
		return sys_seterror(L, 0);
	} while (dp->n >= dp->max);
    }

    /* Try directly move data between threads */
    if (dp->nwaits && !dp->td) {
	dp->td = td;
	dp->nput = nput;
	thread_event_signal(&dp->tev);
	thread_yield(L);
	dp->td = NULL;
	if (!dp->nput) return 0;  /* moved to thread */
	dp->nput = 0;
    }

    /* Keep data in the storage */
    {
	int top = dp->top;

	lua_pushinteger(L, nput);
	do {
	    lua_rawseti(L, 1, ++top);
	} while (nput--);
	dp->top = top;

	/* notify event_queue */
	if (!dp->n++ && dp->trigger)
	    sys_trigger_notify(&dp->trigger, SYS_EVREAD);

	thread_event_signal(&dp->tev);
    }
    return 0;
}
Esempio n. 4
0
/*
 * Returns: [thread_ludata, main thread_ludata]
 */
static int
thread_self (lua_State *L)
{
    struct sys_thread *td = sys_get_thread();

    if (!td) return 0;

    lua_pushlightuserdata(L, td);
    lua_pushlightuserdata(L, td->vmtd);
    return 2;
}
Esempio n. 5
0
void
sys_vm_enter (void)
{
    struct sys_thread *td;

    if (g_TLSIndex == INVALID_TLS_INDEX)
	return;

    td = sys_get_thread();
    sys_vm2_enter(td);

    if (td && td->interrupted) {
	lua_pushlightuserdata(td->L, &g_TLSIndex);
	lua_error(td->L);
    }
}
Esempio n. 6
0
static int
channel_put (lua_State *L)
{
    struct sys_thread *td = sys_get_thread();
    struct channel *chan = checkudata(L, 1, CHANNEL_TYPENAME);
    int nput = lua_gettop(L) - 1;

    if (!td) luaL_argerror(L, 0, "Threading not initialized");
    if (!nput) luaL_argerror(L, 2, "data expected");

    lua_getfenv(L, 1);  /* get the storage table */
    lua_insert(L, 1);

    sys_vm_leave();

    thread_critsect_enter(&chan->mutex);
    thread_cond_signal(&chan->put);

    /* move the data to storage */
    {
	int top = chan->top;

	lua_pushinteger(L, nput);
	do {
	    lua_rawseti(L, 1, ++top);
	} while (nput--);
	chan->top = top;
        chan->n++;
    }

    while (chan->n > chan->max) {
        thread_cond_wait(&chan->get, &chan->mutex, TIMEOUT_INFINITE);
    }

    thread_critsect_leave(&chan->mutex);

    sys_vm_enter();
    return 0;
}
Esempio n. 7
0
/*
 * Arguments: filename (string) | function_dump (string),
 *	[arguments (string | number | boolean | lightuserdata) ...]
 * Returns: [thread_ludata]
 */
static int
thread_runvm (lua_State *L)
{
    const char *path = luaL_checkstring(L, 1);
    lua_State *NL = NULL;
    struct sys_vmthread *vmtd = (struct sys_vmthread *) sys_get_thread();
#ifndef _WIN32
    pthread_attr_t attr;
#else
    HANDLE hThr;
#endif
    int res = 0;

    if (!vmtd) luaL_argerror(L, 0, "Threading not initialized");

    NL = luaL_newstate();
    if (!NL) goto err;

    thread_openlibs(NL);

    if (path[0] == LUA_SIGNATURE[0]
     ? luaL_loadbuffer(NL, path, lua_rawlen(L, 1), "thread")
     : luaL_loadfile(NL, path)) {
	lua_pushstring(L, lua_tostring(NL, -1));  /* error message */
	lua_close(NL);
	lua_error(L);
    }

    /* Arguments */
    lua_pushlightuserdata(NL, vmtd);  /* master */
    {
	int i, top = lua_gettop(L);

	for (i = 2; i <= top; ++i) {
	    switch (lua_type(L, i)) {
	    case LUA_TSTRING:
		lua_pushstring(NL, lua_tostring(L, i));
		break;
	    case LUA_TNUMBER:
		lua_pushnumber(NL, lua_tonumber(L, i));
		break;
	    case LUA_TBOOLEAN:
		lua_pushboolean(NL, lua_toboolean(L, i));
		break;
	    case LUA_TLIGHTUSERDATA:
	    case LUA_TUSERDATA:
		lua_pushlightuserdata(NL, lua_touserdata(L, i));
		break;
	    default:
		luaL_argerror(L, i, "primitive type expected");
	    }
	}
    }

    if (vmthread_new(NL, &vmtd))
	goto err_clean;

#ifndef _WIN32
    res = pthread_attr_init(&attr);
    if (res) goto err_clean;
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    res = pthread_create(&vmtd->td.tid, &attr,
     (thread_func_t) thread_startvm, vmtd);
    pthread_attr_destroy(&attr);
    if (!res) {
#else
    hThr = (HANDLE) _beginthreadex(NULL, 0,
     (thread_func_t) thread_startvm, vmtd, 0, &vmtd->td.tid);
    if (hThr) {
	CloseHandle(hThr);
#endif
	lua_pushlightuserdata(L, vmtd);
	return 1;
    }
 err_clean:
    lua_close(NL);
 err:
    return sys_seterror(L, res);
}

/*
 * Arguments: thread_ludata
 */
static int
thread_interrupt (lua_State *L)
{
    struct sys_thread *td = lua_touserdata(L, 1);

    td->interrupted = 1;
#ifndef _WIN32
    pthread_kill(td->tid, SYS_SIGINTR);
#endif
    return 0;
}

static int
thread_yield (lua_State *L)
{
    (void) L;

    sys_vm_leave();
#ifndef _WIN32
    sched_yield();
#else
    Sleep(0);
#endif
    sys_vm_enter();
    return 0;
}
Esempio n. 8
0
/*
 * Arguments: function, [arguments (any) ...]
 * Returns: [thread_ludata]
 */
static int
thread_run (lua_State *L)
{
    struct sys_thread *vmtd = sys_get_thread();
    lua_State *NL;
    struct sys_thread *td;
#ifndef _WIN32
    pthread_attr_t attr;
    int res = 0;
#else
    HANDLE hThr;
    const int res = 0;
#endif

    if (!vmtd) luaL_argerror(L, 0, "Threading not initialized");
    luaL_checktype(L, 1, LUA_TFUNCTION);

    NL = lua_newthread(L);
    if (!NL) goto err;

    td = lua_newuserdata(L, sizeof(struct sys_thread));
    memset(td, 0, sizeof(struct sys_thread));
    td->mutex = vmtd->mutex;
    td->L = NL;
    td->vmtd = vmtd->vmtd;

#ifndef _WIN32
    if ((res = pthread_attr_init(&attr))
     || (res = pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE)))
	goto err;
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    res = pthread_create(&td->tid, &attr,
     (thread_func_t) thread_start, td);
    pthread_attr_destroy(&attr);
    if (!res) {
#else
    hThr = (HANDLE) _beginthreadex(NULL, THREAD_STACK_SIZE,
     (thread_func_t) thread_start, td, 0, &td->tid);
    if (hThr) {
	CloseHandle(hThr);
#endif
	thread_settable(L, NL, td->tid);  /* save thread to avoid GC */
	lua_xmove(L, NL, lua_gettop(L));  /* move function and args to NL */

	lua_pushlightuserdata(L, td);
	return 1;
    }
 err:
    return sys_seterror(L, res);
}


/*
 * Arguments: function, master (thread_ludata),
 *	[arguments (string | number | boolean | lightuserdata) ...],
 *	thread, thread_udata
 */
static THREAD_FUNC_API
thread_startvm (struct sys_thread *td)
{
    lua_State *L = td->L;

    thread_settable(L, L, td->tid);

    sys_set_thread(td);
    sys_vm2_enter(td);

    if (lua_pcall(L, lua_gettop(L) - 1, 0, 0)) {
	if (td->interrupted && lua_touserdata(L, -1) == &g_TLSIndex)
	    lua_pop(L, 1);
	else
	    lua_error(L);
    }

    /* notify event_queue */
    if (td->trigger)
	sys_trigger_notify(&td->trigger, SYS_EVEOF | SYS_EVDEL);

    lua_close(L);
    return 0;
}