summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/luv/src
diff options
context:
space:
mode:
author ImJezze <jezze@gmx.net>2016-02-21 11:48:45 +0100
committer ImJezze <jezze@gmx.net>2016-02-21 11:48:45 +0100
commitcc24a339d8c0517259084b5c178d784626ba965c (patch)
tree9868e9687b5802ae0a3733712a3bbeb3bc75c953 /3rdparty/luv/src
parentb5daabda5495dea5c50e17961ecfed2ea8619d76 (diff)
Merge remote-tracking branch 'refs/remotes/mamedev/master'
Second attempt
Diffstat (limited to '3rdparty/luv/src')
-rw-r--r--3rdparty/luv/src/async.c63
-rw-r--r--3rdparty/luv/src/check.c59
-rw-r--r--3rdparty/luv/src/constants.c649
-rw-r--r--3rdparty/luv/src/dns.c296
-rw-r--r--3rdparty/luv/src/fs.c614
-rw-r--r--3rdparty/luv/src/fs_event.c97
-rw-r--r--3rdparty/luv/src/fs_poll.c90
-rw-r--r--3rdparty/luv/src/handle.c173
-rw-r--r--3rdparty/luv/src/idle.c59
-rw-r--r--3rdparty/luv/src/lhandle.c116
-rw-r--r--3rdparty/luv/src/lhandle.h67
-rw-r--r--3rdparty/luv/src/loop.c92
-rw-r--r--3rdparty/luv/src/lreq.c71
-rw-r--r--3rdparty/luv/src/lreq.h43
-rw-r--r--3rdparty/luv/src/lthreadpool.h48
-rw-r--r--3rdparty/luv/src/luv.c519
-rw-r--r--3rdparty/luv/src/luv.h109
-rw-r--r--3rdparty/luv/src/misc.c316
-rw-r--r--3rdparty/luv/src/pipe.c114
-rw-r--r--3rdparty/luv/src/poll.c100
-rw-r--r--3rdparty/luv/src/prepare.c59
-rw-r--r--3rdparty/luv/src/process.c266
-rw-r--r--3rdparty/luv/src/req.c52
-rw-r--r--3rdparty/luv/src/schema.c16
-rw-r--r--3rdparty/luv/src/signal.c72
-rw-r--r--3rdparty/luv/src/stream.c263
-rw-r--r--3rdparty/luv/src/tcp.c182
-rw-r--r--3rdparty/luv/src/thread.c353
-rw-r--r--3rdparty/luv/src/timer.c84
-rw-r--r--3rdparty/luv/src/tty.c65
-rw-r--r--3rdparty/luv/src/udp.c260
-rw-r--r--3rdparty/luv/src/util.c56
-rw-r--r--3rdparty/luv/src/util.h26
-rw-r--r--3rdparty/luv/src/work.c224
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);
+ }
+}