diff options
author | 2016-02-21 11:48:45 +0100 | |
---|---|---|
committer | 2016-02-21 11:48:45 +0100 | |
commit | cc24a339d8c0517259084b5c178d784626ba965c (patch) | |
tree | 9868e9687b5802ae0a3733712a3bbeb3bc75c953 /3rdparty/luv/src | |
parent | b5daabda5495dea5c50e17961ecfed2ea8619d76 (diff) |
Merge remote-tracking branch 'refs/remotes/mamedev/master'
Second attempt
Diffstat (limited to '3rdparty/luv/src')
34 files changed, 5673 insertions, 0 deletions
diff --git a/3rdparty/luv/src/async.c b/3rdparty/luv/src/async.c new file mode 100644 index 00000000000..87ae0cc0460 --- /dev/null +++ b/3rdparty/luv/src/async.c @@ -0,0 +1,63 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" +#include "lthreadpool.h" + +static uv_async_t* luv_check_async(lua_State* L, int index) { + uv_async_t* handle = luv_checkudata(L, index, "uv_async"); + luaL_argcheck(L, handle->type == UV_ASYNC && handle->data, index, "Expected uv_async_t"); + return handle; +} + +static void luv_async_cb(uv_async_t* handle) { + lua_State* L = luv_state(handle->loop); + luv_handle_t* data = handle->data; + int n = luv_thread_arg_push(L, data->extra); + luv_call_callback(L, data, LUV_ASYNC, n); + luv_thread_arg_clear(data->extra); +} + +static int luv_new_async(lua_State* L) { + uv_async_t* handle; + luv_handle_t* data; + int ret; + luaL_checktype(L, 1, LUA_TFUNCTION); + handle = luv_newuserdata(L, sizeof(*handle)); + ret = uv_async_init(luv_loop(L), handle, luv_async_cb); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + data = luv_setup_handle(L); + data->extra = malloc(sizeof(luv_thread_arg_t)); + memset(data->extra, 0, sizeof(luv_thread_arg_t)); + handle->data = data; + luv_check_callback(L, handle->data, LUV_ASYNC, 1); + return 1; +} + +static int luv_async_send(lua_State* L) { + int ret; + uv_async_t* handle = luv_check_async(L, 1); + luv_thread_arg_t* arg = ((luv_handle_t*) handle->data)->extra; + + luv_thread_arg_set(L, arg, 2, lua_gettop(L), 0); + ret = uv_async_send(handle); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} diff --git a/3rdparty/luv/src/check.c b/3rdparty/luv/src/check.c new file mode 100644 index 00000000000..dbd330ae255 --- /dev/null +++ b/3rdparty/luv/src/check.c @@ -0,0 +1,59 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +static uv_check_t* luv_check_check(lua_State* L, int index) { + uv_check_t* handle = luv_checkudata(L, index, "uv_check"); + luaL_argcheck(L, handle->type == UV_CHECK && handle->data, index, "Expected uv_check_t"); + return handle; +} + +static int luv_new_check(lua_State* L) { + uv_check_t* handle = luv_newuserdata(L, sizeof(*handle)); + int ret = uv_check_init(luv_loop(L), handle); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + handle->data = luv_setup_handle(L); + return 1; +} + +static void luv_check_cb(uv_check_t* handle) { + lua_State* L = luv_state(handle->loop); + luv_handle_t* data = handle->data; + luv_call_callback(L, data, LUV_CHECK, 0); +} + +static int luv_check_start(lua_State* L) { + uv_check_t* handle = luv_check_check(L, 1); + int ret; + luv_check_callback(L, handle->data, LUV_CHECK, 2); + ret = uv_check_start(handle, luv_check_cb); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_check_stop(lua_State* L) { + uv_check_t* handle = luv_check_check(L, 1); + int ret = uv_check_stop(handle); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + diff --git a/3rdparty/luv/src/constants.c b/3rdparty/luv/src/constants.c new file mode 100644 index 00000000000..3417028c438 --- /dev/null +++ b/3rdparty/luv/src/constants.c @@ -0,0 +1,649 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "luv.h" + +static int luv_constants(lua_State* L) { + lua_newtable(L); + + // File open bitwise flags O_* +#ifdef O_RDONLY + lua_pushinteger(L, O_RDONLY); + lua_setfield(L, -2, "O_RDONLY"); +#endif +#ifdef O_WRONLY + lua_pushinteger(L, O_WRONLY); + lua_setfield(L, -2, "O_WRONLY"); +#endif +#ifdef O_RDWR + lua_pushinteger(L, O_RDWR); + lua_setfield(L, -2, "O_RDWR"); +#endif +#ifdef O_APPEND + lua_pushinteger(L, O_APPEND); + lua_setfield(L, -2, "O_APPEND"); +#endif +#ifdef O_CREAT + lua_pushinteger(L, O_CREAT); + lua_setfield(L, -2, "O_CREAT"); +#endif +#ifdef O_DSYNC + lua_pushinteger(L, O_DSYNC); + lua_setfield(L, -2, "O_DSYNC"); +#endif +#ifdef O_EXCL + lua_pushinteger(L, O_EXCL); + lua_setfield(L, -2, "O_EXCL"); +#endif +#ifdef O_EXLOCK + lua_pushinteger(L, O_EXLOCK); + lua_setfield(L, -2, "O_EXLOCK"); +#endif +#ifdef O_NOCTTY + lua_pushinteger(L, O_NOCTTY); + lua_setfield(L, -2, "O_NOCTTY"); +#endif +#ifdef O_NONBLOCK + lua_pushinteger(L, O_NONBLOCK); + lua_setfield(L, -2, "O_NONBLOCK"); +#endif +#ifdef O_RSYNC + lua_pushinteger(L, O_RSYNC); + lua_setfield(L, -2, "O_RSYNC"); +#endif +#ifdef O_SYNC + lua_pushinteger(L, O_SYNC); + lua_setfield(L, -2, "O_SYNC"); +#endif +#ifdef O_TRUNC + lua_pushinteger(L, O_TRUNC); + lua_setfield(L, -2, "O_TRUNC"); +#endif + + // Socket types SOCK_* +#ifdef SOCK_STREAM + lua_pushinteger(L, SOCK_STREAM); + lua_setfield(L, -2, "SOCK_STREAM"); +#endif +#ifdef SOCK_DGRAM + lua_pushinteger(L, SOCK_DGRAM); + lua_setfield(L, -2, "SOCK_DGRAM"); +#endif +#ifdef SOCK_SEQPACKET + lua_pushinteger(L, SOCK_SEQPACKET); + lua_setfield(L, -2, "SOCK_SEQPACKET"); +#endif +#ifdef SOCK_RAW + lua_pushinteger(L, SOCK_RAW); + lua_setfield(L, -2, "SOCK_RAW"); +#endif +#ifdef SOCK_RDM + lua_pushinteger(L, SOCK_RDM); + lua_setfield(L, -2, "SOCK_RDM"); +#endif + + // AF_* +#ifdef AF_UNIX + lua_pushinteger(L, AF_UNIX); + lua_setfield(L, -2, "AF_UNIX"); +#endif +#ifdef AF_INET + lua_pushinteger(L, AF_INET); + lua_setfield(L, -2, "AF_INET"); +#endif +#ifdef AF_INET6 + lua_pushinteger(L, AF_INET6); + lua_setfield(L, -2, "AF_INET6"); +#endif +#ifdef AF_IPX + lua_pushinteger(L, AF_IPX); + lua_setfield(L, -2, "AF_IPX"); +#endif +#ifdef AF_NETLINK + lua_pushinteger(L, AF_NETLINK); + lua_setfield(L, -2, "AF_NETLINK"); +#endif +#ifdef AF_X25 + lua_pushinteger(L, AF_X25); + lua_setfield(L, -2, "AF_X25"); +#endif +#ifdef AF_AX25 + lua_pushinteger(L, AF_AX25); + lua_setfield(L, -2, "AF_AX25"); +#endif +#ifdef AF_ATMPVC + lua_pushinteger(L, AF_ATMPVC); + lua_setfield(L, -2, "AF_ATMPVC"); +#endif +#ifdef AF_APPLETALK + lua_pushinteger(L, AF_APPLETALK); + lua_setfield(L, -2, "AF_APPLETALK"); +#endif +#ifdef AF_PACKET + lua_pushinteger(L, AF_PACKET); + lua_setfield(L, -2, "AF_PACKET"); +#endif + + // AI_* +#ifdef AI_ADDRCONFIG + lua_pushinteger(L, AI_ADDRCONFIG); + lua_setfield(L, -2, "AI_ADDRCONFIG"); +#endif +#ifdef AI_V4MAPPED + lua_pushinteger(L, AI_V4MAPPED); + lua_setfield(L, -2, "AI_V4MAPPED"); +#endif +#ifdef AI_ALL + lua_pushinteger(L, AI_ALL); + lua_setfield(L, -2, "AI_ALL"); +#endif +#ifdef AI_NUMERICHOST + lua_pushinteger(L, AI_NUMERICHOST); + lua_setfield(L, -2, "AI_NUMERICHOST"); +#endif +#ifdef AI_PASSIVE + lua_pushinteger(L, AI_PASSIVE); + lua_setfield(L, -2, "AI_PASSIVE"); +#endif +#ifdef AI_NUMERICSERV + lua_pushinteger(L, AI_NUMERICSERV); + lua_setfield(L, -2, "AI_NUMERICSERV"); +#endif + + // Signals +#ifdef SIGHUP + lua_pushinteger(L, SIGHUP); + lua_setfield(L, -2, "SIGHUP"); +#endif +#ifdef SIGINT + lua_pushinteger(L, SIGINT); + lua_setfield(L, -2, "SIGINT"); +#endif +#ifdef SIGQUIT + lua_pushinteger(L, SIGQUIT); + lua_setfield(L, -2, "SIGQUIT"); +#endif +#ifdef SIGILL + lua_pushinteger(L, SIGILL); + lua_setfield(L, -2, "SIGILL"); +#endif +#ifdef SIGTRAP + lua_pushinteger(L, SIGTRAP); + lua_setfield(L, -2, "SIGTRAP"); +#endif +#ifdef SIGABRT + lua_pushinteger(L, SIGABRT); + lua_setfield(L, -2, "SIGABRT"); +#endif +#ifdef SIGIOT + lua_pushinteger(L, SIGIOT); + lua_setfield(L, -2, "SIGIOT"); +#endif +#ifdef SIGBUS + lua_pushinteger(L, SIGBUS); + lua_setfield(L, -2, "SIGBUS"); +#endif +#ifdef SIGFPE + lua_pushinteger(L, SIGFPE); + lua_setfield(L, -2, "SIGFPE"); +#endif +#ifdef SIGKILL + lua_pushinteger(L, SIGKILL); + lua_setfield(L, -2, "SIGKILL"); +#endif +#ifdef SIGUSR1 + lua_pushinteger(L, SIGUSR1); + lua_setfield(L, -2, "SIGUSR1"); +#endif +#ifdef SIGSEGV + lua_pushinteger(L, SIGSEGV); + lua_setfield(L, -2, "SIGSEGV"); +#endif +#ifdef SIGUSR2 + lua_pushinteger(L, SIGUSR2); + lua_setfield(L, -2, "SIGUSR2"); +#endif +#ifdef SIGPIPE + lua_pushinteger(L, SIGPIPE); + lua_setfield(L, -2, "SIGPIPE"); +#endif +#ifdef SIGALRM + lua_pushinteger(L, SIGALRM); + lua_setfield(L, -2, "SIGALRM"); +#endif +#ifdef SIGTERM + lua_pushinteger(L, SIGTERM); + lua_setfield(L, -2, "SIGTERM"); +#endif +#ifdef SIGCHLD + lua_pushinteger(L, SIGCHLD); + lua_setfield(L, -2, "SIGCHLD"); +#endif +#ifdef SIGSTKFLT + lua_pushinteger(L, SIGSTKFLT); + lua_setfield(L, -2, "SIGSTKFLT"); +#endif +#ifdef SIGCONT + lua_pushinteger(L, SIGCONT); + lua_setfield(L, -2, "SIGCONT"); +#endif +#ifdef SIGSTOP + lua_pushinteger(L, SIGSTOP); + lua_setfield(L, -2, "SIGSTOP"); +#endif +#ifdef SIGTSTP + lua_pushinteger(L, SIGTSTP); + lua_setfield(L, -2, "SIGTSTP"); +#endif +#ifdef SIGBREAK + lua_pushinteger(L, SIGBREAK); + lua_setfield(L, -2, "SIGBREAK"); +#endif +#ifdef SIGTTIN + lua_pushinteger(L, SIGTTIN); + lua_setfield(L, -2, "SIGTTIN"); +#endif +#ifdef SIGTTOU + lua_pushinteger(L, SIGTTOU); + lua_setfield(L, -2, "SIGTTOU"); +#endif +#ifdef SIGURG + lua_pushinteger(L, SIGURG); + lua_setfield(L, -2, "SIGURG"); +#endif +#ifdef SIGXCPU + lua_pushinteger(L, SIGXCPU); + lua_setfield(L, -2, "SIGXCPU"); +#endif +#ifdef SIGXFSZ + lua_pushinteger(L, SIGXFSZ); + lua_setfield(L, -2, "SIGXFSZ"); +#endif +#ifdef SIGVTALRM + lua_pushinteger(L, SIGVTALRM); + lua_setfield(L, -2, "SIGVTALRM"); +#endif +#ifdef SIGPROF + lua_pushinteger(L, SIGPROF); + lua_setfield(L, -2, "SIGPROF"); +#endif +#ifdef SIGWINCH + lua_pushinteger(L, SIGWINCH); + lua_setfield(L, -2, "SIGWINCH"); +#endif +#ifdef SIGIO + lua_pushinteger(L, SIGIO); + lua_setfield(L, -2, "SIGIO"); +#endif +#ifdef SIGPOLL + lua_pushinteger(L, SIGPOLL); + lua_setfield(L, -2, "SIGPOLL"); +#endif +#ifdef SIGLOST + lua_pushinteger(L, SIGLOST); + lua_setfield(L, -2, "SIGLOST"); +#endif +#ifdef SIGPWR + lua_pushinteger(L, SIGPWR); + lua_setfield(L, -2, "SIGPWR"); +#endif +#ifdef SIGSYS + lua_pushinteger(L, SIGSYS); + lua_setfield(L, -2, "SIGSYS"); +#endif + return 1; +} + +static int luv_af_string_to_num(const char* string) { + if (!string) return AF_UNSPEC; +#ifdef AF_UNIX + if (strcmp(string, "unix") == 0) return AF_UNIX; +#endif +#ifdef AF_INET + if (strcmp(string, "inet") == 0) return AF_INET; +#endif +#ifdef AF_INET6 + if (strcmp(string, "inet6") == 0) return AF_INET6; +#endif +#ifdef AF_IPX + if (strcmp(string, "ipx") == 0) return AF_IPX; +#endif +#ifdef AF_NETLINK + if (strcmp(string, "netlink") == 0) return AF_NETLINK; +#endif +#ifdef AF_X25 + if (strcmp(string, "x25") == 0) return AF_X25; +#endif +#ifdef AF_AX25 + if (strcmp(string, "ax25") == 0) return AF_AX25; +#endif +#ifdef AF_ATMPVC + if (strcmp(string, "atmpvc") == 0) return AF_ATMPVC; +#endif +#ifdef AF_APPLETALK + if (strcmp(string, "appletalk") == 0) return AF_APPLETALK; +#endif +#ifdef AF_PACKET + if (strcmp(string, "packet") == 0) return AF_PACKET; +#endif + return 0; +} + +static const char* luv_af_num_to_string(const int num) { + switch (num) { +#ifdef AF_UNIX + case AF_UNIX: return "unix"; +#endif +#ifdef AF_INET + case AF_INET: return "inet"; +#endif +#ifdef AF_INET6 + case AF_INET6: return "inet6"; +#endif +#ifdef AF_IPX + case AF_IPX: return "ipx"; +#endif +#ifdef AF_NETLINK + case AF_NETLINK: return "netlink"; +#endif +#ifdef AF_X25 + case AF_X25: return "x25"; +#endif +#ifdef AF_AX25 + case AF_AX25: return "ax25"; +#endif +#ifdef AF_ATMPVC + case AF_ATMPVC: return "atmpvc"; +#endif +#ifdef AF_APPLETALK + case AF_APPLETALK: return "appletalk"; +#endif +#ifdef AF_PACKET + case AF_PACKET: return "packet"; +#endif + } + return NULL; +} + + +static int luv_sock_string_to_num(const char* string) { + if (!string) return 0; +#ifdef SOCK_STREAM + if (strcmp(string, "stream") == 0) return SOCK_STREAM; +#endif +#ifdef SOCK_DGRAM + if (strcmp(string, "dgram") == 0) return SOCK_DGRAM; +#endif +#ifdef SOCK_SEQPACKET + if (strcmp(string, "seqpacket") == 0) return SOCK_SEQPACKET; +#endif +#ifdef SOCK_RAW + if (strcmp(string, "raw") == 0) return SOCK_RAW; +#endif +#ifdef SOCK_RDM + if (strcmp(string, "rdm") == 0) return SOCK_RDM; +#endif + return 0; +} + +static const char* luv_sock_num_to_string(const int num) { + switch (num) { +#ifdef SOCK_STREAM + case SOCK_STREAM: return "stream"; +#endif +#ifdef SOCK_DGRAM + case SOCK_DGRAM: return "dgram"; +#endif +#ifdef SOCK_SEQPACKET + case SOCK_SEQPACKET: return "seqpacket"; +#endif +#ifdef SOCK_RAW + case SOCK_RAW: return "raw"; +#endif +#ifdef SOCK_RDM + case SOCK_RDM: return "rdm"; +#endif + } + return NULL; +} + +static int luv_sig_string_to_num(const char* string) { + if (!string) return 0; +#ifdef SIGHUP + if (strcmp(string, "sighup") == 0) return SIGHUP; +#endif +#ifdef SIGINT + if (strcmp(string, "sigint") == 0) return SIGINT; +#endif +#ifdef SIGQUIT + if (strcmp(string, "sigquit") == 0) return SIGQUIT; +#endif +#ifdef SIGILL + if (strcmp(string, "sigill") == 0) return SIGILL; +#endif +#ifdef SIGTRAP + if (strcmp(string, "sigtrap") == 0) return SIGTRAP; +#endif +#ifdef SIGABRT + if (strcmp(string, "sigabrt") == 0) return SIGABRT; +#endif +#ifdef SIGIOT + if (strcmp(string, "sigiot") == 0) return SIGIOT; +#endif +#ifdef SIGBUS + if (strcmp(string, "sigbus") == 0) return SIGBUS; +#endif +#ifdef SIGFPE + if (strcmp(string, "sigfpe") == 0) return SIGFPE; +#endif +#ifdef SIGKILL + if (strcmp(string, "sigkill") == 0) return SIGKILL; +#endif +#ifdef SIGUSR1 + if (strcmp(string, "sigusr1") == 0) return SIGUSR1; +#endif +#ifdef SIGSEGV + if (strcmp(string, "sigsegv") == 0) return SIGSEGV; +#endif +#ifdef SIGUSR2 + if (strcmp(string, "sigusr2") == 0) return SIGUSR2; +#endif +#ifdef SIGPIPE + if (strcmp(string, "sigpipe") == 0) return SIGPIPE; +#endif +#ifdef SIGALRM + if (strcmp(string, "sigalrm") == 0) return SIGALRM; +#endif +#ifdef SIGTERM + if (strcmp(string, "sigterm") == 0) return SIGTERM; +#endif +#ifdef SIGCHLD + if (strcmp(string, "sigchld") == 0) return SIGCHLD; +#endif +#ifdef SIGSTKFLT + if (strcmp(string, "sigstkflt") == 0) return SIGSTKFLT; +#endif +#ifdef SIGCONT + if (strcmp(string, "sigcont") == 0) return SIGCONT; +#endif +#ifdef SIGSTOP + if (strcmp(string, "sigstop") == 0) return SIGSTOP; +#endif +#ifdef SIGTSTP + if (strcmp(string, "sigtstp") == 0) return SIGTSTP; +#endif +#ifdef SIGBREAK + if (strcmp(string, "sigbreak") == 0) return SIGBREAK; +#endif +#ifdef SIGTTIN + if (strcmp(string, "sigttin") == 0) return SIGTTIN; +#endif +#ifdef SIGTTOU + if (strcmp(string, "sigttou") == 0) return SIGTTOU; +#endif +#ifdef SIGURG + if (strcmp(string, "sigurg") == 0) return SIGURG; +#endif +#ifdef SIGXCPU + if (strcmp(string, "sigxcpu") == 0) return SIGXCPU; +#endif +#ifdef SIGXFSZ + if (strcmp(string, "sigxfsz") == 0) return SIGXFSZ; +#endif +#ifdef SIGVTALRM + if (strcmp(string, "sigvtalrm") == 0) return SIGVTALRM; +#endif +#ifdef SIGPROF + if (strcmp(string, "sigprof") == 0) return SIGPROF; +#endif +#ifdef SIGWINCH + if (strcmp(string, "sigwinch") == 0) return SIGWINCH; +#endif +#ifdef SIGIO + if (strcmp(string, "sigio") == 0) return SIGIO; +#endif +#ifdef SIGPOLL + if (strcmp(string, "sigpoll") == 0) return SIGPOLL; +#endif +#ifdef SIGLOST + if (strcmp(string, "siglost") == 0) return SIGLOST; +#endif +#ifdef SIGPWR + if (strcmp(string, "sigpwr") == 0) return SIGPWR; +#endif +#ifdef SIGSYS + if (strcmp(string, "sigsys") == 0) return SIGSYS; +#endif + return 0; +} + +static const char* luv_sig_num_to_string(const int num) { + switch (num) { +#ifdef SIGHUP + case SIGHUP: return "sighup"; +#endif +#ifdef SIGINT + case SIGINT: return "sigint"; +#endif +#ifdef SIGQUIT + case SIGQUIT: return "sigquit"; +#endif +#ifdef SIGILL + case SIGILL: return "sigill"; +#endif +#ifdef SIGTRAP + case SIGTRAP: return "sigtrap"; +#endif +#ifdef SIGABRT + case SIGABRT: return "sigabrt"; +#endif +#ifdef SIGIOT +# if SIGIOT != SIGABRT + case SIGIOT: return "sigiot"; +# endif +#endif +#ifdef SIGBUS + case SIGBUS: return "sigbus"; +#endif +#ifdef SIGFPE + case SIGFPE: return "sigfpe"; +#endif +#ifdef SIGKILL + case SIGKILL: return "sigkill"; +#endif +#ifdef SIGUSR1 + case SIGUSR1: return "sigusr1"; +#endif +#ifdef SIGSEGV + case SIGSEGV: return "sigsegv"; +#endif +#ifdef SIGUSR2 + case SIGUSR2: return "sigusr2"; +#endif +#ifdef SIGPIPE + case SIGPIPE: return "sigpipe"; +#endif +#ifdef SIGALRM + case SIGALRM: return "sigalrm"; +#endif +#ifdef SIGTERM + case SIGTERM: return "sigterm"; +#endif +#ifdef SIGCHLD + case SIGCHLD: return "sigchld"; +#endif +#ifdef SIGSTKFLT + case SIGSTKFLT: return "sigstkflt"; +#endif +#ifdef SIGCONT + case SIGCONT: return "sigcont"; +#endif +#ifdef SIGSTOP + case SIGSTOP: return "sigstop"; +#endif +#ifdef SIGTSTP + case SIGTSTP: return "sigtstp"; +#endif +#ifdef SIGBREAK + case SIGBREAK: return "sigbreak"; +#endif +#ifdef SIGTTIN + case SIGTTIN: return "sigttin"; +#endif +#ifdef SIGTTOU + case SIGTTOU: return "sigttou"; +#endif +#ifdef SIGURG + case SIGURG: return "sigurg"; +#endif +#ifdef SIGXCPU + case SIGXCPU: return "sigxcpu"; +#endif +#ifdef SIGXFSZ + case SIGXFSZ: return "sigxfsz"; +#endif +#ifdef SIGVTALRM + case SIGVTALRM: return "sigvtalrm"; +#endif +#ifdef SIGPROF + case SIGPROF: return "sigprof"; +#endif +#ifdef SIGWINCH + case SIGWINCH: return "sigwinch"; +#endif +#ifdef SIGIO + case SIGIO: return "sigio"; +#endif +#ifdef SIGPOLL +# if SIGPOLL != SIGIO + case SIGPOLL: return "sigpoll"; +# endif +#endif +#ifdef SIGLOST + case SIGLOST: return "siglost"; +#endif +#ifdef SIGPWR +# if SIGPWR != SIGLOST + case SIGPWR: return "sigpwr"; +# endif +#endif +#ifdef SIGSYS + case SIGSYS: return "sigsys"; +#endif + } + return NULL; +} diff --git a/3rdparty/luv/src/dns.c b/3rdparty/luv/src/dns.c new file mode 100644 index 00000000000..f3446f30985 --- /dev/null +++ b/3rdparty/luv/src/dns.c @@ -0,0 +1,296 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "luv.h" +#ifndef WIN32 +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#endif + +static void luv_pushaddrinfo(lua_State* L, struct addrinfo* res) { + char ip[INET6_ADDRSTRLEN]; + int port, i = 0; + const char *addr; + struct addrinfo* curr = res; + lua_newtable(L); + for (curr = res; curr; curr = curr->ai_next) { + if (curr->ai_family == AF_INET || curr->ai_family == AF_INET6) { + lua_newtable(L); + if (curr->ai_family == AF_INET) { + addr = (char*) &((struct sockaddr_in*) curr->ai_addr)->sin_addr; + port = ((struct sockaddr_in*) curr->ai_addr)->sin_port; + } else { + addr = (char*) &((struct sockaddr_in6*) curr->ai_addr)->sin6_addr; + port = ((struct sockaddr_in6*) curr->ai_addr)->sin6_port; + } + lua_pushstring(L, luv_af_num_to_string(curr->ai_family)); + lua_setfield(L, -2, "family"); + uv_inet_ntop(curr->ai_family, addr, ip, INET6_ADDRSTRLEN); + lua_pushstring(L, ip); + lua_setfield(L, -2, "addr"); + if (ntohs(port)) { + lua_pushinteger(L, ntohs(port)); + lua_setfield(L, -2, "port"); + } + lua_pushstring(L, luv_sock_num_to_string(curr->ai_socktype)); + lua_setfield(L, -2, "socktype"); + lua_pushstring(L, luv_af_num_to_string(curr->ai_protocol)); + lua_setfield(L, -2, "protocol"); + if (curr->ai_canonname) { + lua_pushstring(L, curr->ai_canonname); + lua_setfield(L, -2, "canonname"); + } + lua_rawseti(L, -2, ++i); + } + } +} + +static void luv_getaddrinfo_cb(uv_getaddrinfo_t* req, int status, struct addrinfo* res) { + lua_State* L = luv_state(req->loop); + int nargs; + + if (status < 0) { + luv_status(L, status); + nargs = 1; + } + else { + lua_pushnil(L); + luv_pushaddrinfo(L, res); + nargs = 2; + } + luv_fulfill_req(L, req->data, nargs); + luv_cleanup_req(L, req->data); + req->data = NULL; + if (res) uv_freeaddrinfo(res); +} + + +static int luv_getaddrinfo(lua_State* L) { + uv_getaddrinfo_t* req; + const char* node; + const char* service; + struct addrinfo hints_s; + struct addrinfo* hints = &hints_s; + int ret, ref; + if (lua_isnoneornil(L, 1)) node = NULL; + else node = luaL_checkstring(L, 1); + if (lua_isnoneornil(L, 2)) service = NULL; + else service = luaL_checkstring(L, 2); + if (!lua_isnoneornil(L, 3)) luaL_checktype(L, 3, LUA_TTABLE); + else hints = NULL; + ref = lua_isnoneornil(L, 4) ? LUA_NOREF : luv_check_continuation(L, 4); + if (hints) { + // Initialize the hints + memset(hints, 0, sizeof(*hints)); + + // Process the `family` hint. + lua_getfield(L, 3, "family"); + if (lua_isnumber(L, -1)) { + hints->ai_family = lua_tointeger(L, -1); + } + else if (lua_isstring(L, -1)) { + hints->ai_family = luv_af_string_to_num(lua_tostring(L, -1)); + } + else if (lua_isnil(L, -1)) { + hints->ai_family = AF_UNSPEC; + } + else { + luaL_argerror(L, 3, "family hint must be string if set"); + } + lua_pop(L, 1); + + // Process `socktype` hint + lua_getfield(L, 3, "socktype"); + if (lua_isnumber(L, -1)) { + hints->ai_socktype = lua_tointeger(L, -1); + } + else if (lua_isstring(L, -1)) { + hints->ai_socktype = luv_sock_string_to_num(lua_tostring(L, -1)); + } + else if (!lua_isnil(L, -1)) { + return luaL_argerror(L, 3, "socktype hint must be string if set"); + } + lua_pop(L, 1); + + // Process the `protocol` hint + lua_getfield(L, 3, "protocol"); + if (lua_isnumber(L, -1)) { + hints->ai_protocol = lua_tointeger(L, -1); + } + else if (lua_isstring(L, -1)) { + int protocol = luv_af_string_to_num(lua_tostring(L, -1)); + if (protocol) { + hints->ai_protocol = protocol; + } + else { + return luaL_argerror(L, 3, "Invalid protocol hint"); + } + } + else if (!lua_isnil(L, -1)) { + return luaL_argerror(L, 3, "protocol hint must be string if set"); + } + lua_pop(L, 1); + + lua_getfield(L, 3, "addrconfig"); + if (lua_toboolean(L, -1)) hints->ai_flags |= AI_ADDRCONFIG; + lua_pop(L, 1); + + lua_getfield(L, 3, "v4mapped"); + if (lua_toboolean(L, -1)) hints->ai_flags |= AI_V4MAPPED; + lua_pop(L, 1); + + lua_getfield(L, 3, "all"); + if (lua_toboolean(L, -1)) hints->ai_flags |= AI_ALL; + lua_pop(L, 1); + + lua_getfield(L, 3, "numerichost"); + if (lua_toboolean(L, -1)) hints->ai_flags |= AI_NUMERICHOST; + lua_pop(L, 1); + + lua_getfield(L, 3, "passive"); + if (lua_toboolean(L, -1)) hints->ai_flags |= AI_PASSIVE; + lua_pop(L, 1); + + lua_getfield(L, 3, "numericserv"); + if (lua_toboolean(L, -1)) { + hints->ai_flags |= AI_NUMERICSERV; + /* On OS X upto at least OSX 10.9, getaddrinfo crashes + * if AI_NUMERICSERV is set and the servname is NULL or "0". + * This workaround avoids a segfault in libsystem. + */ + if (NULL == service) service = "00"; + } + lua_pop(L, 1); + + lua_getfield(L, 3, "canonname"); + if (lua_toboolean(L, -1)) hints->ai_flags |= AI_CANONNAME; + lua_pop(L, 1); + } + + req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + + ret = uv_getaddrinfo(luv_loop(L), req, ref == LUA_NOREF ? NULL : luv_getaddrinfo_cb, node, service, hints); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + if (ref == LUA_NOREF) { + + lua_pop(L, 1); + luv_pushaddrinfo(L, req->addrinfo); + uv_freeaddrinfo(req->addrinfo); + luv_cleanup_req(L, req->data); + } + return 1; +} + +static void luv_getnameinfo_cb(uv_getnameinfo_t* req, int status, const char* hostname, const char* service) { + lua_State* L = luv_state(req->loop); + + int nargs; + + if (status < 0) { + luv_status(L, status); + nargs = 1; + } + else { + lua_pushnil(L); + lua_pushstring(L, hostname); + lua_pushstring(L, service); + nargs = 3; + } + + luv_fulfill_req(L, req->data, nargs); + luv_cleanup_req(L, req->data); + req->data = NULL; +} + +static int luv_getnameinfo(lua_State* L) { + uv_getnameinfo_t* req; + struct sockaddr_storage addr; + const char* ip = NULL; + int flags = 0; + int ret, ref, port = 0; + + luaL_checktype(L, 1, LUA_TTABLE); + memset(&addr, 0, sizeof(addr)); + + lua_getfield(L, 1, "ip"); + if (lua_isstring(L, -1)) { + ip = lua_tostring(L, -1); + } + else if (!lua_isnil(L, -1)) { + luaL_argerror(L, 1, "ip property must be string if set"); + } + lua_pop(L, 1); + + lua_getfield(L, 1, "port"); + if (lua_isnumber(L, -1)) { + port = lua_tointeger(L, -1); + } + else if (!lua_isnil(L, -1)) { + luaL_argerror(L, 1, "port property must be integer if set"); + } + lua_pop(L, 1); + + if (ip || port) { + if (!ip) ip = "0.0.0.0"; + if (!uv_ip4_addr(ip, port, (struct sockaddr_in*)&addr)) { + addr.ss_family = AF_INET; + } + else if (!uv_ip6_addr(ip, port, (struct sockaddr_in6*)&addr)) { + addr.ss_family = AF_INET6; + } + else { + return luaL_argerror(L, 1, "Invalid ip address or port"); + } + } + + lua_getfield(L, 1, "family"); + if (lua_isnumber(L, -1)) { + addr.ss_family = lua_tointeger(L, -1); + } + else if (lua_isstring(L, -1)) { + addr.ss_family = luv_af_string_to_num(lua_tostring(L, -1)); + } + else if (!lua_isnil(L, -1)) { + luaL_argerror(L, 1, "family must be string if set"); + } + lua_pop(L, 1); + + ref = lua_isnoneornil(L, 2) ? LUA_NOREF : luv_check_continuation(L, 2); + + req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + + ret = uv_getnameinfo(luv_loop(L), req, ref == LUA_NOREF ? NULL : luv_getnameinfo_cb, (struct sockaddr*)&addr, flags); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + if (ref == LUA_NOREF) { + lua_pop(L, 1); + lua_pushstring(L, req->host); + lua_pushstring(L, req->service); + luv_cleanup_req(L, req->data); + return 2; + } + return 1; +} + diff --git a/3rdparty/luv/src/fs.c b/3rdparty/luv/src/fs.c new file mode 100644 index 00000000000..bacf11ea647 --- /dev/null +++ b/3rdparty/luv/src/fs.c @@ -0,0 +1,614 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "luv.h" + +static uv_fs_t* luv_check_fs(lua_State* L, int index) { + uv_fs_t* req = luaL_checkudata(L, index, "uv_req"); + luaL_argcheck(L, req->type = UV_FS && req->data, index, "Expected uv_fs_t"); + return req; +} + +static void luv_push_timespec_table(lua_State* L, const uv_timespec_t* t) { + lua_createtable(L, 0, 2); + lua_pushinteger(L, t->tv_sec); + lua_setfield(L, -2, "sec"); + lua_pushinteger(L, t->tv_nsec); + lua_setfield(L, -2, "nsec"); +} + +static void luv_push_stats_table(lua_State* L, const uv_stat_t* s) { + const char* type = NULL; + lua_createtable(L, 0, 23); + lua_pushinteger(L, s->st_dev); + lua_setfield(L, -2, "dev"); + lua_pushinteger(L, s->st_mode); + lua_setfield(L, -2, "mode"); + lua_pushinteger(L, s->st_nlink); + lua_setfield(L, -2, "nlink"); + lua_pushinteger(L, s->st_uid); + lua_setfield(L, -2, "uid"); + lua_pushinteger(L, s->st_gid); + lua_setfield(L, -2, "gid"); + lua_pushinteger(L, s->st_rdev); + lua_setfield(L, -2, "rdev"); + lua_pushinteger(L, s->st_ino); + lua_setfield(L, -2, "ino"); + lua_pushinteger(L, s->st_size); + lua_setfield(L, -2, "size"); + lua_pushinteger(L, s->st_blksize); + lua_setfield(L, -2, "blksize"); + lua_pushinteger(L, s->st_blocks); + lua_setfield(L, -2, "blocks"); + lua_pushinteger(L, s->st_flags); + lua_setfield(L, -2, "flags"); + lua_pushinteger(L, s->st_gen); + lua_setfield(L, -2, "gen"); + luv_push_timespec_table(L, &s->st_atim); + lua_setfield(L, -2, "atime"); + luv_push_timespec_table(L, &s->st_mtim); + lua_setfield(L, -2, "mtime"); + luv_push_timespec_table(L, &s->st_ctim); + lua_setfield(L, -2, "ctime"); + luv_push_timespec_table(L, &s->st_birthtim); + lua_setfield(L, -2, "birthtime"); + if (S_ISREG(s->st_mode)) { + type = "file"; + } + else if (S_ISDIR(s->st_mode)) { + type = "directory"; + } + else if (S_ISLNK(s->st_mode)) { + type = "link"; + } + else if (S_ISFIFO(s->st_mode)) { + type = "fifo"; + } +#ifdef S_ISSOCK + else if (S_ISSOCK(s->st_mode)) { + type = "socket"; + } +#endif + else if (S_ISCHR(s->st_mode)) { + type = "char"; + } + else if (S_ISBLK(s->st_mode)) { + type = "block"; + } + if (type) { + lua_pushstring(L, type); + lua_setfield(L, -2, "type"); + } +} + +static int luv_check_flags(lua_State* L, int index) { + const char* string; + if (lua_isnumber(L, index)) { + return lua_tointeger(L, index); + } + else if (!lua_isstring(L, index)) { + return luaL_argerror(L, index, "Expected string or integer for file open mode"); + } + string = lua_tostring(L, index); + + if (strcmp(string, "r") == 0) return O_RDONLY; +#ifdef O_SYNC + if (strcmp(string, "rs") == 0 || + strcmp(string, "sr") == 0) return O_RDONLY | O_SYNC; +#endif + if (strcmp(string, "r+") == 0) return O_RDWR; +#ifdef O_SYNC + if (strcmp(string, "rs+") == 0 || + strcmp(string, "sr+") == 0) return O_RDWR | O_SYNC; +#endif + if (strcmp(string, "w") == 0) return O_TRUNC | O_CREAT | O_WRONLY; + if (strcmp(string, "wx") == 0 || + strcmp(string, "xw") == 0) return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL; + if (strcmp(string, "w+") == 0) return O_TRUNC | O_CREAT | O_RDWR; + if (strcmp(string, "wx+") == 0 || + strcmp(string, "xw+") == 0) return O_TRUNC | O_CREAT | O_RDWR | O_EXCL; + if (strcmp(string, "a") == 0) return O_APPEND | O_CREAT | O_WRONLY; + if (strcmp(string, "ax") == 0 || + strcmp(string, "xa") == 0) return O_APPEND | O_CREAT | O_WRONLY | O_EXCL; + if (strcmp(string, "a+") == 0) return O_APPEND | O_CREAT | O_RDWR; + if (strcmp(string, "ax+") == 0 || + strcmp(string, "xa+") == 0) return O_APPEND | O_CREAT | O_RDWR | O_EXCL; + + return luaL_error(L, "Unknown file open flag '%s'", string); +} + +static int luv_check_amode(lua_State* L, int index) { + size_t i; + int mode; + const char* string; + if (lua_isnumber(L, index)) { + return lua_tointeger(L, index); + } + else if (!lua_isstring(L, index)) { + return luaL_argerror(L, index, "Expected string or integer for file access mode check"); + } + string = lua_tostring(L, index); + mode = 0; + for (i = 0; i < strlen(string); ++i) { + switch (string[i]) { + case 'r': case 'R': + mode |= R_OK; + break; + case 'w': case 'W': + mode |= W_OK; + break; + case 'x': case 'X': + mode |= X_OK; + break; + default: + return luaL_argerror(L, index, "Unknown character in access mode string"); + } + } + return mode; +} + +/* Processes a result and pushes the data onto the stack + returns the number of items pushed */ +static int push_fs_result(lua_State* L, uv_fs_t* req) { + luv_req_t* data = req->data; + + if (req->fs_type == UV_FS_ACCESS) { + lua_pushboolean(L, req->result >= 0); + return 1; + } + + if (req->result < 0) { + lua_pushnil(L); + if (req->path) { + lua_pushfstring(L, "%s: %s: %s", uv_err_name(req->result), uv_strerror(req->result), req->path); + } + else { + lua_pushfstring(L, "%s: %s", uv_err_name(req->result), uv_strerror(req->result)); + } + return 2; + } + + switch (req->fs_type) { + case UV_FS_CLOSE: + case UV_FS_RENAME: + case UV_FS_UNLINK: + case UV_FS_RMDIR: + case UV_FS_MKDIR: + case UV_FS_FTRUNCATE: + case UV_FS_FSYNC: + case UV_FS_FDATASYNC: + case UV_FS_LINK: + case UV_FS_SYMLINK: + case UV_FS_CHMOD: + case UV_FS_FCHMOD: + case UV_FS_CHOWN: + case UV_FS_FCHOWN: + case UV_FS_UTIME: + case UV_FS_FUTIME: + lua_pushboolean(L, 1); + return 1; + + case UV_FS_OPEN: + case UV_FS_SENDFILE: + case UV_FS_WRITE: + lua_pushinteger(L, req->result); + return 1; + + case UV_FS_STAT: + case UV_FS_LSTAT: + case UV_FS_FSTAT: + luv_push_stats_table(L, &req->statbuf); + return 1; + + case UV_FS_MKDTEMP: + lua_pushstring(L, req->path); + return 1; + + case UV_FS_READLINK: + case UV_FS_REALPATH: + lua_pushstring(L, (char*)req->ptr); + return 1; + + case UV_FS_READ: + lua_pushlstring(L, data->data, req->result); + return 1; + + case UV_FS_SCANDIR: + // Expose the userdata for the request. + lua_rawgeti(L, LUA_REGISTRYINDEX, data->req_ref); + return 1; + + default: + lua_pushnil(L); + lua_pushfstring(L, "UNKNOWN FS TYPE %d\n", req->fs_type); + return 2; + } + +} + +static void luv_fs_cb(uv_fs_t* req) { + lua_State* L = luv_state(req->loop); + + int nargs = push_fs_result(L, req); + if (nargs == 2 && lua_isnil(L, -nargs)) { + // If it was an error, convert to (err, value) format. + lua_remove(L, -nargs); + nargs--; + } + else { + // Otherwise insert a nil in front to convert to (err, value) format. + lua_pushnil(L); + lua_insert(L, -nargs - 1); + nargs++; + } + luv_fulfill_req(L, req->data, nargs); + if (req->fs_type != UV_FS_SCANDIR) { + luv_cleanup_req(L, req->data); + req->data = NULL; + uv_fs_req_cleanup(req); + } +} + +#define FS_CALL(func, req, ...) { \ + int ret, sync; \ + luv_req_t* data = req->data; \ + sync = data->callback_ref == LUA_NOREF; \ + ret = uv_fs_##func(luv_loop(L), req, __VA_ARGS__, \ + sync ? NULL : luv_fs_cb); \ + if (req->fs_type != UV_FS_ACCESS && ret < 0) { \ + lua_pushnil(L); \ + if (req->path) { \ + lua_pushfstring(L, "%s: %s: %s", uv_err_name(req->result), uv_strerror(req->result), req->path); \ + } \ + else { \ + lua_pushfstring(L, "%s: %s", uv_err_name(req->result), uv_strerror(req->result)); \ + } \ + lua_pushstring(L, uv_err_name(req->result)); \ + luv_cleanup_req(L, req->data); \ + req->data = NULL; \ + uv_fs_req_cleanup(req); \ + return 3; \ + } \ + if (sync) { \ + int nargs = push_fs_result(L, req); \ + if (req->fs_type != UV_FS_SCANDIR) { \ + luv_cleanup_req(L, req->data); \ + req->data = NULL; \ + uv_fs_req_cleanup(req); \ + } \ + return nargs; \ + } \ + lua_rawgeti(L, LUA_REGISTRYINDEX, data->req_ref); \ + return 1; \ +} + +static int luv_fs_close(lua_State* L) { + uv_file file = luaL_checkinteger(L, 1); + int ref = luv_check_continuation(L, 2); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(close, req, file); +} + +static int luv_fs_open(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + int flags = luv_check_flags(L, 2); + int mode = luaL_checkinteger(L, 3); + int ref = luv_check_continuation(L, 4); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(open, req, path, flags, mode); +} + +static int luv_fs_read(lua_State* L) { + uv_file file = luaL_checkinteger(L, 1); + int64_t len = luaL_checkinteger(L, 2); + int64_t offset = luaL_checkinteger(L, 3); + uv_buf_t buf; + int ref; + uv_fs_t* req; + char* data = malloc(len); + if (!data) return luaL_error(L, "Failure to allocate buffer"); + buf = uv_buf_init(data, len); + ref = luv_check_continuation(L, 4); + req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + // TODO: find out why we can't just use req->ptr for the base + ((luv_req_t*)req->data)->data = buf.base; + FS_CALL(read, req, file, &buf, 1, offset); +} + +static int luv_fs_unlink(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + int ref = luv_check_continuation(L, 2); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(unlink, req, path); +} + +static int luv_fs_write(lua_State* L) { + uv_file file = luaL_checkinteger(L, 1); + uv_buf_t buf; + int64_t offset; + int ref; + uv_fs_t* req; + size_t count; + uv_buf_t *bufs = NULL; + + if (lua_istable(L, 2)) { + bufs = luv_prep_bufs(L, 2, &count); + buf.base = NULL; + } + else if (lua_isstring(L, 2)) { + luv_check_buf(L, 2, &buf); + count = 1; + } + else { + return luaL_argerror(L, 2, "data must be string or table of strings"); + } + + offset = luaL_checkinteger(L, 3); + ref = luv_check_continuation(L, 4); + req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + req->ptr = buf.base; + ((luv_req_t*)req->data)->data = bufs; + FS_CALL(write, req, file, bufs ? bufs : &buf, count, offset); +} + +static int luv_fs_mkdir(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + int mode = luaL_checkinteger(L, 2); + int ref = luv_check_continuation(L, 3); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(mkdir, req, path, mode); +} + +static int luv_fs_mkdtemp(lua_State* L) { + const char* tpl = luaL_checkstring(L, 1); + int ref = luv_check_continuation(L, 2); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(mkdtemp, req, tpl); +} + +static int luv_fs_rmdir(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + int ref = luv_check_continuation(L, 2); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(rmdir, req, path); +} + +static int luv_fs_scandir(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + int flags = 0; // TODO: find out what these flags are. + int ref = luv_check_continuation(L, 2); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(scandir, req, path, flags); +} + +static int luv_fs_scandir_next(lua_State* L) { + uv_fs_t* req = luv_check_fs(L, 1); + uv_dirent_t ent; + int ret = uv_fs_scandir_next(req, &ent); + const char* type; + if (ret == UV_EOF) { + luv_cleanup_req(L, req->data); + req->data = NULL; + uv_fs_req_cleanup(req); + return 0; + } + if (ret < 0) return luv_error(L, ret); + lua_pushstring(L, ent.name); + switch (ent.type) { + case UV_DIRENT_UNKNOWN: return 1; + case UV_DIRENT_FILE: type = "file"; break; + case UV_DIRENT_DIR: type = "directory"; break; + case UV_DIRENT_LINK: type = "link"; break; + case UV_DIRENT_FIFO: type = "fifo"; break; + case UV_DIRENT_SOCKET: type = "socket"; break; + case UV_DIRENT_CHAR: type = "char"; break; + case UV_DIRENT_BLOCK: type = "block"; break; + default: assert(0); + } + lua_pushstring(L, type); + return 2; +} + +static int luv_fs_stat(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + int ref = luv_check_continuation(L, 2); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(stat, req, path); +} + +static int luv_fs_fstat(lua_State* L) { + uv_file file = luaL_checkinteger(L, 1); + int ref = luv_check_continuation(L, 2); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(fstat, req, file); +} + +static int luv_fs_lstat(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + int ref = luv_check_continuation(L, 2); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(lstat, req, path); +} + +static int luv_fs_rename(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + const char* new_path = luaL_checkstring(L, 2); + int ref = luv_check_continuation(L, 3); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(rename, req, path, new_path); +} + +static int luv_fs_fsync(lua_State* L) { + uv_file file = luaL_checkinteger(L, 1); + int ref = luv_check_continuation(L, 2); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(fsync, req, file); +} + +static int luv_fs_fdatasync(lua_State* L) { + uv_file file = luaL_checkinteger(L, 1); + int ref = luv_check_continuation(L, 2); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(fdatasync, req, file); +} + +static int luv_fs_ftruncate(lua_State* L) { + uv_file file = luaL_checkinteger(L, 1); + int64_t offset = luaL_checkinteger(L, 2); + int ref = luv_check_continuation(L, 3); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(ftruncate, req, file, offset); +} + +static int luv_fs_sendfile(lua_State* L) { + uv_file out_fd = luaL_checkinteger(L, 1); + uv_file in_fd = luaL_checkinteger(L, 2); + int64_t in_offset = luaL_checkinteger(L, 3); + size_t length = luaL_checkinteger(L, 4); + int ref = luv_check_continuation(L, 5); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(sendfile, req, out_fd, in_fd, in_offset, length); +} + +static int luv_fs_access(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + int amode = luv_check_amode(L, 2); + int ref = luv_check_continuation(L, 3); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(access, req, path, amode); +} + +static int luv_fs_chmod(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + int mode = luaL_checkinteger(L, 2); + int ref = luv_check_continuation(L, 3); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(chmod, req, path, mode); +} + +static int luv_fs_fchmod(lua_State* L) { + uv_file file = luaL_checkinteger(L, 1); + int mode = luaL_checkinteger(L, 2); + int ref = luv_check_continuation(L, 3); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(fchmod, req, file, mode); +} + +static int luv_fs_utime(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + double atime = luaL_checknumber(L, 2); + double mtime = luaL_checknumber(L, 3); + int ref = luv_check_continuation(L, 4); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(utime, req, path, atime, mtime); +} + +static int luv_fs_futime(lua_State* L) { + uv_file file = luaL_checkinteger(L, 1); + double atime = luaL_checknumber(L, 2); + double mtime = luaL_checknumber(L, 3); + int ref = luv_check_continuation(L, 4); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(futime, req, file, atime, mtime); +} + +static int luv_fs_link(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + const char* new_path = luaL_checkstring(L, 2); + int ref = luv_check_continuation(L, 3); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(link, req, path, new_path); +} + +static int luv_fs_symlink(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + const char* new_path = luaL_checkstring(L, 2); + int flags = 0, ref; + uv_fs_t* req; + if (lua_type(L, 3) == LUA_TTABLE) { + lua_getfield(L, 3, "dir"); + if (lua_toboolean(L, -1)) flags |= UV_FS_SYMLINK_DIR; + lua_pop(L, 1); + lua_getfield(L, 3, "junction"); + if (lua_toboolean(L, -1)) flags |= UV_FS_SYMLINK_JUNCTION; + lua_pop(L, 1); + } + ref = luv_check_continuation(L, 4); + req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + + FS_CALL(symlink, req, path, new_path, flags); +} + +static int luv_fs_readlink(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + int ref = luv_check_continuation(L, 2); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(readlink, req, path); +} + +static int luv_fs_realpath(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + int ref = luv_check_continuation(L, 2); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(realpath, req, path); +} + +static int luv_fs_chown(lua_State* L) { + const char* path = luaL_checkstring(L, 1); + uv_uid_t uid = luaL_checkinteger(L, 2); + uv_uid_t gid = luaL_checkinteger(L, 3); + int ref = luv_check_continuation(L, 4); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(chown, req, path, uid, gid); +} + +static int luv_fs_fchown(lua_State* L) { + uv_file file = luaL_checkinteger(L, 1); + uv_uid_t uid = luaL_checkinteger(L, 2); + uv_uid_t gid = luaL_checkinteger(L, 3); + int ref = luv_check_continuation(L, 4); + uv_fs_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + FS_CALL(fchown, req, file, uid, gid); +} diff --git a/3rdparty/luv/src/fs_event.c b/3rdparty/luv/src/fs_event.c new file mode 100644 index 00000000000..52bda788421 --- /dev/null +++ b/3rdparty/luv/src/fs_event.c @@ -0,0 +1,97 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "luv.h" + +static uv_fs_event_t* luv_check_fs_event(lua_State* L, int index) { + uv_fs_event_t* handle = luv_checkudata(L, index, "uv_fs_event"); + luaL_argcheck(L, handle->type == UV_FS_EVENT && handle->data, index, "Expected uv_fs_event_t"); + return handle; +} + +static int luv_new_fs_event(lua_State* L) { + uv_fs_event_t* handle = luv_newuserdata(L, sizeof(*handle)); + int ret = uv_fs_event_init(luv_loop(L), handle); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + handle->data = luv_setup_handle(L); + return 1; +} + +static void luv_fs_event_cb(uv_fs_event_t* handle, const char* filename, int events, int status) { + lua_State* L = luv_state(handle->loop); + + // err + luv_status(L, status); + + // filename + lua_pushstring(L, filename); + + // events + lua_newtable(L); + if (events & UV_RENAME) { + lua_pushboolean(L, 1); + lua_setfield(L, -2, "rename"); + } + if (events & UV_CHANGE) { + lua_pushboolean(L, 1); + lua_setfield(L, -2, "change"); + } + + luv_call_callback(L, handle->data, LUV_FS_EVENT, 3); +} + +static int luv_fs_event_start(lua_State* L) { + uv_fs_event_t* handle = luv_check_fs_event(L, 1); + const char* path = luaL_checkstring(L, 2); + int flags = 0, ret; + luaL_checktype(L, 3, LUA_TTABLE); + lua_getfield(L, 3, "watch_entry"); + if (lua_toboolean(L, -1)) flags |= UV_FS_EVENT_WATCH_ENTRY; + lua_pop(L, 1); + lua_getfield(L, 3, "stat"); + if (lua_toboolean(L, -1)) flags |= UV_FS_EVENT_STAT; + lua_pop(L, 1); + lua_getfield(L, 3, "recursive"); + if (lua_toboolean(L, -1)) flags |= UV_FS_EVENT_RECURSIVE; + lua_pop(L, 1); + luv_check_callback(L, handle->data, LUV_FS_EVENT, 4); + ret = uv_fs_event_start(handle, luv_fs_event_cb, path, flags); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_fs_event_stop(lua_State* L) { + uv_fs_event_t* handle = luv_check_fs_event(L, 1); + int ret = uv_fs_event_stop(handle); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_fs_event_getpath(lua_State* L) { + uv_fs_event_t* handle = luv_check_fs_event(L, 1); + size_t len = 2*PATH_MAX; + char buf[2*PATH_MAX]; + int ret = uv_fs_event_getpath(handle, buf, &len); + if (ret < 0) return luv_error(L, ret); + lua_pushlstring(L, buf, len); + return 1; +} diff --git a/3rdparty/luv/src/fs_poll.c b/3rdparty/luv/src/fs_poll.c new file mode 100644 index 00000000000..7ead32f322c --- /dev/null +++ b/3rdparty/luv/src/fs_poll.c @@ -0,0 +1,90 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "luv.h" + +static uv_fs_poll_t* luv_check_fs_poll(lua_State* L, int index) { + uv_fs_poll_t* handle = luv_checkudata(L, index, "uv_fs_poll"); + luaL_argcheck(L, handle->type == UV_FS_POLL && handle->data, index, "Expected uv_fs_poll_t"); + return handle; +} + +static int luv_new_fs_poll(lua_State* L) { + uv_fs_poll_t* handle = luv_newuserdata(L, sizeof(*handle)); + int ret = uv_fs_poll_init(luv_loop(L), handle); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + handle->data = luv_setup_handle(L); + return 1; +} + +static void luv_fs_poll_cb(uv_fs_poll_t* handle, int status, const uv_stat_t* prev, const uv_stat_t* curr) { + lua_State* L = luv_state(handle->loop); + + // err + luv_status(L, status); + + // prev + if (prev) { + luv_push_stats_table(L, prev); + } + else { + lua_pushnil(L); + } + + // curr + if (curr) { + luv_push_stats_table(L, curr); + } + else { + lua_pushnil(L); + } + + luv_call_callback(L, handle->data, LUV_FS_POLL, 3); +} + +static int luv_fs_poll_start(lua_State* L) { + uv_fs_poll_t* handle = luv_check_fs_poll(L, 1); + const char* path = luaL_checkstring(L, 2); + unsigned int interval = luaL_checkinteger(L, 3); + int ret; + luv_check_callback(L, handle->data, LUV_FS_POLL, 4); + ret = uv_fs_poll_start(handle, luv_fs_poll_cb, path, interval); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_fs_poll_stop(lua_State* L) { + uv_fs_poll_t* handle = luv_check_fs_poll(L, 1); + int ret = uv_fs_poll_stop(handle); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_fs_poll_getpath(lua_State* L) { + uv_fs_poll_t* handle = luv_check_fs_poll(L, 1); + size_t len = 2*PATH_MAX; + char buf[2*PATH_MAX]; + int ret = uv_fs_poll_getpath(handle, buf, &len); + if (ret < 0) return luv_error(L, ret); + lua_pushlstring(L, buf, len); + return 1; +} diff --git a/3rdparty/luv/src/handle.c b/3rdparty/luv/src/handle.c new file mode 100644 index 00000000000..3efd2982641 --- /dev/null +++ b/3rdparty/luv/src/handle.c @@ -0,0 +1,173 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +static void* luv_newuserdata(lua_State* L, size_t sz) { + void* handle = malloc(sz); + if (handle) { + *(void**)lua_newuserdata(L, sizeof(void*)) = handle; + } + return handle; +} + +static void* luv_checkudata(lua_State* L, int ud, const char* tname) { + return *(void**) luaL_checkudata(L, ud, tname); +} + +static uv_handle_t* luv_check_handle(lua_State* L, int index) { + int isHandle; + uv_handle_t* handle; + if (!(handle = *(void**)lua_touserdata(L, index))) { goto fail; } + lua_getfield(L, LUA_REGISTRYINDEX, "uv_handle"); + lua_getmetatable(L, index < 0 ? index - 1 : index); + lua_rawget(L, -2); + isHandle = lua_toboolean(L, -1); + lua_pop(L, 2); + if (isHandle) { return handle; } + fail: luaL_argerror(L, index, "Expected uv_handle userdata"); + return NULL; +} + +// Show the libuv type instead of generic "userdata" +static int luv_handle_tostring(lua_State* L) { + uv_handle_t* handle = luv_check_handle(L, 1); + switch (handle->type) { +#define XX(uc, lc) case UV_##uc: lua_pushfstring(L, "uv_"#lc"_t: %p", handle); break; + UV_HANDLE_TYPE_MAP(XX) +#undef XX + default: lua_pushfstring(L, "uv_handle_t: %p", handle); break; + } + return 1; +} + +static int luv_is_active(lua_State* L) { + uv_handle_t* handle = luv_check_handle(L, 1); + int ret = uv_is_active(handle); + if (ret < 0) return luv_error(L, ret); + lua_pushboolean(L, ret); + return 1; +} + +static int luv_is_closing(lua_State* L) { + uv_handle_t* handle = luv_check_handle(L, 1); + int ret = uv_is_closing(handle); + if (ret < 0) return luv_error(L, ret); + lua_pushboolean(L, ret); + return 1; +} + +static void luv_close_cb(uv_handle_t* handle) { + lua_State* L = luv_state(handle->loop); + luv_handle_t* data = handle->data; + if (!data) return; + luv_call_callback(L, data, LUV_CLOSED, 0); + luv_cleanup_handle(L, data); + handle->data = NULL; +} + +static int luv_close(lua_State* L) { + uv_handle_t* handle = luv_check_handle(L, 1); + if (uv_is_closing(handle)) { + luaL_error(L, "handle %p is already closing", handle); + } + if (!lua_isnoneornil(L, 2)) { + luv_check_callback(L, handle->data, LUV_CLOSED, 2); + } + uv_close(handle, luv_close_cb); + return 0; +} + +static void luv_gc_cb(uv_handle_t* handle) { + luv_close_cb(handle); + free(handle); +} + +static int luv_handle_gc(lua_State* L) { + void** udata = lua_touserdata(L, 1); + uv_handle_t* handle = *udata; + if (handle != NULL) { + if (!uv_is_closing(handle)) + uv_close(handle, luv_gc_cb); + else + free(*udata); + + *udata = NULL; + } + + return 0; +} + +static int luv_ref(lua_State* L) { + uv_handle_t* handle = luv_check_handle(L, 1); + uv_ref(handle); + return 0; +} + +static int luv_unref(lua_State* L) { + uv_handle_t* handle = luv_check_handle(L, 1); + uv_unref(handle); + return 0; +} + +static int luv_has_ref(lua_State* L) { + uv_handle_t* handle = luv_check_handle(L, 1); + int ret = uv_has_ref(handle); + if (ret < 0) return luv_error(L, ret); + lua_pushboolean(L, ret); + return 1; +} + +static int luv_send_buffer_size(lua_State* L) { + uv_handle_t* handle = luv_check_handle(L, 1); + int value; + int ret; + if (lua_isnoneornil(L, 2)) { + value = 0; + } + else { + value = luaL_checkinteger(L, 2); + } + ret = uv_send_buffer_size(handle, &value); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_recv_buffer_size(lua_State* L) { + uv_handle_t* handle = luv_check_handle(L, 1); + int value; + int ret; + if (lua_isnoneornil(L, 2)) { + value = 0; + } + else { + value = luaL_checkinteger(L, 2); + } + ret = uv_recv_buffer_size(handle, &value); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_fileno(lua_State* L) { + uv_handle_t* handle = luv_check_handle(L, 1); + uv_os_fd_t fd; + int ret = uv_fileno(handle, &fd); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, (LUA_INTEGER)(ptrdiff_t)fd); + return 1; +} diff --git a/3rdparty/luv/src/idle.c b/3rdparty/luv/src/idle.c new file mode 100644 index 00000000000..132cbe43c33 --- /dev/null +++ b/3rdparty/luv/src/idle.c @@ -0,0 +1,59 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +static uv_idle_t* luv_check_idle(lua_State* L, int index) { + uv_idle_t* handle = luv_checkudata(L, index, "uv_idle"); + luaL_argcheck(L, handle->type == UV_IDLE && handle->data, index, "Expected uv_idle_t"); + return handle; +} + +static int luv_new_idle(lua_State* L) { + uv_idle_t* handle = luv_newuserdata(L, sizeof(*handle)); + int ret = uv_idle_init(luv_loop(L), handle); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + handle->data = luv_setup_handle(L); + return 1; +} + +static void luv_idle_cb(uv_idle_t* handle) { + lua_State* L = luv_state(handle->loop); + luv_handle_t* data = handle->data; + luv_call_callback(L, data, LUV_IDLE, 0); +} + +static int luv_idle_start(lua_State* L) { + uv_idle_t* handle = luv_check_idle(L, 1); + int ret; + luv_check_callback(L, handle->data, LUV_IDLE, 2); + ret = uv_idle_start(handle, luv_idle_cb); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_idle_stop(lua_State* L) { + uv_idle_t* handle = luv_check_idle(L, 1); + int ret = uv_idle_stop(handle); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + diff --git a/3rdparty/luv/src/lhandle.c b/3rdparty/luv/src/lhandle.c new file mode 100644 index 00000000000..c8cf294504e --- /dev/null +++ b/3rdparty/luv/src/lhandle.c @@ -0,0 +1,116 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "lhandle.h" + +static luv_handle_t* luv_setup_handle(lua_State* L) { + luv_handle_t* data; + const uv_handle_t* handle = *(void**)lua_touserdata(L, -1); + luaL_checktype(L, -1, LUA_TUSERDATA); + + data = malloc(sizeof(*data)); + if (!data) luaL_error(L, "Can't allocate luv handle"); + + #define XX(uc, lc) case UV_##uc: \ + luaL_getmetatable(L, "uv_"#lc); \ + break; + switch (handle->type) { + UV_HANDLE_TYPE_MAP(XX) + default: + luaL_error(L, "Unknown handle type"); + return NULL; + } + #undef XX + + lua_setmetatable(L, -2); + + lua_pushvalue(L, -1); + + data->ref = luaL_ref(L, LUA_REGISTRYINDEX); + data->callbacks[0] = LUA_NOREF; + data->callbacks[1] = LUA_NOREF; + data->extra = NULL; + return data; +} + +static void luv_check_callback(lua_State* L, luv_handle_t* data, luv_callback_id id, int index) { + luaL_checktype(L, index, LUA_TFUNCTION); + luaL_unref(L, LUA_REGISTRYINDEX, data->callbacks[id]); + lua_pushvalue(L, index); + data->callbacks[id] = luaL_ref(L, LUA_REGISTRYINDEX); +} + +static int traceback (lua_State *L) { + if (!lua_isstring(L, 1)) /* 'message' not a string? */ + return 1; /* keep it intact */ + lua_pushglobaltable(L); + lua_getfield(L, -1, "debug"); + lua_remove(L, -2); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + return 1; + } + lua_getfield(L, -1, "traceback"); + if (!lua_isfunction(L, -1)) { + lua_pop(L, 2); + return 1; + } + lua_pushvalue(L, 1); /* pass error message */ + lua_pushinteger(L, 2); /* skip this function and traceback */ + lua_call(L, 2, 1); /* call debug.traceback */ + return 1; +} + +static void luv_call_callback(lua_State* L, luv_handle_t* data, luv_callback_id id, int nargs) { + int ref = data->callbacks[id]; + if (ref == LUA_NOREF) { + lua_pop(L, nargs); + } + else { + // Get the traceback function in case of error + lua_pushcfunction(L, traceback); + // And insert it before the args if there are any. + if (nargs) { + lua_insert(L, -1 - nargs); + } + // Get the callback + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + // And insert it before the args if there are any. + if (nargs) { + lua_insert(L, -1 - nargs); + } + + if (lua_pcall(L, nargs, 0, -2 - nargs)) { + fprintf(stderr, "Uncaught Error: %s\n", lua_tostring(L, -1)); + exit(-1); + } + // Remove the traceback function + lua_pop(L, 1); + } +} + +static void luv_cleanup_handle(lua_State* L, luv_handle_t* data) { + luaL_unref(L, LUA_REGISTRYINDEX, data->ref); + luaL_unref(L, LUA_REGISTRYINDEX, data->callbacks[0]); + luaL_unref(L, LUA_REGISTRYINDEX, data->callbacks[1]); + if (data->extra) + free(data->extra); + free(data); +} + +static void luv_find_handle(lua_State* L, luv_handle_t* data) { + lua_rawgeti(L, LUA_REGISTRYINDEX, data->ref); +} diff --git a/3rdparty/luv/src/lhandle.h b/3rdparty/luv/src/lhandle.h new file mode 100644 index 00000000000..f6c0733719b --- /dev/null +++ b/3rdparty/luv/src/lhandle.h @@ -0,0 +1,67 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef LUV_LHANDLE_H +#define LUV_LHANDLE_H + +#include "luv.h" + +/* There are two slots for holding callbacks. One is for the CLOSED event. + The other slot is for all others since they never conflict in practice. +*/ +#define luv_callback_id int +#define LUV_CLOSED 0 +#define LUV_TIMEOUT 1 +#define LUV_PREPARE 1 +#define LUV_IDLE 1 +#define LUV_CHECK 1 +#define LUV_ASYNC 1 +#define LUV_POLL 1 +#define LUV_SIGNAL 1 +#define LUV_EXIT 1 +#define LUV_CONNECTION 1 +#define LUV_READ 1 +#define LUV_RECV 1 +#define LUV_FS_EVENT 1 +#define LUV_FS_POLL 1 + +/* Ref for userdata and event callbacks */ +typedef struct { + int ref; + int callbacks[2]; + void* extra; +} luv_handle_t; + +/* Setup the handle at the top of the stack */ +static luv_handle_t* luv_setup_handle(lua_State* L); + +/* Store a lua callback in a luv_handle for future callbacks. + Either replace an existing callback by id or append a new one at the end. +*/ +static void luv_check_callback(lua_State* L, luv_handle_t* data, luv_callback_id id, int index); + +/* Lookup a function and call it with nargs + If there is no such function, pop the args. +*/ +static void luv_call_callback(lua_State* L, luv_handle_t* data, luv_callback_id id, int nargs); + +/* Push a userdata on the stack from a handle */ +static void luv_find_handle(lua_State* L, luv_handle_t* data); + +/* Recursivly free the luv_handle and all event handlers */ +static void luv_cleanup_handle(lua_State* L, luv_handle_t* data); + +#endif diff --git a/3rdparty/luv/src/loop.c b/3rdparty/luv/src/loop.c new file mode 100644 index 00000000000..33c49d3f64c --- /dev/null +++ b/3rdparty/luv/src/loop.c @@ -0,0 +1,92 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +static int luv_loop_close(lua_State* L) { + int ret = uv_loop_close(luv_loop(L)); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +// These are the same order as uv_run_mode which also starts at 0 +static const char *const luv_runmodes[] = { + "default", "once", "nowait", NULL +}; + +static int luv_run(lua_State* L) { + int mode = luaL_checkoption(L, 1, "default", luv_runmodes); + int ret = uv_run(luv_loop(L), mode); + if (ret < 0) return luv_error(L, ret); + lua_pushboolean(L, ret); + return 1; +} + +static int luv_loop_alive(lua_State* L) { + int ret = uv_loop_alive(luv_loop(L)); + if (ret < 0) return luv_error(L, ret); + lua_pushboolean(L, ret); + return 1; +} + +static int luv_stop(lua_State* L) { + uv_stop(luv_loop(L)); + return 0; +} + +static int luv_backend_fd(lua_State* L) { + int ret = uv_backend_fd(luv_loop(L)); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_backend_timeout(lua_State* L) { + int ret = uv_backend_timeout(luv_loop(L)); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_now(lua_State* L) { + uint64_t now = uv_now(luv_loop(L)); + lua_pushinteger(L, now); + return 1; +} + +static int luv_update_time(lua_State* L) { + uv_update_time(luv_loop(L)); + return 0; +} + +static void luv_walk_cb(uv_handle_t* handle, void* arg) { + lua_State* L = arg; + luv_handle_t* data = handle->data; + + // Sanity check + // Most invalid values are large and refs are small, 0x1000000 is arbitrary. + assert(data && data->ref < 0x1000000); + + lua_pushvalue(L, 1); // Copy the function + luv_find_handle(L, data); // Get the userdata + lua_call(L, 1, 0); // Call the function +} + +static int luv_walk(lua_State* L) { + luaL_checktype(L, 1, LUA_TFUNCTION); + uv_walk(luv_loop(L), luv_walk_cb, L); + return 0; +} diff --git a/3rdparty/luv/src/lreq.c b/3rdparty/luv/src/lreq.c new file mode 100644 index 00000000000..38ed6a77eb0 --- /dev/null +++ b/3rdparty/luv/src/lreq.c @@ -0,0 +1,71 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "lreq.h" + + +static int luv_check_continuation(lua_State* L, int index) { + if (lua_isnoneornil(L, index)) return LUA_NOREF; + luaL_checktype(L, index, LUA_TFUNCTION); + lua_pushvalue(L, index); + return luaL_ref(L, LUA_REGISTRYINDEX); +} + +// Store a lua callback in a luv_req for the continuation. +// The uv_req_t is assumed to be at the top of the stack +static luv_req_t* luv_setup_req(lua_State* L, int callback_ref) { + luv_req_t* data; + + luaL_checktype(L, -1, LUA_TUSERDATA); + + data = malloc(sizeof(*data)); + if (!data) luaL_error(L, "Problem allocating luv request"); + + luaL_getmetatable(L, "uv_req"); + lua_setmetatable(L, -2); + + lua_pushvalue(L, -1); + data->req_ref = luaL_ref(L, LUA_REGISTRYINDEX); + data->callback_ref = callback_ref; + data->data_ref = LUA_NOREF; + data->data = NULL; + + return data; +} + + +static void luv_fulfill_req(lua_State* L, luv_req_t* data, int nargs) { + if (data->callback_ref == LUA_NOREF) { + lua_pop(L, nargs); + } + else { + // Get the callback + lua_rawgeti(L, LUA_REGISTRYINDEX, data->callback_ref); + // And insert it before the args if there are any. + if (nargs) { + lua_insert(L, -1 - nargs); + } + lua_call(L, nargs, 0); + } +} + +static void luv_cleanup_req(lua_State* L, luv_req_t* data) { + luaL_unref(L, LUA_REGISTRYINDEX, data->req_ref); + luaL_unref(L, LUA_REGISTRYINDEX, data->callback_ref); + luaL_unref(L, LUA_REGISTRYINDEX, data->data_ref); + free(data->data); + free(data); +} diff --git a/3rdparty/luv/src/lreq.h b/3rdparty/luv/src/lreq.h new file mode 100644 index 00000000000..a8b147e057b --- /dev/null +++ b/3rdparty/luv/src/lreq.h @@ -0,0 +1,43 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef LUV_LREQ_H +#define LUV_LREQ_H + +#include "luv.h" + +typedef struct { + int req_ref; /* ref for uv_req_t's userdata */ + int callback_ref; /* ref for callback */ + int data_ref; /* ref for write data */ + void* data; /* extra data */ +} luv_req_t; + +/* Used in the top of a setup function to check the arg + and ref the callback to an integer. +*/ +static int luv_check_continuation(lua_State* L, int index); + +/* setup a luv_req_t. The userdata is assumed to be at the + top of the stack. +*/ +static luv_req_t* luv_setup_req(lua_State* L, int ref); + +static void luv_fulfill_req(lua_State* L, luv_req_t* data, int nargs); + +static void luv_cleanup_req(lua_State* L, luv_req_t* data); + +#endif diff --git a/3rdparty/luv/src/lthreadpool.h b/3rdparty/luv/src/lthreadpool.h new file mode 100644 index 00000000000..0994746bc52 --- /dev/null +++ b/3rdparty/luv/src/lthreadpool.h @@ -0,0 +1,48 @@ +/* +* Copyright 2014 The Luvit Authors. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +*/ +#ifndef LUV_LTHREADPOOL_H +#define LUV_LTHREADPOOL_H + +#include "luv.h" + +#define LUV_THREAD_MAXNUM_ARG 9 + +typedef struct { + /* only support LUA_TNIL, LUA_TBOOLEAN, LUA_TLIGHTUSERDATA, LUA_TNUMBER, LUA_TSTRING*/ + int type; + union + { + lua_Number num; + int boolean; + void* userdata; + struct { + const char* base; + size_t len; + } str; + } val; +} luv_val_t; + +typedef struct { + int argc; + luv_val_t argv[LUV_THREAD_MAXNUM_ARG]; +} luv_thread_arg_t; + +static int luv_thread_arg_set(lua_State* L, luv_thread_arg_t* args, int idx, int top, int flag); +static int luv_thread_arg_push(lua_State* L, const luv_thread_arg_t* args); +static void luv_thread_arg_clear(luv_thread_arg_t* args); + +#endif //LUV_LTHREADPOOL_H diff --git a/3rdparty/luv/src/luv.c b/3rdparty/luv/src/luv.c new file mode 100644 index 00000000000..7b552d68d53 --- /dev/null +++ b/3rdparty/luv/src/luv.c @@ -0,0 +1,519 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "luv.h" +#include "util.c" +#include "lhandle.c" +#include "lreq.c" +#include "loop.c" +#include "req.c" +#include "handle.c" +#include "timer.c" +#include "prepare.c" +#include "check.c" +#include "idle.c" +#include "async.c" +#include "poll.c" +#include "signal.c" +#include "process.c" +#include "stream.c" +#include "tcp.c" +#include "pipe.c" +#include "tty.c" +#include "udp.c" +#include "fs_event.c" +#include "fs_poll.c" +#include "fs.c" +#include "dns.c" +#include "thread.c" +#include "work.c" +#include "misc.c" +#include "constants.c" + +static const luaL_Reg luv_functions[] = { + // loop.c + {"loop_close", luv_loop_close}, + {"run", luv_run}, + {"loop_alive", luv_loop_alive}, + {"stop", luv_stop}, + {"backend_fd", luv_backend_fd}, + {"backend_timeout", luv_backend_timeout}, + {"now", luv_now}, + {"update_time", luv_update_time}, + {"walk", luv_walk}, + + // req.c + {"cancel", luv_cancel}, + + // handle.c + {"is_active", luv_is_active}, + {"is_closing", luv_is_closing}, + {"close", luv_close}, + {"ref", luv_ref}, + {"unref", luv_unref}, + {"has_ref", luv_has_ref}, + {"send_buffer_size", luv_send_buffer_size}, + {"recv_buffer_size", luv_recv_buffer_size}, + {"fileno", luv_fileno}, + + // timer.c + {"new_timer", luv_new_timer}, + {"timer_start", luv_timer_start}, + {"timer_stop", luv_timer_stop}, + {"timer_again", luv_timer_again}, + {"timer_set_repeat", luv_timer_set_repeat}, + {"timer_get_repeat", luv_timer_get_repeat}, + + // prepare.c + {"new_prepare", luv_new_prepare}, + {"prepare_start", luv_prepare_start}, + {"prepare_stop", luv_prepare_stop}, + + // check.c + {"new_check", luv_new_check}, + {"check_start", luv_check_start}, + {"check_stop", luv_check_stop}, + + // idle.c + {"new_idle", luv_new_idle}, + {"idle_start", luv_idle_start}, + {"idle_stop", luv_idle_stop}, + + // async.c + {"new_async", luv_new_async}, + {"async_send", luv_async_send}, + + // poll.c + {"new_poll", luv_new_poll}, + {"new_socket_poll", luv_new_socket_poll}, + {"poll_start", luv_poll_start}, + {"poll_stop", luv_poll_stop}, + + // signal.c + {"new_signal", luv_new_signal}, + {"signal_start", luv_signal_start}, + {"signal_stop", luv_signal_stop}, + + // process.c + {"disable_stdio_inheritance", luv_disable_stdio_inheritance}, + {"spawn", luv_spawn}, + {"process_kill", luv_process_kill}, + {"kill", luv_kill}, + + // stream.c + {"shutdown", luv_shutdown}, + {"listen", luv_listen}, + {"accept", luv_accept}, + {"read_start", luv_read_start}, + {"read_stop", luv_read_stop}, + {"write", luv_write}, + {"write2", luv_write2}, + {"try_write", luv_try_write}, + {"is_readable", luv_is_readable}, + {"is_writable", luv_is_writable}, + {"stream_set_blocking", luv_stream_set_blocking}, + + // tcp.c + {"new_tcp", luv_new_tcp}, + {"tcp_open", luv_tcp_open}, + {"tcp_nodelay", luv_tcp_nodelay}, + {"tcp_keepalive", luv_tcp_keepalive}, + {"tcp_simultaneous_accepts", luv_tcp_simultaneous_accepts}, + {"tcp_bind", luv_tcp_bind}, + {"tcp_getpeername", luv_tcp_getpeername}, + {"tcp_getsockname", luv_tcp_getsockname}, + {"tcp_connect", luv_tcp_connect}, + {"tcp_write_queue_size", luv_write_queue_size}, + + // pipe.c + {"new_pipe", luv_new_pipe}, + {"pipe_open", luv_pipe_open}, + {"pipe_bind", luv_pipe_bind}, + {"pipe_connect", luv_pipe_connect}, + {"pipe_getsockname", luv_pipe_getsockname}, + {"pipe_getpeername", luv_pipe_getpeername}, + {"pipe_pending_instances", luv_pipe_pending_instances}, + {"pipe_pending_count", luv_pipe_pending_count}, + {"pipe_pending_type", luv_pipe_pending_type}, + + // tty.c + {"new_tty", luv_new_tty}, + {"tty_set_mode", luv_tty_set_mode}, + {"tty_reset_mode", luv_tty_reset_mode}, + {"tty_get_winsize", luv_tty_get_winsize}, + + // udp.c + {"new_udp", luv_new_udp}, + {"udp_open", luv_udp_open}, + {"udp_bind", luv_udp_bind}, + {"udp_getsockname", luv_udp_getsockname}, + {"udp_set_membership", luv_udp_set_membership}, + {"udp_set_multicast_loop", luv_udp_set_multicast_loop}, + {"udp_set_multicast_ttl", luv_udp_set_multicast_ttl}, + {"udp_set_multicast_interface", luv_udp_set_multicast_interface}, + {"udp_set_broadcast", luv_udp_set_broadcast}, + {"udp_set_ttl", luv_udp_set_ttl}, + {"udp_send", luv_udp_send}, + {"udp_try_send", luv_udp_try_send}, + {"udp_recv_start", luv_udp_recv_start}, + {"udp_recv_stop", luv_udp_recv_stop}, + + // fs_event.c + {"new_fs_event", luv_new_fs_event}, + {"fs_event_start", luv_fs_event_start}, + {"fs_event_stop", luv_fs_event_stop}, + {"fs_event_getpath", luv_fs_event_getpath}, + + // fs_poll.c + {"new_fs_poll", luv_new_fs_poll}, + {"fs_poll_start", luv_fs_poll_start}, + {"fs_poll_stop", luv_fs_poll_stop}, + {"fs_poll_getpath", luv_fs_poll_getpath}, + + // fs.c + {"fs_close", luv_fs_close}, + {"fs_open", luv_fs_open}, + {"fs_read", luv_fs_read}, + {"fs_unlink", luv_fs_unlink}, + {"fs_write", luv_fs_write}, + {"fs_mkdir", luv_fs_mkdir}, + {"fs_mkdtemp", luv_fs_mkdtemp}, + {"fs_rmdir", luv_fs_rmdir}, + {"fs_scandir", luv_fs_scandir}, + {"fs_scandir_next", luv_fs_scandir_next}, + {"fs_stat", luv_fs_stat}, + {"fs_fstat", luv_fs_fstat}, + {"fs_lstat", luv_fs_lstat}, + {"fs_rename", luv_fs_rename}, + {"fs_fsync", luv_fs_fsync}, + {"fs_fdatasync", luv_fs_fdatasync}, + {"fs_ftruncate", luv_fs_ftruncate}, + {"fs_sendfile", luv_fs_sendfile}, + {"fs_access", luv_fs_access}, + {"fs_chmod", luv_fs_chmod}, + {"fs_fchmod", luv_fs_fchmod}, + {"fs_utime", luv_fs_utime}, + {"fs_futime", luv_fs_futime}, + {"fs_link", luv_fs_link}, + {"fs_symlink", luv_fs_symlink}, + {"fs_readlink", luv_fs_readlink}, + {"fs_realpath", luv_fs_realpath}, + {"fs_chown", luv_fs_chown}, + {"fs_fchown", luv_fs_fchown}, + + // dns.c + {"getaddrinfo", luv_getaddrinfo}, + {"getnameinfo", luv_getnameinfo}, + + // misc.c + {"chdir", luv_chdir}, + {"os_homedir", luv_os_homedir}, + {"cpu_info", luv_cpu_info}, + {"cwd", luv_cwd}, + {"exepath", luv_exepath}, + {"get_process_title", luv_get_process_title}, + {"get_total_memory", luv_get_total_memory}, + {"get_free_memory", luv_get_free_memory}, + {"getpid", luv_getpid}, +#ifndef _WIN32 + {"getuid", luv_getuid}, + {"setuid", luv_setuid}, + {"getgid", luv_getgid}, + {"setgid", luv_setgid}, +#endif + {"getrusage", luv_getrusage}, + {"guess_handle", luv_guess_handle}, + {"hrtime", luv_hrtime}, + {"interface_addresses", luv_interface_addresses}, + {"loadavg", luv_loadavg}, + {"resident_set_memory", luv_resident_set_memory}, + {"set_process_title", luv_set_process_title}, + {"uptime", luv_uptime}, + {"version", luv_version}, + {"version_string", luv_version_string}, + + // thread.c + {"new_thread", luv_new_thread}, + {"thread_equal", luv_thread_equal}, + {"thread_self", luv_thread_self}, + {"thread_join", luv_thread_join}, + {"sleep", luv_thread_sleep}, + + // work.c + {"new_work", luv_new_work}, + {"queue_work", luv_queue_work}, + + {NULL, NULL} +}; + +static const luaL_Reg luv_handle_methods[] = { + // handle.c + {"is_active", luv_is_active}, + {"is_closing", luv_is_closing}, + {"close", luv_close}, + {"ref", luv_ref}, + {"unref", luv_unref}, + {"has_ref", luv_has_ref}, + {"send_buffer_size", luv_send_buffer_size}, + {"recv_buffer_size", luv_recv_buffer_size}, + {"fileno", luv_fileno}, + {NULL, NULL} +}; + +static const luaL_Reg luv_async_methods[] = { + {"send", luv_async_send}, + {NULL, NULL} +}; + +static const luaL_Reg luv_check_methods[] = { + {"start", luv_check_start}, + {"stop", luv_check_stop}, + {NULL, NULL} +}; + +static const luaL_Reg luv_fs_event_methods[] = { + {"start", luv_fs_event_start}, + {"stop", luv_fs_event_stop}, + {"getpath", luv_fs_event_getpath}, + {NULL, NULL} +}; + +static const luaL_Reg luv_fs_poll_methods[] = { + {"start", luv_fs_poll_start}, + {"stop", luv_fs_poll_stop}, + {"getpath", luv_fs_poll_getpath}, + {NULL, NULL} +}; + +static const luaL_Reg luv_idle_methods[] = { + {"start", luv_idle_start}, + {"stop", luv_idle_stop}, + {NULL, NULL} +}; + +static const luaL_Reg luv_stream_methods[] = { + {"shutdown", luv_shutdown}, + {"listen", luv_listen}, + {"accept", luv_accept}, + {"read_start", luv_read_start}, + {"read_stop", luv_read_stop}, + {"write", luv_write}, + {"write2", luv_write2}, + {"try_write", luv_try_write}, + {"is_readable", luv_is_readable}, + {"is_writable", luv_is_writable}, + {"set_blocking", luv_stream_set_blocking}, + {NULL, NULL} +}; + +static const luaL_Reg luv_pipe_methods[] = { + {"open", luv_pipe_open}, + {"bind", luv_pipe_bind}, + {"connect", luv_pipe_connect}, + {"getsockname", luv_pipe_getsockname}, + {"getpeername", luv_pipe_getpeername}, + {"pending_instances", luv_pipe_pending_instances}, + {"pending_count", luv_pipe_pending_count}, + {"pending_type", luv_pipe_pending_type}, + {NULL, NULL} +}; + +static const luaL_Reg luv_poll_methods[] = { + {"start", luv_poll_start}, + {"stop", luv_poll_stop}, + {NULL, NULL} +}; + +static const luaL_Reg luv_prepare_methods[] = { + {"start", luv_prepare_start}, + {"stop", luv_prepare_stop}, + {NULL, NULL} +}; + +static const luaL_Reg luv_process_methods[] = { + {"kill", luv_process_kill}, + {NULL, NULL} +}; + +static const luaL_Reg luv_tcp_methods[] = { + {"open", luv_tcp_open}, + {"nodelay", luv_tcp_nodelay}, + {"keepalive", luv_tcp_keepalive}, + {"simultaneous_accepts", luv_tcp_simultaneous_accepts}, + {"bind", luv_tcp_bind}, + {"getpeername", luv_tcp_getpeername}, + {"getsockname", luv_tcp_getsockname}, + {"connect", luv_tcp_connect}, + {"write_queue_size", luv_write_queue_size}, + {NULL, NULL} +}; + +static const luaL_Reg luv_timer_methods[] = { + {"start", luv_timer_start}, + {"stop", luv_timer_stop}, + {"again", luv_timer_again}, + {"set_repeat", luv_timer_set_repeat}, + {"get_repeat", luv_timer_get_repeat}, + {NULL, NULL} +}; + +static const luaL_Reg luv_tty_methods[] = { + {"set_mode", luv_tty_set_mode}, + {"get_winsize", luv_tty_get_winsize}, + {NULL, NULL} +}; + +static const luaL_Reg luv_udp_methods[] = { + {"open", luv_udp_open}, + {"bind", luv_udp_bind}, + {"bindgetsockname", luv_udp_getsockname}, + {"set_membership", luv_udp_set_membership}, + {"set_multicast_loop", luv_udp_set_multicast_loop}, + {"set_multicast_ttl", luv_udp_set_multicast_ttl}, + {"set_multicast_interface", luv_udp_set_multicast_interface}, + {"set_broadcast", luv_udp_set_broadcast}, + {"set_ttl", luv_udp_set_ttl}, + {"send", luv_udp_send}, + {"try_send", luv_udp_try_send}, + {"recv_start", luv_udp_recv_start}, + {"recv_stop", luv_udp_recv_stop}, + {NULL, NULL} +}; + +static const luaL_Reg luv_signal_methods[] = { + {"start", luv_signal_start}, + {"stop", luv_signal_stop}, + {NULL, NULL} +}; + +static void luv_handle_init(lua_State* L) { + + lua_newtable(L); +#define XX(uc, lc) \ + luaL_newmetatable (L, "uv_"#lc); \ + lua_pushcfunction(L, luv_handle_tostring); \ + lua_setfield(L, -2, "__tostring"); \ + lua_pushcfunction(L, luv_handle_gc); \ + lua_setfield(L, -2, "__gc"); \ + luaL_newlib(L, luv_##lc##_methods); \ + luaL_setfuncs(L, luv_handle_methods, 0); \ + lua_setfield(L, -2, "__index"); \ + lua_pushboolean(L, 1); \ + lua_rawset(L, -3); + + UV_HANDLE_TYPE_MAP(XX) +#undef XX + lua_setfield(L, LUA_REGISTRYINDEX, "uv_handle"); + + lua_newtable(L); + + luaL_getmetatable(L, "uv_pipe"); + lua_getfield(L, -1, "__index"); + luaL_setfuncs(L, luv_stream_methods, 0); + lua_pop(L, 1); + lua_pushboolean(L, 1); + lua_rawset(L, -3); + + luaL_getmetatable(L, "uv_tcp"); + lua_getfield(L, -1, "__index"); + luaL_setfuncs(L, luv_stream_methods, 0); + lua_pop(L, 1); + lua_pushboolean(L, 1); + lua_rawset(L, -3); + + luaL_getmetatable(L, "uv_tty"); + lua_getfield(L, -1, "__index"); + luaL_setfuncs(L, luv_stream_methods, 0); + lua_pop(L, 1); + lua_pushboolean(L, 1); + lua_rawset(L, -3); + + lua_setfield(L, LUA_REGISTRYINDEX, "uv_stream"); +} + +LUALIB_API lua_State* luv_state(uv_loop_t* loop) { + return loop->data; +} + +// TODO: find out if storing this somehow in an upvalue is faster +LUALIB_API uv_loop_t* luv_loop(lua_State* L) { + uv_loop_t* loop; + lua_pushstring(L, "uv_loop"); + lua_rawget(L, LUA_REGISTRYINDEX); + loop = lua_touserdata(L, -1); + lua_pop(L, 1); + return loop; +} + +static void walk_cb(uv_handle_t *handle, void *arg) +{ + (void)arg; + if (!uv_is_closing(handle)) { + uv_close(handle, luv_close_cb); + } +} + +static int loop_gc(lua_State *L) { + uv_loop_t* loop = luv_loop(L); + // Call uv_close on every active handle + uv_walk(loop, walk_cb, NULL); + // Run the event loop until all handles are successfully closed + while (uv_loop_close(loop)) { + uv_run(loop, UV_RUN_DEFAULT); + } + return 0; +} + +LUALIB_API int luaopen_luv (lua_State *L) { + + uv_loop_t* loop; + int ret; + + // Setup the uv_loop meta table for a proper __gc + luaL_newmetatable(L, "uv_loop.meta"); + lua_pushstring(L, "__gc"); + lua_pushcfunction(L, loop_gc); + lua_settable(L, -3); + + loop = lua_newuserdata(L, sizeof(*loop)); + ret = uv_loop_init(loop); + if (ret < 0) { + return luaL_error(L, "%s: %s\n", uv_err_name(ret), uv_strerror(ret)); + } + // setup the metatable for __gc + luaL_getmetatable(L, "uv_loop.meta"); + lua_setmetatable(L, -2); + // Tell the state how to find the loop. + lua_pushstring(L, "uv_loop"); + lua_insert(L, -2); + lua_rawset(L, LUA_REGISTRYINDEX); + lua_pop(L, 1); + + // Tell the loop how to find the state. + loop->data = L; + + luv_req_init(L); + luv_handle_init(L); + luv_thread_init(L); + luv_work_init(L); + + luaL_newlib(L, luv_functions); + luv_constants(L); + lua_setfield(L, -2, "constants"); + + return 1; +} diff --git a/3rdparty/luv/src/luv.h b/3rdparty/luv/src/luv.h new file mode 100644 index 00000000000..681384da363 --- /dev/null +++ b/3rdparty/luv/src/luv.h @@ -0,0 +1,109 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef LUV_H +#define LUV_H +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> +#include "uv.h" + +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +#if defined(_WIN32) +# include <fcntl.h> +# include <sys/types.h> +# include <sys/stat.h> +# ifndef __MINGW32__ +# define S_ISREG(x) (((x) & _S_IFMT) == _S_IFREG) +# define S_ISDIR(x) (((x) & _S_IFMT) == _S_IFDIR) +# define S_ISFIFO(x) (((x) & _S_IFMT) == _S_IFIFO) +# define S_ISCHR(x) (((x) & _S_IFMT) == _S_IFCHR) +# define S_ISBLK(x) 0 +# endif +# define S_ISLNK(x) (((x) & S_IFLNK) == S_IFLNK) +# define S_ISSOCK(x) 0 +#else +# include <unistd.h> +#endif + +#ifndef PATH_MAX +#define PATH_MAX (8096) +#endif + +#ifndef MAX_TITLE_LENGTH +#define MAX_TITLE_LENGTH (8192) +#endif + +#if LUA_VERSION_NUM < 502 +# define lua_rawlen lua_objlen +/* lua_...uservalue: Something very different, but it should get the job done */ +# define lua_getuservalue lua_getfenv +# define lua_setuservalue lua_setfenv +# define luaL_newlib(L,l) (lua_newtable(L), luaL_register(L,NULL,l)) +# define luaL_setfuncs(L,l,n) (assert(n==0), luaL_register(L,NULL,l)) +# define lua_resume(L,F,n) lua_resume(L,n) +# define lua_pushglobaltable(L) lua_pushvalue(L, LUA_GLOBALSINDEX) +#endif + +/* There is a 1-1 relation between a lua_State and a uv_loop_t + These helpers will give you one if you have the other + These are exposed for extensions built with luv + This allows luv to be used in multithreaded applications. +*/ +LUALIB_API lua_State* luv_state(uv_loop_t* loop); +/* All libuv callbacks will lua_call directly from this root-per-thread state +*/ +LUALIB_API uv_loop_t* luv_loop(lua_State* L); + +/* This is the main hook to load the library. + This can be called multiple times in a process as long + as you use a different lua_State and thread for each. +*/ +LUALIB_API int luaopen_luv (lua_State *L); + +#include "util.h" +#include "lhandle.h" +#include "lreq.h" + +/* From stream.c */ +static uv_stream_t* luv_check_stream(lua_State* L, int index); +static void luv_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf); +static void luv_check_buf(lua_State *L, int idx, uv_buf_t *pbuf); +static uv_buf_t* luv_prep_bufs(lua_State* L, int index, size_t *count); + +/* from tcp.c */ +static void parse_sockaddr(lua_State* L, struct sockaddr_storage* address, int addrlen); +static void luv_connect_cb(uv_connect_t* req, int status); + +/* From fs.c */ +static void luv_push_stats_table(lua_State* L, const uv_stat_t* s); + +/* from constants.c */ +static int luv_af_string_to_num(const char* string); +static const char* luv_af_num_to_string(const int num); +static int luv_sock_string_to_num(const char* string); +static const char* luv_sock_num_to_string(const int num); +static int luv_sig_string_to_num(const char* string); +static const char* luv_sig_num_to_string(const int num); + +typedef lua_State* (*luv_acquire_vm)(); +typedef void (*luv_release_vm)(lua_State* L); +LUALIB_API void luv_set_thread_cb(luv_acquire_vm acquire, luv_release_vm release); + +#endif diff --git a/3rdparty/luv/src/misc.c b/3rdparty/luv/src/misc.c new file mode 100644 index 00000000000..64c9e3d5822 --- /dev/null +++ b/3rdparty/luv/src/misc.c @@ -0,0 +1,316 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "luv.h" +#ifdef _WIN32 +#include <process.h> +#endif + +static int luv_guess_handle(lua_State* L) { + uv_file file = luaL_checkinteger(L, 1); + switch (uv_guess_handle(file)) { +#define XX(uc, lc) case UV_##uc: lua_pushstring(L, #lc); break; + UV_HANDLE_TYPE_MAP(XX) +#undef XX + case UV_FILE: lua_pushstring(L, "file"); break; + default: return 0; + } + return 1; +} + +static int luv_version(lua_State* L) { + lua_pushinteger(L, uv_version()); + return 1; +} + +static int luv_version_string(lua_State* L) { + lua_pushstring(L, uv_version_string()); + return 1; +} + +static int luv_get_process_title(lua_State* L) { + char title[MAX_TITLE_LENGTH]; + int ret = uv_get_process_title(title, MAX_TITLE_LENGTH); + if (ret < 0) return luv_error(L, ret); + lua_pushstring(L, title); + return 1; +} + +static int luv_set_process_title(lua_State* L) { + const char* title = luaL_checkstring(L, 1); + int ret = uv_set_process_title(title); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_resident_set_memory(lua_State* L) { + size_t rss; + int ret = uv_resident_set_memory(&rss); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, rss); + return 1; +} + +static int luv_uptime(lua_State* L) { + double uptime; + int ret = uv_uptime(&uptime); + if (ret < 0) return luv_error(L, ret); + lua_pushnumber(L, uptime); + return 1; +} + +static void luv_push_timeval_table(lua_State* L, const uv_timeval_t* t) { + lua_createtable(L, 0, 2); + lua_pushinteger(L, t->tv_sec); + lua_setfield(L, -2, "sec"); + lua_pushinteger(L, t->tv_usec); + lua_setfield(L, -2, "usec"); +} + +static int luv_getrusage(lua_State* L) { + uv_rusage_t rusage; + int ret = uv_getrusage(&rusage); + if (ret < 0) return luv_error(L, ret); + lua_createtable(L, 0, 16); + // user CPU time used + luv_push_timeval_table(L, &rusage.ru_utime); + lua_setfield(L, -2, "utime"); + // system CPU time used + luv_push_timeval_table(L, &rusage.ru_stime); + lua_setfield(L, -2, "stime"); + // maximum resident set size + lua_pushinteger(L, rusage.ru_maxrss); + lua_setfield(L, -2, "maxrss"); + // integral shared memory size + lua_pushinteger(L, rusage.ru_ixrss); + lua_setfield(L, -2, "ixrss"); + // integral unshared data size + lua_pushinteger(L, rusage.ru_idrss); + lua_setfield(L, -2, "idrss"); + // integral unshared stack size + lua_pushinteger(L, rusage.ru_isrss); + lua_setfield(L, -2, "isrss"); + // page reclaims (soft page faults) + lua_pushinteger(L, rusage.ru_minflt); + lua_setfield(L, -2, "minflt"); + // page faults (hard page faults) + lua_pushinteger(L, rusage.ru_majflt); + lua_setfield(L, -2, "majflt"); + // swaps + lua_pushinteger(L, rusage.ru_nswap); + lua_setfield(L, -2, "nswap"); + // block input operations + lua_pushinteger(L, rusage.ru_inblock); + lua_setfield(L, -2, "inblock"); + // block output operations + lua_pushinteger(L, rusage.ru_oublock); + lua_setfield(L, -2, "oublock"); + // IPC messages sent + lua_pushinteger(L, rusage.ru_msgsnd); + lua_setfield(L, -2, "msgsnd"); + // IPC messages received + lua_pushinteger(L, rusage.ru_msgrcv); + lua_setfield(L, -2, "msgrcv"); + // signals received + lua_pushinteger(L, rusage.ru_nsignals); + lua_setfield(L, -2, "nsignals"); + // voluntary context switches + lua_pushinteger(L, rusage.ru_nvcsw); + lua_setfield(L, -2, "nvcsw"); + // involuntary context switches + lua_pushinteger(L, rusage.ru_nivcsw); + lua_setfield(L, -2, "nivcsw"); + return 1; +} + +static int luv_cpu_info(lua_State* L) { + uv_cpu_info_t* cpu_infos; + int count, i; + int ret = uv_cpu_info(&cpu_infos, &count); + if (ret < 0) return luv_error(L, ret); + lua_newtable(L); + + for (i = 0; i < count; i++) { + lua_newtable(L); + lua_pushstring(L, cpu_infos[i].model); + lua_setfield(L, -2, "model"); + lua_pushnumber(L, cpu_infos[i].speed); + lua_setfield(L, -2, "speed"); + lua_newtable(L); + lua_pushnumber(L, cpu_infos[i].cpu_times.user); + lua_setfield(L, -2, "user"); + lua_pushnumber(L, cpu_infos[i].cpu_times.nice); + lua_setfield(L, -2, "nice"); + lua_pushnumber(L, cpu_infos[i].cpu_times.sys); + lua_setfield(L, -2, "sys"); + lua_pushnumber(L, cpu_infos[i].cpu_times.idle); + lua_setfield(L, -2, "idle"); + lua_pushnumber(L, cpu_infos[i].cpu_times.irq); + lua_setfield(L, -2, "irq"); + lua_setfield(L, -2, "times"); + lua_rawseti(L, -2, i + 1); + } + + uv_free_cpu_info(cpu_infos, count); + return 1; +} + +static int luv_interface_addresses(lua_State* L) { + uv_interface_address_t* interfaces; + int count, i; + char ip[INET6_ADDRSTRLEN]; + char netmask[INET6_ADDRSTRLEN]; + + uv_interface_addresses(&interfaces, &count); + + lua_newtable(L); + + for (i = 0; i < count; i++) { + lua_getfield(L, -1, interfaces[i].name); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setfield(L, -3, interfaces[i].name); + } + lua_newtable(L); + lua_pushboolean(L, interfaces[i].is_internal); + lua_setfield(L, -2, "internal"); + + lua_pushlstring(L, interfaces[i].phys_addr, sizeof(interfaces[i].phys_addr)); + lua_setfield(L, -2, "mac"); + + if (interfaces[i].address.address4.sin_family == AF_INET) { + uv_ip4_name(&interfaces[i].address.address4, ip, sizeof(ip)); + uv_ip4_name(&interfaces[i].netmask.netmask4, netmask, sizeof(netmask)); + } else if (interfaces[i].address.address4.sin_family == AF_INET6) { + uv_ip6_name(&interfaces[i].address.address6, ip, sizeof(ip)); + uv_ip6_name(&interfaces[i].netmask.netmask6, netmask, sizeof(netmask)); + } else { + strncpy(ip, "<unknown sa family>", INET6_ADDRSTRLEN); + strncpy(netmask, "<unknown sa family>", INET6_ADDRSTRLEN); + } + lua_pushstring(L, ip); + lua_setfield(L, -2, "ip"); + lua_pushstring(L, netmask); + lua_setfield(L, -2, "netmask"); + + lua_pushstring(L, luv_af_num_to_string(interfaces[i].address.address4.sin_family)); + lua_setfield(L, -2, "family"); + lua_rawseti(L, -2, lua_rawlen (L, -2) + 1); + lua_pop(L, 1); + } + uv_free_interface_addresses(interfaces, count); + return 1; +} + +static int luv_loadavg(lua_State* L) { + double avg[3]; + uv_loadavg(avg); + lua_pushnumber(L, avg[0]); + lua_pushnumber(L, avg[1]); + lua_pushnumber(L, avg[2]); + return 3; +} + +static int luv_exepath(lua_State* L) { + size_t size = 2*PATH_MAX; + char exe_path[2*PATH_MAX]; + int ret = uv_exepath(exe_path, &size); + if (ret < 0) return luv_error(L, ret); + lua_pushlstring(L, exe_path, size); + return 1; +} + +static int luv_cwd(lua_State* L) { + size_t size = 2*PATH_MAX; + char path[2*PATH_MAX]; + int ret = uv_cwd(path, &size); + if (ret < 0) return luv_error(L, ret); + lua_pushlstring(L, path, size); + return 1; +} + +static int luv_chdir(lua_State* L) { + int ret = uv_chdir(luaL_checkstring(L, 1)); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_os_homedir(lua_State* L) { + size_t size = 2*PATH_MAX; + char homedir[2*PATH_MAX]; + int ret = uv_os_homedir(homedir, &size); + if (ret < 0) return luv_error(L, ret); + lua_pushlstring(L, homedir, size); + return 1; +} + +static int luv_get_total_memory(lua_State* L) { + lua_pushnumber(L, uv_get_total_memory()); + return 1; +} + +static int luv_get_free_memory(lua_State* L) { + lua_pushnumber(L, uv_get_free_memory()); + return 1; +} + +static int luv_hrtime(lua_State* L) { + lua_pushnumber(L, uv_hrtime()); + return 1; +} + +static int luv_getpid(lua_State* L){ + int pid = getpid(); + lua_pushinteger(L, pid); + return 1; +} + +#ifndef _WIN32 +static int luv_getuid(lua_State* L){ + int uid = getuid(); + lua_pushinteger(L, uid); + return 1; +} + +static int luv_getgid(lua_State* L){ + int gid = getgid(); + lua_pushinteger(L, gid); + return 1; +} + +static int luv_setuid(lua_State* L){ + int uid = luaL_checkinteger(L, 1); + int r = setuid(uid); + if (-1 == r) { + luaL_error(L, "Error setting UID"); + } + return 0; +} + +static int luv_setgid(lua_State* L){ + int gid = luaL_checkinteger(L, 1); + int r = setgid(gid); + if (-1 == r) { + luaL_error(L, "Error setting GID"); + } + return 0; +} +#endif diff --git a/3rdparty/luv/src/pipe.c b/3rdparty/luv/src/pipe.c new file mode 100644 index 00000000000..b490c1597b3 --- /dev/null +++ b/3rdparty/luv/src/pipe.c @@ -0,0 +1,114 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +static uv_pipe_t* luv_check_pipe(lua_State* L, int index) { + uv_pipe_t* handle = luv_checkudata(L, index, "uv_pipe"); + luaL_argcheck(L, handle->type == UV_NAMED_PIPE && handle->data, index, "Expected uv_pipe_t"); + return handle; +} + +static int luv_new_pipe(lua_State* L) { + uv_pipe_t* handle; + int ipc, ret; + luaL_checktype(L, 1, LUA_TBOOLEAN); + ipc = lua_toboolean(L, 1); + handle = luv_newuserdata(L, sizeof(*handle)); + ret = uv_pipe_init(luv_loop(L), handle, ipc); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + handle->data = luv_setup_handle(L); + return 1; +} + +static int luv_pipe_open(lua_State* L) { + uv_pipe_t* handle = luv_check_pipe(L, 1); + uv_file file = luaL_checkinteger(L, 2); + int ret = uv_pipe_open(handle, file); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_pipe_bind(lua_State* L) { + uv_pipe_t* handle = luv_check_pipe(L, 1); + const char* name = luaL_checkstring(L, 2); + int ret = uv_pipe_bind(handle, name); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_pipe_connect(lua_State* L) { + uv_pipe_t* handle = luv_check_pipe(L, 1); + const char* name = luaL_checkstring(L, 2); + int ref = luv_check_continuation(L, 3); + uv_connect_t* req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + uv_pipe_connect(req, handle, name, luv_connect_cb); + return 1; +} + +static int luv_pipe_getsockname(lua_State* L) { + uv_pipe_t* handle = luv_check_pipe(L, 1); + size_t len = 2*PATH_MAX; + char buf[2*PATH_MAX]; + int ret = uv_pipe_getsockname(handle, buf, &len); + if (ret < 0) return luv_error(L, ret); + lua_pushlstring(L, buf, len); + return 1; +} + +static int luv_pipe_getpeername(lua_State* L) { + uv_pipe_t* handle = luv_check_pipe(L, 1); + size_t len = 2*PATH_MAX; + char buf[2*PATH_MAX]; + int ret = uv_pipe_getpeername(handle, buf, &len); + if (ret < 0) return luv_error(L, ret); + lua_pushlstring(L, buf, len); + return 1; +} + +static int luv_pipe_pending_instances(lua_State* L) { + uv_pipe_t* handle = luv_check_pipe(L, 1); + int count = luaL_checkinteger(L, 2); + uv_pipe_pending_instances(handle, count); + return 0; +} + +static int luv_pipe_pending_count(lua_State* L) { + uv_pipe_t* handle = luv_check_pipe(L, 1); + lua_pushinteger(L, uv_pipe_pending_count(handle)); + return 1; +} + +static int luv_pipe_pending_type(lua_State* L) { + uv_pipe_t* handle = luv_check_pipe(L, 1); + uv_handle_type type = uv_pipe_pending_type(handle); + const char* type_name; + switch (type) { +#define XX(uc, lc) \ + case UV_##uc: type_name = #lc; break; + UV_HANDLE_TYPE_MAP(XX) +#undef XX + default: return 0; + } + lua_pushstring(L, type_name); + return 1; +} diff --git a/3rdparty/luv/src/poll.c b/3rdparty/luv/src/poll.c new file mode 100644 index 00000000000..e007c9f9634 --- /dev/null +++ b/3rdparty/luv/src/poll.c @@ -0,0 +1,100 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +static uv_poll_t* luv_check_poll(lua_State* L, int index) { + uv_poll_t* handle = luv_checkudata(L, index, "uv_poll"); + luaL_argcheck(L, handle->type == UV_POLL && handle->data, index, "Expected uv_poll_t"); + return handle; +} + +static int luv_new_poll(lua_State* L) { + int fd = luaL_checkinteger(L, 1); + uv_poll_t* handle = luv_newuserdata(L, sizeof(*handle)); + int ret = uv_poll_init(luv_loop(L), handle, fd); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + handle->data = luv_setup_handle(L); + return 1; +} + +static int luv_new_socket_poll(lua_State* L) { + int fd = luaL_checkinteger(L, 1); + uv_poll_t* handle = luv_newuserdata(L, sizeof(*handle)); + int ret = uv_poll_init_socket(luv_loop(L), handle, fd); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + handle->data = luv_setup_handle(L); + return 1; +} + +// These are the same order as uv_run_mode which also starts at 0 +static const char *const luv_pollevents[] = { + "r", "w", "rw", NULL +}; + +static void luv_poll_cb(uv_poll_t* handle, int status, int events) { + lua_State* L = luv_state(handle->loop); + luv_handle_t* data = handle->data; + const char* evtstr; + + if (status < 0) { + fprintf(stderr, "%s: %s\n", uv_err_name(status), uv_strerror(status)); + lua_pushstring(L, uv_err_name(status)); + } + else { + lua_pushnil(L); + } + + switch (events) { + case UV_READABLE: evtstr = "r"; break; + case UV_WRITABLE: evtstr = "w"; break; + case UV_READABLE|UV_WRITABLE: evtstr = "rw"; break; + default: evtstr = ""; break; + } + lua_pushstring(L, evtstr); + + luv_call_callback(L, data, LUV_POLL, 2); +} + +static int luv_poll_start(lua_State* L) { + uv_poll_t* handle = luv_check_poll(L, 1); + int events, ret; + switch (luaL_checkoption(L, 2, "rw", luv_pollevents)) { + case 0: events = UV_READABLE; break; + case 1: events = UV_WRITABLE; break; + case 2: events = UV_READABLE | UV_WRITABLE; break; + default: events = 0; /* unreachable */ + } + luv_check_callback(L, handle->data, LUV_POLL, 3); + ret = uv_poll_start(handle, events, luv_poll_cb); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_poll_stop(lua_State* L) { + uv_poll_t* handle = luv_check_poll(L, 1); + int ret = uv_poll_stop(handle); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} diff --git a/3rdparty/luv/src/prepare.c b/3rdparty/luv/src/prepare.c new file mode 100644 index 00000000000..6577439a466 --- /dev/null +++ b/3rdparty/luv/src/prepare.c @@ -0,0 +1,59 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +static uv_prepare_t* luv_check_prepare(lua_State* L, int index) { + uv_prepare_t* handle = luv_checkudata(L, index, "uv_prepare"); + luaL_argcheck(L, handle->type == UV_PREPARE && handle->data, index, "Expected uv_prepare_t"); + return handle; +} + +static int luv_new_prepare(lua_State* L) { + uv_prepare_t* handle = luv_newuserdata(L, sizeof(*handle)); + int ret = uv_prepare_init(luv_loop(L), handle); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + handle->data = luv_setup_handle(L); + return 1; +} + +static void luv_prepare_cb(uv_prepare_t* handle) { + lua_State* L = luv_state(handle->loop); + luv_handle_t* data = handle->data; + luv_call_callback(L, data, LUV_PREPARE, 0); +} + +static int luv_prepare_start(lua_State* L) { + uv_prepare_t* handle = luv_check_prepare(L, 1); + int ret; + luv_check_callback(L, handle->data, LUV_PREPARE, 2); + ret = uv_prepare_start(handle, luv_prepare_cb); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_prepare_stop(lua_State* L) { + uv_prepare_t* handle = luv_check_prepare(L, 1); + int ret = uv_prepare_stop(handle); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + diff --git a/3rdparty/luv/src/process.c b/3rdparty/luv/src/process.c new file mode 100644 index 00000000000..d939503868b --- /dev/null +++ b/3rdparty/luv/src/process.c @@ -0,0 +1,266 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +static int luv_disable_stdio_inheritance(lua_State* L) { + (void)L; + uv_disable_stdio_inheritance(); + return 0; +} + +static uv_process_t* luv_check_process(lua_State* L, int index) { + uv_process_t* handle = luv_checkudata(L, index, "uv_process"); + luaL_argcheck(L, handle->type == UV_PROCESS && handle->data, index, "Expected uv_process_t"); + return handle; +} + +static void exit_cb(uv_process_t* handle, int64_t exit_status, int term_signal) { + lua_State* L = luv_state(handle->loop); + luv_handle_t* data = handle->data; + lua_pushinteger(L, exit_status); + lua_pushinteger(L, term_signal); + luv_call_callback(L, data, LUV_EXIT, 2); +} + +static void luv_spawn_close_cb(uv_handle_t* handle) { + lua_State *L = luv_state(handle->loop); + luv_cleanup_handle(L, handle->data); +} + +static void luv_clean_options(uv_process_options_t* options) { + free(options->args); + free(options->stdio); + free(options->env); +} + +static int luv_spawn(lua_State* L) { + uv_process_t* handle; + uv_process_options_t options; + size_t i, len = 0; + int ret; + + memset(&options, 0, sizeof(options)); + options.exit_cb = exit_cb; + options.file = luaL_checkstring(L, 1); + options.flags = 0; + + // Make sure the 2nd argument is a table + luaL_checktype(L, 2, LUA_TTABLE); + + // get the args list + lua_getfield(L, 2, "args"); + // +1 for inserted command at front + if (lua_type(L, -1) == LUA_TTABLE) { + len = 1 + lua_rawlen(L, -1); + } + else if (lua_type(L, -1) != LUA_TNIL) { + luv_clean_options(&options); + return luaL_argerror(L, 3, "args option must be table"); + } + else { + len = 1; + } + // +1 for null terminator at end + options.args = malloc((len + 1) * sizeof(*options.args)); + if (!options.args) { + luv_clean_options(&options); + return luaL_error(L, "Problem allocating args"); + } + options.args[0] = (char*)options.file; + for (i = 1; i < len; ++i) { + lua_rawgeti(L, -1, i); + options.args[i] = (char*)lua_tostring(L, -1); + lua_pop(L, 1); + } + options.args[len] = NULL; + lua_pop(L, 1); + + // get the stdio list + lua_getfield(L, 2, "stdio"); + if (lua_type(L, -1) == LUA_TTABLE) { + options.stdio_count = len = lua_rawlen(L, -1); + options.stdio = malloc(len * sizeof(*options.stdio)); + if (!options.stdio) { + luv_clean_options(&options); + return luaL_error(L, "Problem allocating stdio"); + } + for (i = 0; i < len; ++i) { + lua_rawgeti(L, -1, i + 1); + // integers are assumed to be file descripters + if (lua_type(L, -1) == LUA_TNUMBER) { + options.stdio[i].flags = UV_INHERIT_FD; + options.stdio[i].data.fd = lua_tointeger(L, -1); + } + // userdata is assumed to be a uv_stream_t instance + else if (lua_type(L, -1) == LUA_TUSERDATA) { + uv_os_fd_t fd; + uv_stream_t* stream = luv_check_stream(L, -1); + int err = uv_fileno((uv_handle_t*)stream, &fd); + if (err == UV_EINVAL || err == UV_EBADF) { + // stdin (fd 0) is read-only, stdout and stderr (fds 1 & 2) are + // write-only, and all fds > 2 are read-write + int flags = UV_CREATE_PIPE; + if (i == 0 || i > 2) + flags |= UV_READABLE_PIPE; + if (i != 0) + flags |= UV_WRITABLE_PIPE; + options.stdio[i].flags = flags; + } + else { + options.stdio[i].flags = UV_INHERIT_STREAM; + } + options.stdio[i].data.stream = stream; + } + else if (lua_type(L, -1) == LUA_TNIL) { + options.stdio[i].flags = UV_IGNORE; + } + else { + luv_clean_options(&options); + return luaL_argerror(L, 2, "stdio table entries must be nil, uv_stream_t, or integer"); + } + lua_pop(L, 1); + } + } + else if (lua_type(L, -1) != LUA_TNIL) { + luv_clean_options(&options); + return luaL_argerror(L, 2, "stdio option must be table"); + } + lua_pop(L, 1); + + // Get the env + lua_getfield(L, 2, "env"); + if (lua_type(L, -1) == LUA_TTABLE) { + len = lua_rawlen(L, -1); + options.env = malloc((len + 1) * sizeof(*options.env)); + if (!options.env) { + luv_clean_options(&options); + return luaL_error(L, "Problem allocating env"); + } + for (i = 0; i < len; ++i) { + lua_rawgeti(L, -1, i + 1); + options.env[i] = (char*)lua_tostring(L, -1); + lua_pop(L, 1); + } + options.env[len] = NULL; + } + else if (lua_type(L, -1) != LUA_TNIL) { + luv_clean_options(&options); + return luaL_argerror(L, 2, "env option must be table"); + } + lua_pop(L, 1); + + // Get the cwd + lua_getfield(L, 2, "cwd"); + if (lua_type(L, -1) == LUA_TSTRING) { + options.cwd = (char*)lua_tostring(L, -1); + } + else if (lua_type(L, -1) != LUA_TNIL) { + luv_clean_options(&options); + return luaL_argerror(L, 2, "cwd option must be string"); + } + lua_pop(L, 1); + + // Check for uid + lua_getfield(L, 2, "uid"); + if (lua_type(L, -1) == LUA_TNUMBER) { + options.uid = lua_tointeger(L, -1); + options.flags |= UV_PROCESS_SETUID; + } + else if (lua_type(L, -1) != LUA_TNIL) { + luv_clean_options(&options); + return luaL_argerror(L, 2, "uid option must be number"); + } + lua_pop(L, 1); + + // Check for gid + lua_getfield(L, 2, "gid"); + if (lua_type(L, -1) == LUA_TNUMBER) { + options.gid = lua_tointeger(L, -1); + options.flags |= UV_PROCESS_SETGID; + } + else if (lua_type(L, -1) != LUA_TNIL) { + luv_clean_options(&options); + return luaL_argerror(L, 2, "gid option must be number"); + } + lua_pop(L, 1); + + // Check for the boolean flags + lua_getfield(L, 2, "verbatim"); + if (lua_toboolean(L, -1)) { + options.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS; + } + lua_pop(L, 1); + lua_getfield(L, 2, "detached"); + if (lua_toboolean(L, -1)) { + options.flags |= UV_PROCESS_DETACHED; + } + lua_pop(L, 1); + lua_getfield(L, 2, "hide"); + if (lua_toboolean(L, -1)) { + options.flags |= UV_PROCESS_WINDOWS_HIDE; + } + lua_pop(L, 1); + + handle = luv_newuserdata(L, sizeof(*handle)); + handle->type = UV_PROCESS; + handle->data = luv_setup_handle(L); + + if (!lua_isnoneornil(L, 3)) { + luv_check_callback(L, handle->data, LUV_EXIT, 3); + } + + ret = uv_spawn(luv_loop(L), handle, &options); + + luv_clean_options(&options); + if (ret < 0) { + /* The async callback is required here because luajit GC may reclaim the + * luv handle before libuv is done closing it down. + */ + uv_close((uv_handle_t*)handle, luv_spawn_close_cb); + return luv_error(L, ret); + } + lua_pushinteger(L, handle->pid); + return 2; +} + +static int luv_parse_signal(lua_State* L, int slot) { + if (lua_isnumber(L, slot)) { + return lua_tonumber(L, slot); + } + if (lua_isstring(L, slot)) { + return luv_sig_string_to_num(lua_tostring(L, slot)); + } + return SIGTERM; +} + +static int luv_process_kill(lua_State* L) { + uv_process_t* handle = luv_check_process(L, 1); + int signum = luv_parse_signal(L, 2); + int ret = uv_process_kill(handle, signum); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_kill(lua_State* L) { + int pid = luaL_checkinteger(L, 1); + int signum = luv_parse_signal(L, 2); + int ret = uv_kill(pid, signum); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} diff --git a/3rdparty/luv/src/req.c b/3rdparty/luv/src/req.c new file mode 100644 index 00000000000..6d7b7e4a30b --- /dev/null +++ b/3rdparty/luv/src/req.c @@ -0,0 +1,52 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +static uv_req_t* luv_check_req(lua_State* L, int index) { + uv_req_t* req = luaL_checkudata(L, index, "uv_req"); + luaL_argcheck(L, req->data, index, "Expected uv_req_t"); + return req; +} + +static int luv_req_tostring(lua_State* L) { + uv_req_t* req = luaL_checkudata(L, 1, "uv_req"); + switch (req->type) { +#define XX(uc, lc) case UV_##uc: lua_pushfstring(L, "uv_"#lc"_t: %p", req); break; + UV_REQ_TYPE_MAP(XX) +#undef XX + default: lua_pushfstring(L, "uv_req_t: %p", req); break; + } + return 1; +} + +static void luv_req_init(lua_State* L) { + luaL_newmetatable (L, "uv_req"); + lua_pushcfunction(L, luv_req_tostring); + lua_setfield(L, -2, "__tostring"); + lua_pop(L, 1); +} + +// Metamethod to allow storing anything in the userdata's environment +static int luv_cancel(lua_State* L) { + uv_req_t* req = luv_check_req(L, 1); + int ret = uv_cancel(req); + if (ret < 0) return luv_error(L, ret); + luv_cleanup_req(L, req->data); + req->data = NULL; + lua_pushinteger(L, ret); + return 1; +} diff --git a/3rdparty/luv/src/schema.c b/3rdparty/luv/src/schema.c new file mode 100644 index 00000000000..e7b82e11d66 --- /dev/null +++ b/3rdparty/luv/src/schema.c @@ -0,0 +1,16 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ diff --git a/3rdparty/luv/src/signal.c b/3rdparty/luv/src/signal.c new file mode 100644 index 00000000000..48ace2bf601 --- /dev/null +++ b/3rdparty/luv/src/signal.c @@ -0,0 +1,72 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +static uv_signal_t* luv_check_signal(lua_State* L, int index) { + uv_signal_t* handle = luv_checkudata(L, index, "uv_signal"); + luaL_argcheck(L, handle->type == UV_SIGNAL && handle->data, index, "Expected uv_signal_t"); + return handle; +} + +static int luv_new_signal(lua_State* L) { + uv_signal_t* handle = luv_newuserdata(L, sizeof(*handle)); + int ret = uv_signal_init(luv_loop(L), handle); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + handle->data = luv_setup_handle(L); + return 1; +} + +static void luv_signal_cb(uv_signal_t* handle, int signum) { + lua_State* L = luv_state(handle->loop); + luv_handle_t* data = handle->data; + lua_pushstring(L, luv_sig_num_to_string(signum)); + luv_call_callback(L, data, LUV_SIGNAL, 1); +} + +static int luv_signal_start(lua_State* L) { + uv_signal_t* handle = luv_check_signal(L, 1); + int signum, ret; + if (lua_isnumber(L, 2)) { + signum = lua_tointeger(L, 2); + } + else if (lua_isstring(L, 2)) { + signum = luv_sig_string_to_num(luaL_checkstring(L, 2)); + luaL_argcheck(L, signum, 2, "Invalid Signal name"); + } + else { + return luaL_argerror(L, 2, "Missing Signal name"); + } + + if (!lua_isnoneornil(L, 3)) { + luv_check_callback(L, handle->data, LUV_SIGNAL, 3); + } + ret = uv_signal_start(handle, luv_signal_cb, signum); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_signal_stop(lua_State* L) { + uv_signal_t* handle = luv_check_signal(L, 1); + int ret = uv_signal_stop(handle); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} diff --git a/3rdparty/luv/src/stream.c b/3rdparty/luv/src/stream.c new file mode 100644 index 00000000000..5009e04f097 --- /dev/null +++ b/3rdparty/luv/src/stream.c @@ -0,0 +1,263 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +static void luv_check_buf(lua_State *L, int idx, uv_buf_t *pbuf) { + size_t len; + pbuf->base = (char*)luaL_checklstring(L, idx, &len); + pbuf->len = len; +} + +static uv_stream_t* luv_check_stream(lua_State* L, int index) { + int isStream; + uv_stream_t* handle; + if (!(handle = *(void**) lua_touserdata(L, index))) { goto fail; } + lua_getfield(L, LUA_REGISTRYINDEX, "uv_stream"); + lua_getmetatable(L, index < 0 ? index - 1 : index); + lua_rawget(L, -2); + isStream = lua_toboolean(L, -1); + lua_pop(L, 2); + if (isStream) { return handle; } + fail: luaL_argerror(L, index, "Expected uv_stream userdata"); + return NULL; +} + +static void luv_shutdown_cb(uv_shutdown_t* req, int status) { + lua_State* L = luv_state(req->handle->loop); + luv_status(L, status); + luv_fulfill_req(L, req->data, 1); + luv_cleanup_req(L, req->data); + req->data = NULL; +} + +static int luv_shutdown(lua_State* L) { + uv_stream_t* handle = luv_check_stream(L, 1); + int ref = luv_check_continuation(L, 2); + uv_shutdown_t* req = lua_newuserdata(L, sizeof(*req)); + int ret; + req->data = luv_setup_req(L, ref); + ret = uv_shutdown(req, handle, luv_shutdown_cb); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + return 1; +} + +static void luv_connection_cb(uv_stream_t* handle, int status) { + lua_State* L = luv_state(handle->loop); + luv_status(L, status); + luv_call_callback(L, handle->data, LUV_CONNECTION, 1); +} + +static int luv_listen(lua_State* L) { + uv_stream_t* handle = luv_check_stream(L, 1); + int backlog = luaL_checkinteger(L, 2); + int ret; + luv_check_callback(L, handle->data, LUV_CONNECTION, 3); + ret = uv_listen(handle, backlog, luv_connection_cb); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_accept(lua_State* L) { + uv_stream_t* server = luv_check_stream(L, 1); + uv_stream_t* client = luv_check_stream(L, 2); + int ret = uv_accept(server, client); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static void luv_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { + (void)handle; + buf->base = malloc(suggested_size); + assert(buf->base); + buf->len = suggested_size; +} + +static void luv_read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { + lua_State* L = luv_state(handle->loop); + int nargs; + + if (nread > 0) { + lua_pushnil(L); + lua_pushlstring(L, buf->base, nread); + nargs = 2; + } + + free(buf->base); + if (nread == 0) return; + + if (nread == UV_EOF) { + nargs = 0; + } + else if (nread < 0) { + luv_status(L, nread); + nargs = 1; + } + + luv_call_callback(L, handle->data, LUV_READ, nargs); +} + +static int luv_read_start(lua_State* L) { + uv_stream_t* handle = luv_check_stream(L, 1); + int ret; + luv_check_callback(L, handle->data, LUV_READ, 2); + ret = uv_read_start(handle, luv_alloc_cb, luv_read_cb); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_read_stop(lua_State* L) { + uv_stream_t* handle = luv_check_stream(L, 1); + int ret = uv_read_stop(handle); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static void luv_write_cb(uv_write_t* req, int status) { + lua_State* L = luv_state(req->handle->loop); + luv_status(L, status); + luv_fulfill_req(L, req->data, 1); + luv_cleanup_req(L, req->data); + req->data = NULL; +} + +static uv_buf_t* luv_prep_bufs(lua_State* L, int index, size_t *count) { + uv_buf_t *bufs; + size_t i; + *count = lua_rawlen(L, index); + bufs = malloc(sizeof(uv_buf_t) * *count); + for (i = 0; i < *count; ++i) { + lua_rawgeti(L, index, i + 1); + luv_check_buf(L, -1, &bufs[i]); + lua_pop(L, 1); + } + return bufs; +} + +static int luv_write(lua_State* L) { + uv_stream_t* handle = luv_check_stream(L, 1); + uv_write_t* req; + int ret, ref; + ref = luv_check_continuation(L, 3); + req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + if (lua_istable(L, 2)) { + size_t count; + uv_buf_t *bufs = luv_prep_bufs(L, 2, &count); + ret = uv_write(req, handle, bufs, count, luv_write_cb); + free(bufs); + } + else if (lua_isstring(L, 2)) { + uv_buf_t buf; + luv_check_buf(L, 2, &buf); + ret = uv_write(req, handle, &buf, 1, luv_write_cb); + } + else { + return luaL_argerror(L, 2, "data must be string or table of strings"); + } + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + lua_pushvalue(L, 2); + ((luv_req_t*)req->data)->data_ref = luaL_ref(L, LUA_REGISTRYINDEX); + return 1; +} + +static int luv_write2(lua_State* L) { + uv_stream_t* handle = luv_check_stream(L, 1); + uv_write_t* req; + int ret, ref; + uv_stream_t* send_handle; + send_handle = luv_check_stream(L, 3); + ref = luv_check_continuation(L, 4); + req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + if (lua_istable(L, 2)) { + size_t count; + uv_buf_t *bufs = luv_prep_bufs(L, 2, &count); + ret = uv_write2(req, handle, bufs, count, send_handle, luv_write_cb); + free(bufs); + } + else if (lua_isstring(L, 2)) { + uv_buf_t buf; + luv_check_buf(L, 2, &buf); + ret = uv_write2(req, handle, &buf, 1, send_handle, luv_write_cb); + } + else { + return luaL_argerror(L, 2, "data must be string or table of strings"); + } + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + lua_pushvalue(L, 2); + ((luv_req_t*)req->data)->data_ref = luaL_ref(L, LUA_REGISTRYINDEX); + return 1; +} + +static int luv_try_write(lua_State* L) { + uv_stream_t* handle = luv_check_stream(L, 1); + int ret; + if (lua_istable(L, 2)) { + size_t count; + uv_buf_t *bufs = luv_prep_bufs(L, 2, &count); + ret = uv_try_write(handle, bufs, count); + free(bufs); + } + else if (lua_isstring(L, 2)) { + uv_buf_t buf; + luv_check_buf(L, 2, &buf); + ret = uv_try_write(handle, &buf, 1); + } + else { + return luaL_argerror(L, 2, "data must be string or table of strings"); + } + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_is_readable(lua_State* L) { + uv_stream_t* handle = luv_check_stream(L, 1); + lua_pushboolean(L, uv_is_readable(handle)); + return 1; +} + +static int luv_is_writable(lua_State* L) { + uv_stream_t* handle = luv_check_stream(L, 1); + lua_pushboolean(L, uv_is_writable(handle)); + return 1; +} + +static int luv_stream_set_blocking(lua_State* L) { + uv_stream_t* handle = luv_check_stream(L, 1); + int blocking, ret; + luaL_checktype(L, 2, LUA_TBOOLEAN); + blocking = lua_toboolean(L, 2); + ret = uv_stream_set_blocking(handle, blocking); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + diff --git a/3rdparty/luv/src/tcp.c b/3rdparty/luv/src/tcp.c new file mode 100644 index 00000000000..7ffef5ae763 --- /dev/null +++ b/3rdparty/luv/src/tcp.c @@ -0,0 +1,182 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +static uv_tcp_t* luv_check_tcp(lua_State* L, int index) { + uv_tcp_t* handle = luv_checkudata(L, index, "uv_tcp"); + luaL_argcheck(L, handle->type == UV_TCP && handle->data, index, "Expected uv_tcp_t"); + return handle; +} + +static int luv_new_tcp(lua_State* L) { + uv_tcp_t* handle = luv_newuserdata(L, sizeof(*handle)); + int ret = uv_tcp_init(luv_loop(L), handle); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + handle->data = luv_setup_handle(L); + return 1; +} + +static int luv_tcp_open(lua_State* L) { + uv_tcp_t* handle = luv_check_tcp(L, 1); + uv_os_sock_t sock = luaL_checkinteger(L, 2); + int ret = uv_tcp_open(handle, sock); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_tcp_nodelay(lua_State* L) { + uv_tcp_t* handle = luv_check_tcp(L, 1); + int ret, enable; + luaL_checktype(L, 2, LUA_TBOOLEAN); + enable = lua_toboolean(L, 2); + ret = uv_tcp_nodelay(handle, enable); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_tcp_keepalive(lua_State* L) { + uv_tcp_t* handle = luv_check_tcp(L, 1); + int ret, enable; + unsigned int delay = 0; + luaL_checktype(L, 2, LUA_TBOOLEAN); + enable = lua_toboolean(L, 2); + if (enable) { + delay = luaL_checkinteger(L, 3); + } + ret = uv_tcp_keepalive(handle, enable, delay); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_tcp_simultaneous_accepts(lua_State* L) { + uv_tcp_t* handle = luv_check_tcp(L, 1); + int ret, enable; + luaL_checktype(L, 2, LUA_TBOOLEAN); + enable = lua_toboolean(L, 2); + ret = uv_tcp_simultaneous_accepts(handle, enable); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_tcp_bind(lua_State* L) { + uv_tcp_t* handle = luv_check_tcp(L, 1); + const char* host = luaL_checkstring(L, 2); + int port = luaL_checkinteger(L, 3); + unsigned int flags = 0; + struct sockaddr_storage addr; + int ret; + if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) && + uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) { + return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port); + } + if (lua_type(L, 4) == LUA_TTABLE) { + lua_getfield(L, 4, "ipv6only"); + if (lua_toboolean(L, -1)) flags |= UV_TCP_IPV6ONLY; + lua_pop(L, 1); + } + ret = uv_tcp_bind(handle, (struct sockaddr*)&addr, flags); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static void parse_sockaddr(lua_State* L, struct sockaddr_storage* address, int addrlen) { + char ip[INET6_ADDRSTRLEN]; + int port = 0; + lua_newtable(L); + if (address->ss_family == AF_INET) { + struct sockaddr_in* addrin = (struct sockaddr_in*)address; + uv_inet_ntop(AF_INET, &(addrin->sin_addr), ip, addrlen); + port = ntohs(addrin->sin_port); + } else if (address->ss_family == AF_INET6) { + struct sockaddr_in6* addrin6 = (struct sockaddr_in6*)address; + uv_inet_ntop(AF_INET6, &(addrin6->sin6_addr), ip, addrlen); + port = ntohs(addrin6->sin6_port); + } + + lua_pushstring(L, luv_af_num_to_string(address->ss_family)); + lua_setfield(L, -2, "family"); + lua_pushinteger(L, port); + lua_setfield(L, -2, "port"); + lua_pushstring(L, ip); + lua_setfield(L, -2, "ip"); +} + +static int luv_tcp_getsockname(lua_State* L) { + uv_tcp_t* handle = luv_check_tcp(L, 1); + struct sockaddr_storage address; + int addrlen = sizeof(address); + int ret = uv_tcp_getsockname(handle, (struct sockaddr*)&address, &addrlen); + if (ret < 0) return luv_error(L, ret); + parse_sockaddr(L, &address, addrlen); + return 1; +} + +static int luv_tcp_getpeername(lua_State* L) { + uv_tcp_t* handle = luv_check_tcp(L, 1); + struct sockaddr_storage address; + int addrlen = sizeof(address); + int ret = uv_tcp_getpeername(handle, (struct sockaddr*)&address, &addrlen); + if (ret < 0) return luv_error(L, ret); + parse_sockaddr(L, &address, addrlen); + return 1; +} + + +static void luv_connect_cb(uv_connect_t* req, int status) { + lua_State* L = luv_state(req->handle->loop); + luv_status(L, status); + luv_fulfill_req(L, req->data, 1); + luv_cleanup_req(L, req->data); + req->data = NULL; +} + +static int luv_write_queue_size(lua_State* L) { + uv_tcp_t* handle = luv_check_tcp(L, 1); + lua_pushinteger(L, handle->write_queue_size); + return 1; +} + +static int luv_tcp_connect(lua_State* L) { + uv_tcp_t* handle = luv_check_tcp(L, 1); + const char* host = luaL_checkstring(L, 2); + int port = luaL_checkinteger(L, 3); + struct sockaddr_storage addr; + uv_connect_t* req; + int ret, ref; + if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) && + uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) { + return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port); + } + ref = luv_check_continuation(L, 4); + + req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + ret = uv_tcp_connect(req, handle, (struct sockaddr*)&addr, luv_connect_cb); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + return 1; +} diff --git a/3rdparty/luv/src/thread.c b/3rdparty/luv/src/thread.c new file mode 100644 index 00000000000..cc53011e6ed --- /dev/null +++ b/3rdparty/luv/src/thread.c @@ -0,0 +1,353 @@ +/* +* Copyright 2014 The Luvit Authors. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +*/ +#include "luv.h" +#include "lthreadpool.h" + +typedef struct { + uv_thread_t handle; + char* code; + int len; + int argc; + luv_thread_arg_t arg; +} luv_thread_t; + +static luv_acquire_vm acquire_vm_cb = NULL; +static luv_release_vm release_vm_cb = NULL; + +static lua_State* luv_thread_acquire_vm() { + lua_State* L = luaL_newstate(); + + // Add in the lua standard libraries + luaL_openlibs(L); + + // Get package.loaded, so we can store uv in it. + lua_getglobal(L, "package"); + lua_getfield(L, -1, "loaded"); + lua_remove(L, -2); // Remove package + + // Store uv module definition at loaded.uv + luaopen_luv(L); + lua_setfield(L, -2, "luv"); + lua_pop(L, 1); + + return L; +} + +static void luv_thread_release_vm(lua_State* L) { + lua_close(L); +} + +static int luv_thread_arg_set(lua_State* L, luv_thread_arg_t* args, int idx, int top, int flag) +{ + int i; + idx = idx > 0 ? idx : 1; + i = idx; + while (i <= top && i <= LUV_THREAD_MAXNUM_ARG + idx) + { + luv_val_t *arg = args->argv + i - idx; + arg->type = lua_type(L, i); + switch (arg->type) + { + case LUA_TNIL: + break; + case LUA_TBOOLEAN: + arg->val.boolean = lua_toboolean(L, i); + break; + case LUA_TNUMBER: + arg->val.num = lua_tonumber(L, i); + break; + case LUA_TLIGHTUSERDATA: + arg->val.userdata = lua_touserdata(L, i); + break; + case LUA_TSTRING: + { + const char* p = lua_tolstring(L, i, &arg->val.str.len); + arg->val.str.base = malloc(arg->val.str.len); + if (arg->val.str.base == NULL) + { + perror("out of memory"); + return 0; + } + memcpy((void*)arg->val.str.base, p, arg->val.str.len); + break; + } + case LUA_TUSERDATA: + if (flag == 1) { + arg->val.userdata = luv_check_handle(L, i); + break; + } + default: + fprintf(stderr, "Error: thread arg not support type '%s' at %d", + luaL_typename(L, arg->type), i); + exit(-1); + break; + } + i++; + } + args->argc = i - idx; + return args->argc; +} + +static void luv_thread_arg_clear(luv_thread_arg_t* args) { + int i; + for (i = 0; i < args->argc; i++) + { + if (args->argv[i].type == LUA_TSTRING) + { + free((void*)args->argv[i].val.str.base); + } + } + memset(args, 0, sizeof(*args)); + args->argc = 0; +} + +static void luv_thread_setup_handle(lua_State* L, uv_handle_t* handle) { + *(void**) lua_newuserdata(L, sizeof(void*)) = handle; + +#define XX(uc, lc) case UV_##uc: \ + luaL_getmetatable(L, "uv_"#lc); \ + break; + switch (handle->type) { + UV_HANDLE_TYPE_MAP(XX) + default: + luaL_error(L, "Unknown handle type"); + } +#undef XX + + lua_setmetatable(L, -2); +} + +static int luv_thread_arg_push(lua_State* L, const luv_thread_arg_t* args) { + int i = 0; + while (i < args->argc) + { + const luv_val_t* arg = args->argv + i; + switch (arg->type) + { + case LUA_TNIL: + lua_pushnil(L); + break; + case LUA_TBOOLEAN: + lua_pushboolean(L, arg->val.boolean); + break; + case LUA_TLIGHTUSERDATA: + lua_pushlightuserdata(L, arg->val.userdata); + break; + case LUA_TNUMBER: + lua_pushnumber(L, arg->val.num); + break; + case LUA_TSTRING: + lua_pushlstring(L, arg->val.str.base, arg->val.str.len); + break; + case LUA_TUSERDATA: + luv_thread_setup_handle(L, arg->val.userdata); + break; + default: + fprintf(stderr, "Error: thread arg not support type %s at %d", + luaL_typename(L, arg->type), i + 1); + } + i++; + }; + return i; +} + +int thread_dump(lua_State* L, const void* p, size_t sz, void* B) +{ + (void)L; + luaL_addlstring((luaL_Buffer*) B, (const char*) p, sz); + return 0; +} + +static const char* luv_thread_dumped(lua_State* L, int idx, size_t* l) { + if (lua_isstring(L, idx)) { + return lua_tolstring(L, idx, l); + } else { + const char* buff = NULL; + int top = lua_gettop(L); + luaL_Buffer b; + luaL_checktype(L, idx, LUA_TFUNCTION); + lua_pushvalue(L, idx); + luaL_buffinit(L, &b); +#if LUA_VERSION_NUM>=503 + int test_lua_dump = (lua_dump(L, thread_dump, &b, 1) == 0); +#else + int test_lua_dump = (lua_dump(L, thread_dump, &b) == 0); +#endif + if (test_lua_dump) { + luaL_pushresult(&b); + buff = lua_tolstring(L, -1, l); + } else + luaL_error(L, "Error: unable to dump given function"); + lua_settop(L, top); + + return buff; + } +} + +static luv_thread_t* luv_check_thread(lua_State* L, int index) +{ + luv_thread_t* thread = luaL_checkudata(L, index, "uv_thread"); + return thread; +} + +static int luv_thread_gc(lua_State* L) { + luv_thread_t* tid = luv_check_thread(L, 1); + free(tid->code); + tid->code = NULL; + tid->len = 0; + luv_thread_arg_clear(&tid->arg); + return 0; +} + +static int luv_thread_tostring(lua_State* L) +{ + luv_thread_t* thd = luv_check_thread(L, 1); + lua_pushfstring(L, "uv_thread_t: %p", thd->handle); + return 1; +} + +static void luv_thread_cb(void* varg) { + luv_thread_t* thd = (luv_thread_t*)varg; + lua_State* L = acquire_vm_cb(); + if (luaL_loadbuffer(L, thd->code, thd->len, "=thread") == 0) + { + int top = lua_gettop(L); + int i = luv_thread_arg_push(L, &thd->arg); + + for (i = 0; i < thd->arg.argc; i++) { + if (thd->arg.argv[i].type == LUA_TUSERDATA) { + lua_pushlightuserdata(L, thd->arg.argv[i].val.userdata); + lua_pushvalue(L, top + i + 1); + lua_rawset(L, LUA_REGISTRYINDEX); + } + } + + if (lua_pcall(L, i, 0, 0)) { + fprintf(stderr, "Uncaught Error in thread: %s\n", lua_tostring(L, -1)); + } + + for (i = 0; i < thd->arg.argc; i++) { + if (thd->arg.argv[i].type == LUA_TUSERDATA) { + lua_pushlightuserdata(L, thd->arg.argv[i].val.userdata); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushnil(L); + lua_setmetatable(L, -2); + lua_pop(L, 1); + + lua_pushlightuserdata(L, thd->arg.argv[i].val.userdata); + lua_pushnil(L); + lua_rawset(L, LUA_REGISTRYINDEX); + } + } + + } else { + fprintf(stderr, "Uncaught Error: %s\n", lua_tostring(L, -1)); + } + release_vm_cb(L); +} + +static int luv_new_thread(lua_State* L) { + int ret; + size_t len; + const char* buff; + luv_thread_t* thread; + thread = lua_newuserdata(L, sizeof(*thread)); + memset(thread, 0, sizeof(*thread)); + luaL_getmetatable(L, "uv_thread"); + lua_setmetatable(L, -2); + + buff = luv_thread_dumped(L, 1, &len); + + thread->argc = luv_thread_arg_set(L, &thread->arg, 2, lua_gettop(L) - 1, 1); + thread->len = len; + thread->code = malloc(thread->len); + memcpy(thread->code, buff, len); + + ret = uv_thread_create(&thread->handle, luv_thread_cb, thread); + if (ret < 0) return luv_error(L, ret); + + return 1; +} + +static int luv_thread_join(lua_State* L) { + luv_thread_t* tid = luv_check_thread(L, 1); + int ret = uv_thread_join(&tid->handle); + if (ret < 0) return luv_error(L, ret); + lua_pushboolean(L, 1); + return 1; +} + +static int luv_thread_self(lua_State* L) +{ + luv_thread_t* thread; + uv_thread_t t = uv_thread_self(); + thread = lua_newuserdata(L, sizeof(*thread)); + memset(thread, 0, sizeof(*thread)); + memcpy(&thread->handle, &t, sizeof(t)); + luaL_getmetatable(L, "uv_thread"); + lua_setmetatable(L, -2); + return 1; +} + +static int luv_thread_equal(lua_State* L) { + luv_thread_t* t1 = luv_check_thread(L, 1); + luv_thread_t* t2 = luv_check_thread(L, 2); + int ret = uv_thread_equal(&t1->handle, &t2->handle); + lua_pushboolean(L, ret); + return 1; +} + +/* Pause the calling thread for a number of milliseconds. */ +static int luv_thread_sleep(lua_State* L) { +#ifdef _WIN32 + DWORD msec = luaL_checkinteger(L, 1); + Sleep(msec); +#else + lua_Integer msec = luaL_checkinteger(L, 1); + usleep(msec * 1000); +#endif + return 0; +} + +static const luaL_Reg luv_thread_methods[] = { + {"equal", luv_thread_equal}, + {"join", luv_thread_join}, + {NULL, NULL} +}; + +static void luv_thread_init(lua_State* L) { + luaL_newmetatable(L, "uv_thread"); + lua_pushcfunction(L, luv_thread_tostring); + lua_setfield(L, -2, "__tostring"); + lua_pushcfunction(L, luv_thread_equal); + lua_setfield(L, -2, "__eq"); + lua_pushcfunction(L, luv_thread_gc); + lua_setfield(L, -2, "__gc"); + lua_newtable(L); + luaL_setfuncs(L, luv_thread_methods, 0); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); + + if (acquire_vm_cb == NULL) acquire_vm_cb = luv_thread_acquire_vm; + if (release_vm_cb == NULL) release_vm_cb = luv_thread_release_vm; +} + +LUALIB_API void luv_set_thread_cb(luv_acquire_vm acquire, luv_release_vm release) +{ + acquire_vm_cb = acquire; + release_vm_cb = release; +} diff --git a/3rdparty/luv/src/timer.c b/3rdparty/luv/src/timer.c new file mode 100644 index 00000000000..b283f1fc8b2 --- /dev/null +++ b/3rdparty/luv/src/timer.c @@ -0,0 +1,84 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +static uv_timer_t* luv_check_timer(lua_State* L, int index) { + uv_timer_t* handle = luv_checkudata(L, index, "uv_timer"); + luaL_argcheck(L, handle->type == UV_TIMER && handle->data, index, "Expected uv_timer_t"); + return handle; +} + +static int luv_new_timer(lua_State* L) { + uv_timer_t* handle = luv_newuserdata(L, sizeof(*handle)); + int ret = uv_timer_init(luv_loop(L), handle); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + handle->data = luv_setup_handle(L); + return 1; +} + +static void luv_timer_cb(uv_timer_t* handle) { + lua_State* L = luv_state(handle->loop); + luv_handle_t* data = handle->data; + luv_call_callback(L, data, LUV_TIMEOUT, 0); +} + +static int luv_timer_start(lua_State* L) { + uv_timer_t* handle = luv_check_timer(L, 1); + uint64_t timeout; + uint64_t repeat; + int ret; + timeout = luaL_checkinteger(L, 2); + repeat = luaL_checkinteger(L, 3); + luv_check_callback(L, handle->data, LUV_TIMEOUT, 4); + ret = uv_timer_start(handle, luv_timer_cb, timeout, repeat); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_timer_stop(lua_State* L) { + uv_timer_t* handle = luv_check_timer(L, 1); + int ret = uv_timer_stop(handle); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_timer_again(lua_State* L) { + uv_timer_t* handle = luv_check_timer(L, 1); + int ret = uv_timer_again(handle); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_timer_set_repeat(lua_State* L) { + uv_timer_t* handle = luv_check_timer(L, 1); + uint64_t repeat = luaL_checkinteger(L, 2); + uv_timer_set_repeat(handle, repeat); + return 0; +} + +static int luv_timer_get_repeat(lua_State* L) { + uv_timer_t* handle = luv_check_timer(L, 1); + uint64_t repeat = uv_timer_get_repeat(handle); + lua_pushinteger(L, repeat); + return 1; +} diff --git a/3rdparty/luv/src/tty.c b/3rdparty/luv/src/tty.c new file mode 100644 index 00000000000..9232dc07603 --- /dev/null +++ b/3rdparty/luv/src/tty.c @@ -0,0 +1,65 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +static uv_tty_t* luv_check_tty(lua_State* L, int index) { + uv_tty_t* handle = luv_checkudata(L, index, "uv_tty"); + luaL_argcheck(L, handle->type == UV_TTY && handle->data, index, "Expected uv_tty_t"); + return handle; +} + +static int luv_new_tty(lua_State* L) { + int readable, ret; + uv_tty_t* handle; + uv_file fd = luaL_checkinteger(L, 1); + luaL_checktype(L, 2, LUA_TBOOLEAN); + readable = lua_toboolean(L, 2); + handle = luv_newuserdata(L, sizeof(*handle)); + ret = uv_tty_init(luv_loop(L), handle, fd, readable); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + handle->data = luv_setup_handle(L); + return 1; +} + +static int luv_tty_set_mode(lua_State* L) { + uv_tty_t* handle = luv_check_tty(L, 1); + int mode = luaL_checkinteger(L, 2); + int ret = uv_tty_set_mode(handle, mode); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_tty_reset_mode(lua_State* L) { + int ret = uv_tty_reset_mode(); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_tty_get_winsize(lua_State* L) { + uv_tty_t* handle = luv_check_tty(L, 1); + int width, height; + int ret = uv_tty_get_winsize(handle, &width, &height); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, width); + lua_pushinteger(L, height); + return 2; +} diff --git a/3rdparty/luv/src/udp.c b/3rdparty/luv/src/udp.c new file mode 100644 index 00000000000..9cc25555559 --- /dev/null +++ b/3rdparty/luv/src/udp.c @@ -0,0 +1,260 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +static uv_udp_t* luv_check_udp(lua_State* L, int index) { + uv_udp_t* handle = luv_checkudata(L, index, "uv_udp"); + luaL_argcheck(L, handle->type == UV_UDP && handle->data, index, "Expected uv_udp_t"); + return handle; +} + +static int luv_new_udp(lua_State* L) { + uv_udp_t* handle = luv_newuserdata(L, sizeof(*handle)); + int ret = uv_udp_init(luv_loop(L), handle); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + handle->data = luv_setup_handle(L); + return 1; +} + +static int luv_udp_open(lua_State* L) { + uv_udp_t* handle = luv_check_udp(L, 1); + uv_os_sock_t sock = luaL_checkinteger(L, 2); + int ret = uv_udp_open(handle, sock); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_udp_bind(lua_State* L) { + uv_udp_t* handle = luv_check_udp(L, 1); + const char* host = luaL_checkstring(L, 2); + int port = luaL_checkinteger(L, 3); + unsigned int flags = 0; + struct sockaddr_storage addr; + int ret; + if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) && + uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) { + return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port); + } + if (lua_type(L, 4) == LUA_TTABLE) { + luaL_checktype(L, 4, LUA_TTABLE); + lua_getfield(L, 4, "reuseaddr"); + if (lua_toboolean(L, -1)) flags |= UV_UDP_REUSEADDR; + lua_pop(L, 1); + lua_getfield(L, 4, "ipv6only"); + if (lua_toboolean(L, -1)) flags |= UV_UDP_IPV6ONLY; + lua_pop(L, 1); + } + ret = uv_udp_bind(handle, (struct sockaddr*)&addr, flags); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_udp_getsockname(lua_State* L) { + uv_udp_t* handle = luv_check_udp(L, 1); + struct sockaddr_storage address; + int addrlen = sizeof(address); + int ret = uv_udp_getsockname(handle, (struct sockaddr*)&address, &addrlen); + if (ret < 0) return luv_error(L, ret); + parse_sockaddr(L, &address, addrlen); + return 1; +} + +// These are the same order as uv_membership which also starts at 0 +static const char *const luv_membership_opts[] = { + "leave", "join", NULL +}; + +static int luv_udp_set_membership(lua_State* L) { + uv_udp_t* handle = luv_check_udp(L, 1); + const char* multicast_addr = luaL_checkstring(L, 2); + const char* interface_addr = luaL_checkstring(L, 3); + uv_membership membership = luaL_checkoption(L, 4, NULL, luv_membership_opts); + int ret = uv_udp_set_membership(handle, multicast_addr, interface_addr, membership); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_udp_set_multicast_loop(lua_State* L) { + uv_udp_t* handle = luv_check_udp(L, 1); + int on, ret; + luaL_checktype(L, 2, LUA_TBOOLEAN); + on = lua_toboolean(L, 2); + ret = uv_udp_set_multicast_loop(handle, on); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_udp_set_multicast_ttl(lua_State* L) { + uv_udp_t* handle = luv_check_udp(L, 1); + int ttl, ret; + ttl = luaL_checkinteger(L, 2); + ret = uv_udp_set_multicast_ttl(handle, ttl); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_udp_set_multicast_interface(lua_State* L) { + uv_udp_t* handle = luv_check_udp(L, 1); + const char* interface_addr = luaL_checkstring(L, 2); + int ret = uv_udp_set_multicast_interface(handle, interface_addr); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_udp_set_broadcast(lua_State* L) { + uv_udp_t* handle = luv_check_udp(L, 1); + int on, ret; + luaL_checktype(L, 2, LUA_TBOOLEAN); + on = lua_toboolean(L, 2); + ret =uv_udp_set_broadcast(handle, on); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_udp_set_ttl(lua_State* L) { + uv_udp_t* handle = luv_check_udp(L, 1); + int ttl, ret; + ttl = luaL_checknumber(L, 2); + ret = uv_udp_set_ttl(handle, ttl); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static void luv_udp_send_cb(uv_udp_send_t* req, int status) { + lua_State* L = luv_state(req->handle->loop); + luv_status(L, status); + luv_fulfill_req(L, req->data, 1); + luv_cleanup_req(L, req->data); + req->data = NULL; +} + +static int luv_udp_send(lua_State* L) { + uv_udp_t* handle = luv_check_udp(L, 1); + uv_udp_send_t* req; + uv_buf_t buf; + int ret, port, ref; + const char* host; + struct sockaddr_storage addr; + luv_check_buf(L, 2, &buf); + host = luaL_checkstring(L, 3); + port = luaL_checkinteger(L, 4); + if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) && + uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) { + return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port); + } + ref = luv_check_continuation(L, 5); + req = lua_newuserdata(L, sizeof(*req)); + req->data = luv_setup_req(L, ref); + ret = uv_udp_send(req, handle, &buf, 1, (struct sockaddr*)&addr, luv_udp_send_cb); + if (ret < 0) { + lua_pop(L, 1); + return luv_error(L, ret); + } + return 1; + +} + +static int luv_udp_try_send(lua_State* L) { + uv_udp_t* handle = luv_check_udp(L, 1); + uv_buf_t buf; + int ret, port; + const char* host; + struct sockaddr_storage addr; + luv_check_buf(L, 2, &buf); + host = luaL_checkstring(L, 3); + port = luaL_checkinteger(L, 4); + if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) && + uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) { + return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port); + } + ret = uv_udp_try_send(handle, &buf, 1, (struct sockaddr*)&addr); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static void luv_udp_recv_cb(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) { + lua_State* L = luv_state(handle->loop); + + // err + if (nread < 0) { + luv_status(L, nread); + } + else { + lua_pushnil(L); + } + + // data + if (nread == 0) { + if (addr) { + lua_pushstring(L, ""); + } + else { + lua_pushnil(L); + } + } + else if (nread > 0) { + lua_pushlstring(L, buf->base, nread); + } + if (buf) free(buf->base); + + // address + if (addr) { + parse_sockaddr(L, (struct sockaddr_storage*)addr, sizeof *addr); + } + else { + lua_pushnil(L); + } + + // flags + lua_newtable(L); + if (flags & UV_UDP_PARTIAL) { + lua_pushboolean(L, 1); + lua_setfield(L, -2, "partial"); + } + + luv_call_callback(L, handle->data, LUV_RECV, 4); +} + +static int luv_udp_recv_start(lua_State* L) { + uv_udp_t* handle = luv_check_udp(L, 1); + int ret; + luv_check_callback(L, handle->data, LUV_RECV, 2); + ret = uv_udp_recv_start(handle, luv_alloc_cb, luv_udp_recv_cb); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} + +static int luv_udp_recv_stop(lua_State* L) { + uv_udp_t* handle = luv_check_udp(L, 1); + int ret = uv_udp_recv_stop(handle); + if (ret < 0) return luv_error(L, ret); + lua_pushinteger(L, ret); + return 1; +} diff --git a/3rdparty/luv/src/util.c b/3rdparty/luv/src/util.c new file mode 100644 index 00000000000..c7b98c1759a --- /dev/null +++ b/3rdparty/luv/src/util.c @@ -0,0 +1,56 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "luv.h" + +void luv_stack_dump(lua_State* L, const char* name) { + int i, l; + fprintf(stderr, "\nAPI STACK DUMP %p %d: %s\n", L, lua_status(L), name); + for (i = 1, l = lua_gettop(L); i <= l; i++) { + int type = lua_type(L, i); + switch (type) { + case LUA_TSTRING: + fprintf(stderr, " %d %s \"%s\"\n", i, lua_typename(L, type), lua_tostring(L, i)); + break; + case LUA_TNUMBER: + fprintf(stderr, " %d %s %ld\n", i, lua_typename(L, type), (long int) lua_tointeger(L, i)); + break; + case LUA_TUSERDATA: + fprintf(stderr, " %d %s %p\n", i, lua_typename(L, type), lua_touserdata(L, i)); + break; + default: + fprintf(stderr, " %d %s\n", i, lua_typename(L, type)); + break; + } + } + assert(l == lua_gettop(L)); +} + +static int luv_error(lua_State* L, int status) { + lua_pushnil(L); + lua_pushfstring(L, "%s: %s", uv_err_name(status), uv_strerror(status)); + lua_pushstring(L, uv_err_name(status)); + return 3; +} + +static void luv_status(lua_State* L, int status) { + if (status < 0) { + lua_pushstring(L, uv_err_name(status)); + } + else { + lua_pushnil(L); + } +} diff --git a/3rdparty/luv/src/util.h b/3rdparty/luv/src/util.h new file mode 100644 index 00000000000..c669c0430db --- /dev/null +++ b/3rdparty/luv/src/util.h @@ -0,0 +1,26 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef LUV_UTIL_H +#define LUV_UTIL_H + +#include "luv.h" + +void luv_stack_dump(lua_State* L, const char* name); +static int luv_error(lua_State* L, int ret); +static void luv_status(lua_State* L, int status); + +#endif diff --git a/3rdparty/luv/src/work.c b/3rdparty/luv/src/work.c new file mode 100644 index 00000000000..e40212f1e7c --- /dev/null +++ b/3rdparty/luv/src/work.c @@ -0,0 +1,224 @@ +/* +* Copyright 2014 The Luvit Authors. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +*/ +#include "luv.h" + +#include "lthreadpool.h" + +typedef struct { + lua_State* L; /* vm in main */ + char* code; /* thread entry code */ + size_t len; + + uv_async_t async; + int async_cb; /* ref, run in main, call when async message received, NYI */ + int after_work_cb; /* ref, run in main ,call after work cb*/ +} luv_work_ctx_t; + +typedef struct { + uv_work_t work; + luv_work_ctx_t* ctx; + + luv_thread_arg_t arg; +} luv_work_t; + +static uv_key_t L_key; + +static luv_work_ctx_t* luv_check_work_ctx(lua_State* L, int index) +{ + luv_work_ctx_t* ctx = luaL_checkudata(L, index, "luv_work_ctx"); + return ctx; +} + +static int luv_work_ctx_gc(lua_State *L) +{ + luv_work_ctx_t* ctx = luv_check_work_ctx(L, 1); + free(ctx->code); + luaL_unref(L, LUA_REGISTRYINDEX, ctx->after_work_cb); + luaL_unref(L, LUA_REGISTRYINDEX, ctx->async_cb); + + return 0; +} + +static int luv_work_ctx_tostring(lua_State* L) +{ + luv_work_ctx_t* ctx = luv_check_work_ctx(L, 1); + lua_pushfstring(L, "luv_work_ctx_t: %p", ctx); + return 1; +} + +static void luv_work_cb(uv_work_t* req) +{ + luv_work_t* work = req->data; + luv_work_ctx_t* ctx = work->ctx; + lua_State *L = uv_key_get(&L_key); + int top; + if (L == NULL) { + /* vm reuse in threadpool */ + L = acquire_vm_cb(); + uv_key_set(&L_key, L); + } + + top = lua_gettop(L); + lua_pushlstring(L, ctx->code, ctx->len); + lua_rawget(L, LUA_REGISTRYINDEX); + if (lua_isnil(L, -1)) + { + lua_pop(L, 1); + + lua_pushlstring(L, ctx->code, ctx->len); + if (luaL_loadbuffer(L, ctx->code, ctx->len, "=pool") != 0) + { + fprintf(stderr, "Uncaught Error: %s\n", lua_tostring(L, -1)); + lua_pop(L, 2); + + lua_pushnil(L); + } else + { + lua_pushvalue(L, -1); + lua_insert(L, lua_gettop(L) - 2); + lua_rawset(L, LUA_REGISTRYINDEX); + } + } + + if (lua_isfunction(L, -1)) + { + int i = luv_thread_arg_push(L, &work->arg); + if (lua_pcall(L, i, LUA_MULTRET, 0)) { + fprintf(stderr, "Uncaught Error in thread: %s\n", lua_tostring(L, -1)); + } + luv_thread_arg_clear(&work->arg); + luv_thread_arg_set(L, &work->arg, top + 1, lua_gettop(L), 0); + lua_settop(L, top); + } else { + fprintf(stderr, "Uncaught Error: %s can't be work entry\n", + lua_typename(L, lua_type(L,-1))); + } +} + +static void luv_after_work_cb(uv_work_t* req, int status) { + luv_work_t* work = req->data; + luv_work_ctx_t* ctx = work->ctx; + lua_State*L = ctx->L; + int i; + (void)status; + lua_rawgeti(L, LUA_REGISTRYINDEX, ctx->after_work_cb); + i = luv_thread_arg_push(L, &work->arg); + if (lua_pcall(L, i, 0, 0)) + { + fprintf(stderr, "Uncaught Error in thread: %s\n", lua_tostring(L, -1)); + } + + //ref down to ctx + lua_pushlightuserdata(L, work); + lua_pushnil(L); + lua_rawset(L, LUA_REGISTRYINDEX); + + luv_thread_arg_clear(&work->arg); + free(work); +} + +static void async_cb(uv_async_t *handle) +{ + luv_work_t*work = handle->data; + luv_work_ctx_t* ctx = work->ctx; + lua_State*L = ctx->L; + int i; + lua_rawgeti(L, LUA_REGISTRYINDEX, ctx->async_cb); + i = luv_thread_arg_push(L, &work->arg); + if (lua_pcall(L, i, 0, 0)) + { + fprintf(stderr, "Uncaught Error in thread: %s\n", lua_tostring(L, -1)); + } +} + +static int luv_new_work(lua_State* L) { + size_t len; + const char* buff; + luv_work_ctx_t* ctx; + + buff = luv_thread_dumped(L, 1, &len); + luaL_checktype(L, 2, LUA_TFUNCTION); + if(!lua_isnoneornil(L, 3)) + luaL_checktype(L, 3, LUA_TFUNCTION); + + ctx = lua_newuserdata(L, sizeof(*ctx)); + memset(ctx, 0, sizeof(*ctx)); + + ctx->len = len; + ctx->code = malloc(ctx->len); + memcpy(ctx->code, buff, len); + + lua_pushvalue(L, 2); + ctx->after_work_cb = luaL_ref(L, LUA_REGISTRYINDEX); + if (lua_gettop(L) == 4) { + lua_pushvalue(L, 3); + ctx->async_cb = luaL_ref(L, LUA_REGISTRYINDEX); + uv_async_init(luv_loop(L), &ctx->async, async_cb); + } else + ctx->async_cb = LUA_REFNIL; + ctx->L = L; + luaL_getmetatable(L, "luv_work_ctx"); + lua_setmetatable(L, -2); + return 1; +} + +static int luv_queue_work(lua_State* L) { + int top = lua_gettop(L); + luv_work_ctx_t* ctx = luv_check_work_ctx(L, 1); + luv_work_t* work = malloc(sizeof(*work)); + int ret; + + luv_thread_arg_set(L, &work->arg, 2, top, 0); + work->ctx = ctx; + work->work.data = work; + ret = uv_queue_work(luv_loop(L), &work->work, luv_work_cb, luv_after_work_cb); + if (ret < 0) { + free(work); + return luv_error(L, ret); + } + + //ref up to ctx + lua_pushlightuserdata(L, work); + lua_pushvalue(L, 1); + lua_rawset(L, LUA_REGISTRYINDEX); + + lua_pushboolean(L, 1); + return 1; +} + +static const luaL_Reg luv_work_ctx_methods[] = { + {"queue", luv_queue_work}, + {NULL, NULL} +}; + +static int key_inited = 0; +static void luv_work_init(lua_State* L) { + luaL_newmetatable(L, "luv_work_ctx"); + lua_pushcfunction(L, luv_work_ctx_tostring); + lua_setfield(L, -2, "__tostring"); + lua_pushcfunction(L, luv_work_ctx_gc); + lua_setfield(L, -2, "__gc"); + lua_newtable(L); + luaL_setfuncs(L, luv_work_ctx_methods, 0); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); + + if (key_inited==0) { + key_inited = 1; + uv_key_create(&L_key); + } +} |