Пример #1
0
/*
 * Arguments: thread_udata
 */
static int
thread_done (lua_State *L)
{
  struct sys_thread *td = checkudata(L, 1, THREAD_TYPENAME);

  if (td->L) {
    if (thread_isvm(td)) {
      thread_critsect_leave(td->vmcsp);
      thread_critsect_del(td->vmcsp);
    } else {
      sys_vm2_leave(td);
#ifndef _WIN32
      {
        THREAD_FUNC_RES v;
        pthread_join(td->tid, &v);
      }
#else
      WaitForSingleObject(td->tid, INFINITE);
      CloseHandle(td->tid);
#endif
      sys_vm2_enter(td);
    }
    (void) thread_cond_del(&td->cond);

    lua_rawgetp(L, LUA_REGISTRYINDEX, THREAD_KEY_ADDRESS);
    lua_pushnil(L);
    lua_rawsetp(L, -2, td->L); /* coroutine */
    lua_pop(L, 1);

    td->L = NULL;
  }
  return 0;
}
Пример #2
0
/*
 * Arguments: pipe_udata
 */
static int
pipe_close (lua_State *L)
{
    struct pipe_ref *pr = checkudata(L, 1, PIPE_TYPENAME);
    struct pipe *pp = pr->pipe;

    if (pp) {
	thread_critsect_t *csp = pipe_critsect_ptr(pp);
	int nref;

	thread_critsect_enter(csp);
	nref = pp->nref--;
	thread_critsect_leave(csp);

	if (!nref) {
	    thread_critsect_del(&pp->cs);
	    thread_cond_del(&pp->put_cond);
	    thread_cond_del(&pp->get_cond);

	    /* deallocate buffers */
	    if (pp->rbuf) {
		struct pipe_buf *rpb = pp->rbuf, *wpb = pp->wbuf;
		do {
		    struct pipe_buf *pb = rpb->next_buf;
		    free(rpb);
		    rpb = pb;
		} while (rpb != wpb);
	    }
	    free(pp);
	}
	pr->pipe = NULL;
    }
    return 0;
}
Пример #3
0
void
sys_vm2_leave (struct sys_thread *td)
{
  lua_assert(td);

  sys_vm2_preleave(td);
  thread_critsect_leave(td->vmcsp);
}
Пример #4
0
/*
 * Arguments: pipe_udata
 * Returns: [number]
 */
static int
pipe_count (lua_State *L)
{
    struct pipe *pp = lua_unboxpointer(L, 1, PIPE_TYPENAME);
    thread_critsect_t *csp = pipe_critsect_ptr(pp);
    unsigned int nmsg;

    thread_critsect_enter(csp);
    nmsg = pp->nmsg;
    thread_critsect_leave(csp);

    lua_pushinteger(L, nmsg);
    return 1;
}
Пример #5
0
void
sys_vm_leave (lua_State *L)
{
  (void) L;

  if (g_TLSIndex != INVALID_TLS_INDEX) {
    struct sys_thread *td = sys_thread_get();

    if (td) {
      sys_vm2_preleave(td);
      thread_critsect_leave(td->vmcsp);
    }
  }
}
Пример #6
0
static int
channel_get (lua_State *L)
{
    struct channel *chan = checkudata(L, 1, CHANNEL_TYPENAME);
    const msec_t timeout = lua_isnoneornil(L, 2)
     ? TIMEOUT_INFINITE : (msec_t) lua_tointeger(L, 2);
    int nput;
    int idx;
    int i;

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

    sys_vm_leave();

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

    /* wait signal */
    while (chan->n == 0) {
        thread_cond_wait(&chan->put, &chan->mutex, timeout);
    }

    /* get from storage */
    idx = chan->idx + 1;

    lua_rawgeti(L, 1, idx);
    nput = lua_tointeger(L, -1);
    lua_pushnil(L);
    lua_rawseti(L, 1, idx);
    chan->idx = idx + nput;

    for (i = chan->idx; i > idx; --i) {
        lua_rawgeti(L, 1, i);
        lua_pushnil(L);
        lua_rawseti(L, 1, i);
    }

    if (chan->idx == chan->top) chan->idx = chan->top = 0;
    chan->n--;

    thread_critsect_leave(&chan->mutex);

    sys_vm_enter();

    return nput;
}
Пример #7
0
/*
 * Returns: pipe_udata, dest. thread (ludata)
 */
static int
pipe_xdup (lua_State *L)
{
    struct pipe_ref *pr = checkudata(L, 1, PIPE_TYPENAME);
    lua_State *L2 = (lua_State *) lua_touserdata(L, 2);
    struct pipe *pp = pr->pipe;
    thread_critsect_t *csp = pipe_critsect_ptr(pp);
    struct pipe_ref *pr2;

    if (!L2) luaL_argerror(L, 2, "VM-thread expected");

    pr2 = lua_newuserdata(L2, sizeof(struct pipe_ref));
    *pr2 = *pr;
    luaL_getmetatable(L2, PIPE_TYPENAME);
    lua_setmetatable(L2, -2);

    thread_critsect_enter(csp);
    pp->nref++;
    thread_critsect_leave(csp);
    return 0;
}
Пример #8
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;
}
Пример #9
0
/*
 * Arguments: pipe_udata, [timeout (milliseconds)]
 * Returns: [pipe_udata | timedout (false), message_items (any) ...]
 */
