예제 #1
0
파일: sys_thread.c 프로젝트: tnodir/luasys
/*
 * 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
파일: sys_thread.c 프로젝트: tnodir/luasys
/*
 * 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);
}
예제 #3
0
파일: sys_thread.c 프로젝트: LuaDist/luasys
/*
 * Arguments: function, [arguments (any) ...]
 */
static THREAD_FUNC_API
thread_start (struct sys_thread *td)
{
    lua_State *L = td->L;

    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);

    /* remove reference to self */
    td = sys_del_thread(td);

    sys_vm2_leave(td);
    return 0;
}
예제 #4
0
파일: sys_thread.c 프로젝트: LuaDist/luasys
/*
 * 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);
}
예제 #5
0
static int
pipe_cond_wait (thread_cond_t *condp, thread_critsect_t *csp,
                struct sys_thread *td, const msec_t timeout)
{
    int res;

    sys_vm2_leave(td);
    res = thread_cond_wait_nolock(condp, csp, timeout);
    sys_vm2_enter(td);
    return res;
}
예제 #6
0
파일: sys_thread.c 프로젝트: tnodir/luasys
void
sys_thread_switch (struct sys_thread *td)
{
  sys_vm2_leave(td);
#ifndef _WIN32
  sched_yield();
#else
  SwitchToThread();
#endif
  sys_vm2_enter(td);
}
예제 #7
0
파일: sys_thread.c 프로젝트: tnodir/luasys
/*
 * Arguments: function, [arguments (any) ...]
 */
static THREAD_FUNC_API
thread_start (struct sys_thread *td)
{
  lua_State *L = td->L;

  sys_thread_set(td);
  sys_vm2_enter(td);

  if (lua_pcall(L, lua_gettop(L) - 1, 1, 0))
    thread_error_abort(L);

  return thread_exit(td);
}
예제 #8
0
파일: sys_thread.c 프로젝트: LuaDist/luasys
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);
    }
}
예제 #9
0
파일: sys_thread.c 프로젝트: tnodir/luasys
static int
thread_cond_wait_vm (thread_cond_t *condp, struct sys_thread *td,
                     const msec_t timeout)
{
  int res;

#if defined(USE_PTHREAD_SYNC)
  sys_vm2_preleave(td);
  res = thread_cond_wait_nolock(condp, td->vmcsp, timeout);
  sys_vm2_postenter(td);
#else
  sys_vm2_leave(td);
  res = thread_handle_wait(*condp, timeout);
  sys_vm2_enter(td);
#endif

  return res;
}
예제 #10
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);
}
예제 #11
0
파일: sys_thread.c 프로젝트: tnodir/luasys
/*
 * Arguments: [status (number)]
 */
