/* * Arguments: evq_udata, ev_ludata, [reuse_fd (boolean)] * Returns: [evq_udata] */ static int levq_del (lua_State *L) { struct event_queue *evq = checkudata(L, 1, EVQ_TYPENAME); struct event *ev = levq_toevent(L, 2); const int reuse_fd = lua_toboolean(L, 3); int res = 0; lua_assert(ev); #undef ARG_LAST #define ARG_LAST 1 #ifdef EVQ_POST_INIT if (ev == evq->ev_post) evq->ev_post = NULL; #endif if (!event_deleted(ev)) res = evq_del(ev, reuse_fd); if (!(ev->flags & (EVENT_ACTIVE | EVENT_DELETE))) levq_del_event(evq, ev); ev->flags |= EVENT_DELETE; if (!res) { lua_settop(L, 1); return 1; } return sys_seterror(L, 0); }
/* * 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); }
/* * Returns: [evq_udata] */ static int levq_new (lua_State *L) { struct event_queue *evq = lua_newuserdata(L, sizeof(struct event_queue)); memset(evq, 0, sizeof(struct event_queue)); lua_assert(sizeof(struct event) >= sizeof(struct timeout_queue)); lua_assert(sizeof(struct event) >= sizeof(struct evq_sync_op)); if (!evq_init(evq)) { lua_State *NL; luaL_getmetatable(L, EVQ_TYPENAME); lua_setmetatable(L, -2); lua_newtable(L); /* environ. (EVQ_CORO_ENV) */ lua_pushvalue(L, -1); lua_setfenv(L, -3); NL = lua_newthread(L); if (!NL) return 0; evq->L = NL; lua_rawsetp(L, -2, NL); /* save coroutine to avoid GC */ lua_newtable(L); /* {ev_id => cb_func} (EVQ_CORO_CALLBACK) */ lua_newtable(L); /* {ev_id => obj_udata} (EVQ_CORO_UDATA) */ lua_xmove(L, NL, 3); return 1; } return sys_seterror(L, 0); }
/* * Arguments: sd_udata, new_sd_udata, [sock_addr_udata] * Returns: [new_sd_udata | false (EAGAIN)] */ static int sock_accept (lua_State *L) { sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME); sd_t *sdp = checkudata(L, 2, SD_TYPENAME); struct sock_addr *from = lua_isnoneornil(L, 3) ? NULL : checkudata(L, 3, SA_TYPENAME); struct sockaddr *sap = NULL; socklen_t *slp = NULL; if (from) { sap = &from->u.addr; slp = &from->addrlen; } #ifndef _WIN32 do sd = accept(sd, sap, slp); while (sd == -1 && SYS_ERRNO == EINTR); #else sd = accept(sd, sap, slp); #endif if (sd != (sd_t) -1) { *sdp = sd; lua_settop(L, 2); return 1; } else if (SYS_EAGAIN(SYS_ERRNO)) { lua_pushboolean(L, 0); return 1; } return sys_seterror(L, 0); }
/* * Arguments: path (string) * Returns: [total_bytes (number), available_bytes (number), * free_bytes (number)] */ static int sys_statfs (lua_State *L) { const char *path = luaL_checkstring(L, 1); int64_t ntotal, navail, nfree; int res; #ifndef _WIN32 struct statvfs buf; sys_vm_leave(L); res = statvfs(path, &buf); sys_vm_enter(L); ntotal = buf.f_blocks * buf.f_frsize; nfree = buf.f_bfree * buf.f_bsize; navail = buf.f_bavail * buf.f_bsize; #else ULARGE_INTEGER na, nt, nf; SetErrorMode(SEM_FAILCRITICALERRORS); /* for floppy disks */ { void *os_path = utf8_to_filename(path); if (!os_path) return sys_seterror(L, ERROR_NOT_ENOUGH_MEMORY); sys_vm_leave(L); res = is_WinNT ? !GetDiskFreeSpaceExW(os_path, &na, &nt, &nf) : !GetDiskFreeSpaceExA(os_path, &na, &nt, &nf); free(os_path); sys_vm_enter(L); } ntotal = (int64_t) nt.QuadPart; nfree = (int64_t) nf.QuadPart; navail = (int64_t) na.QuadPart; #endif if (!res) { lua_pushnumber(L, (lua_Number) ntotal); lua_pushnumber(L, (lua_Number) navail); lua_pushnumber(L, (lua_Number) nfree); return 3; } return sys_seterror(L, 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; }
/* * Arguments: dpool_udata, data_items (any) ... */ static int dpool_put (lua_State *L) { struct sys_thread *td = sys_get_thread(); 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_pushlightuserdata(L, (void *) DPOOL_PUTONFULL); lua_rawget(L, 1); lua_insert(L, 2); lua_call(L, 1 + nput, LUA_MULTRET); nput = lua_gettop(L) - 1; if (!nput) return 0; } else do { if (thread_event_wait(&dp->tev, TIMEOUT_INFINITE)) 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); thread_yield(L); 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; /* notify event_queue */ if (!dp->n++ && dp->trigger) sys_trigger_notify(&dp->trigger, SYS_EVREAD); thread_event_signal(&dp->tev); } return 0; }
/* * Arguments: sd_udata, nonblocking (boolean) * Returns: [sd_udata] */ static int sock_nonblocking (lua_State *L) { sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME); unsigned long opt = lua_toboolean(L, 2); lua_settop(L, 1); return !ioctlsocket(sd, FIONBIO, &opt) ? 1 : sys_seterror(L, 0); }
/* * Arguments: fd_udata, path (string), [permissions (number)] * Returns: [fd_udata] */ static int sys_create (lua_State *L) { fd_t fd, *fdp = checkudata(L, 1, FD_TYPENAME); const char *path = luaL_checkstring(L, 2); #ifndef _WIN32 mode_t perm = (mode_t) luaL_optinteger(L, 3, SYS_FILE_PERMISSIONS); #endif #ifndef _WIN32 sys_vm_leave(L); fd = creat(path, perm); sys_vm_enter(L); #else { const int flags = GENERIC_WRITE; const DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; const DWORD creation = CREATE_ALWAYS; const DWORD attr = FILE_ATTRIBUTE_NORMAL | SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION; void *os_path = utf8_to_filename(path); if (!os_path) return sys_seterror(L, ERROR_NOT_ENOUGH_MEMORY); sys_vm_leave(L); fd = is_WinNT ? CreateFileW(os_path, flags, share, NULL, creation, attr, NULL) : CreateFileA(os_path, flags, share, NULL, creation, attr, NULL); free(os_path); sys_vm_enter(L); } #endif if (fd != (fd_t) -1) { *fdp = fd; lua_settop(L, 1); return 1; } return sys_seterror(L, 0); }
/* * Arguments: path (string) * Returns: [boolean] */ static int sys_chroot (lua_State *L) { const char *path = luaL_checkstring(L, 1); if (!chroot(path)) { lua_pushboolean(L, 1); return 1; } return sys_seterror(L, 0); }
/* * Arguments: sd_udata, [backlog (number)] * Returns: [sd_udata] */ static int sock_listen (lua_State *L) { sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME); const int backlog = luaL_optinteger(L, 2, SOMAXCONN); if (!listen(sd, backlog)) { lua_settop(L, 1); return 1; } return sys_seterror(L, 0); }
/* * Arguments: sd_udata, sock_addr_udata * Returns: [sd_udata] */ static int sock_bind (lua_State *L) { sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME); struct sock_addr *sap = checkudata(L, 2, SA_TYPENAME); if (!bind(sd, &sap->u.addr, sap->addrlen)) { lua_settop(L, 1); return 1; } return sys_seterror(L, 0); }
/* * Arguments: sd_udata * Returns: [sd_udata] */ static int sock_shutdown (lua_State *L) { sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME); /* SHUT_RD (SD_RECEIVE) has different behavior in unix and win32 */ if (!shutdown(sd, SHUT_WR)) { lua_settop(L, 1); return 1; } return sys_seterror(L, 0); }
/* * Arguments: path (string), [permissions (number)] * Returns: [boolean] */ static int sys_mkfifo (lua_State *L) { const char *path = luaL_checkstring(L, 1); mode_t perm = (mode_t) luaL_optinteger(L, 2, SYS_FILE_PERMISSIONS); if (!mkfifo(path, perm)) { lua_pushboolean(L, 1); return 1; } return sys_seterror(L, 0); }
/* * Arguments: evq_udata, signal (string), ignore (boolean) * Returns: [evq_udata] */ static int levq_ignore_signal (lua_State *L) { struct event_queue *evq = checkudata(L, 1, EVQ_TYPENAME); const int signo = sig_flags[luaL_checkoption(L, 2, NULL, sig_names)]; const int ignore = lua_toboolean(L, 3); if (!evq_ignore_signal(evq, signo, ignore)) { lua_settop(L, 1); return 1; } return sys_seterror(L, 0); }
/* * Arguments: evq_udata, [signal (string)] * Returns: [evq_udata] */ static int levq_signal (lua_State *L) { struct event_queue *evq = checkudata(L, 1, EVQ_TYPENAME); const int signo = lua_isnoneornil(L, 2) ? EVQ_SIGEVQ : sig_flags[luaL_checkoption(L, 2, NULL, sig_names)]; if (!evq_signal(evq, signo)) { lua_settop(L, 1); return 1; } return sys_seterror(L, 0); }
/* * Arguments: [buffer_max_size (number), buffer_min_size (number)] * Returns: [pipe_udata] */ static int pipe_new (lua_State *L) { const unsigned int max_size = (unsigned int) luaL_optinteger(L, 1, PIPE_BUF_MAXSIZE); const unsigned int min_size = (unsigned int) luaL_optinteger(L, 2, PIPE_BUF_MINSIZE); struct pipe_ref *pr; struct pipe *pp; if (min_size > max_size || min_size < PIPE_BUF_MINSIZE || max_size > PIPE_BUF_MAXSIZE /* (max_size / min_size) should be power of 2 */ || ((max_size / min_size) & (max_size / min_size - 1)) != 0) luaL_argerror(L, 1, "invalid size"); pr = lua_newuserdata(L, sizeof(struct pipe_ref)); pp = calloc(sizeof(struct pipe), 1); if (!pp) goto err; pr->pipe = pp; pr->put_timeout = TIMEOUT_INFINITE; luaL_getmetatable(L, PIPE_TYPENAME); lua_setmetatable(L, -2); if (thread_critsect_new(&pp->cs) || thread_cond_new(&pp->put_cond) || thread_cond_new(&pp->get_cond)) goto err; /* allocate initial buffer */ { struct pipe_buf *pb = malloc(min_size); if (!pb) goto err; memset(pb, 0, sizeof(struct pipe_buf)); pb->len = min_size - PIPE_BUF_EXTRASIZE; pb->next_buf = pb; pp->rbuf = pp->wbuf = pb; pp->buf_size = min_size; } pp->buf_max_size = max_size; return 1; err: return sys_seterror(L, 0); }
/* * Arguments: existing_path (string), new_path (string) * Returns: [boolean] */ static int sys_rename (lua_State *L) { const char *old = luaL_checkstring(L, 1); const char *new = luaL_checkstring(L, 2); int res; #ifndef _WIN32 sys_vm_leave(L); res = rename(old, new); sys_vm_enter(L); #else { void *os_old = utf8_to_filename(old); void *os_new = utf8_to_filename(new); if (!os_old || !os_new) { free(os_old); free(os_new); return sys_seterror(L, ERROR_NOT_ENOUGH_MEMORY); } sys_vm_leave(L); res = is_WinNT ? !MoveFileW(os_old, os_new) : !MoveFileA(os_old, os_new); free(os_old); free(os_new); sys_vm_enter(L); } #endif if (!res) { lua_pushboolean(L, 1); return 1; } return sys_seterror(L, 0); }
/* * Arguments: path (string) * Returns: [string] */ static int sys_realpath (lua_State *L) { const char *path = luaL_checkstring(L, 1); #ifndef _WIN32 char real[PATH_MAX]; if (realpath(path, real)) { lua_pushstring(L, real); return 1; } #else void *os_path = utf8_to_filename(path); if (!os_path) return sys_seterror(L, ERROR_NOT_ENOUGH_MEMORY); { WCHAR os_real[MAX_PATHNAME]; const int n = is_WinNT ? GetFullPathNameW(os_path, MAX_PATHNAME, os_real, NULL) : GetFullPathNameA(os_path, MAX_PATHNAME, (char *) os_real, NULL); free(os_path); if (n != 0 && n < MAX_PATHNAME) { void *real = filename_to_utf8(os_real); if (!real) return sys_seterror(L, ERROR_NOT_ENOUGH_MEMORY); lua_pushstring(L, real); free(real); return 1; } } #endif return sys_seterror(L, 0); }
/* * Arguments: reg_udata, subkey (string) * Returns: [reg_udata] */ static int reg_del_key (lua_State *L) { HKEY hk = lua_unboxpointer(L, 1, WREG_TYPENAME); const char *subkey = luaL_checkstring(L, 2); int res; res = RegDeleteKeyA(hk, subkey); if (!res) { lua_settop(L, 1); return 1; } return sys_seterror(L, res); }
/* * Arguments: reg_udata, [name (string)] * Returns: [reg_udata] */ static int reg_del_value (lua_State *L) { HKEY hk = lua_unboxpointer(L, 1, WREG_TYPENAME); const char *name = lua_tostring(L, 2); int res; res = RegDeleteValueA(hk, name); if (!res) { lua_settop(L, 1); return 1; } return sys_seterror(L, res); }
/* * Arguments: sd_udata, option (string), * [value_lo (number), value_hi (number)] * Returns: [sd_udata | value_lo (number), value_hi (number)] */ static int sock_sockopt (lua_State *L) { static const int opt_flags[] = { SO_REUSEADDR, SO_TYPE, SO_ERROR, SO_DONTROUTE, SO_SNDBUF, SO_RCVBUF, SO_SNDLOWAT, SO_RCVLOWAT, SO_BROADCAST, SO_KEEPALIVE, SO_OOBINLINE, SO_LINGER, #define OPTNAMES_TCP 12 TCP_NODELAY, #define OPTNAMES_IP 13 IP_MULTICAST_TTL, IP_MULTICAST_IF, IP_MULTICAST_LOOP }; static const char *const opt_names[] = { "reuseaddr", "type", "error", "dontroute", "sndbuf", "rcvbuf", "sndlowat", "rcvlowat", "broadcast", "keepalive", "oobinline", "linger", "tcp_nodelay", "multicast_ttl", "multicast_if", "multicast_loop", NULL }; #undef OPT_START #define OPT_START 2 sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME); const int optname = luaL_checkoption(L, OPT_START, NULL, opt_names); const int level = (optname < OPTNAMES_TCP) ? SOL_SOCKET : (optname < OPTNAMES_IP ? IPPROTO_TCP : IPPROTO_IP); const int optflag = opt_flags[optname]; int optval[4]; socklen_t optlen = sizeof(int); const int nargs = lua_gettop(L); if (nargs > OPT_START) { optval[0] = lua_tointeger(L, OPT_START + 1); if (nargs > OPT_START + 1) { optval[1] = lua_tointeger(L, OPT_START + 2); optlen *= 2; } if (!setsockopt(sd, level, optflag, (char *) &optval, optlen)) { lua_settop(L, 1); return 1; } } else if (!getsockopt(sd, level, optflag, (char *) &optval, &optlen)) { lua_pushinteger(L, optval[0]); if (optlen <= sizeof(int)) return 1; lua_pushinteger(L, optval[1]); return 2; } return sys_seterror(L, 0); }
/* * Returns: [rand_udata] */ static int sys_random (lua_State *L) { #ifndef _WIN32 fd_t *fdp = lua_newuserdata(L, sizeof(fd_t)); #if defined(__OpenBSD__) *fdp = open("/dev/arandom", O_RDONLY, 0); if (*fdp == (fd_t) -1) *fdp = open("/dev/urandom", O_RDONLY, 0); #else *fdp = open("/dev/urandom", O_RDONLY, 0); #endif if (*fdp != (fd_t) -1) { #else HCRYPTPROV *p = lua_newuserdata(L, sizeof(void *)); if (CryptAcquireContext(p, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { #endif luaL_getmetatable(L, RAND_TYPENAME); lua_setmetatable(L, -2); return 1; } return sys_seterror(L, 0); } /* * Arguments: rand_udata */ static int rand_close (lua_State *L) { #ifndef _WIN32 fd_t *fdp = (fd_t *) checkudata(L, 1, RAND_TYPENAME); if (*fdp != (fd_t) -1) { close(*fdp); *fdp = (fd_t) -1; } #else HCRYPTPROV *p = (HCRYPTPROV *) checkudata(L, 1, RAND_TYPENAME); if (*p != (HCRYPTPROV) -1) { CryptReleaseContext(*p, 0); *p = (HCRYPTPROV) -1; } #endif return 0; }
/* * Arguments: sd_udata, binary_address (multiaddr), * [binary_address_ipv4 (interface) | interface_ipv6 (number), * add/drop (boolean)] * Returns: [sd_udata] */ static int sock_membership (lua_State *L) { sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME); int len, af; const char *maddrp = sock_checkladdr(L, 2, &len, &af); const int optflag = !lua_isboolean(L, -1) || lua_toboolean(L, -1) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; union { struct ip_mreq ip; #ifdef IPPROTO_IPV6 struct ipv6_mreq ip6; #endif } mr; int level, mr_len; memset(&mr, 0, sizeof(mr)); if (af == AF_INET) { const char *ifacep = (lua_type(L, 3) == LUA_TSTRING) ? sock_checkladdr(L, 3, &len, &af) : NULL; if (ifacep && af != AF_INET) luaL_argerror(L, 3, "invalid interface"); memcpy(&mr.ip.imr_multiaddr, maddrp, len); if (ifacep) memcpy(&mr.ip.imr_interface, ifacep, len); level = IPPROTO_IP; mr_len = sizeof(struct ip_mreq); } else { #ifdef IPPROTO_IPV6 memcpy(&mr.ip6.ipv6mr_multiaddr, maddrp, len); mr.ip6.ipv6mr_interface = lua_tointeger(L, 3); level = IPPROTO_IPV6; mr_len = sizeof(struct ipv6_mreq); #else luaL_argerror(L, 2, "invalid family"); #endif } if (!setsockopt(sd, level, optflag, (char *) &mr, mr_len)) { lua_settop(L, 1); return 1; } return sys_seterror(L, 0); }
/* * Arguments: dpool_udata, [timeout (milliseconds)] * Returns: [signalled/timedout (boolean)] */ static int dpool_wait (lua_State *L) { 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 res; res = thread_event_wait(&dp->tev, timeout); if (res >= 0) { lua_pushboolean(L, !res); return 1; } return sys_seterror(L, 0); }
/* * Arguments: ecb_udata, {string | membuf_udata} ... * Returns: [success/partial (boolean), count (number)] */ static int ecb_write (lua_State *L) { LPEXTENSION_CONTROL_BLOCK ecb = lua_unboxpointer(L, 1, ECB_TYPENAME); size_t n = 0; /* number of chars actually write */ int i, narg = lua_gettop(L); if (ecb->dwHttpStatusCode & ECB_STATUS_HEADERS_SEND) { ecb->dwHttpStatusCode ^= ECB_STATUS_HEADERS_SEND; lua_pushfstring(L, "HTTP/1.1 %d\r\n", (ecb->dwHttpStatusCode & ECB_STATUS_MASK)); lua_rawgetp(L, LUA_REGISTRYINDEX, ecb); lua_pushliteral(L, "\r\n"); lua_concat(L, 3); lua_insert(L, 2); ++narg; } for (i = 2; i <= narg; ++i) { struct sys_buffer sb; int nw; if (!sys_buffer_read_init(L, i, &sb) || sb.size == 0) /* don't close the connection */ continue; sys_vm_leave(); { DWORD l = sb.size; nw = ecb->WriteClient(ecb->ConnID, sb.ptr.w, &l, 0) ? (int) l : -1; } sys_vm_enter(); if (nw == -1) { if (n > 0) break; return sys_seterror(L, 0); } n += nw; sys_buffer_read_next(&sb, nw); if ((size_t) nw < sb.size) break; } lua_pushboolean(L, (i > narg)); lua_pushinteger(L, n); return 2; }
/* * Arguments: reg_udata, [root (reg_udata | string), subkey (string), * mode (string: "r", "w", "rw")] * Returns: [reg_udata] */ static int reg_open (lua_State *L) { HKEY *hkp = checkudata(L, 1, WREG_TYPENAME); HKEY hk = reg_root2key(L, 2); const char *subkey = lua_tostring(L, 3); REGSAM desired = reg_mode2sam(L, 4); int res; res = RegOpenKeyExA(hk, subkey, 0, desired, hkp); if (!res) { lua_settop(L, 1); return 1; } return sys_seterror(L, res); }
/* * Returns: [dpool_udata] */ static int thread_data_pool (lua_State *L) { struct data_pool *dp = lua_newuserdata(L, sizeof(struct data_pool)); memset(dp, 0, sizeof(struct data_pool)); dp->max = (unsigned int) -1; if (!thread_event_new(&dp->tev)) { luaL_getmetatable(L, DPOOL_TYPENAME); lua_setmetatable(L, -2); lua_newtable(L); /* data and callbacks storage */ lua_setfenv(L, -2); return 1; } return sys_seterror(L, 0); }
/* * Arguments: [timeout (milliseconds)] * Returns: [boolean] */ static int thread_suspend_wrap (lua_State *L) { struct sys_thread *td = sys_thread_get(); const msec_t timeout = lua_isnoneornil(L, 1) ? TIMEOUT_INFINITE : (msec_t) lua_tointeger(L, 1); const int res = sys_thread_suspend(td, timeout); if (res >= 0) { if (res == 1) { lua_pushboolean(L, 0); return 1; /* timed out */ } lua_pushboolean(L, 1); return 1; } return sys_seterror(L, 0); }
static int thread_channel (lua_State *L) { struct channel *chan = lua_newuserdata(L, sizeof(struct channel)); memset(chan, 0, sizeof(struct channel)); chan->max = (unsigned int) -1; if (!thread_cond_new(&chan->put) && !thread_cond_new(&chan->get)) { thread_critsect_new(&chan->mutex); luaL_getmetatable(L, CHANNEL_TYPENAME); lua_setmetatable(L, -2); lua_newtable(L); /* data storage */ lua_setfenv(L, -2); return 1; } return sys_seterror(L, 0); }