/* * 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}, #if LUV_UV_VERSION_GEQ(1, 12, 0) {"signal_start_oneshot", luv_signal_start_oneshot}, #endif {"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}, #if LUV_UV_VERSION_GEQ(1, 14, 0) {"fs_copyfile", luv_fs_copyfile }, #endif // dns.c {"getaddrinfo", luv_getaddrinfo}, {"getnameinfo", luv_getnameinfo}, // misc.c {"chdir", luv_chdir}, {"os_homedir", luv_os_homedir}, {"os_tmpdir", luv_os_tmpdir}, {"os_get_passwd", luv_os_get_passwd}, {"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}, #ifndef _WIN32 {"print_all_handles", luv_print_all_handles}, {"print_active_handles", luv_print_active_handles}, #endif #if LUV_UV_VERSION_GEQ(1, 12, 0) {"os_getenv", luv_os_getenv}, {"os_setenv", luv_os_setenv}, {"os_unsetenv", luv_os_unsetenv}, {"os_gethostname", luv_os_gethostname}, #endif #if LUV_UV_VERSION_GEQ(1, 16, 0) {"if_indextoname", luv_if_indextoname}, {"if_indextoiid", luv_if_indextoiid}, {"os_getppid", luv_os_getppid }, #endif #if LUV_UV_VERSION_GEQ(1, 18, 0) {"os_getpid", luv_os_getpid }, #endif // 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}, // util.c #if LUV_UV_VERSION_GEQ(1, 10, 0) {"translate_sys_error", luv_translate_sys_error}, #endif {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}, {"getsockname", 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 (lua_State*)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 = (uv_loop_t*)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 = (uv_loop_t*)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; }