/* * 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; }
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; }
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); } } }
/* * 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; }
/* * 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); }
/* * 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: 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 */ }
/* * 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; }
/* * 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; } } }