static THREAD_FUNC_RES
thread_exit (struct sys_thread *td)
{
  struct sys_thread *reftd = td->reftd;
  const int is_vm = thread_isvm(td);
  lua_Integer res;

  td->sched_ctx = NULL;

  if (td->flags != SYS_THREAD_KILLED) {
    td->flags = SYS_THREAD_KILLED;
    td->exit_status = lua_tointeger(td->L, -1);
  }
  res = td->exit_status;

  if (is_vm) {
    thread_waitvm(td->vmtd, TIMEOUT_INFINITE);
    lua_close(td->L);
  } else {
    struct sys_thread *vmtd = thread_getvm(td);

#ifndef _WIN32
    pthread_cond_broadcast(&td->cond);
#endif
    /* stop collector to prevent self-deadlock on GC */
    lua_gc(vmtd->L, LUA_GCSTOP, 0);
    sys_thread_del(td);
    lua_gc(vmtd->L, LUA_GCRESTART, 0);
    sys_vm2_leave(vmtd);
  }

  /* decrease VM-thread's reference count */
  if (reftd) {
    struct sys_vmthread *vmref = reftd->vmtd;

    sys_vm2_enter(reftd);
    if (is_vm) {
      reftd->flags = SYS_THREAD_KILLED;
      reftd->exit_status = res;
#ifndef _WIN32
      pthread_cond_broadcast(&reftd->cond);
#endif
      sys_thread_del(reftd);
    }
    if (!--vmref->nref) {
#ifndef _WIN32
      pthread_cond_broadcast(&vmref->td.cond);
#else
      (void) thread_cond_signal(&vmref->td.cond);
#endif
    }
    sys_vm2_leave(reftd);
  }

#ifndef _WIN32
  pthread_exit((THREAD_FUNC_RES) res);
#else
  _endthreadex((THREAD_FUNC_RES) res);
#endif
  return 0;
}
예제 #12
0
파일: sys_thread.c 프로젝트: LuaDist/luasys
/*
 * 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;
}
예제 #13
0
파일: select.c 프로젝트: ELMERzark/luasys
EVQ_API int
evq_wait (struct event_queue *evq, struct sys_thread *td, msec_t timeout)
{
  struct event *ev_ready;
  fd_set work_readset = evq->readset;
  fd_set work_writeset = evq->writeset;
  struct timeval tv, *tvp;
  struct event **events = evq->events;
  const int npolls = evq->npolls;
  int i, nready, max_fd;

  if (timeout != 0L) {
    timeout = timeout_get(evq->tq, timeout, evq->now);
    if (timeout == 0L) {
      ev_ready = timeout_process(evq->tq, NULL, evq->now);
      goto end;
    }
  }
  if (timeout == TIMEOUT_INFINITE)
    tvp = NULL;
  else {
    tv.tv_sec = timeout / 1000;
    tv.tv_usec = (timeout % 1000) * 1000;
    tvp = &tv;
  }

  max_fd = evq->max_fd;
  if (max_fd == -1) {
    for (i = 1; i < npolls; ++i) {
      struct event *ev = events[i];
      if (max_fd < ev->fd)
        max_fd = ev->fd;
    }
    evq->max_fd = max_fd;
  }

  if (td) sys_vm2_leave(td);
  nready = select(max_fd + 1, &work_readset, &work_writeset, NULL, tvp);
  if (td) sys_vm2_enter(td);

  evq->now = sys_milliseconds();

  if (nready == -1)
    return (errno == EINTR) ? 0 : -1;

  ev_ready = evq->ev_ready;
  if (tvp) {
    if (!nready) {
      if (evq->tq) {
        struct event *ev = timeout_process(evq->tq, ev_ready, evq->now);
        if (ev != ev_ready) {
          ev_ready = ev;
          goto end;
        }
      }
      return SYS_ERR_TIMEOUT;
    }

    timeout = evq->now;
  }

  if (FD_ISSET(evq->sig_fd[0], &work_readset)) {
    ev_ready = signal_process_interrupt(evq, ev_ready, timeout);
    --nready;
  }

  for (i = 1; i < npolls && nready; i++) {
    struct event *ev = events[i];
    unsigned int res = 0;

    if ((ev->flags & EVENT_READ) && FD_ISSET(ev->fd, &work_readset))
      res |= EVENT_READ_RES;
    else if ((ev->flags & EVENT_WRITE) && FD_ISSET(ev->fd, &work_writeset))
      res |= EVENT_WRITE_RES;

    if (!res) continue;

    ev->flags |= res;
    if (!(ev->flags & EVENT_ACTIVE)) {
      ev->flags |= EVENT_ACTIVE;
      if (ev->flags & EVENT_ONESHOT)
        evq_del(ev, 1);
      else if (ev->tq && !(ev->flags & EVENT_TIMEOUT_MANUAL))
        timeout_reset(ev, timeout);

      ev->next_ready = ev_ready;
      ev_ready = ev;
    }
    --nready;
  }
  if (!ev_ready) return 0;
 end:
  evq->ev_ready = ev_ready;
  return 0;
}