/* * Arguments: pipe_udata */ static int pipe_close (lua_State *L) { struct pipe_ref *pr = checkudata(L, 1, PIPE_TYPENAME); struct pipe *pp = pr->pipe; if (pp) { thread_critsect_t *csp = pipe_critsect_ptr(pp); int nref; thread_critsect_enter(csp); nref = pp->nref--; thread_critsect_leave(csp); if (!nref) { thread_critsect_del(&pp->cs); thread_cond_del(&pp->put_cond); thread_cond_del(&pp->get_cond); /* deallocate buffers */ if (pp->rbuf) { struct pipe_buf *rpb = pp->rbuf, *wpb = pp->wbuf; do { struct pipe_buf *pb = rpb->next_buf; free(rpb); rpb = pb; } while (rpb != wpb); } free(pp); } pr->pipe = NULL; } return 0; }
void sys_vm2_enter (struct sys_thread *td) { lua_assert(td); thread_critsect_enter(td->vmcsp); sys_vm2_postenter(td); }
/* * Arguments: pipe_udata * Returns: [number] */ static int pipe_count (lua_State *L) { struct pipe *pp = lua_unboxpointer(L, 1, PIPE_TYPENAME); thread_critsect_t *csp = pipe_critsect_ptr(pp); unsigned int nmsg; thread_critsect_enter(csp); nmsg = pp->nmsg; thread_critsect_leave(csp); lua_pushinteger(L, nmsg); return 1; }
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); } } }
static int channel_get (lua_State *L) { struct channel *chan = checkudata(L, 1, CHANNEL_TYPENAME); const msec_t timeout = lua_isnoneornil(L, 2) ? TIMEOUT_INFINITE : (msec_t) lua_tointeger(L, 2); int nput; int idx; int i; lua_settop(L, 1); lua_getfenv(L, 1); /* storage */ lua_insert(L, 1); sys_vm_leave(); thread_critsect_enter(&chan->mutex); thread_cond_signal(&chan->get); /* wait signal */ while (chan->n == 0) { thread_cond_wait(&chan->put, &chan->mutex, timeout); } /* get from storage */ idx = chan->idx + 1; lua_rawgeti(L, 1, idx); nput = lua_tointeger(L, -1); lua_pushnil(L); lua_rawseti(L, 1, idx); chan->idx = idx + nput; for (i = chan->idx; i > idx; --i) { lua_rawgeti(L, 1, i); lua_pushnil(L); lua_rawseti(L, 1, i); } if (chan->idx == chan->top) chan->idx = chan->top = 0; chan->n--; thread_critsect_leave(&chan->mutex); sys_vm_enter(); return nput; }
/* * Returns: pipe_udata, dest. thread (ludata) */ static int pipe_xdup (lua_State *L) { struct pipe_ref *pr = checkudata(L, 1, PIPE_TYPENAME); lua_State *L2 = (lua_State *) lua_touserdata(L, 2); struct pipe *pp = pr->pipe; thread_critsect_t *csp = pipe_critsect_ptr(pp); struct pipe_ref *pr2; if (!L2) luaL_argerror(L, 2, "VM-thread expected"); pr2 = lua_newuserdata(L2, sizeof(struct pipe_ref)); *pr2 = *pr; luaL_getmetatable(L2, PIPE_TYPENAME); lua_setmetatable(L2, -2); thread_critsect_enter(csp); pp->nref++; thread_critsect_leave(csp); return 0; }
static int channel_put (lua_State *L) { struct sys_thread *td = sys_get_thread(); struct channel *chan = checkudata(L, 1, CHANNEL_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); /* get the storage table */ lua_insert(L, 1); sys_vm_leave(); thread_critsect_enter(&chan->mutex); thread_cond_signal(&chan->put); /* move the data to storage */ { int top = chan->top; lua_pushinteger(L, nput); do { lua_rawseti(L, 1, ++top); } while (nput--); chan->top = top; chan->n++; } while (chan->n > chan->max) { thread_cond_wait(&chan->get, &chan->mutex, TIMEOUT_INFINITE); } thread_critsect_leave(&chan->mutex); sys_vm_enter(); return 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; }