/* * 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; }
/* * 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; }
void sys_vm_leave (void) { if (g_TLSIndex == INVALID_TLS_INDEX) return; sys_vm2_leave(sys_get_thread()); }
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; }
void sys_thread_switch (struct sys_thread *td) { sys_vm2_leave(td); #ifndef _WIN32 sched_yield(); #else SwitchToThread(); #endif sys_vm2_enter(td); }
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; }
/* * 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); }
/* * 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; }
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; }