Exemple #1
0
/*
 * Arguments: ..., function, [arguments (any) ...]
 * Returns: [results (any) ...]
 */
static int
levq_sync_call (lua_State *L, struct event_queue *evq,
                struct evq_sync_op *op,
                const int is_sched_add, const int fn_idx)
{
    op->L = L;
    op->fn_idx = fn_idx;
    op->status = 0;
    op->is_sched_add = is_sched_add;
    op->next = evq->sync_op;

    evq->sync_op = op;
    evq_signal(evq, EVQ_SIGEVQ);

    if (is_sched_add) {
	lua_pushlightuserdata(L, op);  /* sync_op_ludata */
	return 1;
    } else {
	struct sys_thread *td = sys_thread_get();
	const int old_top = fn_idx - 1;

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

	op->td = td;
	sys_thread_suspend(td, TIMEOUT_INFINITE);  /* wait result */

	if (op->status) lua_error(L);
	return lua_gettop(L) - old_top;
    }
}
Exemple #2
0
/*
 * Arguments: function, [arguments (any) ...]
 * Returns: [thread_udata]
 */
static int
thread_run (lua_State *L)
{
  struct sys_thread *td, *vmtd = sys_thread_get();

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

  td = sys_thread_new(L, vmtd, NULL, 1);
  if (!td) goto err;

  lua_insert(L, 1);  /* thread_udata */

  /* function and arguments */
  {
    const int n = lua_gettop(L) - 1;
    luaL_checkstack(td->L, n, NULL);
    lua_xmove(L, td->L, n);
  }

  if (!sys_thread_create(td, 0)) {
    return 1;
  }
  sys_thread_del(td);
 err:
  return sys_seterror(L, 0);
}
Exemple #3
0
/*
 * Arguments: [stack_size (number)]
 * Returns: [boolean]
 */
static int
thread_init (lua_State *L)
{
  const size_t stack_size = (size_t) luaL_optinteger(L, 1, THREAD_STACK_SIZE);
  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_thread_get();
  if (!td) {
    td = thread_newvm(L, NULL, 0);
    if (!td) goto err;

    sys_thread_set(td);
    sys_vm2_enter(td);
  }
  td->vmtd->stack_size = stack_size;

  lua_pushboolean(L, 1);
  return 1;
 err:
  return sys_seterror(L, 0);
}
Exemple #4
0
/*
 * Arguments: dpool_udata, data_items (any) ...
 */
static int
dpool_put (lua_State *L)
{
    struct sys_thread *td = sys_thread_get();
    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_rawgetp(L, 1, (void *) DPOOL_PUTONFULL);
	    lua_insert(L, 2);
	    lua_call(L, 1 + nput, LUA_MULTRET);
	    nput = lua_gettop(L) - 1;
	    if (!nput) return 0;
	} else {
	    do {
		const int res = thread_event_wait(&dp->tev, td,
		 TIMEOUT_INFINITE);

		sys_thread_check(td);
		if (res) 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);
	sys_thread_switch(0);
	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;

	if (!dp->n++) {
	    thread_event_signal(&dp->tev);
	}
    }
    return 0;
}
Exemple #5
0
int
sys_eintr (void)
{
#ifndef _WIN32
  if (SYS_ERRNO == EINTR) {
    struct sys_thread *td = sys_thread_get();
    return !(td && td->flags);
  }
#endif
  return 0;
}
Exemple #6
0
/*
 * Returns: thread_udata, is_main (boolean)
 */
static int
thread_self (lua_State *L)
{
  struct sys_thread *td = sys_thread_get();

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

  lua_rawgetp(L, LUA_REGISTRYINDEX, THREAD_KEY_ADDRESS);
  lua_rawgetp(L, -1, td);
  lua_pushboolean(L, thread_isvm(td));
  return 2;
}
Exemple #7
0
static int
thread_switch_wrap (lua_State *L)
{
  struct sys_thread *td = sys_thread_get();

  (void) L;

  if (td) {
    sys_thread_switch(td);
    sys_thread_check(td, L);
  }
  return 0;
}
Exemple #8
0
int
sys_thread_suspend (struct sys_thread *td, const msec_t timeout)
{
  int res;

  lua_assert(td && td == sys_thread_get());

  td->suspended = 1;
  do {
    res = thread_cond_wait_vm(&td->cond, td, timeout);
  } while (td->suspended && !res);
  return res;
}
Exemple #9
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);
    }
  }
}
Exemple #10
0
void
sys_vm_enter (lua_State *L)
{
  if (g_TLSIndex != INVALID_TLS_INDEX) {
    struct sys_thread *td = sys_thread_get();

    if (td) {
      thread_critsect_enter(td->vmcsp);
      sys_vm2_postenter(td);

      if (td->flags) sys_thread_check(td, L);
    }
  }
}
Exemple #11
0
/*
 * Arguments: [timeout (milliseconds)]
 * Returns: [boolean]
 */