static int
pipe_get (lua_State *L)
{
    struct sys_thread *td = sys_thread_get();
    struct pipe *pp = lua_unboxpointer(L, 1, PIPE_TYPENAME);
    const msec_t timeout = lua_isnoneornil(L, 2)
     ? TIMEOUT_INFINITE : (msec_t) lua_tointeger(L, 2);
    thread_critsect_t *csp = pipe_critsect_ptr(pp);
    struct message msg;

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

    /* read message from buffer */
    thread_critsect_enter(csp);
    for (; ; ) {
	if (pp->nmsg) {
	    struct pipe_buf *pb = pp->rbuf;
	    struct pipe_buf buf = *pb;
	    struct message *mp = pipe_buf_ptr(pb, buf.begin);

	    if (!mp->size) {  /* buffer is wrapped */
		mp = pipe_buf_ptr(pb, 0);
		buf.begin = 0;
	    }

	    memcpy(&msg, mp, mp->size);
	    buf.begin += mp->size;
	    if (buf.begin == buf.end) {
		buf.begin = buf.end = 0;
		if (pp->nmsg > 1)
		    pp->rbuf = buf.next_buf;
	    } else if (buf.begin == buf.len) {
		buf.begin = 0;
	    }
	    *pb = buf;
	    if (--pp->nmsg && pp->signal_on_put) {
		(void) thread_cond_signal(&pp->put_cond);
	    }
	} else {
	    /* wait `put' signal */
	    int res;

	    pp->signal_on_put++;
	    res = pipe_cond_wait(&pp->put_cond, csp, td, timeout);
	    pp->signal_on_put--;

	    if (!res) continue;
	    thread_critsect_leave(csp);

	    sys_thread_check(td);
	    if (res == 1) {
		lua_pushboolean(L, 0);
		return 1;  /* timed out */
	    }
	    return sys_seterror(L, 0);
	}
	break;
    }
    if (pp->signal_on_get) {
	(void) thread_cond_signal(&pp->get_cond);
    }
    thread_critsect_leave(csp);

    lua_settop(L, 1);
    return 1 + pipe_msg_parse(L, &msg);  /* deconstruct the message */
}
Пример #10
0
/*
 * Arguments: pipe_udata, message_items (any) ...
 * Returns: [pipe_udata | timedout (false)]
 */
static int
pipe_put (lua_State *L)
{
    struct sys_thread *td = sys_thread_get();
    struct pipe_ref *pr = checkudata(L, 1, PIPE_TYPENAME);
    struct pipe *pp = pr->pipe;
    thread_critsect_t *csp = pipe_critsect_ptr(pp);
    struct message msg;

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

    pipe_msg_build(L, &msg, 2);  /* construct the message */

    /* write message to buffer */
    thread_critsect_enter(csp);
    for (; ; ) {
	struct pipe_buf *pb = pp->wbuf;
	struct pipe_buf buf = *pb;
	const int wrapped = (buf.end < buf.begin);
	const unsigned int len = (wrapped ? buf.begin : buf.len) - buf.end;

	if (msg.size > len) {
	    if (!wrapped && buf.begin > msg.size) {
		/* wrap the buffer */
		struct message *mp = pipe_buf_ptr(pb, buf.end);
		mp->size = 0;  /* sentinel tag */
		buf.end = 0;
	    } else if (pb != buf.next_buf
	     && !buf.next_buf->begin && !buf.next_buf->end) {
		/* use next free buffer */
		pb = pp->wbuf = buf.next_buf;
		buf = *pb;
	    } else {
		const unsigned int buf_size = pp->buf_size;
		struct pipe_buf *wpb = (2 * buf_size <= pp->buf_max_size)
		 ? malloc(buf_size) : NULL;

		if (wpb) {
		    /* allocate new buffer */
		    buf.begin = buf.end = 0;
		    buf.len = buf_size - PIPE_BUF_EXTRASIZE;
		    /* buf->next_buf is already correct */
		    pb->next_buf = wpb;

		    pp->buf_size = buf_size * 2;
		    pp->wbuf = wpb;
		    pb = wpb;
		} else {
		    /* wait `get' signal */
		    int res;

		    pp->signal_on_get++;
		    res = pipe_cond_wait(&pp->get_cond, csp, td, pr->put_timeout);

		    if (--pp->signal_on_get) {
			(void) thread_cond_signal(&pp->get_cond);
		    }
		    if (!res) continue;
		    thread_critsect_leave(csp);

		    sys_thread_check(td);
		    if (res == 1) {
			lua_pushboolean(L, 0);
			return 1;  /* timed out */
		    }
		    return sys_seterror(L, 0);
		}
	    }
	}

	memcpy(pipe_buf_ptr(pb, buf.end), &msg, msg.size);
	buf.end += msg.size;
	*pb = buf;
	pp->nmsg++;
	break;
    }
    if (pp->signal_on_put) {
	(void) thread_cond_signal(&pp->put_cond);
    }
    thread_critsect_leave(csp);

    lua_settop(L, 1);
    return 1;
}