Beispiel #1
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;
}
Beispiel #2
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;
}
Beispiel #3
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);
    }
  }
}
Beispiel #4
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;
}
Beispiel #5
0
/*
 * Arguments: thread_udata, [timeout (milliseconds)]
 * Returns: [status (number) | timeout (false) | no_workers (true)]
 */
static int
thread_wait (lua_State *L)
{
  struct sys_thread *td = checkudata(L, 1, THREAD_TYPENAME);
  const msec_t timeout = lua_isnoneornil(L, 2)
   ? TIMEOUT_INFINITE : (msec_t) lua_tointeger(L, 2);
  int res;

  if (thread_isvm(td)) {
    res = thread_waitvm(td->vmtd, timeout);
    if (!res) {
      lua_pushboolean(L, 1);  /* no workers */
      return 1;
    }
  } else {
    if (td->flags == SYS_THREAD_KILLED)
      goto result;

#ifndef _WIN32
    do {
      res = thread_cond_wait_vm(&td->cond, td, timeout);
      sys_thread_check(td, L);
    } while (td->flags != SYS_THREAD_KILLED && !res);
#else
    sys_vm_leave(L);
    res = thread_handle_wait(td->tid, timeout);
    sys_vm_enter(L);
#endif
  }

  if (res >= 0) {
    if (res == 1) {
      lua_pushboolean(L, 0);
      return 1;  /* timed out */
    }
 result:
    lua_pushinteger(L, td->exit_status);
    return 1;
  }
  return sys_seterror(L, 0);
}
Beispiel #6
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);
}
Beispiel #7
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 */
}
Beispiel #8
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;
}
Beispiel #9
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;
	}
    }
}