static int
thread_suspend_wrap (lua_State *L)
{
  struct sys_thread *td = sys_thread_get();
  const msec_t timeout = lua_isnoneornil(L, 1)
   ? TIMEOUT_INFINITE : (msec_t) lua_tointeger(L, 1);
  const int res = sys_thread_suspend(td, timeout);

  if (res >= 0) {
    if (res == 1) {
      lua_pushboolean(L, 0);
      return 1;  /* timed out */
    }
    lua_pushboolean(L, 1);
    return 1;
  }
  return sys_seterror(L, 0);
}
Exemple #12
0
/*
 * Arguments: thread_udata,
 *	[success/failure (boolean) | status (number)]
 */
static int
thread_set_terminate (lua_State *L)
{
  struct sys_thread *td = checkudata(L, 1, THREAD_TYPENAME);
  const lua_Integer status = !lua_isboolean(L, 2) ? lua_tointeger(L, 2)
   : (lua_toboolean(L, 2) ? EXIT_SUCCESS : EXIT_FAILURE);

  td = thread_unfake(td);
  td->exit_status = status;
  td->flags = SYS_THREAD_TERMINATE;

  if (td == sys_thread_get())
    thread_exit(td);
  else
    (void) thread_cancel_syncio(td->tid);

  return 0;
}
Exemple #13
0
/*
 * Arguments: thread_udata, [recover/interrupt (boolean)]
 */
static int
thread_set_interrupt (lua_State *L)
{
  struct sys_thread *td = checkudata(L, 1, THREAD_TYPENAME);
  const int recover = lua_toboolean(L, 2);

  td = thread_unfake(td);
  if (recover) {
    td->flags &= ~SYS_THREAD_INTERRUPT;
    return 0;
  }

  td->flags = SYS_THREAD_INTERRUPT;
  if (td == sys_thread_get())
    sys_thread_check(td, L);
  else
    (void) thread_cancel_syncio(td->tid);

  return 0;
}
Exemple #14
0
/*
 * Arguments: ecb_udata, [membuf_udata, count (number)]
 * Returns: [string | count (number)]
 */
static int
ecb_read (lua_State *L)
{
  LPEXTENSION_CONTROL_BLOCK ecb = lua_unboxpointer(L, 1, ECB_TYPENAME);
  size_t n = !lua_isnumber(L, -1) ? ~((size_t) 0)
   : (size_t) lua_tointeger(L, -1);
  const size_t len = n;  /* how much total to read */
  size_t rlen;  /* how much to read */
  int nr;  /* number of bytes actually read */
  struct sys_thread *td = sys_thread_get();
  struct sys_buffer sb;
  char buf[SYS_BUFSIZE];
  int res = 0;

  sys_buffer_write_init(L, 2, &sb, buf, sizeof(buf));
  do {
    rlen = (n <= sb.size) ? n : sb.size;
    if (td) sys_vm2_leave(td);
    {
      DWORD l;
      nr = ecb->ReadClient(ecb->ConnID, sb.ptr.w, &l) ? (int) l : -1;
    }
    if (td) sys_vm2_enter(td);
    if (nr == -1) break;
    n -= nr;  /* still have to read `n' bytes */
  } while ((n != 0L && nr == (int) rlen)  /* until end of count or eof */
   && sys_buffer_write_next(L, &sb, buf, 0));
  if (nr <= 0 && len == n) {
    res = -1;
  } else {
    if (!sys_buffer_write_done(L, &sb, buf, nr))
      lua_pushinteger(L, len - n);
  }
  if (td) sys_thread_check(td);
  if (!res) return 1;
  return sys_seterror(L, 0);
}
Exemple #15
0
/*
 * Arguments: dpool_udata, [timeout (milliseconds)]
 * Returns: data_items (any) ...
 */
static int
dpool_get (lua_State *L)
{
    struct sys_thread *td = sys_thread_get();
    struct data_pool *dp = checkudata(L, 1, DPOOL_TYPENAME);
    const msec_t timeout = lua_isnoneornil(L, 2)
     ? TIMEOUT_INFINITE : (msec_t) lua_tointeger(L, 2);
    int nput;

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

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

    if ((dp->flags & DPOOL_GETONEMPTY) && !dp->n) {
	lua_rawgetp(L, 1, (void *) DPOOL_GETONEMPTY);
	lua_insert(L, 2);
	lua_call(L, 1, LUA_MULTRET);
	nput = lua_gettop(L) - 1;
	if (nput) return nput;
    }

    for (; ; ) {
	/* get from storage */
	if (dp->n) {
	    const int idx = dp->idx + 1;
	    int i;

	    lua_rawgeti(L, 1, idx);
	    nput = lua_tointeger(L, -1);
	    lua_pushnil(L);
	    lua_rawseti(L, 1, idx);
	    dp->idx = idx + nput;
	    for (i = dp->idx; i > idx; --i) {
		lua_rawgeti(L, 1, i);
		lua_pushnil(L);
		lua_rawseti(L, 1, i);
	    }
	    if (dp->idx == dp->top)
		dp->idx = dp->top = 0;
	    if (dp->n-- == dp->max) {
		thread_event_signal(&dp->tev);
	    }
	    return nput;
	}

	/* wait signal */
	{
	    int res;

	    dp->nwaits++;
	    res = thread_event_wait(&dp->tev, td, timeout);
	    dp->nwaits--;

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

	/* get directly from another thread */
	nput = dp->nput;
	if (nput) {
	    dp->nput = 0;
	    luaL_checkstack(L, nput, NULL);
	    lua_xmove(dp->td->L, L, nput);
	    return nput;
	}
    }
}
Exemple #16
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;
}
Exemple #17
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 */
}
Exemple #18
0
/*
 * Arguments: options (table: {1..n: library names, "cpu": number}),
 *	filename (string) | function_dump (string),
 *	[arguments (string | number | boolean | ludata | share_object) ...]
 * Returns: [thread_udata]
 */
static int
thread_runvm (lua_State *L)
{
  const char *path = luaL_checkstring(L, 2);
  struct sys_thread *vmtd = sys_thread_get();
  struct sys_thread *td, *faketd;
  lua_State *NL;
  unsigned int loadlibs = ~0U;  /* load all standard libraries */
  int is_affin = 0, cpu = 0;

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

  /* options */
  if (lua_istable(L, 1)) {
    unsigned int libs = 0;
    int i;

    for (i = 1; ; ++i) {
      const char *s;
      lua_rawgeti(L, 1, i);
      s = lua_tostring(L, -1);
      if (!s || !*s) {
        if (s) loadlibs = 0;  /* don't load any libraries */
        lua_pop(L, 1);
        break;
      }
      libs |= 1 << luaL_checkoption(L, -1, NULL, stdlib_names);
      lua_pop(L, 1);
    }
    if (libs) loadlibs = libs;

    /* CPU affinity */
    lua_getfield(L, 1, "cpu");
    if (lua_type(L, -1) == LUA_TNUMBER) {
      cpu = (int) lua_tointeger(L, -1);
      is_affin = 1;
    }
    lua_pop(L, 1);
  }

  td = thread_newvm(NULL, vmtd, loadlibs);
  if (!td) goto err;

  faketd = sys_thread_new(L, vmtd, td, 1);
  if (!faketd) goto err;

  lua_replace(L, 1);  /* fake thread_udata */

  if (is_affin)
    td->vmtd->cpu = cpu;

  NL = td->L;

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

  /* arguments */
  {
    int i, top = lua_gettop(L);

    luaL_checkstack(NL, top + LUA_MINSTACK, "too many arguments");

    for (i = ARG_LAST + 1; i <= top; ++i) {
      switch (lua_type(L, i)) {
      case LUA_TSTRING:
        {
          size_t len;
          const char *s = lua_tolstring(L, i, &len);
          lua_pushlstring(NL, s, len);
        }
        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:
        lua_pushlightuserdata(NL, lua_touserdata(L, i));
        break;
      case LUA_TUSERDATA:
        if (!luaL_getmetafield(L, i, THREAD_XDUP_TAG))
          luaL_argerror(L, i, "shareable object expected");
        lua_pushvalue(L, i);
        lua_pushlightuserdata(L, NL);
        lua_call(L, 2, 0);
        break;
      case LUA_TNIL:
        lua_pushnil(NL);
        break;
      default:
        luaL_argerror(L, i, "primitive type expected");
      }
    }
  }

  if (!sys_thread_create(td, is_affin)) {
    faketd->tid = td->tid;
    lua_settop(L, 1);
    return 1;
  }
  lua_close(NL);
 err:
  return sys_seterror(L, 0);
}