├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── README.md ├── cmake └── LuaNativeObjects.cmake ├── epoll.nobj.lua ├── examples ├── epoller.lua └── nixio_server.lua ├── rockspecs ├── lua-epoll-1.0-1.rockspec └── lua-epoll-scm-0.rockspec ├── src ├── epoller.nobj.lua ├── error.nobj.lua └── pre_generated-epoll.nobj.c └── tests └── test_epoll.lua /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .*.swp 3 | *.so 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | env: 4 | matrix: 5 | - LUA=lua5.1 LIBLUA=liblua5.1-dev LUA_INCDIR=/usr/include/lua5.1 LUA_LIB=lua5.1 6 | - LUA=lua5.2 LIBLUA=liblua5.2-dev LUA_INCDIR=/usr/include/lua5.2 LUA_LIB=lua5.2 7 | - LUA=luajit LIBLUA=libluajit-5.1-dev LUA_INCDIR=/usr/include/luajit-2.0 LUA_LIB=luajit-5.1 8 | 9 | branches: 10 | only: 11 | - master 12 | 13 | compiler: 14 | - gcc 15 | 16 | before_install: 17 | - if [ $LUA = "luajit" ]; then 18 | sudo add-apt-repository ppa:mwild1/ppa -y && sudo apt-get update -y; 19 | fi 20 | 21 | install: 22 | - sudo apt-get install $LUA -y 23 | - sudo apt-get install $LIBLUA -y 24 | - LUA_LIBDIR=`pkg-config $LUA --variable=libdir` 25 | - INSTALL_LMOD=`pkg-config $LUA --variable=INSTALL_LMOD` 26 | - INSTALL_CMOD=`pkg-config $LUA --variable=INSTALL_CMOD` 27 | ## make sure there is a 'lua' command. 28 | - if [ ! -x /usr/bin/lua ]; then 29 | sudo ln -s `which $LUA` /usr/bin/lua; 30 | fi 31 | 32 | script: 33 | #### build using pre-generated bindings. 34 | - mkdir build; cd build 35 | - cmake .. -DLUA_LIBRARIES=$LUA_LIBDIR -DLUA_INCLUDE_DIR=$LUA_INCDIR 36 | -DINSTALL_LMOD=$INSTALL_LMOD -DINSTALL_CMOD=$INSTALL_CMOD 37 | - make 38 | - sudo make install 39 | # Run tests. 40 | - echo "TEST" | $LUA ../tests/test_epoll.lua 41 | - cd .. ; rm -rf build 42 | #### Re-Generate bindings. 43 | - git clone git://github.com/Neopallium/LuaNativeObjects.git; 44 | - mkdir build; cd build 45 | - cmake .. -DLUA_LIBRARIES=$LUA_LIBDIR -DLUA_INCLUDE_DIR=$LUA_INCDIR 46 | -DLUA_NATIVE_OBJECTS_PATH=$TRAVIS_BUILD_DIR/LuaNativeObjects 47 | -DUSE_PRE_GENERATED_BINDINGS=OFF -DGENERATE_LUADOCS=OFF 48 | -DINSTALL_LMOD=$INSTALL_LMOD -DINSTALL_CMOD=$INSTALL_CMOD 49 | - make 50 | - sudo make install 51 | # Run tests. 52 | - echo "TEST" | $LUA ../tests/test_epoll.lua 53 | 54 | notifications: 55 | email: 56 | on_failure: always 57 | on_success: change 58 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Lua bindings for epoll 3 | # 4 | cmake_minimum_required(VERSION 3.18) 5 | 6 | project(lua-epoll C) 7 | 8 | set(BUILD_SHARED_LIBS TRUE) 9 | 10 | set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) 11 | 12 | set(INSTALL_CMOD share/lua/cmod CACHE PATH "Directory to install Lua binary modules (configure lua via LUA_CPATH)") 13 | 14 | set(COMMON_CFLAGS "${CFLAGS}") 15 | set(COMMON_LDFLAGS) 16 | set(COMMON_LIBS) 17 | 18 | ## Lua 5.x 19 | include(FindLua) 20 | if(NOT ${LUA_FOUND}) 21 | message(FATAL_ERROR "The FindLua module could not find lua :-(") 22 | endif() 23 | set(COMMON_LIBS "${COMMON_LIBS};${LUA_LIBRARIES}") 24 | 25 | if(WIN32) 26 | set(COMMON_CFLAGS "${COMMON_CFLAGS} -I${LUA_INCLUDE_DIR}") 27 | set(COMMON_LDFLAGS "${COMMON_LDFLAGS} ${LUA_LIBRARY}") 28 | endif() 29 | ## MAC OSX needs extra linker flags 30 | if(APPLE) 31 | set(COMMON_LDFLAGS "${COMMON_LDFLAGS} -undefined dynamic_lookup") 32 | endif() 33 | 34 | ## check for epoll support 35 | include(CheckCSourceCompiles) 36 | check_c_source_compiles(" 37 | #include 38 | 39 | int main(int argc, char *argv[]) { 40 | int fd = epoll_create(10); 41 | return 0; 42 | }" HAVE_EPOLL) 43 | 44 | if(NOT HAVE_EPOLL) 45 | message(FATAL_ERROR "epoll support required!") 46 | endif(NOT HAVE_EPOLL) 47 | 48 | ## LuaNativeObjects 49 | include(LuaNativeObjects) 50 | 51 | include_directories(${CMAKE_CURRENT_SOURCE_DIR} 52 | ${CMAKE_CURRENT_BINARY_DIR} 53 | ${LUA_INCLUDE_DIR}) 54 | 55 | ## LuaEpoll 56 | set(LUA_EPOLL_SRC 57 | epoll.nobj.lua 58 | ) 59 | 60 | if(${USE_PRE_GENERATED_BINDINGS}) 61 | set(LUA_EPOLL_SRC src/pre_generated-epoll.nobj.c) 62 | else() 63 | # Generate Lua bindings. 64 | GenLuaNativeObjects(LUA_EPOLL_SRC) 65 | endif() 66 | 67 | add_library(lua-epoll MODULE ${LUA_EPOLL_SRC}) 68 | target_link_libraries(lua-epoll ${COMMON_LIBS}) 69 | set_target_properties(lua-epoll PROPERTIES PREFIX "") 70 | set_target_properties(lua-epoll PROPERTIES COMPILE_FLAGS "${COMMON_CFLAGS}") 71 | set_target_properties(lua-epoll PROPERTIES OUTPUT_NAME epoll) 72 | 73 | install(TARGETS lua-epoll 74 | DESTINATION "${INSTALL_CMOD}") 75 | 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | lua-epoll 2 | ======= 3 | 4 | [![travis-ci status](https://secure.travis-ci.org/Neopallium/lua-epoll.png?branch=master)](http://travis-ci.org/Neopallium/lua-epoll/builds) 5 | 6 | Lightweight epoll wrapper. 7 | 8 | See the `examples/nixio_server.lua` for an example of how to use. 9 | 10 | Installing 11 | ---------- 12 | 13 | ### Install lua-epoll version 1.0: 14 | 15 | luarocks install Neopallium/lua-epoll 1.0-1 16 | 17 | 18 | ### Install lua-epoll: 19 | 20 | luarocks install https://github.com/Neopallium/lua-epoll/raw/master/lua-epoll-scm-0.rockspec 21 | 22 | 23 | To re-generating the bindings 24 | ----------------------------- 25 | 26 | You will need to install LuaNativeObjects and set the CMake variable `USE_PRE_GENERATED_BINDINGS` to FALSE. 27 | By default CMake will use the pre-generated bindings that are include in the project. 28 | 29 | Build Dependencies 30 | ------------------ 31 | 32 | Optional dependency for re-generating Lua bindings from `*.nobj.lua` files: 33 | 34 | * [LuaNativeObjects](https://github.com/Neopallium/LuaNativeObjects), this is the bindings generator used to convert the `*.nobj.lua` files into a native Lua module. 35 | 36 | -------------------------------------------------------------------------------- /cmake/LuaNativeObjects.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Lua Native Objects 3 | # 4 | 5 | find_program(LUA_NATIVE_OBJECTS_EXECUTABLE native_objects.lua 6 | PATHS ${CMAKE_SOURCE_DIR}/../LuaNativeObjects 7 | DOC "LuaNativeObjects executable path") 8 | set(USE_PRE_GENERATED_BINDINGS TRUE CACHE BOOL 9 | "Set this to FALSE to re-generate bindings using LuaNativeObjects") 10 | set(GENERATE_LUADOCS TRUE CACHE BOOL 11 | "Set this to FALSE to avoid generation of docs using LuaDoc") 12 | 13 | macro(GenLuaNativeObjects _src_files_var) 14 | set(_new_src_files) 15 | foreach(_src_file ${${_src_files_var}}) 16 | if(_src_file MATCHES ".nobj.lua") 17 | string(REGEX REPLACE ".nobj.lua" ".nobj.c" _src_file_out ${_src_file}) 18 | string(REGEX REPLACE ".nobj.lua" ".nobj.ffi.lua" _ffi_file_out ${_src_file}) 19 | add_custom_command(OUTPUT ${_src_file_out} ${_ffi_file_out} 20 | COMMAND ${LUA_NATIVE_OBJECTS_EXECUTABLE} -outpath ${CMAKE_CURRENT_BINARY_DIR} -gen lua ${_src_file} 21 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 22 | DEPENDS ${_src_file} 23 | ) 24 | set_source_files_properties(${_src_file_out} PROPERTIES GENERATED TRUE) 25 | set_source_files_properties(${_ffi_file_out} PROPERTIES GENERATED TRUE) 26 | if (${GENERATE_LUADOCS}) 27 | string(REGEX REPLACE ".nobj.lua" "" _doc_base ${_src_file}) 28 | string(REGEX REPLACE ".nobj.lua" ".luadoc" _doc_file_out ${_src_file}) 29 | add_custom_target(${_doc_file_out} ALL 30 | COMMAND ${LUA_NATIVE_OBJECTS_EXECUTABLE} -outpath docs -gen luadoc ${_src_file} 31 | COMMAND luadoc -nofiles -d docs docs 32 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 33 | DEPENDS ${_src_file} 34 | ) 35 | endif() 36 | set_source_files_properties(${_doc_file_out} PROPERTIES GENERATED TRUE) 37 | set(_new_src_files ${_new_src_files} ${_src_file_out}) 38 | else(_src_file MATCHES ".nobj.lua") 39 | set(_new_src_files ${_new_src_files} ${_src_file}) 40 | endif(_src_file MATCHES ".nobj.lua") 41 | endforeach(_src_file) 42 | set(${_src_files_var} ${_new_src_files}) 43 | endmacro(GenLuaNativeObjects _src_files_var) 44 | 45 | -------------------------------------------------------------------------------- /epoll.nobj.lua: -------------------------------------------------------------------------------- 1 | 2 | -- make generated variable nicer. 3 | set_variable_format "%s" 4 | 5 | c_module "epoll" { 6 | 7 | -- enable FFI bindings support. 8 | luajit_ffi = true, 9 | luajit_ffi_load_cmodule = true, 10 | 11 | sys_include "sys/epoll.h", 12 | sys_include "unistd.h", 13 | 14 | export_definitions { 15 | "EPOLLIN", 16 | "EPOLLOUT", 17 | "EPOLLRDHUP", 18 | "EPOLLPRI", 19 | "EPOLLERR", 20 | "EPOLLET", 21 | "EPOLLONESHOT", 22 | }, 23 | 24 | subfiles { 25 | "src/error.nobj.lua", 26 | "src/epoller.nobj.lua", 27 | }, 28 | 29 | c_function "new" { 30 | var_in{ "int", "size", is_optional = true, default = 64 }, 31 | c_export_call { "Epoller *", "!this" } "epoller_create" { "int", "size"}, 32 | }, 33 | } 34 | 35 | -------------------------------------------------------------------------------- /examples/epoller.lua: -------------------------------------------------------------------------------- 1 | 2 | local epoll = require"epoll" 3 | 4 | local bit = require"bit" 5 | local band = bit.band 6 | 7 | local setmetatable = setmetatable 8 | local pairs = pairs 9 | 10 | local EPOLLIN = epoll.EPOLLIN 11 | local EPOLLOUT = epoll.EPOLLOUT 12 | local EPOLLERR = epoll.EPOLLERR 13 | 14 | local poll_mt = {} 15 | poll_mt.__index = poll_mt 16 | 17 | function poll_mt:add(sock, events) 18 | local fd = sock:fileno() 19 | self.socks[fd] = sock 20 | return self.epoll:add(fd, events, fd) 21 | end 22 | 23 | function poll_mt:mod(sock, events) 24 | local fd = sock:fileno() 25 | self.socks[fd] = sock 26 | return self.epoll:mod(fd, events, fd) 27 | end 28 | 29 | function poll_mt:del(sock) 30 | local fd = sock:fileno() 31 | -- check if the socket is registered. 32 | sock = self.socks[fd] 33 | if sock then 34 | -- clear registered socket. 35 | self.socks[fd] = nil 36 | -- remove events for socket. 37 | return self.epoll:del(fd) 38 | end 39 | end 40 | 41 | local function make_event_callback(self, socks) 42 | return function (fd, ev) 43 | -- call registered callback. 44 | local sock = socks[fd] 45 | if not sock then return end 46 | local event_cb = sock.on_io_event 47 | if event_cb then 48 | event_cb(sock, ev) 49 | else 50 | self:del(sock) 51 | end 52 | end 53 | end 54 | 55 | local function _loop_step_cb(epoll, event_cb, timeout) 56 | end 57 | 58 | function poll_mt:step(timeout) 59 | assert(self.epoll:wait_callback(self.event_cb, timeout or -1)) 60 | end 61 | 62 | local events = {} 63 | function poll_mt:start() 64 | local epoll = self.epoll 65 | local socks = self.socks 66 | local event_cb = self.event_cb 67 | self.is_running = true 68 | while self.is_running do 69 | --epoll:wait_callback(event_cb, -1) 70 | ---[[ 71 | local num = epoll:wait(events, -1) 72 | for i=1,num,2 do 73 | local fd, ev = events[i], events[i+1] 74 | -- call registered callback. 75 | local sock = socks[fd] 76 | if not sock then return end 77 | local event_cb = sock.on_io_event 78 | if event_cb then 79 | event_cb(sock, ev) 80 | else 81 | self:del(sock) 82 | end 83 | end 84 | --]] 85 | end 86 | end 87 | 88 | function poll_mt:stop() 89 | self.is_running = false 90 | end 91 | 92 | function poll_mt:close() 93 | return self.epoll:close() 94 | end 95 | 96 | module(...) 97 | 98 | for k,v in pairs(epoll) do 99 | if k:sub(1,5) == 'EPOLL' then 100 | _M[k] = v 101 | end 102 | end 103 | 104 | function new() 105 | local self 106 | local socks = {} 107 | self = setmetatable({ 108 | epoll = epoll.new(), 109 | event_cb = make_event_callback(self, socks), 110 | socks = socks, 111 | }, poll_mt) 112 | return self 113 | end 114 | 115 | -------------------------------------------------------------------------------- /examples/nixio_server.lua: -------------------------------------------------------------------------------- 1 | 2 | local epoller = require"epoller" 3 | local nixio = require"nixio" 4 | 5 | local poller = epoller.new() 6 | 7 | local wsock_meth = {} 8 | local wsock_mt = { __index = wsock_meth } 9 | 10 | function wsock_meth:fileno() 11 | return self.sock:fileno() 12 | end 13 | 14 | function wsock_meth:close() 15 | local sock = self.sock 16 | if not sock then return end 17 | local fd = sock:fileno() 18 | poller:del(self) 19 | self.sock = nil 20 | sock:close() 21 | end 22 | 23 | local function wrap_sock(sock, on_io_event) 24 | return setmetatable({ sock = sock, on_io_event = on_io_event }, wsock_mt) 25 | end 26 | 27 | local function accept_connection(server, cb) 28 | local client = server:accept() 29 | local fd = client:fileno() 30 | client:setblocking(false) 31 | client = wrap_sock(client, cb) 32 | -- register callback for read events. 33 | poller:add(client, epoller.EPOLLIN) 34 | return client 35 | end 36 | 37 | local function new_acceptor(host, port, family, cb) 38 | local sock = nixio.socket(family or 'inet', 'stream') 39 | local fd = sock:fileno() 40 | sock:setblocking(false) 41 | assert(sock:setsockopt('socket', 'reuseaddr', 1)) 42 | if host == '*' then host = nil end 43 | assert(sock:bind(host, port)) 44 | assert(sock:listen(1024)) 45 | -- register callback for read events. 46 | sock = wrap_sock(sock, cb) 47 | poller:add(sock, epoller.EPOLLIN) 48 | return sock 49 | end 50 | 51 | local function new_client(server) 52 | accept_connection(server, function(wsock, events) 53 | local sock = wsock.sock 54 | local msg = sock:recv(1024) 55 | if msg and #msg > 0 then 56 | sock:send("echo:" .. msg) 57 | else 58 | print('closing client') 59 | wsock:close() 60 | end 61 | end) 62 | end 63 | 64 | local function new_server(port) 65 | print("listen on:", port) 66 | new_acceptor('*', port, 'inet', function(wsock, events) 67 | print("accept new client on:", port) 68 | new_client(wsock.sock) 69 | end) 70 | end 71 | 72 | for i=1,#arg do 73 | new_server(arg[i]) 74 | end 75 | 76 | if #arg == 0 then 77 | new_server("1080") 78 | end 79 | 80 | poller:start() 81 | 82 | -------------------------------------------------------------------------------- /rockspecs/lua-epoll-1.0-1.rockspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | 3 | package = 'lua-epoll' 4 | version = '1.0-1' 5 | source = { 6 | url = 'git://github.com/Neopallium/lua-epoll.git', 7 | branch = "v1.0", 8 | } 9 | description = { 10 | summary = "Lightweight wrapper for epoll.", 11 | detailed = '', 12 | homepage = 'https://github.com/Neopallium/lua-epoll', 13 | license = 'MIT', 14 | maintainer = "Robert G. Jakabosky", 15 | } 16 | dependencies = { 17 | 'lua >= 5.1, < 5.5', 18 | } 19 | build = { 20 | type = "builtin", 21 | modules = { 22 | epoll = { 23 | sources = { "src/pre_generated-epoll.nobj.c" }, 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rockspecs/lua-epoll-scm-0.rockspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | 3 | package = 'lua-epoll' 4 | version = 'scm-0' 5 | source = { 6 | url = 'git://github.com/Neopallium/lua-epoll.git' 7 | } 8 | description = { 9 | summary = "Lightweight wrapper for epoll.", 10 | detailed = '', 11 | homepage = 'https://github.com/Neopallium/lua-epoll', 12 | license = 'MIT', 13 | maintainer = "Robert G. Jakabosky", 14 | } 15 | dependencies = { 16 | 'lua >= 5.1, < 5.5', 17 | } 18 | build = { 19 | type = "builtin", 20 | modules = { 21 | epoll = { 22 | sources = { "src/pre_generated-epoll.nobj.c" }, 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/epoller.nobj.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2011 by Robert G. Jakabosky 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in 11 | -- all copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | -- THE SOFTWARE. 20 | 21 | local epoll_types = [[ 22 | typedef union epoll_data { 23 | void *ptr; 24 | int fd; 25 | uint32_t u32; 26 | uint64_t u64; 27 | } epoll_data_t; 28 | 29 | struct epoll_event { 30 | uint32_t events; /* Epoll events */ 31 | epoll_data_t data; /* User data variable */ 32 | } __attribute__ ((__packed__)); 33 | 34 | typedef struct epoll_event epoll_event; 35 | ]] 36 | 37 | local Epoller_type = [[ 38 | typedef struct Epoller { 39 | int epfd; 40 | int size; 41 | int count; 42 | struct epoll_event *events; 43 | } Epoller; 44 | 45 | int epoller_wait(Epoller *this, int timeout); 46 | ]] 47 | 48 | object "Epoller" { 49 | sys_include "string.h", 50 | -- main Epoller C code. 51 | c_source(Epoller_type), 52 | c_source[[ 53 | #define EPOLLER_MIN_SIZE 20 54 | static void epoller_resize(Epoller *this, int newsize) { 55 | if(newsize < EPOLLER_MIN_SIZE) newsize = EPOLLER_MIN_SIZE; 56 | this->events = (struct epoll_event *)realloc(this->events, newsize * sizeof(struct epoll_event)); 57 | this->size = newsize; 58 | } 59 | 60 | static void epoller_grow(Epoller *this) { 61 | if(this->size > this->count) return; 62 | epoller_resize(this, this->count + 50); 63 | } 64 | 65 | Epoller *epoller_create(int size) { 66 | Epoller *this; 67 | 68 | this = (Epoller *)calloc(1, sizeof(Epoller)); 69 | #ifdef EPOLL_CLOEXEC 70 | this->epfd = epoll_create1(EPOLL_CLOEXEC); 71 | #else 72 | this->epfd = epoll_create(1024); 73 | #endif 74 | this->size = 0; 75 | this->count = 0; 76 | this->events = NULL; 77 | epoller_resize(this, size); 78 | 79 | return this; 80 | } 81 | 82 | void epoller_destroy(Epoller *this) { 83 | close(this->epfd); 84 | free(this->events); 85 | free(this); 86 | } 87 | 88 | static int epoller_ctl(Epoller *this, int op, int fd, uint32_t events, uint64_t id) { 89 | struct epoll_event event; 90 | event.events = events; 91 | event.data.u64 = id; 92 | return epoll_ctl(this->epfd, op, fd, &event); 93 | } 94 | 95 | int epoller_add(Epoller *this, int fd, uint32_t events, uint64_t id) { 96 | this->count++; 97 | epoller_grow(this); 98 | return epoller_ctl(this, EPOLL_CTL_ADD, fd, events, id); 99 | } 100 | 101 | int epoller_mod(Epoller *this, int fd, uint32_t events, uint64_t id) { 102 | return epoller_ctl(this, EPOLL_CTL_MOD, fd, events, id); 103 | } 104 | 105 | int epoller_del(Epoller *this, int fd) { 106 | this->count--; 107 | return epoller_ctl(this, EPOLL_CTL_DEL, fd, 0, 0); 108 | } 109 | 110 | int epoller_wait(Epoller *this, int timeout) { 111 | return epoll_wait(this->epfd, this->events, this->size, timeout); 112 | } 113 | 114 | ]], 115 | -- register epoll & Epoller datastures with FFI. 116 | ffi_cdef(epoll_types), 117 | ffi_cdef(Epoller_type), 118 | 119 | constructor { 120 | var_in{ "int", "size", is_optional = true, default = 64 }, 121 | c_call "Epoller *" "epoller_create" { "int", "size"}, 122 | }, 123 | destructor "close" { 124 | c_method_call "void" "epoller_destroy" {}, 125 | }, 126 | 127 | method "add" { 128 | c_method_call "errno_rc" "epoller_add" { "int", "fd", "uint32_t", "events", "uint64_t", "id" }, 129 | }, 130 | method "mod" { 131 | c_method_call "errno_rc" "epoller_mod" { "int", "fd", "uint32_t", "events", "uint64_t", "id" }, 132 | }, 133 | method "del" { 134 | c_method_call "errno_rc" "epoller_del" { "int", "fd" }, 135 | }, 136 | method "wait" { 137 | var_in{ "", "events" }, 138 | c_source "pre_src" [[ 139 | luaL_checktype(L, ${events::idx}, LUA_TTABLE); 140 | ]], 141 | c_method_call { "errno_rc", "rc" } "epoller_wait" { "int", "timeout" }, 142 | c_source[[ 143 | if(${rc} > 0) { 144 | int idx; 145 | int n; 146 | /* fill 'events' table with event pairs. */ 147 | for(n = 0, idx = 1; n < ${rc}; n++) { 148 | lua_pushinteger(L, ${this}->events[n].data.u64); 149 | lua_rawseti(L, ${events::idx}, idx); idx++; 150 | lua_pushinteger(L, ${this}->events[n].events); 151 | lua_rawseti(L, ${events::idx}, idx); idx++; 152 | } 153 | lua_pushinteger(L, rc); 154 | return 1; 155 | } else if(${rc} == 0) { 156 | lua_pushinteger(L, rc); 157 | return 1; 158 | } 159 | ]], 160 | ffi_source[[ 161 | if (${rc} > 0) then 162 | local idx = 1 163 | -- fill 'events' table with event pairs. 164 | for n=0,(${rc}-1) do 165 | ${events}[idx] = tonumber(${this}.events[n].data.u64) 166 | idx = idx + 1 167 | ${events}[idx] = tonumber(${this}.events[n].events) 168 | idx = idx + 1 169 | end 170 | return ${rc} 171 | elseif (${rc} == 0) then 172 | return ${rc} 173 | end 174 | ]], 175 | }, 176 | method "wait_callback" { 177 | var_in{ "", "event_cb" }, 178 | c_source "pre_src" [[ 179 | luaL_checktype(L, ${event_cb::idx}, LUA_TFUNCTION); 180 | ]], 181 | c_method_call { "errno_rc", "rc" } "epoller_wait" { "int", "timeout" }, 182 | c_source[[ 183 | if(${rc} > 0) { 184 | int n; 185 | /* call 'event_cb' for each pair. */ 186 | for(n = 0; n < ${rc}; n++) { 187 | lua_pushvalue(L, ${event_cb::idx}); 188 | lua_pushinteger(L, ${this}->events[n].data.u64); 189 | lua_pushinteger(L, ${this}->events[n].events); 190 | lua_call(L, 2, 0); 191 | } 192 | lua_pushinteger(L, rc); 193 | return 1; 194 | } else if(${rc} == 0) { 195 | lua_pushinteger(L, rc); 196 | return 1; 197 | } 198 | ]], 199 | ffi_source[[ 200 | if (${rc} > 0) then 201 | -- call 'event_cb' for each pair. 202 | for n=0,(${rc}-1) do 203 | ${event_cb}(tonumber(${this}.events[n].data.u64), tonumber(${this}.events[n].events)) 204 | end 205 | return ${rc} 206 | elseif (${rc} == 0) then 207 | return ${rc} 208 | end 209 | ]], 210 | }, 211 | } 212 | -------------------------------------------------------------------------------- /src/error.nobj.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2011 by Robert G. Jakabosky 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in 11 | -- all copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | -- THE SOFTWARE. 20 | 21 | -- E* error values. 22 | meta_object "Errors" { 23 | map_constants_bidirectional = true, 24 | export_definitions { 25 | "EPERM", -- Operation not permitted 26 | "ENOENT", -- No such file or directory 27 | "ESRCH", -- No such process 28 | "EINTR", -- Interrupted system call 29 | "EIO", -- I/O error 30 | "ENXIO", -- No such device or address 31 | "E2BIG", -- Argument list too long 32 | "ENOEXEC", -- Exec format error 33 | "EBADF", -- Bad file number 34 | "ECHILD", -- No child processes 35 | "EAGAIN", -- Try again 36 | "ENOMEM", -- Out of memory 37 | "EACCES", -- Permission denied 38 | "EFAULT", -- Bad address 39 | "ENOTBLK", -- Block device required 40 | "EBUSY", -- Device or resource busy 41 | "EEXIST", -- File exists 42 | "EXDEV", -- Cross-device link 43 | "ENODEV", -- No such device 44 | "ENOTDIR", -- Not a directory 45 | "EISDIR", -- Is a directory 46 | "EINVAL", -- Invalid argument 47 | "ENFILE", -- File table overflow 48 | "EMFILE", -- Too many open files 49 | "ENOTTY", -- Not a typewriter 50 | "ETXTBSY", -- Text file busy 51 | "EFBIG", -- File too large 52 | "ENOSPC", -- No space left on device 53 | "ESPIPE", -- Illegal seek 54 | "EROFS", -- Read-only file system 55 | "EMLINK", -- Too many links 56 | "EPIPE", -- Broken pipe 57 | "EDOM", -- Math argument out of domain of func 58 | "ERANGE", -- Math result not representable 59 | 60 | "EDEADLK", -- Resource deadlock would occur 61 | "EDEADLOCK", -- EDEADLK 62 | "ENAMETOOLONG", -- File name too long 63 | "ENOLCK", -- No record locks available 64 | "ENOSYS", -- Function not implemented 65 | "ENOTEMPTY", -- Directory not empty 66 | "ELOOP", -- Too many symbolic links encountered 67 | "EWOULDBLOCK", -- Operation would block 68 | "ENOMSG", -- No message of desired type 69 | "EIDRM", -- Identifier removed 70 | "ECHRNG", -- Channel number out of range 71 | "EL2NSYNC", -- Level 2 not synchronized 72 | "EL3HLT", -- Level 3 halted 73 | "EL3RST", -- Level 3 reset 74 | "ELNRNG", -- Link number out of range 75 | "EUNATCH", -- Protocol driver not attached 76 | "ENOCSI", -- No CSI structure available 77 | "EL2HLT", -- Level 2 halted 78 | "EBADE", -- Invalid exchange 79 | "EBADR", -- Invalid request descriptor 80 | "EXFULL", -- Exchange full 81 | "ENOANO", -- No anode 82 | "EBADRQC", -- Invalid request code 83 | "EBADSLT", -- Invalid slot 84 | 85 | "EBFONT", -- Bad font file format 86 | "ENOSTR", -- Device not a stream 87 | "ENODATA", -- No data available 88 | "ETIME", -- Timer expired 89 | "ENOSR", -- Out of streams resources 90 | "ENONET", -- Machine is not on the network 91 | "ENOPKG", -- Package not installed 92 | "EREMOTE", -- Object is remote 93 | "ENOLINK", -- Link has been severed 94 | "EADV", -- Advertise error 95 | "ESRMNT", -- Srmount error 96 | "ECOMM", -- Communication error on send 97 | "EPROTO", -- Protocol error 98 | "EMULTIHOP", -- Multihop attempted 99 | "EDOTDOT", -- RFS specific error 100 | "EBADMSG", -- Not a data message 101 | "EOVERFLOW", -- Value too large for defined data type 102 | "ENOTUNIQ", -- Name not unique on network 103 | "EBADFD", -- File descriptor in bad state 104 | "EREMCHG", -- Remote address changed 105 | "ELIBACC", -- Can not access a needed shared library 106 | "ELIBBAD", -- Accessing a corrupted shared library 107 | "ELIBSCN", -- .lib section in a.out corrupted 108 | "ELIBMAX", -- Attempting to link in too many shared libraries 109 | "ELIBEXEC", -- Cannot exec a shared library directly 110 | "EILSEQ", -- Illegal byte sequence 111 | "ERESTART", -- Interrupted system call should be restarted 112 | "ESTRPIPE", -- Streams pipe error 113 | "EUSERS", -- Too many users 114 | "ENOTSOCK", -- Socket operation on non-socket 115 | "EDESTADDRREQ", -- Destination address required 116 | "EMSGSIZE", -- Message too long 117 | "EPROTOTYPE", -- Protocol wrong type for socket 118 | "ENOPROTOOPT", -- Protocol not available 119 | "EPROTONOSUPPORT", -- Protocol not supported 120 | "ESOCKTNOSUPPORT", -- Socket type not supported 121 | "EOPNOTSUPP", -- Operation not supported on transport endpoint 122 | "EPFNOSUPPORT", -- Protocol family not supported 123 | "EAFNOSUPPORT", -- Address family not supported by protocol 124 | "EADDRINUSE", -- Address already in use 125 | "EADDRNOTAVAIL", -- Cannot assign requested address 126 | "ENETDOWN", -- Network is down 127 | "ENETUNREACH", -- Network is unreachable 128 | "ENETRESET", -- Network dropped connection because of reset 129 | "ECONNABORTED", -- Software caused connection abort 130 | "ECONNRESET", -- Connection reset by peer 131 | "ENOBUFS", -- No buffer space available 132 | "EISCONN", -- Transport endpoint is already connected 133 | "ENOTCONN", -- Transport endpoint is not connected 134 | "ESHUTDOWN", -- Cannot send after transport endpoint shutdown 135 | "ETOOMANYREFS", -- Too many references: cannot splice 136 | "ETIMEDOUT", -- Connection timed out 137 | "ECONNREFUSED", -- Connection refused 138 | "EHOSTDOWN", -- Host is down 139 | "EHOSTUNREACH", -- No route to host 140 | "EALREADY", -- Operation already in progress 141 | "EINPROGRESS", -- Operation now in progress 142 | "ESTALE", -- Stale NFS file handle 143 | "EUCLEAN", -- Structure needs cleaning 144 | "ENOTNAM", -- Not a XENIX named type file 145 | "ENAVAIL", -- No XENIX semaphores available 146 | "EISNAM", -- Is a named type file 147 | "EREMOTEIO", -- Remote I/O error 148 | "EDQUOT", -- Quota exceeded 149 | 150 | "ENOMEDIUM", -- No medium found 151 | "EMEDIUMTYPE", -- Wrong medium type 152 | "ECANCELED", -- Operation Canceled 153 | "ENOKEY", -- Required key not available 154 | "EKEYEXPIRED", -- Key has expired 155 | "EKEYREVOKED", -- Key has been revoked 156 | "EKEYREJECTED", -- Key was rejected by service 157 | 158 | -- for robust mutexes 159 | "EOWNERDEAD", -- Owner died 160 | "ENOTRECOVERABLE", -- State not recoverable 161 | 162 | "ERFKILL", -- Operation not possible due to RF-kill 163 | }, 164 | 165 | method "description" { 166 | var_in{ "", "err" }, 167 | var_out{ "char *", "msg", need_buffer = 1024 }, 168 | c_source "pre" [[ 169 | int err_type; 170 | int err_num = -1; 171 | ]], 172 | c_source[[ 173 | err_type = lua_type(L, ${err::idx}); 174 | if(err_type == LUA_TSTRING) { 175 | lua_pushvalue(L, ${err::idx}); 176 | lua_rawget(L, ${this::idx}); 177 | if(lua_isnumber(L, -1)) { 178 | err_num = lua_tointeger(L, -1); 179 | } 180 | lua_pop(L, 1); 181 | } else if(err_type == LUA_TNUMBER) { 182 | err_num = lua_tointeger(L, ${err::idx}); 183 | } else { 184 | return luaL_argerror(L, ${err::idx}, "expected string/number"); 185 | } 186 | if(err_num < 0) { 187 | lua_pushnil(L); 188 | lua_pushliteral(L, "UNKNOWN ERROR"); 189 | return 2; 190 | } 191 | strerror_r(err_num, ${msg}, ${msg_len}); 192 | ${msg_len} = strlen(${msg}); 193 | ]], 194 | }, 195 | } 196 | 197 | -- Convert 'errno' codes into strings. 198 | -- 199 | -- This is an error code wrapper object, it converts C-style 'int' return error code 200 | -- into Lua-style 'nil, "Error message"' return values. 201 | -- 202 | ffi_source "ffi_src" [[ 203 | -- get Errors table to map errno to error name. 204 | local Error_names = _M.Errors 205 | ]] 206 | 207 | c_source "extra_code" [[ 208 | static char epoll_Errors_key[] = "epoll_Errors_key"; 209 | ]] 210 | 211 | c_source "module_init_src" [[ 212 | /* Cache reference to epoll.Errors table for errno->string convertion. */ 213 | lua_pushlightuserdata(L, epoll_Errors_key); 214 | lua_getfield(L, -2, "Errors"); 215 | lua_rawset(L, LUA_REGISTRYINDEX); 216 | ]] 217 | 218 | error_code "errno_rc" "int" { 219 | sys_include"string.h", 220 | ffi_type = "int", 221 | is_error_check = function(rec) return "(-1 == ${" .. rec.name .. "})" end, 222 | ffi_is_error_check = function(rec) return "(-1 == ${" .. rec.name .. "})" end, 223 | default = "0", 224 | c_source [[ 225 | if(-1 == err) { 226 | /* get Errors table. */ 227 | lua_pushlightuserdata(L, epoll_Errors_key); 228 | lua_rawget(L, LUA_REGISTRYINDEX); 229 | /* convert errno to string. */ 230 | lua_rawgeti(L, -1, errno); 231 | /* remove Errors table. */ 232 | lua_remove(L, -2); 233 | if(!lua_isnil(L, -1)) { 234 | /* found error. */ 235 | return; 236 | } 237 | /* Unknown error. */ 238 | lua_pop(L, 1); 239 | err_str = "UNKNOWN ERROR"; 240 | } 241 | ]], 242 | ffi_source [[ 243 | if(-1 == err) then 244 | err_str = Error_names[ffi.errno()] 245 | end 246 | ]], 247 | } 248 | 249 | -------------------------------------------------------------------------------- /src/pre_generated-epoll.nobj.c: -------------------------------------------------------------------------------- 1 | /*********************************************************************************************** 2 | ************************************************************************************************ 3 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 4 | !!!!!!!! Warning this file was generated from a set of *.nobj.lua definition files !!!!!!!!!!!!! 5 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 6 | ************************************************************************************************ 7 | ***********************************************************************************************/ 8 | 9 | #include "lua.h" 10 | #include "lauxlib.h" 11 | #include "lualib.h" 12 | 13 | /* some Lua 5.0 compatibility support. */ 14 | #if !defined(lua_pushliteral) 15 | #define lua_pushliteral(L, s) lua_pushstring(L, "" s, (sizeof(s)/sizeof(char))-1) 16 | #endif 17 | 18 | #if !defined(LUA_VERSION_NUM) 19 | #define lua_pushinteger(L, n) lua_pushnumber(L, (lua_Number)n) 20 | #define luaL_Reg luaL_reg 21 | #endif 22 | 23 | /* 24 | ** Adapted from Lua 5.2.0 luaL_setfuncs. 25 | */ 26 | static void nobj_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { 27 | luaL_checkstack(L, nup, "too many upvalues"); 28 | for (; l->name != NULL; l++) { /* fill the table with given functions */ 29 | int i; 30 | for (i = 0; i < nup; i++) /* copy upvalues to the top */ 31 | lua_pushvalue(L, -nup); 32 | lua_pushstring(L, l->name); 33 | lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ 34 | lua_settable(L, -(nup + 3)); 35 | } 36 | lua_pop(L, nup); /* remove upvalues */ 37 | } 38 | 39 | /* some Lua 5.1 compatibility support. */ 40 | #if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM == 501) 41 | 42 | #define lua_load_no_mode(L, reader, data, source) \ 43 | lua_load(L, reader, data, source) 44 | 45 | #define lua_rawlen(L, idx) lua_objlen(L, idx) 46 | 47 | #endif 48 | 49 | #if LUA_VERSION_NUM >= 502 50 | 51 | #define lua_load_no_mode(L, reader, data, source) \ 52 | lua_load(L, reader, data, source, NULL) 53 | 54 | static int luaL_typerror (lua_State *L, int narg, const char *tname) { 55 | const char *msg = lua_pushfstring(L, "%s expected, got %s", 56 | tname, luaL_typename(L, narg)); 57 | return luaL_argerror(L, narg, msg); 58 | } 59 | 60 | #endif 61 | 62 | #define REG_PACKAGE_IS_CONSTRUCTOR 0 63 | #define REG_MODULES_AS_GLOBALS 0 64 | #define REG_OBJECTS_AS_GLOBALS 0 65 | #define OBJ_DATA_HIDDEN_METATABLE 1 66 | #define USE_FIELD_GET_SET_METHODS 0 67 | #define LUAJIT_FFI 1 68 | 69 | 70 | #include 71 | #include 72 | #include 73 | 74 | 75 | 76 | #include 77 | #include 78 | #include 79 | #include 80 | 81 | #ifdef _MSC_VER 82 | #define __WINDOWS__ 83 | #else 84 | #if defined(_WIN32) 85 | #define __WINDOWS__ 86 | #endif 87 | #endif 88 | 89 | #ifdef __WINDOWS__ 90 | 91 | /* for MinGW32 compiler need to include */ 92 | #ifdef __GNUC__ 93 | #include 94 | #include 95 | #else 96 | 97 | /* define some standard types missing on Windows. */ 98 | #ifndef __INT32_MAX__ 99 | typedef __int32 int32_t; 100 | typedef unsigned __int32 uint32_t; 101 | #endif 102 | #ifndef __INT64_MAX__ 103 | typedef __int64 int64_t; 104 | typedef unsigned __int64 uint64_t; 105 | #endif 106 | typedef int bool; 107 | #ifndef true 108 | #define true 1 109 | #endif 110 | #ifndef false 111 | #define false 0 112 | #endif 113 | 114 | #endif 115 | 116 | /* wrap strerror_s(). */ 117 | #ifdef __GNUC__ 118 | #ifndef strerror_r 119 | #define strerror_r(errno, buf, buflen) do { \ 120 | strncpy((buf), strerror(errno), (buflen)-1); \ 121 | (buf)[(buflen)-1] = '\0'; \ 122 | } while(0) 123 | #endif 124 | #else 125 | #ifndef strerror_r 126 | #define strerror_r(errno, buf, buflen) strerror_s((buf), (buflen), (errno)) 127 | #endif 128 | #endif 129 | 130 | #define FUNC_UNUSED 131 | 132 | #define LUA_NOBJ_API __declspec(dllexport) 133 | 134 | #else 135 | 136 | #define LUA_NOBJ_API LUALIB_API 137 | 138 | #include 139 | #include 140 | 141 | #define FUNC_UNUSED __attribute__((unused)) 142 | 143 | #endif 144 | 145 | #if defined(__GNUC__) && (__GNUC__ >= 4) 146 | #define assert_obj_type(type, obj) \ 147 | assert(__builtin_types_compatible_p(typeof(obj), type *)) 148 | #else 149 | #define assert_obj_type(type, obj) 150 | #endif 151 | 152 | void *nobj_realloc(void *ptr, size_t osize, size_t nsize); 153 | 154 | void *nobj_realloc(void *ptr, size_t osize, size_t nsize) { 155 | (void)osize; 156 | if(0 == nsize) { 157 | free(ptr); 158 | return NULL; 159 | } 160 | return realloc(ptr, nsize); 161 | } 162 | 163 | #define obj_type_free(type, obj) do { \ 164 | assert_obj_type(type, obj); \ 165 | nobj_realloc((obj), sizeof(type), 0); \ 166 | } while(0) 167 | 168 | #define obj_type_new(type, obj) do { \ 169 | assert_obj_type(type, obj); \ 170 | (obj) = nobj_realloc(NULL, 0, sizeof(type)); \ 171 | } while(0) 172 | 173 | typedef struct obj_type obj_type; 174 | 175 | typedef void (*base_caster_t)(void **obj); 176 | 177 | typedef void (*dyn_caster_t)(void **obj, obj_type **type); 178 | 179 | #define OBJ_TYPE_FLAG_WEAK_REF (1<<0) 180 | #define OBJ_TYPE_SIMPLE (1<<1) 181 | #define OBJ_TYPE_IMPORT (1<<2) 182 | struct obj_type { 183 | dyn_caster_t dcaster; /**< caster to support casting to sub-objects. */ 184 | int32_t id; /**< type's id. */ 185 | uint32_t flags; /**< type's flags (weak refs) */ 186 | const char *name; /**< type's object name. */ 187 | }; 188 | 189 | typedef struct obj_base { 190 | int32_t id; 191 | base_caster_t bcaster; 192 | } obj_base; 193 | 194 | typedef enum obj_const_type { 195 | CONST_UNKOWN = 0, 196 | CONST_BOOLEAN = 1, 197 | CONST_NUMBER = 2, 198 | CONST_STRING = 3 199 | } obj_const_type; 200 | 201 | typedef struct obj_const { 202 | const char *name; /**< constant's name. */ 203 | const char *str; 204 | double num; 205 | obj_const_type type; 206 | } obj_const; 207 | 208 | typedef enum obj_field_type { 209 | TYPE_UNKOWN = 0, 210 | TYPE_UINT8 = 1, 211 | TYPE_UINT16 = 2, 212 | TYPE_UINT32 = 3, 213 | TYPE_UINT64 = 4, 214 | TYPE_INT8 = 5, 215 | TYPE_INT16 = 6, 216 | TYPE_INT32 = 7, 217 | TYPE_INT64 = 8, 218 | TYPE_DOUBLE = 9, 219 | TYPE_FLOAT = 10, 220 | TYPE_STRING = 11 221 | } obj_field_type; 222 | 223 | typedef struct obj_field { 224 | const char *name; /**< field's name. */ 225 | uint32_t offset; /**< offset to field's data. */ 226 | obj_field_type type; /**< field's data type. */ 227 | uint32_t flags; /**< is_writable:1bit */ 228 | } obj_field; 229 | 230 | typedef enum { 231 | REG_OBJECT, 232 | REG_PACKAGE, 233 | REG_META, 234 | } module_reg_type; 235 | 236 | typedef struct reg_impl { 237 | const char *if_name; 238 | const void *impl; 239 | } reg_impl; 240 | 241 | typedef struct reg_sub_module { 242 | obj_type *type; 243 | module_reg_type req_type; 244 | const luaL_Reg *pub_funcs; 245 | const luaL_Reg *methods; 246 | const luaL_Reg *metas; 247 | const obj_base *bases; 248 | const obj_field *fields; 249 | const obj_const *constants; 250 | const reg_impl *implements; 251 | int bidirectional_consts; 252 | } reg_sub_module; 253 | 254 | #define OBJ_UDATA_FLAG_OWN (1<<0) 255 | #define OBJ_UDATA_FLAG_LOOKUP (1<<1) 256 | #define OBJ_UDATA_LAST_FLAG (OBJ_UDATA_FLAG_LOOKUP) 257 | typedef struct obj_udata { 258 | void *obj; 259 | uint32_t flags; /**< lua_own:1bit */ 260 | } obj_udata; 261 | 262 | /* use static pointer as key to weak userdata table. */ 263 | static char obj_udata_weak_ref_key[] = "obj_udata_weak_ref_key"; 264 | 265 | /* use static pointer as key to module's private table. */ 266 | static char obj_udata_private_key[] = "obj_udata_private_key"; 267 | 268 | #if LUAJIT_FFI 269 | typedef int (*ffi_export_func_t)(void); 270 | typedef struct ffi_export_symbol { 271 | const char *name; 272 | union { 273 | void *data; 274 | ffi_export_func_t func; 275 | } sym; 276 | } ffi_export_symbol; 277 | #endif 278 | 279 | 280 | 281 | typedef int errno_rc; 282 | 283 | static void error_code__errno_rc__push(lua_State *L, errno_rc err); 284 | 285 | 286 | static obj_type obj_types[] = { 287 | #define obj_type_id_Errors 0 288 | #define obj_type_Errors (obj_types[obj_type_id_Errors]) 289 | { NULL, 0, OBJ_TYPE_FLAG_WEAK_REF, "Errors" }, 290 | #define obj_type_id_Epoller 1 291 | #define obj_type_Epoller (obj_types[obj_type_id_Epoller]) 292 | { NULL, 1, OBJ_TYPE_FLAG_WEAK_REF, "Epoller" }, 293 | {NULL, -1, 0, NULL}, 294 | }; 295 | 296 | 297 | #if LUAJIT_FFI 298 | 299 | /* nobj_ffi_support_enabled_hint should be set to 1 when FFI support is enabled in at-least one 300 | * instance of a LuaJIT state. It should never be set back to 0. */ 301 | static int nobj_ffi_support_enabled_hint = 0; 302 | static const char nobj_ffi_support_key[] = "LuaNativeObject_FFI_SUPPORT"; 303 | static const char nobj_check_ffi_support_code[] = 304 | "local stat, ffi=pcall(require,\"ffi\")\n" /* try loading LuaJIT`s FFI module. */ 305 | "if not stat then return false end\n" 306 | "return true\n"; 307 | 308 | static int nobj_check_ffi_support(lua_State *L) { 309 | int rc; 310 | int err; 311 | 312 | /* check if ffi test has already been done. */ 313 | lua_pushstring(L, nobj_ffi_support_key); 314 | lua_rawget(L, LUA_REGISTRYINDEX); 315 | if(!lua_isnil(L, -1)) { 316 | rc = lua_toboolean(L, -1); 317 | lua_pop(L, 1); 318 | /* use results of previous check. */ 319 | goto finished; 320 | } 321 | lua_pop(L, 1); /* pop nil. */ 322 | 323 | err = luaL_loadbuffer(L, nobj_check_ffi_support_code, 324 | sizeof(nobj_check_ffi_support_code) - 1, nobj_ffi_support_key); 325 | if(0 == err) { 326 | err = lua_pcall(L, 0, 1, 0); 327 | } 328 | if(err) { 329 | const char *msg = ""; 330 | if(lua_isstring(L, -1)) { 331 | msg = lua_tostring(L, -1); 332 | } 333 | printf("Error when checking for FFI-support: %s\n", msg); 334 | lua_pop(L, 1); /* pop error message. */ 335 | return 0; 336 | } 337 | /* check results of test. */ 338 | rc = lua_toboolean(L, -1); 339 | lua_pop(L, 1); /* pop results. */ 340 | /* cache results. */ 341 | lua_pushstring(L, nobj_ffi_support_key); 342 | lua_pushboolean(L, rc); 343 | lua_rawset(L, LUA_REGISTRYINDEX); 344 | 345 | finished: 346 | /* turn-on hint that there is FFI code enabled. */ 347 | if(rc) { 348 | nobj_ffi_support_enabled_hint = 1; 349 | } 350 | 351 | return rc; 352 | } 353 | 354 | typedef struct { 355 | const char **ffi_init_code; 356 | int offset; 357 | } nobj_reader_state; 358 | 359 | static const char *nobj_lua_Reader(lua_State *L, void *data, size_t *size) { 360 | nobj_reader_state *state = (nobj_reader_state *)data; 361 | const char *ptr; 362 | 363 | (void)L; 364 | ptr = state->ffi_init_code[state->offset]; 365 | if(ptr != NULL) { 366 | *size = strlen(ptr); 367 | state->offset++; 368 | } else { 369 | *size = 0; 370 | } 371 | return ptr; 372 | } 373 | 374 | static int nobj_try_loading_ffi(lua_State *L, const char *ffi_mod_name, 375 | const char *ffi_init_code[], const ffi_export_symbol *ffi_exports, int priv_table) 376 | { 377 | nobj_reader_state state = { ffi_init_code, 0 }; 378 | int err; 379 | 380 | /* export symbols to priv_table. */ 381 | while(ffi_exports->name != NULL) { 382 | lua_pushstring(L, ffi_exports->name); 383 | lua_pushlightuserdata(L, ffi_exports->sym.data); 384 | lua_settable(L, priv_table); 385 | ffi_exports++; 386 | } 387 | err = lua_load_no_mode(L, nobj_lua_Reader, &state, ffi_mod_name); 388 | if(0 == err) { 389 | lua_pushvalue(L, -2); /* dup C module's table. */ 390 | lua_pushvalue(L, priv_table); /* move priv_table to top of stack. */ 391 | lua_remove(L, priv_table); 392 | lua_pushvalue(L, LUA_REGISTRYINDEX); 393 | err = lua_pcall(L, 3, 0, 0); 394 | } 395 | if(err) { 396 | const char *msg = ""; 397 | if(lua_isstring(L, -1)) { 398 | msg = lua_tostring(L, -1); 399 | } 400 | printf("Failed to install FFI-based bindings: %s\n", msg); 401 | lua_pop(L, 1); /* pop error message. */ 402 | } 403 | return err; 404 | } 405 | #endif 406 | 407 | 408 | typedef struct { 409 | void *impl; 410 | void *obj; 411 | } obj_implement; 412 | 413 | static FUNC_UNUSED void *obj_implement_luaoptional(lua_State *L, int _index, void **impl, char *if_name) { 414 | void *ud; 415 | if(lua_isnoneornil(L, _index)) { 416 | return NULL; 417 | } 418 | /* get the implements table for this interface. */ 419 | lua_pushlightuserdata(L, if_name); 420 | lua_rawget(L, LUA_REGISTRYINDEX); 421 | 422 | /* get pointer to userdata value & check if it is a userdata value. */ 423 | ud = (obj_implement *)lua_touserdata(L, _index); 424 | if(ud != NULL) { 425 | /* get the userdata's metatable */ 426 | if(lua_getmetatable(L, _index)) { 427 | /* lookup metatable in interface table for this object's implementation of the interface. */ 428 | lua_gettable(L, -2); 429 | } else { 430 | /* no metatable. */ 431 | goto no_interface; 432 | } 433 | #if LUAJIT_FFI 434 | } else if(nobj_ffi_support_enabled_hint) { /* handle cdata. */ 435 | /* get cdata interface check function from interface table. */ 436 | lua_getfield(L, -1, "cdata"); 437 | if(lua_isfunction(L, -1)) { 438 | /* pass cdata to function, return value should be an implmentation. */ 439 | lua_pushvalue(L, _index); 440 | lua_call(L, 1, 1); 441 | /* get pointer to cdata. */ 442 | ud = (void *)lua_topointer(L, _index); 443 | } else { 444 | lua_pop(L, 1); /* pop non-function. */ 445 | goto no_interface; 446 | } 447 | #endif 448 | } else { 449 | goto no_interface; 450 | } 451 | 452 | if(!lua_isnil(L, -1)) { 453 | *impl = lua_touserdata(L, -1); 454 | lua_pop(L, 2); /* pop interface table & implementation. */ 455 | /* object implements interface. */ 456 | return ud; 457 | } else { 458 | lua_pop(L, 1); /* pop nil. */ 459 | } 460 | no_interface: 461 | lua_pop(L, 1); /* pop interface table. */ 462 | return NULL; 463 | } 464 | 465 | static FUNC_UNUSED void *obj_implement_luacheck(lua_State *L, int _index, void **impl, char *type) { 466 | void *ud = obj_implement_luaoptional(L, _index, impl, type); 467 | if(ud == NULL) { 468 | #define ERROR_BUFFER_SIZE 256 469 | char buf[ERROR_BUFFER_SIZE]; 470 | snprintf(buf, ERROR_BUFFER_SIZE-1,"Expected object with %s interface", type); 471 | /* value doesn't implement this interface. */ 472 | luaL_argerror(L, _index, buf); 473 | } 474 | return ud; 475 | } 476 | 477 | /* use static pointer as key to interfaces table. (version 1.0) */ 478 | static char obj_interfaces_table_key[] = "obj_interfaces<1.0>_table_key"; 479 | 480 | static void obj_get_global_interfaces_table(lua_State *L) { 481 | /* get global interfaces table. */ 482 | lua_getfield(L, LUA_REGISTRYINDEX, obj_interfaces_table_key); 483 | if(lua_isnil(L, -1)) { 484 | /* Need to create global interfaces table. */ 485 | lua_pop(L, 1); /* pop nil */ 486 | lua_createtable(L, 0, 4); /* 0 size array part, small hash part. */ 487 | lua_pushvalue(L, -1); /* dup table. */ 488 | /* store interfaces table in Lua registery. */ 489 | lua_setfield(L, LUA_REGISTRYINDEX, obj_interfaces_table_key); 490 | } 491 | } 492 | 493 | static void obj_get_interface(lua_State *L, const char *name, int global_if_tab) { 494 | /* get a interface's implementation table */ 495 | lua_getfield(L, global_if_tab, name); 496 | if(lua_isnil(L, -1)) { 497 | lua_pop(L, 1); /* pop nil */ 498 | /* new interface. (i.e. no object implement it yet.) 499 | * 500 | * create an empty table for this interface that will be used when an 501 | * implementation is registered for this interface. 502 | */ 503 | lua_createtable(L, 0, 2); /* 0 size array part, small hash part. */ 504 | lua_pushvalue(L, -1); /* dup table. */ 505 | lua_setfield(L, global_if_tab, name); /* store interface in global interfaces table. */ 506 | } 507 | } 508 | 509 | static int obj_get_userdata_interface(lua_State *L) { 510 | /* get the userdata's metatable */ 511 | if(lua_getmetatable(L, 2)) { 512 | /* lookup metatable in interface table for the userdata's implementation of the interface. */ 513 | lua_gettable(L, 1); 514 | if(!lua_isnil(L, -1)) { 515 | /* return the implementation. */ 516 | return 1; 517 | } 518 | } 519 | /* no metatable or no implementation. */ 520 | return 0; 521 | } 522 | 523 | static void obj_interface_register(lua_State *L, char *name, int global_if_tab) { 524 | /* get the table of implementations for this interface. */ 525 | obj_get_interface(L, name, global_if_tab); 526 | 527 | /* check for 'userdata' function. */ 528 | lua_getfield(L, -1, "userdata"); 529 | if(lua_isnil(L, -1)) { 530 | lua_pop(L, 1); /* pop nil. */ 531 | /* add C function for getting a userdata's implementation. */ 532 | lua_pushcfunction(L, obj_get_userdata_interface); 533 | lua_setfield(L, -2, "userdata"); 534 | } else { 535 | /* already have function. */ 536 | lua_pop(L, 1); /* pop C function. */ 537 | } 538 | /* we are going to use a lightuserdata pointer for fast lookup of the interface's impl. table. */ 539 | lua_pushlightuserdata(L, name); 540 | lua_insert(L, -2); 541 | lua_settable(L, LUA_REGISTRYINDEX); 542 | } 543 | 544 | static void obj_register_interfaces(lua_State *L, char *interfaces[]) { 545 | int i; 546 | int if_tab; 547 | /* get global interfaces table. */ 548 | obj_get_global_interfaces_table(L); 549 | if_tab = lua_gettop(L); 550 | 551 | for(i = 0; interfaces[i] != NULL ; i++) { 552 | obj_interface_register(L, interfaces[i], if_tab); 553 | } 554 | lua_pop(L, 1); /* pop global interfaces table. */ 555 | } 556 | 557 | static void obj_type_register_implement(lua_State *L, const reg_impl *impl, int global_if_tab, int mt_tab) { 558 | /* get the table of implementations for this interface. */ 559 | obj_get_interface(L, impl->if_name, global_if_tab); 560 | 561 | /* register object's implement in the interface table. */ 562 | lua_pushvalue(L, mt_tab); 563 | lua_pushlightuserdata(L, (void *)impl->impl); 564 | lua_settable(L, -3); 565 | 566 | lua_pop(L, 1); /* pop inteface table. */ 567 | } 568 | 569 | static void obj_type_register_implements(lua_State *L, const reg_impl *impls) { 570 | int if_tab; 571 | int mt_tab; 572 | /* get absolute position of object's metatable. */ 573 | mt_tab = lua_gettop(L); 574 | /* get global interfaces table. */ 575 | obj_get_global_interfaces_table(L); 576 | if_tab = lua_gettop(L); 577 | 578 | for(; impls->if_name != NULL ; impls++) { 579 | obj_type_register_implement(L, impls, if_tab, mt_tab); 580 | } 581 | lua_pop(L, 1); /* pop global interfaces table. */ 582 | } 583 | 584 | #ifndef REG_PACKAGE_IS_CONSTRUCTOR 585 | #define REG_PACKAGE_IS_CONSTRUCTOR 1 586 | #endif 587 | 588 | #ifndef REG_MODULES_AS_GLOBALS 589 | #define REG_MODULES_AS_GLOBALS 0 590 | #endif 591 | 592 | /* For Lua 5.2 don't register modules as globals. */ 593 | #if LUA_VERSION_NUM == 502 594 | #undef REG_MODULES_AS_GLOBALS 595 | #define REG_MODULES_AS_GLOBALS 0 596 | #endif 597 | 598 | #ifndef REG_OBJECTS_AS_GLOBALS 599 | #define REG_OBJECTS_AS_GLOBALS 0 600 | #endif 601 | 602 | #ifndef OBJ_DATA_HIDDEN_METATABLE 603 | #define OBJ_DATA_HIDDEN_METATABLE 1 604 | #endif 605 | 606 | static FUNC_UNUSED int obj_import_external_type(lua_State *L, obj_type *type) { 607 | /* find the external type's metatable using it's name. */ 608 | lua_pushstring(L, type->name); 609 | lua_rawget(L, LUA_REGISTRYINDEX); /* external type's metatable. */ 610 | if(!lua_isnil(L, -1)) { 611 | /* found it. Now we will map our 'type' pointer to the metatable. */ 612 | /* REGISTERY[lightuserdata] = REGISTERY[type->name] */ 613 | lua_pushlightuserdata(L, type); /* use our 'type' pointer as lookup key. */ 614 | lua_pushvalue(L, -2); /* dup. type's metatable. */ 615 | lua_rawset(L, LUA_REGISTRYINDEX); /* save external type's metatable. */ 616 | /* NOTE: top of Lua stack still has the type's metatable. */ 617 | return 1; 618 | } else { 619 | lua_pop(L, 1); /* pop nil. */ 620 | } 621 | return 0; 622 | } 623 | 624 | static FUNC_UNUSED int obj_import_external_ffi_type(lua_State *L, obj_type *type) { 625 | /* find the external type's metatable using it's name. */ 626 | lua_pushstring(L, type->name); 627 | lua_rawget(L, LUA_REGISTRYINDEX); /* external type's metatable. */ 628 | if(!lua_isnil(L, -1)) { 629 | /* found it. Now we will map our 'type' pointer to the C check function. */ 630 | /* _priv_table[lightuserdata] = REGISTERY[type->name].c_check */ 631 | lua_getfield(L, -1, "c_check"); 632 | lua_remove(L, -2); /* remove metatable. */ 633 | if(lua_isfunction(L, -1)) { 634 | lua_pushlightuserdata(L, type); /* use our 'type' pointer as lookup key. */ 635 | lua_pushvalue(L, -2); /* dup. check function */ 636 | lua_rawset(L, -4); /* save check function to module's private table. */ 637 | /* NOTE: top of Lua stack still has the type's C check function. */ 638 | return 1; 639 | } else { 640 | lua_pop(L, 1); /* pop non function value. */ 641 | } 642 | } else { 643 | lua_pop(L, 1); /* pop nil. */ 644 | } 645 | return 0; 646 | } 647 | 648 | static FUNC_UNUSED obj_udata *obj_udata_toobj(lua_State *L, int _index) { 649 | obj_udata *ud; 650 | size_t len; 651 | 652 | /* make sure it's a userdata value. */ 653 | ud = (obj_udata *)lua_touserdata(L, _index); 654 | if(ud == NULL) { 655 | luaL_typerror(L, _index, "userdata"); /* is not a userdata value. */ 656 | } 657 | /* verify userdata size. */ 658 | len = lua_rawlen(L, _index); 659 | if(len != sizeof(obj_udata)) { 660 | /* This shouldn't be possible */ 661 | luaL_error(L, "invalid userdata size: size=%d, expected=%d", len, sizeof(obj_udata)); 662 | } 663 | return ud; 664 | } 665 | 666 | static FUNC_UNUSED int obj_udata_is_compatible(lua_State *L, obj_udata *ud, void **obj, base_caster_t *caster, obj_type *type) { 667 | obj_base *base; 668 | obj_type *ud_type; 669 | lua_pushlightuserdata(L, type); 670 | lua_rawget(L, LUA_REGISTRYINDEX); /* type's metatable. */ 671 | recheck_metatable: 672 | if(lua_rawequal(L, -1, -2)) { 673 | *obj = ud->obj; 674 | /* same type no casting needed. */ 675 | return 1; 676 | } else if(lua_isnil(L, -1)) { 677 | lua_pop(L, 1); /* pop nil. */ 678 | if((type->flags & OBJ_TYPE_IMPORT) == 0) { 679 | /* can't resolve internal type. */ 680 | luaL_error(L, "Unknown object type(id=%d, name=%s)", type->id, type->name); 681 | } 682 | /* try to import external type. */ 683 | if(obj_import_external_type(L, type)) { 684 | /* imported type, re-try metatable check. */ 685 | goto recheck_metatable; 686 | } 687 | /* External type not yet available, so the object can't be compatible. */ 688 | } else { 689 | /* Different types see if we can cast to the required type. */ 690 | lua_rawgeti(L, -2, type->id); 691 | base = lua_touserdata(L, -1); 692 | lua_pop(L, 1); /* pop obj_base or nil */ 693 | if(base != NULL) { 694 | *caster = base->bcaster; 695 | /* get the obj_type for this userdata. */ 696 | lua_pushliteral(L, ".type"); 697 | lua_rawget(L, -3); /* type's metatable. */ 698 | ud_type = lua_touserdata(L, -1); 699 | lua_pop(L, 1); /* pop obj_type or nil */ 700 | if(base == NULL) { 701 | luaL_error(L, "bad userdata, missing type info."); 702 | return 0; 703 | } 704 | /* check if userdata is a simple object. */ 705 | if(ud_type->flags & OBJ_TYPE_SIMPLE) { 706 | *obj = ud; 707 | } else { 708 | *obj = ud->obj; 709 | } 710 | return 1; 711 | } 712 | } 713 | return 0; 714 | } 715 | 716 | static FUNC_UNUSED obj_udata *obj_udata_luacheck_internal(lua_State *L, int _index, void **obj, obj_type *type, int not_delete) { 717 | obj_udata *ud; 718 | base_caster_t caster = NULL; 719 | /* make sure it's a userdata value. */ 720 | ud = (obj_udata *)lua_touserdata(L, _index); 721 | if(ud != NULL) { 722 | /* check object type by comparing metatables. */ 723 | if(lua_getmetatable(L, _index)) { 724 | if(obj_udata_is_compatible(L, ud, obj, &(caster), type)) { 725 | lua_pop(L, 2); /* pop both metatables. */ 726 | /* apply caster function if needed. */ 727 | if(caster != NULL && *obj != NULL) { 728 | caster(obj); 729 | } 730 | /* check object pointer. */ 731 | if(*obj == NULL) { 732 | if(not_delete) { 733 | luaL_error(L, "null %s", type->name); /* object was garbage collected? */ 734 | } 735 | return NULL; 736 | } 737 | return ud; 738 | } 739 | } 740 | } else if(!lua_isnoneornil(L, _index)) { 741 | /* handle cdata. */ 742 | /* get private table. */ 743 | lua_pushlightuserdata(L, obj_udata_private_key); 744 | lua_rawget(L, LUA_REGISTRYINDEX); /* private table. */ 745 | /* get cdata type check function from private table. */ 746 | lua_pushlightuserdata(L, type); 747 | lua_rawget(L, -2); 748 | 749 | /* check for function. */ 750 | if(!lua_isnil(L, -1)) { 751 | got_check_func: 752 | /* pass cdata value to type checking function. */ 753 | lua_pushvalue(L, _index); 754 | lua_call(L, 1, 1); 755 | if(!lua_isnil(L, -1)) { 756 | /* valid type get pointer from cdata. */ 757 | lua_pop(L, 2); 758 | *obj = *(void **)lua_topointer(L, _index); 759 | return ud; 760 | } 761 | lua_pop(L, 2); 762 | } else { 763 | lua_pop(L, 1); /* pop nil. */ 764 | if(type->flags & OBJ_TYPE_IMPORT) { 765 | /* try to import external ffi type. */ 766 | if(obj_import_external_ffi_type(L, type)) { 767 | /* imported type. */ 768 | goto got_check_func; 769 | } 770 | /* External type not yet available, so the object can't be compatible. */ 771 | } 772 | } 773 | } 774 | if(not_delete) { 775 | luaL_typerror(L, _index, type->name); /* is not a userdata value. */ 776 | } 777 | return NULL; 778 | } 779 | 780 | static FUNC_UNUSED void *obj_udata_luacheck(lua_State *L, int _index, obj_type *type) { 781 | void *obj = NULL; 782 | obj_udata_luacheck_internal(L, _index, &(obj), type, 1); 783 | return obj; 784 | } 785 | 786 | static FUNC_UNUSED void *obj_udata_luaoptional(lua_State *L, int _index, obj_type *type) { 787 | void *obj = NULL; 788 | if(lua_isnoneornil(L, _index)) { 789 | return obj; 790 | } 791 | obj_udata_luacheck_internal(L, _index, &(obj), type, 1); 792 | return obj; 793 | } 794 | 795 | static FUNC_UNUSED void *obj_udata_luadelete(lua_State *L, int _index, obj_type *type, int *flags) { 796 | void *obj; 797 | obj_udata *ud = obj_udata_luacheck_internal(L, _index, &(obj), type, 0); 798 | if(ud == NULL) return NULL; 799 | *flags = ud->flags; 800 | /* null userdata. */ 801 | ud->obj = NULL; 802 | ud->flags = 0; 803 | /* clear the metatable in invalidate userdata. */ 804 | lua_pushnil(L); 805 | lua_setmetatable(L, _index); 806 | return obj; 807 | } 808 | 809 | static FUNC_UNUSED void obj_udata_luapush(lua_State *L, void *obj, obj_type *type, int flags) { 810 | obj_udata *ud; 811 | /* convert NULL's into Lua nil's. */ 812 | if(obj == NULL) { 813 | lua_pushnil(L); 814 | return; 815 | } 816 | #if LUAJIT_FFI 817 | lua_pushlightuserdata(L, type); 818 | lua_rawget(L, LUA_REGISTRYINDEX); /* type's metatable. */ 819 | if(nobj_ffi_support_enabled_hint && lua_isfunction(L, -1)) { 820 | /* call special FFI "void *" to FFI object convertion function. */ 821 | lua_pushlightuserdata(L, obj); 822 | lua_pushinteger(L, flags); 823 | lua_call(L, 2, 1); 824 | return; 825 | } 826 | #endif 827 | /* check for type caster. */ 828 | if(type->dcaster) { 829 | (type->dcaster)(&obj, &type); 830 | } 831 | /* create new userdata. */ 832 | ud = (obj_udata *)lua_newuserdata(L, sizeof(obj_udata)); 833 | ud->obj = obj; 834 | ud->flags = flags; 835 | /* get obj_type metatable. */ 836 | #if LUAJIT_FFI 837 | lua_insert(L, -2); /* move userdata below metatable. */ 838 | #else 839 | lua_pushlightuserdata(L, type); 840 | lua_rawget(L, LUA_REGISTRYINDEX); /* type's metatable. */ 841 | #endif 842 | lua_setmetatable(L, -2); 843 | } 844 | 845 | static FUNC_UNUSED void *obj_udata_luadelete_weak(lua_State *L, int _index, obj_type *type, int *flags) { 846 | void *obj; 847 | obj_udata *ud = obj_udata_luacheck_internal(L, _index, &(obj), type, 0); 848 | if(ud == NULL) return NULL; 849 | *flags = ud->flags; 850 | /* null userdata. */ 851 | ud->obj = NULL; 852 | ud->flags = 0; 853 | /* clear the metatable in invalidate userdata. */ 854 | lua_pushnil(L); 855 | lua_setmetatable(L, _index); 856 | /* get objects weak table. */ 857 | lua_pushlightuserdata(L, obj_udata_weak_ref_key); 858 | lua_rawget(L, LUA_REGISTRYINDEX); /* weak ref table. */ 859 | /* remove object from weak table. */ 860 | lua_pushlightuserdata(L, obj); 861 | lua_pushnil(L); 862 | lua_rawset(L, -3); 863 | return obj; 864 | } 865 | 866 | static FUNC_UNUSED void obj_udata_luapush_weak(lua_State *L, void *obj, obj_type *type, int flags) { 867 | obj_udata *ud; 868 | 869 | /* convert NULL's into Lua nil's. */ 870 | if(obj == NULL) { 871 | lua_pushnil(L); 872 | return; 873 | } 874 | /* check for type caster. */ 875 | if(type->dcaster) { 876 | (type->dcaster)(&obj, &type); 877 | } 878 | /* get objects weak table. */ 879 | lua_pushlightuserdata(L, obj_udata_weak_ref_key); 880 | lua_rawget(L, LUA_REGISTRYINDEX); /* weak ref table. */ 881 | /* lookup userdata instance from pointer. */ 882 | lua_pushlightuserdata(L, obj); 883 | lua_rawget(L, -2); 884 | if(!lua_isnil(L, -1)) { 885 | lua_remove(L, -2); /* remove objects table. */ 886 | return; 887 | } 888 | lua_pop(L, 1); /* pop nil. */ 889 | 890 | #if LUAJIT_FFI 891 | lua_pushlightuserdata(L, type); 892 | lua_rawget(L, LUA_REGISTRYINDEX); /* type's metatable. */ 893 | if(nobj_ffi_support_enabled_hint && lua_isfunction(L, -1)) { 894 | lua_remove(L, -2); 895 | /* call special FFI "void *" to FFI object convertion function. */ 896 | lua_pushlightuserdata(L, obj); 897 | lua_pushinteger(L, flags); 898 | lua_call(L, 2, 1); 899 | return; 900 | } 901 | #endif 902 | /* create new userdata. */ 903 | ud = (obj_udata *)lua_newuserdata(L, sizeof(obj_udata)); 904 | 905 | /* init. obj_udata. */ 906 | ud->obj = obj; 907 | ud->flags = flags; 908 | /* get obj_type metatable. */ 909 | #if LUAJIT_FFI 910 | lua_insert(L, -2); /* move userdata below metatable. */ 911 | #else 912 | lua_pushlightuserdata(L, type); 913 | lua_rawget(L, LUA_REGISTRYINDEX); /* type's metatable. */ 914 | #endif 915 | lua_setmetatable(L, -2); 916 | 917 | /* add weak reference to object. */ 918 | lua_pushlightuserdata(L, obj); /* push object pointer as the 'key' */ 919 | lua_pushvalue(L, -2); /* push object's udata */ 920 | lua_rawset(L, -4); /* add weak reference to object. */ 921 | lua_remove(L, -2); /* remove objects table. */ 922 | } 923 | 924 | /* default object equal method. */ 925 | static FUNC_UNUSED int obj_udata_default_equal(lua_State *L) { 926 | obj_udata *ud1 = obj_udata_toobj(L, 1); 927 | obj_udata *ud2 = obj_udata_toobj(L, 2); 928 | 929 | lua_pushboolean(L, (ud1->obj == ud2->obj)); 930 | return 1; 931 | } 932 | 933 | /* default object tostring method. */ 934 | static FUNC_UNUSED int obj_udata_default_tostring(lua_State *L) { 935 | obj_udata *ud = obj_udata_toobj(L, 1); 936 | 937 | /* get object's metatable. */ 938 | lua_getmetatable(L, 1); 939 | lua_remove(L, 1); /* remove userdata. */ 940 | /* get the object's name from the metatable */ 941 | lua_getfield(L, 1, ".name"); 942 | lua_remove(L, 1); /* remove metatable */ 943 | /* push object's pointer */ 944 | lua_pushfstring(L, ": %p, flags=%d", ud->obj, ud->flags); 945 | lua_concat(L, 2); 946 | 947 | return 1; 948 | } 949 | 950 | /* 951 | * Simple userdata objects. 952 | */ 953 | static FUNC_UNUSED void *obj_simple_udata_toobj(lua_State *L, int _index) { 954 | void *ud; 955 | 956 | /* make sure it's a userdata value. */ 957 | ud = lua_touserdata(L, _index); 958 | if(ud == NULL) { 959 | luaL_typerror(L, _index, "userdata"); /* is not a userdata value. */ 960 | } 961 | return ud; 962 | } 963 | 964 | static FUNC_UNUSED void * obj_simple_udata_luacheck(lua_State *L, int _index, obj_type *type) { 965 | void *ud; 966 | /* make sure it's a userdata value. */ 967 | ud = lua_touserdata(L, _index); 968 | if(ud != NULL) { 969 | /* check object type by comparing metatables. */ 970 | if(lua_getmetatable(L, _index)) { 971 | lua_pushlightuserdata(L, type); 972 | lua_rawget(L, LUA_REGISTRYINDEX); /* type's metatable. */ 973 | recheck_metatable: 974 | if(lua_rawequal(L, -1, -2)) { 975 | lua_pop(L, 2); /* pop both metatables. */ 976 | return ud; 977 | } else if(lua_isnil(L, -1)) { 978 | lua_pop(L, 1); /* pop nil. */ 979 | if((type->flags & OBJ_TYPE_IMPORT) == 0) { 980 | /* can't resolve internal type. */ 981 | luaL_error(L, "Unknown object type(id=%d, name=%s)", type->id, type->name); 982 | } 983 | /* try to import external type. */ 984 | if(obj_import_external_type(L, type)) { 985 | /* imported type, re-try metatable check. */ 986 | goto recheck_metatable; 987 | } 988 | /* External type not yet available, so the object can't be compatible. */ 989 | return 0; 990 | } 991 | } 992 | } else if(!lua_isnoneornil(L, _index)) { 993 | /* handle cdata. */ 994 | /* get private table. */ 995 | lua_pushlightuserdata(L, obj_udata_private_key); 996 | lua_rawget(L, LUA_REGISTRYINDEX); /* private table. */ 997 | /* get cdata type check function from private table. */ 998 | lua_pushlightuserdata(L, type); 999 | lua_rawget(L, -2); 1000 | 1001 | /* check for function. */ 1002 | if(!lua_isnil(L, -1)) { 1003 | got_check_func: 1004 | /* pass cdata value to type checking function. */ 1005 | lua_pushvalue(L, _index); 1006 | lua_call(L, 1, 1); 1007 | if(!lua_isnil(L, -1)) { 1008 | /* valid type get pointer from cdata. */ 1009 | lua_pop(L, 2); 1010 | return (void *)lua_topointer(L, _index); 1011 | } 1012 | } else { 1013 | if(type->flags & OBJ_TYPE_IMPORT) { 1014 | /* try to import external ffi type. */ 1015 | if(obj_import_external_ffi_type(L, type)) { 1016 | /* imported type. */ 1017 | goto got_check_func; 1018 | } 1019 | /* External type not yet available, so the object can't be compatible. */ 1020 | } 1021 | } 1022 | } 1023 | luaL_typerror(L, _index, type->name); /* is not a userdata value. */ 1024 | return NULL; 1025 | } 1026 | 1027 | static FUNC_UNUSED void * obj_simple_udata_luaoptional(lua_State *L, int _index, obj_type *type) { 1028 | if(lua_isnoneornil(L, _index)) { 1029 | return NULL; 1030 | } 1031 | return obj_simple_udata_luacheck(L, _index, type); 1032 | } 1033 | 1034 | static FUNC_UNUSED void * obj_simple_udata_luadelete(lua_State *L, int _index, obj_type *type) { 1035 | void *obj; 1036 | obj = obj_simple_udata_luacheck(L, _index, type); 1037 | /* clear the metatable to invalidate userdata. */ 1038 | lua_pushnil(L); 1039 | lua_setmetatable(L, _index); 1040 | return obj; 1041 | } 1042 | 1043 | static FUNC_UNUSED void *obj_simple_udata_luapush(lua_State *L, void *obj, int size, obj_type *type) 1044 | { 1045 | void *ud; 1046 | #if LUAJIT_FFI 1047 | lua_pushlightuserdata(L, type); 1048 | lua_rawget(L, LUA_REGISTRYINDEX); /* type's metatable. */ 1049 | if(nobj_ffi_support_enabled_hint && lua_isfunction(L, -1)) { 1050 | /* call special FFI "void *" to FFI object convertion function. */ 1051 | lua_pushlightuserdata(L, obj); 1052 | lua_call(L, 1, 1); 1053 | return obj; 1054 | } 1055 | #endif 1056 | /* create new userdata. */ 1057 | ud = lua_newuserdata(L, size); 1058 | memcpy(ud, obj, size); 1059 | /* get obj_type metatable. */ 1060 | #if LUAJIT_FFI 1061 | lua_insert(L, -2); /* move userdata below metatable. */ 1062 | #else 1063 | lua_pushlightuserdata(L, type); 1064 | lua_rawget(L, LUA_REGISTRYINDEX); /* type's metatable. */ 1065 | #endif 1066 | lua_setmetatable(L, -2); 1067 | 1068 | return ud; 1069 | } 1070 | 1071 | /* default simple object equal method. */ 1072 | static FUNC_UNUSED int obj_simple_udata_default_equal(lua_State *L) { 1073 | void *ud1 = obj_simple_udata_toobj(L, 1); 1074 | size_t len1 = lua_rawlen(L, 1); 1075 | void *ud2 = obj_simple_udata_toobj(L, 2); 1076 | size_t len2 = lua_rawlen(L, 2); 1077 | 1078 | if(len1 == len2) { 1079 | lua_pushboolean(L, (memcmp(ud1, ud2, len1) == 0)); 1080 | } else { 1081 | lua_pushboolean(L, 0); 1082 | } 1083 | return 1; 1084 | } 1085 | 1086 | /* default simple object tostring method. */ 1087 | static FUNC_UNUSED int obj_simple_udata_default_tostring(lua_State *L) { 1088 | void *ud = obj_simple_udata_toobj(L, 1); 1089 | 1090 | /* get object's metatable. */ 1091 | lua_getmetatable(L, 1); 1092 | lua_remove(L, 1); /* remove userdata. */ 1093 | /* get the object's name from the metatable */ 1094 | lua_getfield(L, 1, ".name"); 1095 | lua_remove(L, 1); /* remove metatable */ 1096 | /* push object's pointer */ 1097 | lua_pushfstring(L, ": %p", ud); 1098 | lua_concat(L, 2); 1099 | 1100 | return 1; 1101 | } 1102 | 1103 | static int obj_constructor_call_wrapper(lua_State *L) { 1104 | /* replace '__call' table with constructor function. */ 1105 | lua_pushvalue(L, lua_upvalueindex(1)); 1106 | lua_replace(L, 1); 1107 | 1108 | /* call constructor function with all parameters after the '__call' table. */ 1109 | lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); 1110 | /* return all results from constructor. */ 1111 | return lua_gettop(L); 1112 | } 1113 | 1114 | static void obj_type_register_constants(lua_State *L, const obj_const *constants, int tab_idx, 1115 | int bidirectional) { 1116 | /* register constants. */ 1117 | while(constants->name != NULL) { 1118 | lua_pushstring(L, constants->name); 1119 | switch(constants->type) { 1120 | case CONST_BOOLEAN: 1121 | lua_pushboolean(L, constants->num != 0.0); 1122 | break; 1123 | case CONST_NUMBER: 1124 | lua_pushnumber(L, constants->num); 1125 | break; 1126 | case CONST_STRING: 1127 | lua_pushstring(L, constants->str); 1128 | break; 1129 | default: 1130 | lua_pushnil(L); 1131 | break; 1132 | } 1133 | /* map values back to keys. */ 1134 | if(bidirectional) { 1135 | /* check if value already exists. */ 1136 | lua_pushvalue(L, -1); 1137 | lua_rawget(L, tab_idx - 3); 1138 | if(lua_isnil(L, -1)) { 1139 | lua_pop(L, 1); 1140 | /* add value->key mapping. */ 1141 | lua_pushvalue(L, -1); 1142 | lua_pushvalue(L, -3); 1143 | lua_rawset(L, tab_idx - 4); 1144 | } else { 1145 | /* value already exists. */ 1146 | lua_pop(L, 1); 1147 | } 1148 | } 1149 | lua_rawset(L, tab_idx - 2); 1150 | constants++; 1151 | } 1152 | } 1153 | 1154 | static void obj_type_register_package(lua_State *L, const reg_sub_module *type_reg) { 1155 | const luaL_Reg *reg_list = type_reg->pub_funcs; 1156 | 1157 | /* create public functions table. */ 1158 | if(reg_list != NULL && reg_list[0].name != NULL) { 1159 | /* register functions */ 1160 | nobj_setfuncs(L, reg_list, 0); 1161 | } 1162 | 1163 | obj_type_register_constants(L, type_reg->constants, -1, type_reg->bidirectional_consts); 1164 | 1165 | lua_pop(L, 1); /* drop package table */ 1166 | } 1167 | 1168 | static void obj_type_register_meta(lua_State *L, const reg_sub_module *type_reg) { 1169 | const luaL_Reg *reg_list; 1170 | 1171 | /* create public functions table. */ 1172 | reg_list = type_reg->pub_funcs; 1173 | if(reg_list != NULL && reg_list[0].name != NULL) { 1174 | /* register functions */ 1175 | nobj_setfuncs(L, reg_list, 0); 1176 | } 1177 | 1178 | obj_type_register_constants(L, type_reg->constants, -1, type_reg->bidirectional_consts); 1179 | 1180 | /* register methods. */ 1181 | nobj_setfuncs(L, type_reg->methods, 0); 1182 | 1183 | /* create metatable table. */ 1184 | lua_newtable(L); 1185 | nobj_setfuncs(L, type_reg->metas, 0); /* fill metatable */ 1186 | /* setmetatable on meta-object. */ 1187 | lua_setmetatable(L, -2); 1188 | 1189 | lua_pop(L, 1); /* drop meta-object */ 1190 | } 1191 | 1192 | static void obj_type_register(lua_State *L, const reg_sub_module *type_reg, int priv_table) { 1193 | const luaL_Reg *reg_list; 1194 | obj_type *type = type_reg->type; 1195 | const obj_base *base = type_reg->bases; 1196 | 1197 | if(type_reg->req_type == REG_PACKAGE) { 1198 | obj_type_register_package(L, type_reg); 1199 | return; 1200 | } 1201 | if(type_reg->req_type == REG_META) { 1202 | obj_type_register_meta(L, type_reg); 1203 | return; 1204 | } 1205 | 1206 | /* create public functions table. */ 1207 | reg_list = type_reg->pub_funcs; 1208 | if(reg_list != NULL && reg_list[0].name != NULL) { 1209 | /* register "constructors" as to object's public API */ 1210 | nobj_setfuncs(L, reg_list, 0); /* fill public API table. */ 1211 | 1212 | /* make public API table callable as the default constructor. */ 1213 | lua_newtable(L); /* create metatable */ 1214 | lua_pushliteral(L, "__call"); 1215 | lua_pushcfunction(L, reg_list[0].func); /* push first constructor function. */ 1216 | lua_pushcclosure(L, obj_constructor_call_wrapper, 1); /* make __call wrapper. */ 1217 | lua_rawset(L, -3); /* metatable.__call = */ 1218 | 1219 | #if OBJ_DATA_HIDDEN_METATABLE 1220 | lua_pushliteral(L, "__metatable"); 1221 | lua_pushboolean(L, 0); 1222 | lua_rawset(L, -3); /* metatable.__metatable = false */ 1223 | #endif 1224 | 1225 | /* setmetatable on public API table. */ 1226 | lua_setmetatable(L, -2); 1227 | 1228 | lua_pop(L, 1); /* pop public API table, don't need it any more. */ 1229 | /* create methods table. */ 1230 | lua_newtable(L); 1231 | } else { 1232 | /* register all methods as public functions. */ 1233 | #if OBJ_DATA_HIDDEN_METATABLE 1234 | lua_pop(L, 1); /* pop public API table, don't need it any more. */ 1235 | /* create methods table. */ 1236 | lua_newtable(L); 1237 | #endif 1238 | } 1239 | 1240 | nobj_setfuncs(L, type_reg->methods, 0); /* fill methods table. */ 1241 | 1242 | luaL_newmetatable(L, type->name); /* create metatable */ 1243 | lua_pushliteral(L, ".name"); 1244 | lua_pushstring(L, type->name); 1245 | lua_rawset(L, -3); /* metatable['.name'] = "" */ 1246 | lua_pushliteral(L, ".type"); 1247 | lua_pushlightuserdata(L, type); 1248 | lua_rawset(L, -3); /* metatable['.type'] = lightuserdata -> obj_type */ 1249 | lua_pushlightuserdata(L, type); 1250 | lua_pushvalue(L, -2); /* dup metatable. */ 1251 | lua_rawset(L, LUA_REGISTRYINDEX); /* REGISTRY[type] = metatable */ 1252 | 1253 | /* add metatable to 'priv_table' */ 1254 | lua_pushstring(L, type->name); 1255 | lua_pushvalue(L, -2); /* dup metatable. */ 1256 | lua_rawset(L, priv_table); /* priv_table[""] = metatable */ 1257 | 1258 | nobj_setfuncs(L, type_reg->metas, 0); /* fill metatable */ 1259 | 1260 | /* add obj_bases to metatable. */ 1261 | while(base->id >= 0) { 1262 | lua_pushlightuserdata(L, (void *)base); 1263 | lua_rawseti(L, -2, base->id); 1264 | base++; 1265 | } 1266 | 1267 | obj_type_register_constants(L, type_reg->constants, -2, type_reg->bidirectional_consts); 1268 | 1269 | obj_type_register_implements(L, type_reg->implements); 1270 | 1271 | lua_pushliteral(L, "__index"); 1272 | lua_pushvalue(L, -3); /* dup methods table */ 1273 | lua_rawset(L, -3); /* metatable.__index = methods */ 1274 | #if OBJ_DATA_HIDDEN_METATABLE 1275 | lua_pushliteral(L, "__metatable"); 1276 | lua_pushboolean(L, 0); 1277 | lua_rawset(L, -3); /* hide metatable: 1278 | metatable.__metatable = false */ 1279 | #endif 1280 | lua_pop(L, 2); /* drop metatable & methods */ 1281 | } 1282 | 1283 | static FUNC_UNUSED int lua_checktype_ref(lua_State *L, int _index, int _type) { 1284 | luaL_checktype(L,_index,_type); 1285 | lua_pushvalue(L,_index); 1286 | return luaL_ref(L, LUA_REGISTRYINDEX); 1287 | } 1288 | 1289 | /* use static pointer as key to weak callback_state table. */ 1290 | static char obj_callback_state_weak_ref_key[] = "obj_callback_state_weak_ref_key"; 1291 | 1292 | static FUNC_UNUSED void *nobj_get_callback_state(lua_State *L, int owner_idx, int size) { 1293 | void *cb_state; 1294 | 1295 | lua_pushlightuserdata(L, obj_callback_state_weak_ref_key); /* key for weak table. */ 1296 | lua_rawget(L, LUA_REGISTRYINDEX); /* check if weak table exists already. */ 1297 | if(lua_isnil(L, -1)) { 1298 | lua_pop(L, 1); /* pop nil. */ 1299 | /* create weak table for callback_state */ 1300 | lua_newtable(L); /* weak table. */ 1301 | lua_newtable(L); /* metatable for weak table. */ 1302 | lua_pushliteral(L, "__mode"); 1303 | lua_pushliteral(L, "k"); 1304 | lua_rawset(L, -3); /* metatable.__mode = 'k' weak keys. */ 1305 | lua_setmetatable(L, -2); /* add metatable to weak table. */ 1306 | lua_pushlightuserdata(L, obj_callback_state_weak_ref_key); /* key for weak table. */ 1307 | lua_pushvalue(L, -2); /* dup weak table. */ 1308 | lua_rawset(L, LUA_REGISTRYINDEX); /* add weak table to registry. */ 1309 | } 1310 | 1311 | /* check weak table for callback_state. */ 1312 | lua_pushvalue(L, owner_idx); /* dup. owner as lookup key. */ 1313 | lua_rawget(L, -2); 1314 | if(lua_isnil(L, -1)) { 1315 | lua_pop(L, 1); /* pop nil. */ 1316 | lua_pushvalue(L, owner_idx); /* dup. owner as lookup key. */ 1317 | /* create new callback state. */ 1318 | cb_state = lua_newuserdata(L, size); 1319 | lua_rawset(L, -3); 1320 | lua_pop(L, 1); /* pop */ 1321 | } else { 1322 | /* got existing callback state. */ 1323 | cb_state = lua_touserdata(L, -1); 1324 | lua_pop(L, 2); /* pop , */ 1325 | } 1326 | 1327 | return cb_state; 1328 | } 1329 | 1330 | static FUNC_UNUSED void *nobj_delete_callback_state(lua_State *L, int owner_idx) { 1331 | void *cb_state = NULL; 1332 | 1333 | lua_pushlightuserdata(L, obj_callback_state_weak_ref_key); /* key for weak table. */ 1334 | lua_rawget(L, LUA_REGISTRYINDEX); /* check if weak table exists already. */ 1335 | if(lua_isnil(L, -1)) { 1336 | lua_pop(L, 1); /* pop nil. no weak table, so there is no callback state. */ 1337 | return NULL; 1338 | } 1339 | /* get callback state. */ 1340 | lua_pushvalue(L, owner_idx); /* dup. owner */ 1341 | lua_rawget(L, -2); 1342 | if(lua_isnil(L, -1)) { 1343 | lua_pop(L, 2); /* pop , nil. No callback state for the owner. */ 1344 | } else { 1345 | cb_state = lua_touserdata(L, -1); 1346 | lua_pop(L, 1); /* pop */ 1347 | /* remove callback state. */ 1348 | lua_pushvalue(L, owner_idx); /* dup. owner */ 1349 | lua_pushnil(L); 1350 | lua_rawset(L, -3); 1351 | lua_pop(L, 1); /* pop */ 1352 | } 1353 | 1354 | return cb_state; 1355 | } 1356 | 1357 | 1358 | 1359 | static char *obj_interfaces[] = { 1360 | NULL, 1361 | }; 1362 | 1363 | 1364 | 1365 | #define obj_type_Epoller_check(L, _index) \ 1366 | obj_udata_luacheck(L, _index, &(obj_type_Epoller)) 1367 | #define obj_type_Epoller_optional(L, _index) \ 1368 | obj_udata_luaoptional(L, _index, &(obj_type_Epoller)) 1369 | #define obj_type_Epoller_delete(L, _index, flags) \ 1370 | obj_udata_luadelete_weak(L, _index, &(obj_type_Epoller), flags) 1371 | #define obj_type_Epoller_push(L, obj, flags) \ 1372 | obj_udata_luapush_weak(L, (void *)obj, &(obj_type_Epoller), flags) 1373 | 1374 | 1375 | 1376 | 1377 | static const char *epoll_ffi_lua_code[] = { "local ffi=require\"ffi\"\n" 1378 | "local function ffi_safe_load(name, global)\n" 1379 | " local stat, C = pcall(ffi.load, name, global)\n" 1380 | " if not stat then return nil, C end\n" 1381 | " if global then return ffi.C end\n" 1382 | " return C\n" 1383 | "end\n" 1384 | "local function ffi_load(name, global)\n" 1385 | " return assert(ffi_safe_load(name, global))\n" 1386 | "end\n" 1387 | "\n" 1388 | "local ffi_string = ffi.string\n" 1389 | "\n" 1390 | "local f_cast = ffi.cast\n" 1391 | "local pcall = pcall\n" 1392 | "local error = error\n" 1393 | "local type = type\n" 1394 | "local tonumber = tonumber\n" 1395 | "local tostring = tostring\n" 1396 | "local sformat = require\"string\".format\n" 1397 | "local rawset = rawset\n" 1398 | "local setmetatable = setmetatable\n" 1399 | "local package = (require\"package\") or {}\n" 1400 | "local p_config = package.config\n" 1401 | "local p_cpath = package.cpath\n" 1402 | "\n" 1403 | "\n" 1404 | "local ffi_load_cmodule\n" 1405 | "\n" 1406 | "-- try to detect luvit.\n" 1407 | "if p_config == nil and p_cpath == nil then\n" 1408 | " ffi_load_cmodule = function(name, global)\n" 1409 | " for path,module in pairs(package.loaded) do\n" 1410 | " if module == name then\n" 1411 | " local C, err = ffi_safe_load(path, global)\n" 1412 | " -- return opened library\n" 1413 | " if C then return C end\n" 1414 | " end\n" 1415 | " end\n" 1416 | " error(\"Failed to find: \" .. name)\n" 1417 | " end\n" 1418 | "else\n" 1419 | " ffi_load_cmodule = function(name, global)\n" 1420 | " local dir_sep = p_config:sub(1,1)\n" 1421 | " local path_sep = p_config:sub(3,3)\n" 1422 | " local path_mark = p_config:sub(5,5)\n" 1423 | " local path_match = \"([^\" .. path_sep .. \"]+)\"\n" 1424 | " -- convert dotted name to directory path.\n" 1425 | " name = name:gsub('%.', dir_sep)\n" 1426 | " -- try each path in search path.\n" 1427 | " for path in p_cpath:gmatch(path_match) do\n" 1428 | " local fname = path:gsub(path_mark, name)\n" 1429 | " local C, err = ffi_safe_load(fname, global)\n" 1430 | " -- return opened library\n" 1431 | " if C then return C end\n" 1432 | " end\n" 1433 | " error(\"Failed to find: \" .. name)\n" 1434 | " end\n" 1435 | "end\n" 1436 | "\n" 1437 | "local _M, _priv, reg_table = ...\n" 1438 | "local REG_OBJECTS_AS_GLOBALS = false\n" 1439 | "local C = ffi.C\n" 1440 | "\n" 1441 | "local OBJ_UDATA_FLAG_OWN = 1\n" 1442 | "\n" 1443 | "local function ffi_safe_cdef(block_name, cdefs)\n" 1444 | " local fake_type = \"struct sentinel_\" .. block_name .. \"_ty\"\n" 1445 | " local stat, size = pcall(ffi.sizeof, fake_type)\n" 1446 | " if stat and size > 0 then\n" 1447 | " -- already loaded this cdef block\n" 1448 | " return\n" 1449 | " end\n" 1450 | " cdefs = fake_type .. \"{ int a; int b; int c; };\" .. cdefs\n" 1451 | " return ffi.cdef(cdefs)\n" 1452 | "end\n" 1453 | "\n" 1454 | "ffi_safe_cdef(\"LuaNativeObjects\", [[\n" 1455 | "\n" 1456 | "typedef struct obj_type obj_type;\n" 1457 | "\n" 1458 | "typedef void (*base_caster_t)(void **obj);\n" 1459 | "\n" 1460 | "typedef void (*dyn_caster_t)(void **obj, obj_type **type);\n" 1461 | "\n" 1462 | "struct obj_type {\n" 1463 | " dyn_caster_t dcaster; /**< caster to support casting to sub-objects. */\n" 1464 | " int32_t id; /**< type's id. */\n" 1465 | " uint32_t flags; /**< type's flags (weak refs) */\n" 1466 | " const char *name; /**< type's object name. */\n" 1467 | "};\n" 1468 | "\n" 1469 | "typedef struct obj_base {\n" 1470 | " int32_t id;\n" 1471 | " base_caster_t bcaster;\n" 1472 | "} obj_base;\n" 1473 | "\n" 1474 | "typedef struct obj_udata {\n" 1475 | " void *obj;\n" 1476 | " uint32_t flags; /**< lua_own:1bit */\n" 1477 | "} obj_udata;\n" 1478 | "\n" 1479 | "int memcmp(const void *s1, const void *s2, size_t n);\n" 1480 | "\n" 1481 | "]])\n" 1482 | "\n" 1483 | "local nobj_callback_states = {}\n" 1484 | "local nobj_weak_objects = setmetatable({}, {__mode = \"v\"})\n" 1485 | "local nobj_obj_flags = {}\n" 1486 | "\n" 1487 | "local function obj_ptr_to_id(ptr)\n" 1488 | " return tonumber(f_cast('uintptr_t', ptr))\n" 1489 | "end\n" 1490 | "\n" 1491 | "local function obj_to_id(ptr)\n" 1492 | " return tonumber(f_cast('uintptr_t', f_cast('void *', ptr)))\n" 1493 | "end\n" 1494 | "\n" 1495 | "local function register_default_constructor(_pub, obj_name, constructor)\n" 1496 | " local obj_pub = _pub[obj_name]\n" 1497 | " if type(obj_pub) == 'table' then\n" 1498 | " -- copy table since it might have a locked metatable\n" 1499 | " local new_pub = {}\n" 1500 | " for k,v in pairs(obj_pub) do\n" 1501 | " new_pub[k] = v\n" 1502 | " end\n" 1503 | " setmetatable(new_pub, { __call = function(t,...)\n" 1504 | " return constructor(...)\n" 1505 | " end,\n" 1506 | " __metatable = false,\n" 1507 | " })\n" 1508 | " obj_pub = new_pub\n" 1509 | " else\n" 1510 | " obj_pub = constructor\n" 1511 | " end\n" 1512 | " _pub[obj_name] = obj_pub\n" 1513 | " _M[obj_name] = obj_pub\n" 1514 | " if REG_OBJECTS_AS_GLOBALS then\n" 1515 | " _G[obj_name] = obj_pub\n" 1516 | " end\n" 1517 | "end\n" 1518 | "\n" 1519 | "ffi_safe_cdef(\"BufferIF\", [[\n" 1520 | "typedef struct Buffer_if {\n" 1521 | " const uint8_t * (* const const_data)(void *this_v);\n" 1522 | " size_t (* const get_size)(void *this_v);\n" 1523 | "} BufferIF;\n" 1524 | "]])\n" 1525 | "\n" 1526 | "ffi_safe_cdef(\"MutableBufferIF\", [[\n" 1527 | "typedef struct MutableBuffer_if {\n" 1528 | " uint8_t * (* const data)(void *this_v);\n" 1529 | " size_t (* const get_size)(void *this_v);\n" 1530 | "} MutableBufferIF;\n" 1531 | "]])\n" 1532 | "\n" 1533 | "ffi_safe_cdef(\"FDIF\", [[\n" 1534 | "typedef struct FD_if {\n" 1535 | " int (* const get_fd)(void *this_v);\n" 1536 | " int (* const get_type)(void *this_v);\n" 1537 | "} FDIF;\n" 1538 | "]])\n" 1539 | "\n" 1540 | "local Cmod = ffi_load_cmodule(\"epoll\", false)\n" 1541 | "local C = Cmod\n" 1542 | "\n" 1543 | "ffi.cdef[[\n" 1544 | "typedef int errno_rc;\n" 1545 | "\n" 1546 | "typedef struct Epoller Epoller;\n" 1547 | "\n" 1548 | "]]\n" 1549 | "\n" 1550 | "ffi.cdef[[\n" 1551 | "typedef union epoll_data {\n" 1552 | " void *ptr;\n" 1553 | " int fd;\n" 1554 | " uint32_t u32;\n" 1555 | " uint64_t u64;\n" 1556 | "} epoll_data_t;\n" 1557 | "\n" 1558 | "struct epoll_event {\n" 1559 | " uint32_t events; /* Epoll events */\n" 1560 | " epoll_data_t data; /* User data variable */\n" 1561 | "} __attribute__ ((__packed__));\n" 1562 | "\n" 1563 | "typedef struct epoll_event epoll_event;\n" 1564 | "\n" 1565 | "typedef struct Epoller {\n" 1566 | " int epfd;\n" 1567 | " int size;\n" 1568 | " int count;\n" 1569 | " struct epoll_event *events;\n" 1570 | "} Epoller;\n" 1571 | "\n" 1572 | "int epoller_wait(Epoller *this, int timeout);\n" 1573 | "\n" 1574 | "Epoller * epoller_create(int);\n" 1575 | "\n" 1576 | "void epoller_destroy(Epoller *);\n" 1577 | "\n" 1578 | "errno_rc epoller_add(Epoller *, int, uint32_t, uint64_t);\n" 1579 | "\n" 1580 | "errno_rc epoller_mod(Epoller *, int, uint32_t, uint64_t);\n" 1581 | "\n" 1582 | "errno_rc epoller_del(Epoller *, int);\n" 1583 | "\n" 1584 | "errno_rc epoller_wait(Epoller *, int);\n" 1585 | "\n" 1586 | "\n" 1587 | "]]\n" 1588 | "\n" 1589 | "REG_OBJECTS_AS_GLOBALS = false\n" 1590 | "local _obj_interfaces_ffi = {}\n" 1591 | "local _pub = {}\n" 1592 | "local _meth = {}\n" 1593 | "local _push = {}\n" 1594 | "local _obj_subs = {}\n" 1595 | "for obj_name,mt in pairs(_priv) do\n" 1596 | " if type(mt) == 'table' then\n" 1597 | " _obj_subs[obj_name] = {}\n" 1598 | " if mt.__index then\n" 1599 | " _meth[obj_name] = mt.__index\n" 1600 | " end\n" 1601 | " end\n" 1602 | "end\n" 1603 | "for obj_name,pub in pairs(_M) do\n" 1604 | " _pub[obj_name] = pub\n" 1605 | "end\n" 1606 | "\n" 1607 | "--\n" 1608 | "-- CData Metatable access\n" 1609 | "--\n" 1610 | "local _ctypes = {}\n" 1611 | "local _type_names = {}\n" 1612 | "local _get_mt_key = {}\n" 1613 | "local _ctype_meta_map = {}\n" 1614 | "\n" 1615 | "local f_typeof = ffi.typeof\n" 1616 | "local function get_cdata_type_id(cdata)\n" 1617 | " return tonumber(f_typeof(cdata))\n" 1618 | "end\n" 1619 | "local function get_cdata_mt(cdata)\n" 1620 | " return _ctype_meta_map[tonumber(f_typeof(cdata))]\n" 1621 | "end\n" 1622 | "\n" 1623 | "local function obj_register_ctype(name, ctype)\n" 1624 | " local obj_mt = _priv[name]\n" 1625 | " local obj_type = obj_mt['.type']\n" 1626 | " local obj_ctype = ffi.typeof(ctype)\n" 1627 | " local obj_type_id = tonumber(obj_ctype)\n" 1628 | " _ctypes[name] = obj_ctype\n" 1629 | " _type_names[name] = tostring(obj_ctype)\n" 1630 | " _ctype_meta_map[obj_type_id] = obj_mt\n" 1631 | " _ctype_meta_map[obj_mt] = obj_type_id\n" 1632 | " return obj_mt, obj_type, obj_ctype\n" 1633 | "end\n" 1634 | "\n" 1635 | "--\n" 1636 | "-- Interfaces helper code.\n" 1637 | "--\n" 1638 | "local _obj_interfaces_key = \"obj_interfaces<1.0>_table_key\"\n" 1639 | "local _obj_interfaces_ud = reg_table[_obj_interfaces_key]\n" 1640 | "local _obj_interfaces_key_ffi = _obj_interfaces_key .. \"_LJ2_FFI\"\n" 1641 | "_obj_interfaces_ffi = reg_table[_obj_interfaces_key_ffi]\n" 1642 | "if not _obj_interfaces_ffi then\n" 1643 | " -- create missing interfaces table for FFI bindings.\n" 1644 | " _obj_interfaces_ffi = {}\n" 1645 | " reg_table[_obj_interfaces_key_ffi] = _obj_interfaces_ffi\n" 1646 | "end\n" 1647 | "\n" 1648 | "local function obj_get_userdata_interface(if_name, expected_err)\n" 1649 | " local impls_ud = _obj_interfaces_ud[if_name]\n" 1650 | " if not impls_ud then\n" 1651 | " impls_ud = {}\n" 1652 | " _obj_interfaces_ud[if_name] = impls_ud\n" 1653 | " end\n" 1654 | " -- create cdata check function to be used by non-ffi bindings.\n" 1655 | " if not impls_ud.cdata then\n" 1656 | " function impls_ud.cdata(obj)\n" 1657 | " return assert(impls_ud[get_cdata_mt(obj)], expected_err)\n" 1658 | " end\n" 1659 | " end\n" 1660 | " return impls_ud\n" 1661 | "end\n" 1662 | "\n" 1663 | "local function obj_get_interface_check(if_name, expected_err)\n" 1664 | " local impls_ffi = _obj_interfaces_ffi[if_name]\n" 1665 | " if not impls_ffi then\n" 1666 | " local if_type = ffi.typeof(if_name .. \" *\")\n" 1667 | " local impls_ud = obj_get_userdata_interface(if_name, expected_err)\n" 1668 | " -- create table for FFI-based interface implementations.\n" 1669 | " impls_ffi = setmetatable({}, {\n" 1670 | " __index = function(impls_ffi, mt)\n" 1671 | " local impl = impls_ud[mt]\n" 1672 | " if impl then\n" 1673 | " -- cast to cdata\n" 1674 | " impl = if_type(impl)\n" 1675 | " rawset(impls_ffi, mt, impl)\n" 1676 | " end\n" 1677 | " return impl\n" 1678 | " end})\n" 1679 | " _obj_interfaces_ffi[if_name] = impls_ffi\n" 1680 | "\n" 1681 | " -- create check function for this interface.\n" 1682 | " function impls_ffi.check(obj)\n" 1683 | " local impl\n" 1684 | " if type(obj) == 'cdata' then\n" 1685 | " impl = impls_ffi[get_cdata_type_id(obj)]\n" 1686 | " else\n" 1687 | " impl = impls_ud.userdata(impls_ffi, obj)\n" 1688 | " end\n" 1689 | " return assert(impl, expected_err)\n" 1690 | " end\n" 1691 | " end\n" 1692 | " return impls_ffi.check\n" 1693 | "end\n" 1694 | "\n" 1695 | "local function obj_register_interface(if_name, obj_name)\n" 1696 | " -- loopkup cdata id\n" 1697 | " local obj_mt = _priv[obj_name]\n" 1698 | " local obj_type_id = _ctype_meta_map[obj_mt]\n" 1699 | " local impl_meths = {}\n" 1700 | " local ffi_impls = _obj_interfaces_ffi[if_name]\n" 1701 | " ffi_impls[obj_type_id] = impl_meths\n" 1702 | " _meth[obj_name]['NOBJ_get_' .. if_name] = impl_meths\n" 1703 | " return impl_meths\n" 1704 | "end\n" 1705 | "\n" 1706 | "\n" 1707 | "local obj_type_Epoller_check\n" 1708 | "local obj_type_Epoller_delete\n" 1709 | "local obj_type_Epoller_push\n" 1710 | "\n" 1711 | "do\n" 1712 | " local obj_mt, obj_type, obj_ctype = obj_register_ctype(\"Epoller\", \"Epoller *\")\n" 1713 | "\n" 1714 | " function obj_type_Epoller_check(ptr)\n" 1715 | " -- if ptr is nil or is the correct type, then just return it.\n" 1716 | " if not ptr or ffi.istype(obj_ctype, ptr) then return ptr end\n" 1717 | " -- check if it is a compatible type.\n" 1718 | " local ctype = tostring(ffi.typeof(ptr))\n" 1719 | " local bcaster = _obj_subs.Epoller[ctype]\n" 1720 | " if bcaster then\n" 1721 | " return bcaster(ptr)\n" 1722 | " end\n" 1723 | " return error(\"Expected 'Epoller *'\", 2)\n" 1724 | " end\n" 1725 | "\n" 1726 | " function obj_type_Epoller_delete(ptr)\n" 1727 | " local id = obj_ptr_to_id(ptr)\n" 1728 | " local flags = nobj_obj_flags[id]\n" 1729 | " if not flags then return nil, 0 end\n" 1730 | " ffi.gc(ptr, nil)\n" 1731 | " nobj_obj_flags[id] = nil\n" 1732 | " return ptr, flags\n" 1733 | " end\n" 1734 | "\n" 1735 | " function obj_type_Epoller_push(ptr, flags)\n" 1736 | " local id = obj_ptr_to_id(ptr)\n" 1737 | " -- check weak refs\n" 1738 | " if nobj_obj_flags[id] then return nobj_weak_objects[id] end\n" 1739 | "\n" 1740 | " if flags ~= 0 then\n" 1741 | " nobj_obj_flags[id] = flags\n" 1742 | " ffi.gc(ptr, obj_mt.__gc)\n" 1743 | " end\n" 1744 | " nobj_weak_objects[id] = ptr\n" 1745 | " return ptr\n" 1746 | " end\n" 1747 | "\n" 1748 | " function obj_mt:__tostring()\n" 1749 | " return sformat(\"Epoller: %p, flags=%d\", self, nobj_obj_flags[obj_ptr_to_id(self)] or 0)\n" 1750 | " end\n" 1751 | "\n" 1752 | " -- type checking function for C API.\n" 1753 | " _priv[obj_type] = obj_type_Epoller_check\n" 1754 | " -- push function for C API.\n" 1755 | " reg_table[obj_type] = function(ptr, flags)\n" 1756 | " return obj_type_Epoller_push(ffi.cast(obj_ctype,ptr), flags)\n" 1757 | " end\n" 1758 | "\n" 1759 | " -- export check functions for use in other modules.\n" 1760 | " obj_mt.c_check = obj_type_Epoller_check\n" 1761 | " obj_mt.ffi_check = obj_type_Epoller_check\n" 1762 | "end\n" 1763 | "\n" 1764 | "\n" 1765 | "local obj_type_Buffer_check =\n" 1766 | " obj_get_interface_check(\"BufferIF\", \"Expected object with Buffer interface\")\n" 1767 | "\n" 1768 | "local obj_type_MutableBuffer_check =\n" 1769 | " obj_get_interface_check(\"MutableBufferIF\", \"Expected object with MutableBuffer interface\")\n" 1770 | "\n" 1771 | "local obj_type_FD_check =\n" 1772 | " obj_get_interface_check(\"FDIF\", \"Expected object with FD interface\")\n" 1773 | "\n" 1774 | "\n" 1775 | "-- Start \"Errors\" FFI interface\n" 1776 | "-- End \"Errors\" FFI interface\n" 1777 | "\n" 1778 | "-- get Errors table to map errno to error name.\n" 1779 | "local Error_names = _M.Errors\n" 1780 | "\n" 1781 | "local function error_code__errno_rc__push(err)\n" 1782 | " local err_str\n" 1783 | " if(-1 == err) then\n" 1784 | " err_str = Error_names[ffi.errno()]\n" 1785 | " end\n" 1786 | "\n" 1787 | " return err_str\n" 1788 | "end\n" 1789 | "\n" 1790 | "\n" 1791 | "-- Start \"Epoller\" FFI interface\n" 1792 | "-- method: new\n" 1793 | "function _pub.Epoller.new(size)\n" 1794 | " size = size or 64\n" 1795 | " local this_flags = OBJ_UDATA_FLAG_OWN\n" 1796 | " local self\n" 1797 | " self = C.epoller_create(size)\n" 1798 | " return obj_type_Epoller_push(self, this_flags)\n" 1799 | "end\n" 1800 | "register_default_constructor(_pub,\"Epoller\",_pub.Epoller.new)\n" 1801 | "\n" 1802 | "-- method: close\n" 1803 | "function _meth.Epoller.close(self)\n" 1804 | " local self,this_flags = obj_type_Epoller_delete(self)\n" 1805 | " if not self then return end\n" 1806 | " C.epoller_destroy(self)\n" 1807 | " return \n" 1808 | "end\n" 1809 | "_priv.Epoller.__gc = _meth.Epoller.close\n" 1810 | "\n" 1811 | "-- method: add\n" 1812 | "function _meth.Epoller.add(self, fd, events, id)\n" 1813 | " \n" 1814 | " \n" 1815 | " \n" 1816 | " \n" 1817 | " local rc_epoller_add = 0\n" 1818 | " rc_epoller_add = C.epoller_add(self, fd, events, id)\n" 1819 | " -- check for error.\n" 1820 | " if (-1 == rc_epoller_add) then\n" 1821 | " return nil, error_code__errno_rc__push(rc_epoller_add)\n" 1822 | " end\n" 1823 | " return true\n" 1824 | "end\n" 1825 | "\n" 1826 | "-- method: mod\n" 1827 | "function _meth.Epoller.mod(self, fd, events, id)\n" 1828 | " \n" 1829 | " \n" 1830 | " \n" 1831 | " \n" 1832 | " local rc_epoller_mod = 0\n" 1833 | " rc_epoller_mod = C.epoller_mod(self, fd, events, id)\n" 1834 | " -- check for error.\n" 1835 | " if (-1 == rc_epoller_mod) then\n" 1836 | " return nil, error_code__errno_rc__push(rc_epoller_mod)\n" 1837 | " end\n" 1838 | " return true\n" 1839 | "end\n" 1840 | "\n" 1841 | "-- method: del\n" 1842 | "function _meth.Epoller.del(self, fd)\n" 1843 | " \n" 1844 | " \n" 1845 | " local rc_epoller_del = 0\n" 1846 | " rc_epoller_del = C.epoller_del(self, fd)\n" 1847 | " -- check for error.\n" 1848 | " if (-1 == rc_epoller_del) then\n" 1849 | " return nil, error_code__errno_rc__push(rc_epoller_del)\n" 1850 | " end\n" 1851 | " return true\n" 1852 | "end\n" 1853 | "\n" 1854 | "-- method: wait\n" 1855 | "function _meth.Epoller.wait(self, events, timeout)\n" 1856 | " \n" 1857 | " \n" 1858 | " local rc = 0\n" 1859 | " rc = C.epoller_wait(self, timeout)\n" 1860 | " if (rc > 0) then\n" 1861 | " local idx = 1\n" 1862 | " -- fill 'events' table with event pairs.\n" 1863 | " for n=0,(rc-1) do\n" 1864 | " events[idx] = tonumber(self.events[n].data.u64)\n" 1865 | " idx = idx + 1\n" 1866 | " events[idx] = tonumber(self.events[n].events)\n" 1867 | " idx = idx + 1\n" 1868 | " end\n" 1869 | " return rc\n" 1870 | " elseif (rc == 0) then\n" 1871 | " return rc\n" 1872 | " end\n" 1873 | "\n" 1874 | " -- check for error.\n" 1875 | " if (-1 == rc) then\n" 1876 | " return nil, error_code__errno_rc__push(rc)\n" 1877 | " end\n" 1878 | " return true\n" 1879 | "end\n" 1880 | "\n" 1881 | "-- method: wait_callback\n" 1882 | "function _meth.Epoller.wait_callback(self, event_cb, timeout)\n" 1883 | " \n" 1884 | " \n" 1885 | " local rc = 0\n" 1886 | " rc = C.epoller_wait(self, timeout)\n" 1887 | " if (rc > 0) then\n" 1888 | " -- call 'event_cb' for each pair.\n" 1889 | " for n=0,(rc-1) do\n" 1890 | " event_cb(tonumber(self.events[n].data.u64), tonumber(self.events[n].events))\n" 1891 | " end\n" 1892 | " return rc\n" 1893 | " elseif (rc == 0) then\n" 1894 | " return rc\n" 1895 | " end\n" 1896 | "\n" 1897 | " -- check for error.\n" 1898 | " if (-1 == rc) then\n" 1899 | " return nil, error_code__errno_rc__push(rc)\n" 1900 | " end\n" 1901 | " return true\n" 1902 | "end\n" 1903 | "\n" 1904 | "_push.Epoller = obj_type_Epoller_push\n" 1905 | "ffi.metatype(\"Epoller\", _priv.Epoller)\n" 1906 | "-- End \"Epoller\" FFI interface\n" 1907 | "\n" 1908 | "-- method: new\n" 1909 | "function _M.new(size)\n" 1910 | " size = size or 64\n" 1911 | " local this_flags = OBJ_UDATA_FLAG_OWN\n" 1912 | " local this\n" 1913 | " this = Cmod.epoller_create(size)\n" 1914 | " return obj_type_Epoller_push(this, this_flags)\n" 1915 | "end\n" 1916 | "\n", NULL }; 1917 | static char epoll_Errors_key[] = "epoll_Errors_key"; 1918 | 1919 | typedef struct Epoller { 1920 | int epfd; 1921 | int size; 1922 | int count; 1923 | struct epoll_event *events; 1924 | } Epoller; 1925 | 1926 | int epoller_wait(Epoller *this, int timeout); 1927 | 1928 | #define EPOLLER_MIN_SIZE 20 1929 | static void epoller_resize(Epoller *this, int newsize) { 1930 | if(newsize < EPOLLER_MIN_SIZE) newsize = EPOLLER_MIN_SIZE; 1931 | this->events = (struct epoll_event *)realloc(this->events, newsize * sizeof(struct epoll_event)); 1932 | this->size = newsize; 1933 | } 1934 | 1935 | static void epoller_grow(Epoller *this) { 1936 | if(this->size > this->count) return; 1937 | epoller_resize(this, this->count + 50); 1938 | } 1939 | 1940 | Epoller *epoller_create(int size) { 1941 | Epoller *this; 1942 | 1943 | this = (Epoller *)calloc(1, sizeof(Epoller)); 1944 | #ifdef EPOLL_CLOEXEC 1945 | this->epfd = epoll_create1(EPOLL_CLOEXEC); 1946 | #else 1947 | this->epfd = epoll_create(1024); 1948 | #endif 1949 | this->size = 0; 1950 | this->count = 0; 1951 | this->events = NULL; 1952 | epoller_resize(this, size); 1953 | 1954 | return this; 1955 | } 1956 | 1957 | void epoller_destroy(Epoller *this) { 1958 | close(this->epfd); 1959 | free(this->events); 1960 | free(this); 1961 | } 1962 | 1963 | static int epoller_ctl(Epoller *this, int op, int fd, uint32_t events, uint64_t id) { 1964 | struct epoll_event event; 1965 | event.events = events; 1966 | event.data.u64 = id; 1967 | return epoll_ctl(this->epfd, op, fd, &event); 1968 | } 1969 | 1970 | int epoller_add(Epoller *this, int fd, uint32_t events, uint64_t id) { 1971 | this->count++; 1972 | epoller_grow(this); 1973 | return epoller_ctl(this, EPOLL_CTL_ADD, fd, events, id); 1974 | } 1975 | 1976 | int epoller_mod(Epoller *this, int fd, uint32_t events, uint64_t id) { 1977 | return epoller_ctl(this, EPOLL_CTL_MOD, fd, events, id); 1978 | } 1979 | 1980 | int epoller_del(Epoller *this, int fd) { 1981 | this->count--; 1982 | return epoller_ctl(this, EPOLL_CTL_DEL, fd, 0, 0); 1983 | } 1984 | 1985 | int epoller_wait(Epoller *this, int timeout) { 1986 | return epoll_wait(this->epfd, this->events, this->size, timeout); 1987 | } 1988 | 1989 | 1990 | 1991 | 1992 | /* method: description */ 1993 | static int Errors__description__meth(lua_State *L) { 1994 | size_t msg_len = 0; 1995 | char msg_buf[1024]; 1996 | char * msg = msg_buf; 1997 | int err_type; 1998 | int err_num = -1; 1999 | 2000 | msg_len = 1023; 2001 | err_type = lua_type(L, 2); 2002 | if(err_type == LUA_TSTRING) { 2003 | lua_pushvalue(L, 2); 2004 | lua_rawget(L, 1); 2005 | if(lua_isnumber(L, -1)) { 2006 | err_num = lua_tointeger(L, -1); 2007 | } 2008 | lua_pop(L, 1); 2009 | } else if(err_type == LUA_TNUMBER) { 2010 | err_num = lua_tointeger(L, 2); 2011 | } else { 2012 | return luaL_argerror(L, 2, "expected string/number"); 2013 | } 2014 | if(err_num < 0) { 2015 | lua_pushnil(L); 2016 | lua_pushliteral(L, "UNKNOWN ERROR"); 2017 | return 2; 2018 | } 2019 | strerror_r(err_num, msg, msg_len); 2020 | msg_len = strlen(msg); 2021 | 2022 | if(msg == NULL) lua_pushnil(L); else lua_pushlstring(L, msg,msg_len); 2023 | return 1; 2024 | } 2025 | 2026 | static void error_code__errno_rc__push(lua_State *L, errno_rc err) { 2027 | const char *err_str = NULL; 2028 | if(-1 == err) { 2029 | /* get Errors table. */ 2030 | lua_pushlightuserdata(L, epoll_Errors_key); 2031 | lua_rawget(L, LUA_REGISTRYINDEX); 2032 | /* convert errno to string. */ 2033 | lua_rawgeti(L, -1, errno); 2034 | /* remove Errors table. */ 2035 | lua_remove(L, -2); 2036 | if(!lua_isnil(L, -1)) { 2037 | /* found error. */ 2038 | return; 2039 | } 2040 | /* Unknown error. */ 2041 | lua_pop(L, 1); 2042 | err_str = "UNKNOWN ERROR"; 2043 | } 2044 | 2045 | if(err_str) { 2046 | lua_pushstring(L, err_str); 2047 | } else { 2048 | lua_pushnil(L); 2049 | } 2050 | } 2051 | 2052 | /* method: new */ 2053 | static int Epoller__new__meth(lua_State *L) { 2054 | int size; 2055 | int this_flags = OBJ_UDATA_FLAG_OWN; 2056 | Epoller * this; 2057 | size = luaL_optinteger(L,1,64); 2058 | this = epoller_create(size); 2059 | obj_type_Epoller_push(L, this, this_flags); 2060 | return 1; 2061 | } 2062 | 2063 | /* method: close */ 2064 | static int Epoller__close__meth(lua_State *L) { 2065 | int this_flags = 0; 2066 | Epoller * this; 2067 | this = obj_type_Epoller_delete(L,1,&(this_flags)); 2068 | if(!(this_flags & OBJ_UDATA_FLAG_OWN)) { return 0; } 2069 | epoller_destroy(this); 2070 | return 0; 2071 | } 2072 | 2073 | /* method: add */ 2074 | static int Epoller__add__meth(lua_State *L) { 2075 | Epoller * this; 2076 | int fd; 2077 | uint32_t events; 2078 | uint64_t id; 2079 | errno_rc rc_epoller_add = 0; 2080 | this = obj_type_Epoller_check(L,1); 2081 | fd = luaL_checkinteger(L,2); 2082 | events = luaL_checkinteger(L,3); 2083 | id = luaL_checkinteger(L,4); 2084 | rc_epoller_add = epoller_add(this, fd, events, id); 2085 | /* check for error. */ 2086 | if((-1 == rc_epoller_add)) { 2087 | lua_pushnil(L); 2088 | error_code__errno_rc__push(L, rc_epoller_add); 2089 | } else { 2090 | lua_pushboolean(L, 1); 2091 | lua_pushnil(L); 2092 | } 2093 | return 2; 2094 | } 2095 | 2096 | /* method: mod */ 2097 | static int Epoller__mod__meth(lua_State *L) { 2098 | Epoller * this; 2099 | int fd; 2100 | uint32_t events; 2101 | uint64_t id; 2102 | errno_rc rc_epoller_mod = 0; 2103 | this = obj_type_Epoller_check(L,1); 2104 | fd = luaL_checkinteger(L,2); 2105 | events = luaL_checkinteger(L,3); 2106 | id = luaL_checkinteger(L,4); 2107 | rc_epoller_mod = epoller_mod(this, fd, events, id); 2108 | /* check for error. */ 2109 | if((-1 == rc_epoller_mod)) { 2110 | lua_pushnil(L); 2111 | error_code__errno_rc__push(L, rc_epoller_mod); 2112 | } else { 2113 | lua_pushboolean(L, 1); 2114 | lua_pushnil(L); 2115 | } 2116 | return 2; 2117 | } 2118 | 2119 | /* method: del */ 2120 | static int Epoller__del__meth(lua_State *L) { 2121 | Epoller * this; 2122 | int fd; 2123 | errno_rc rc_epoller_del = 0; 2124 | this = obj_type_Epoller_check(L,1); 2125 | fd = luaL_checkinteger(L,2); 2126 | rc_epoller_del = epoller_del(this, fd); 2127 | /* check for error. */ 2128 | if((-1 == rc_epoller_del)) { 2129 | lua_pushnil(L); 2130 | error_code__errno_rc__push(L, rc_epoller_del); 2131 | } else { 2132 | lua_pushboolean(L, 1); 2133 | lua_pushnil(L); 2134 | } 2135 | return 2; 2136 | } 2137 | 2138 | /* method: wait */ 2139 | static int Epoller__wait__meth(lua_State *L) { 2140 | Epoller * this; 2141 | int timeout; 2142 | errno_rc rc = 0; 2143 | this = obj_type_Epoller_check(L,1); 2144 | timeout = luaL_checkinteger(L,3); 2145 | luaL_checktype(L, 2, LUA_TTABLE); 2146 | 2147 | rc = epoller_wait(this, timeout); 2148 | if(rc > 0) { 2149 | int idx; 2150 | int n; 2151 | /* fill 'events' table with event pairs. */ 2152 | for(n = 0, idx = 1; n < rc; n++) { 2153 | lua_pushinteger(L, this->events[n].data.u64); 2154 | lua_rawseti(L, 2, idx); idx++; 2155 | lua_pushinteger(L, this->events[n].events); 2156 | lua_rawseti(L, 2, idx); idx++; 2157 | } 2158 | lua_pushinteger(L, rc); 2159 | return 1; 2160 | } else if(rc == 0) { 2161 | lua_pushinteger(L, rc); 2162 | return 1; 2163 | } 2164 | 2165 | /* check for error. */ 2166 | if((-1 == rc)) { 2167 | lua_pushnil(L); 2168 | error_code__errno_rc__push(L, rc); 2169 | } else { 2170 | lua_pushboolean(L, 1); 2171 | lua_pushnil(L); 2172 | } 2173 | return 2; 2174 | } 2175 | 2176 | /* method: wait_callback */ 2177 | static int Epoller__wait_callback__meth(lua_State *L) { 2178 | Epoller * this; 2179 | int timeout; 2180 | errno_rc rc = 0; 2181 | this = obj_type_Epoller_check(L,1); 2182 | timeout = luaL_checkinteger(L,3); 2183 | luaL_checktype(L, 2, LUA_TFUNCTION); 2184 | 2185 | rc = epoller_wait(this, timeout); 2186 | if(rc > 0) { 2187 | int n; 2188 | /* call 'event_cb' for each pair. */ 2189 | for(n = 0; n < rc; n++) { 2190 | lua_pushvalue(L, 2); 2191 | lua_pushinteger(L, this->events[n].data.u64); 2192 | lua_pushinteger(L, this->events[n].events); 2193 | lua_call(L, 2, 0); 2194 | } 2195 | lua_pushinteger(L, rc); 2196 | return 1; 2197 | } else if(rc == 0) { 2198 | lua_pushinteger(L, rc); 2199 | return 1; 2200 | } 2201 | 2202 | /* check for error. */ 2203 | if((-1 == rc)) { 2204 | lua_pushnil(L); 2205 | error_code__errno_rc__push(L, rc); 2206 | } else { 2207 | lua_pushboolean(L, 1); 2208 | lua_pushnil(L); 2209 | } 2210 | return 2; 2211 | } 2212 | 2213 | /* method: new */ 2214 | static int epoll__new__func(lua_State *L) { 2215 | int size; 2216 | int this_flags = OBJ_UDATA_FLAG_OWN; 2217 | Epoller * this; 2218 | size = luaL_optinteger(L,1,64); 2219 | this = epoller_create(size); 2220 | obj_type_Epoller_push(L, this, this_flags); 2221 | return 1; 2222 | } 2223 | 2224 | 2225 | 2226 | static const luaL_Reg obj_Errors_pub_funcs[] = { 2227 | {NULL, NULL} 2228 | }; 2229 | 2230 | static const luaL_Reg obj_Errors_methods[] = { 2231 | {"description", Errors__description__meth}, 2232 | {NULL, NULL} 2233 | }; 2234 | 2235 | static const luaL_Reg obj_Errors_metas[] = { 2236 | {NULL, NULL} 2237 | }; 2238 | 2239 | static const obj_const obj_Errors_constants[] = { 2240 | #ifdef ELNRNG 2241 | {"ELNRNG", NULL, ELNRNG, CONST_NUMBER}, 2242 | #endif 2243 | #ifdef EISDIR 2244 | {"EISDIR", NULL, EISDIR, CONST_NUMBER}, 2245 | #endif 2246 | #ifdef EFBIG 2247 | {"EFBIG", NULL, EFBIG, CONST_NUMBER}, 2248 | #endif 2249 | #ifdef EDQUOT 2250 | {"EDQUOT", NULL, EDQUOT, CONST_NUMBER}, 2251 | #endif 2252 | #ifdef EIO 2253 | {"EIO", NULL, EIO, CONST_NUMBER}, 2254 | #endif 2255 | #ifdef EBUSY 2256 | {"EBUSY", NULL, EBUSY, CONST_NUMBER}, 2257 | #endif 2258 | #ifdef ENOEXEC 2259 | {"ENOEXEC", NULL, ENOEXEC, CONST_NUMBER}, 2260 | #endif 2261 | #ifdef ENAVAIL 2262 | {"ENAVAIL", NULL, ENAVAIL, CONST_NUMBER}, 2263 | #endif 2264 | #ifdef EEXIST 2265 | {"EEXIST", NULL, EEXIST, CONST_NUMBER}, 2266 | #endif 2267 | #ifdef EPIPE 2268 | {"EPIPE", NULL, EPIPE, CONST_NUMBER}, 2269 | #endif 2270 | #ifdef ELIBEXEC 2271 | {"ELIBEXEC", NULL, ELIBEXEC, CONST_NUMBER}, 2272 | #endif 2273 | #ifdef ENFILE 2274 | {"ENFILE", NULL, ENFILE, CONST_NUMBER}, 2275 | #endif 2276 | #ifdef ENOMEDIUM 2277 | {"ENOMEDIUM", NULL, ENOMEDIUM, CONST_NUMBER}, 2278 | #endif 2279 | #ifdef EREMOTE 2280 | {"EREMOTE", NULL, EREMOTE, CONST_NUMBER}, 2281 | #endif 2282 | #ifdef ESPIPE 2283 | {"ESPIPE", NULL, ESPIPE, CONST_NUMBER}, 2284 | #endif 2285 | #ifdef EBADFD 2286 | {"EBADFD", NULL, EBADFD, CONST_NUMBER}, 2287 | #endif 2288 | #ifdef ENOENT 2289 | {"ENOENT", NULL, ENOENT, CONST_NUMBER}, 2290 | #endif 2291 | #ifdef EBADMSG 2292 | {"EBADMSG", NULL, EBADMSG, CONST_NUMBER}, 2293 | #endif 2294 | #ifdef ENOTCONN 2295 | {"ENOTCONN", NULL, ENOTCONN, CONST_NUMBER}, 2296 | #endif 2297 | #ifdef ENOPKG 2298 | {"ENOPKG", NULL, ENOPKG, CONST_NUMBER}, 2299 | #endif 2300 | #ifdef EACCES 2301 | {"EACCES", NULL, EACCES, CONST_NUMBER}, 2302 | #endif 2303 | #ifdef EL3HLT 2304 | {"EL3HLT", NULL, EL3HLT, CONST_NUMBER}, 2305 | #endif 2306 | #ifdef EL2NSYNC 2307 | {"EL2NSYNC", NULL, EL2NSYNC, CONST_NUMBER}, 2308 | #endif 2309 | #ifdef EDEADLOCK 2310 | {"EDEADLOCK", NULL, EDEADLOCK, CONST_NUMBER}, 2311 | #endif 2312 | #ifdef ENOTEMPTY 2313 | {"ENOTEMPTY", NULL, ENOTEMPTY, CONST_NUMBER}, 2314 | #endif 2315 | #ifdef ERESTART 2316 | {"ERESTART", NULL, ERESTART, CONST_NUMBER}, 2317 | #endif 2318 | #ifdef EILSEQ 2319 | {"EILSEQ", NULL, EILSEQ, CONST_NUMBER}, 2320 | #endif 2321 | #ifdef EKEYREJECTED 2322 | {"EKEYREJECTED", NULL, EKEYREJECTED, CONST_NUMBER}, 2323 | #endif 2324 | #ifdef EDEADLK 2325 | {"EDEADLK", NULL, EDEADLK, CONST_NUMBER}, 2326 | #endif 2327 | #ifdef EBADF 2328 | {"EBADF", NULL, EBADF, CONST_NUMBER}, 2329 | #endif 2330 | #ifdef ECHILD 2331 | {"ECHILD", NULL, ECHILD, CONST_NUMBER}, 2332 | #endif 2333 | #ifdef EALREADY 2334 | {"EALREADY", NULL, EALREADY, CONST_NUMBER}, 2335 | #endif 2336 | #ifdef ENETDOWN 2337 | {"ENETDOWN", NULL, ENETDOWN, CONST_NUMBER}, 2338 | #endif 2339 | #ifdef ENOLCK 2340 | {"ENOLCK", NULL, ENOLCK, CONST_NUMBER}, 2341 | #endif 2342 | #ifdef ENOTSOCK 2343 | {"ENOTSOCK", NULL, ENOTSOCK, CONST_NUMBER}, 2344 | #endif 2345 | #ifdef ELIBSCN 2346 | {"ELIBSCN", NULL, ELIBSCN, CONST_NUMBER}, 2347 | #endif 2348 | #ifdef ENAMETOOLONG 2349 | {"ENAMETOOLONG", NULL, ENAMETOOLONG, CONST_NUMBER}, 2350 | #endif 2351 | #ifdef EBFONT 2352 | {"EBFONT", NULL, EBFONT, CONST_NUMBER}, 2353 | #endif 2354 | #ifdef ETXTBSY 2355 | {"ETXTBSY", NULL, ETXTBSY, CONST_NUMBER}, 2356 | #endif 2357 | #ifdef EAFNOSUPPORT 2358 | {"EAFNOSUPPORT", NULL, EAFNOSUPPORT, CONST_NUMBER}, 2359 | #endif 2360 | #ifdef EADV 2361 | {"EADV", NULL, EADV, CONST_NUMBER}, 2362 | #endif 2363 | #ifdef EUSERS 2364 | {"EUSERS", NULL, EUSERS, CONST_NUMBER}, 2365 | #endif 2366 | #ifdef ENOKEY 2367 | {"ENOKEY", NULL, ENOKEY, CONST_NUMBER}, 2368 | #endif 2369 | #ifdef ETIME 2370 | {"ETIME", NULL, ETIME, CONST_NUMBER}, 2371 | #endif 2372 | #ifdef EBADR 2373 | {"EBADR", NULL, EBADR, CONST_NUMBER}, 2374 | #endif 2375 | #ifdef ERFKILL 2376 | {"ERFKILL", NULL, ERFKILL, CONST_NUMBER}, 2377 | #endif 2378 | #ifdef ECONNABORTED 2379 | {"ECONNABORTED", NULL, ECONNABORTED, CONST_NUMBER}, 2380 | #endif 2381 | #ifdef EREMOTEIO 2382 | {"EREMOTEIO", NULL, EREMOTEIO, CONST_NUMBER}, 2383 | #endif 2384 | #ifdef EIDRM 2385 | {"EIDRM", NULL, EIDRM, CONST_NUMBER}, 2386 | #endif 2387 | #ifdef ENOTTY 2388 | {"ENOTTY", NULL, ENOTTY, CONST_NUMBER}, 2389 | #endif 2390 | #ifdef ECONNRESET 2391 | {"ECONNRESET", NULL, ECONNRESET, CONST_NUMBER}, 2392 | #endif 2393 | #ifdef EADDRINUSE 2394 | {"EADDRINUSE", NULL, EADDRINUSE, CONST_NUMBER}, 2395 | #endif 2396 | #ifdef EKEYREVOKED 2397 | {"EKEYREVOKED", NULL, EKEYREVOKED, CONST_NUMBER}, 2398 | #endif 2399 | #ifdef ENOMEM 2400 | {"ENOMEM", NULL, ENOMEM, CONST_NUMBER}, 2401 | #endif 2402 | #ifdef EOWNERDEAD 2403 | {"EOWNERDEAD", NULL, EOWNERDEAD, CONST_NUMBER}, 2404 | #endif 2405 | #ifdef EROFS 2406 | {"EROFS", NULL, EROFS, CONST_NUMBER}, 2407 | #endif 2408 | #ifdef EMEDIUMTYPE 2409 | {"EMEDIUMTYPE", NULL, EMEDIUMTYPE, CONST_NUMBER}, 2410 | #endif 2411 | #ifdef ENOSPC 2412 | {"ENOSPC", NULL, ENOSPC, CONST_NUMBER}, 2413 | #endif 2414 | #ifdef ESRMNT 2415 | {"ESRMNT", NULL, ESRMNT, CONST_NUMBER}, 2416 | #endif 2417 | #ifdef ENOBUFS 2418 | {"ENOBUFS", NULL, ENOBUFS, CONST_NUMBER}, 2419 | #endif 2420 | #ifdef EINTR 2421 | {"EINTR", NULL, EINTR, CONST_NUMBER}, 2422 | #endif 2423 | #ifdef ENOMSG 2424 | {"ENOMSG", NULL, ENOMSG, CONST_NUMBER}, 2425 | #endif 2426 | #ifdef ENOCSI 2427 | {"ENOCSI", NULL, ENOCSI, CONST_NUMBER}, 2428 | #endif 2429 | #ifdef EPERM 2430 | {"EPERM", NULL, EPERM, CONST_NUMBER}, 2431 | #endif 2432 | #ifdef ENOSR 2433 | {"ENOSR", NULL, ENOSR, CONST_NUMBER}, 2434 | #endif 2435 | #ifdef EREMCHG 2436 | {"EREMCHG", NULL, EREMCHG, CONST_NUMBER}, 2437 | #endif 2438 | #ifdef EPFNOSUPPORT 2439 | {"EPFNOSUPPORT", NULL, EPFNOSUPPORT, CONST_NUMBER}, 2440 | #endif 2441 | #ifdef EL3RST 2442 | {"EL3RST", NULL, EL3RST, CONST_NUMBER}, 2443 | #endif 2444 | #ifdef EMULTIHOP 2445 | {"EMULTIHOP", NULL, EMULTIHOP, CONST_NUMBER}, 2446 | #endif 2447 | #ifdef EAGAIN 2448 | {"EAGAIN", NULL, EAGAIN, CONST_NUMBER}, 2449 | #endif 2450 | #ifdef ENODEV 2451 | {"ENODEV", NULL, ENODEV, CONST_NUMBER}, 2452 | #endif 2453 | #ifdef ELIBBAD 2454 | {"ELIBBAD", NULL, ELIBBAD, CONST_NUMBER}, 2455 | #endif 2456 | #ifdef ENOSTR 2457 | {"ENOSTR", NULL, ENOSTR, CONST_NUMBER}, 2458 | #endif 2459 | #ifdef ELOOP 2460 | {"ELOOP", NULL, ELOOP, CONST_NUMBER}, 2461 | #endif 2462 | #ifdef ECONNREFUSED 2463 | {"ECONNREFUSED", NULL, ECONNREFUSED, CONST_NUMBER}, 2464 | #endif 2465 | #ifdef ENOPROTOOPT 2466 | {"ENOPROTOOPT", NULL, ENOPROTOOPT, CONST_NUMBER}, 2467 | #endif 2468 | #ifdef ETIMEDOUT 2469 | {"ETIMEDOUT", NULL, ETIMEDOUT, CONST_NUMBER}, 2470 | #endif 2471 | #ifdef EUCLEAN 2472 | {"EUCLEAN", NULL, EUCLEAN, CONST_NUMBER}, 2473 | #endif 2474 | #ifdef ESOCKTNOSUPPORT 2475 | {"ESOCKTNOSUPPORT", NULL, ESOCKTNOSUPPORT, CONST_NUMBER}, 2476 | #endif 2477 | #ifdef ETOOMANYREFS 2478 | {"ETOOMANYREFS", NULL, ETOOMANYREFS, CONST_NUMBER}, 2479 | #endif 2480 | #ifdef EOVERFLOW 2481 | {"EOVERFLOW", NULL, EOVERFLOW, CONST_NUMBER}, 2482 | #endif 2483 | #ifdef EINPROGRESS 2484 | {"EINPROGRESS", NULL, EINPROGRESS, CONST_NUMBER}, 2485 | #endif 2486 | #ifdef ENOTDIR 2487 | {"ENOTDIR", NULL, ENOTDIR, CONST_NUMBER}, 2488 | #endif 2489 | #ifdef EKEYEXPIRED 2490 | {"EKEYEXPIRED", NULL, EKEYEXPIRED, CONST_NUMBER}, 2491 | #endif 2492 | #ifdef E2BIG 2493 | {"E2BIG", NULL, E2BIG, CONST_NUMBER}, 2494 | #endif 2495 | #ifdef ECHRNG 2496 | {"ECHRNG", NULL, ECHRNG, CONST_NUMBER}, 2497 | #endif 2498 | #ifdef EBADSLT 2499 | {"EBADSLT", NULL, EBADSLT, CONST_NUMBER}, 2500 | #endif 2501 | #ifdef ECANCELED 2502 | {"ECANCELED", NULL, ECANCELED, CONST_NUMBER}, 2503 | #endif 2504 | #ifdef ENOTRECOVERABLE 2505 | {"ENOTRECOVERABLE", NULL, ENOTRECOVERABLE, CONST_NUMBER}, 2506 | #endif 2507 | #ifdef ERANGE 2508 | {"ERANGE", NULL, ERANGE, CONST_NUMBER}, 2509 | #endif 2510 | #ifdef ENOSYS 2511 | {"ENOSYS", NULL, ENOSYS, CONST_NUMBER}, 2512 | #endif 2513 | #ifdef EXFULL 2514 | {"EXFULL", NULL, EXFULL, CONST_NUMBER}, 2515 | #endif 2516 | #ifdef EISNAM 2517 | {"EISNAM", NULL, EISNAM, CONST_NUMBER}, 2518 | #endif 2519 | #ifdef ENOTUNIQ 2520 | {"ENOTUNIQ", NULL, ENOTUNIQ, CONST_NUMBER}, 2521 | #endif 2522 | #ifdef ENXIO 2523 | {"ENXIO", NULL, ENXIO, CONST_NUMBER}, 2524 | #endif 2525 | #ifdef ESTALE 2526 | {"ESTALE", NULL, ESTALE, CONST_NUMBER}, 2527 | #endif 2528 | #ifdef EPROTOTYPE 2529 | {"EPROTOTYPE", NULL, EPROTOTYPE, CONST_NUMBER}, 2530 | #endif 2531 | #ifdef ENOTNAM 2532 | {"ENOTNAM", NULL, ENOTNAM, CONST_NUMBER}, 2533 | #endif 2534 | #ifdef ESTRPIPE 2535 | {"ESTRPIPE", NULL, ESTRPIPE, CONST_NUMBER}, 2536 | #endif 2537 | #ifdef EMSGSIZE 2538 | {"EMSGSIZE", NULL, EMSGSIZE, CONST_NUMBER}, 2539 | #endif 2540 | #ifdef ELIBACC 2541 | {"ELIBACC", NULL, ELIBACC, CONST_NUMBER}, 2542 | #endif 2543 | #ifdef EHOSTUNREACH 2544 | {"EHOSTUNREACH", NULL, EHOSTUNREACH, CONST_NUMBER}, 2545 | #endif 2546 | #ifdef EDOM 2547 | {"EDOM", NULL, EDOM, CONST_NUMBER}, 2548 | #endif 2549 | #ifdef EMLINK 2550 | {"EMLINK", NULL, EMLINK, CONST_NUMBER}, 2551 | #endif 2552 | #ifdef ESHUTDOWN 2553 | {"ESHUTDOWN", NULL, ESHUTDOWN, CONST_NUMBER}, 2554 | #endif 2555 | #ifdef EHOSTDOWN 2556 | {"EHOSTDOWN", NULL, EHOSTDOWN, CONST_NUMBER}, 2557 | #endif 2558 | #ifdef EPROTO 2559 | {"EPROTO", NULL, EPROTO, CONST_NUMBER}, 2560 | #endif 2561 | #ifdef ENONET 2562 | {"ENONET", NULL, ENONET, CONST_NUMBER}, 2563 | #endif 2564 | #ifdef EADDRNOTAVAIL 2565 | {"EADDRNOTAVAIL", NULL, EADDRNOTAVAIL, CONST_NUMBER}, 2566 | #endif 2567 | #ifdef ENODATA 2568 | {"ENODATA", NULL, ENODATA, CONST_NUMBER}, 2569 | #endif 2570 | #ifdef ECOMM 2571 | {"ECOMM", NULL, ECOMM, CONST_NUMBER}, 2572 | #endif 2573 | #ifdef EPROTONOSUPPORT 2574 | {"EPROTONOSUPPORT", NULL, EPROTONOSUPPORT, CONST_NUMBER}, 2575 | #endif 2576 | #ifdef EISCONN 2577 | {"EISCONN", NULL, EISCONN, CONST_NUMBER}, 2578 | #endif 2579 | #ifdef EBADE 2580 | {"EBADE", NULL, EBADE, CONST_NUMBER}, 2581 | #endif 2582 | #ifdef EINVAL 2583 | {"EINVAL", NULL, EINVAL, CONST_NUMBER}, 2584 | #endif 2585 | #ifdef ENETRESET 2586 | {"ENETRESET", NULL, ENETRESET, CONST_NUMBER}, 2587 | #endif 2588 | #ifdef ENETUNREACH 2589 | {"ENETUNREACH", NULL, ENETUNREACH, CONST_NUMBER}, 2590 | #endif 2591 | #ifdef ENOLINK 2592 | {"ENOLINK", NULL, ENOLINK, CONST_NUMBER}, 2593 | #endif 2594 | #ifdef EWOULDBLOCK 2595 | {"EWOULDBLOCK", NULL, EWOULDBLOCK, CONST_NUMBER}, 2596 | #endif 2597 | #ifdef ENOANO 2598 | {"ENOANO", NULL, ENOANO, CONST_NUMBER}, 2599 | #endif 2600 | #ifdef EFAULT 2601 | {"EFAULT", NULL, EFAULT, CONST_NUMBER}, 2602 | #endif 2603 | #ifdef EDESTADDRREQ 2604 | {"EDESTADDRREQ", NULL, EDESTADDRREQ, CONST_NUMBER}, 2605 | #endif 2606 | #ifdef ELIBMAX 2607 | {"ELIBMAX", NULL, ELIBMAX, CONST_NUMBER}, 2608 | #endif 2609 | #ifdef EDOTDOT 2610 | {"EDOTDOT", NULL, EDOTDOT, CONST_NUMBER}, 2611 | #endif 2612 | #ifdef EBADRQC 2613 | {"EBADRQC", NULL, EBADRQC, CONST_NUMBER}, 2614 | #endif 2615 | #ifdef ESRCH 2616 | {"ESRCH", NULL, ESRCH, CONST_NUMBER}, 2617 | #endif 2618 | #ifdef EOPNOTSUPP 2619 | {"EOPNOTSUPP", NULL, EOPNOTSUPP, CONST_NUMBER}, 2620 | #endif 2621 | #ifdef EMFILE 2622 | {"EMFILE", NULL, EMFILE, CONST_NUMBER}, 2623 | #endif 2624 | #ifdef EL2HLT 2625 | {"EL2HLT", NULL, EL2HLT, CONST_NUMBER}, 2626 | #endif 2627 | #ifdef ENOTBLK 2628 | {"ENOTBLK", NULL, ENOTBLK, CONST_NUMBER}, 2629 | #endif 2630 | #ifdef EUNATCH 2631 | {"EUNATCH", NULL, EUNATCH, CONST_NUMBER}, 2632 | #endif 2633 | #ifdef EXDEV 2634 | {"EXDEV", NULL, EXDEV, CONST_NUMBER}, 2635 | #endif 2636 | {NULL, NULL, 0.0 , 0} 2637 | }; 2638 | 2639 | static const reg_impl obj_Errors_implements[] = { 2640 | {NULL, NULL} 2641 | }; 2642 | 2643 | static const luaL_Reg obj_Epoller_pub_funcs[] = { 2644 | {"new", Epoller__new__meth}, 2645 | {NULL, NULL} 2646 | }; 2647 | 2648 | static const luaL_Reg obj_Epoller_methods[] = { 2649 | {"close", Epoller__close__meth}, 2650 | {"add", Epoller__add__meth}, 2651 | {"mod", Epoller__mod__meth}, 2652 | {"del", Epoller__del__meth}, 2653 | {"wait", Epoller__wait__meth}, 2654 | {"wait_callback", Epoller__wait_callback__meth}, 2655 | {NULL, NULL} 2656 | }; 2657 | 2658 | static const luaL_Reg obj_Epoller_metas[] = { 2659 | {"__gc", Epoller__close__meth}, 2660 | {"__tostring", obj_udata_default_tostring}, 2661 | {"__eq", obj_udata_default_equal}, 2662 | {NULL, NULL} 2663 | }; 2664 | 2665 | static const obj_base obj_Epoller_bases[] = { 2666 | {-1, NULL} 2667 | }; 2668 | 2669 | static const obj_field obj_Epoller_fields[] = { 2670 | {NULL, 0, 0, 0} 2671 | }; 2672 | 2673 | static const obj_const obj_Epoller_constants[] = { 2674 | {NULL, NULL, 0.0 , 0} 2675 | }; 2676 | 2677 | static const reg_impl obj_Epoller_implements[] = { 2678 | {NULL, NULL} 2679 | }; 2680 | 2681 | static const luaL_Reg epoll_function[] = { 2682 | {"new", epoll__new__func}, 2683 | {NULL, NULL} 2684 | }; 2685 | 2686 | static const obj_const epoll_constants[] = { 2687 | #ifdef EPOLLERR 2688 | {"EPOLLERR", NULL, EPOLLERR, CONST_NUMBER}, 2689 | #endif 2690 | #ifdef EPOLLIN 2691 | {"EPOLLIN", NULL, EPOLLIN, CONST_NUMBER}, 2692 | #endif 2693 | #ifdef EPOLLONESHOT 2694 | {"EPOLLONESHOT", NULL, EPOLLONESHOT, CONST_NUMBER}, 2695 | #endif 2696 | #ifdef EPOLLOUT 2697 | {"EPOLLOUT", NULL, EPOLLOUT, CONST_NUMBER}, 2698 | #endif 2699 | #ifdef EPOLLET 2700 | {"EPOLLET", NULL, EPOLLET, CONST_NUMBER}, 2701 | #endif 2702 | #ifdef EPOLLPRI 2703 | {"EPOLLPRI", NULL, EPOLLPRI, CONST_NUMBER}, 2704 | #endif 2705 | #ifdef EPOLLRDHUP 2706 | {"EPOLLRDHUP", NULL, EPOLLRDHUP, CONST_NUMBER}, 2707 | #endif 2708 | {NULL, NULL, 0.0 , 0} 2709 | }; 2710 | 2711 | 2712 | 2713 | static const reg_sub_module reg_sub_modules[] = { 2714 | { &(obj_type_Errors), REG_META, obj_Errors_pub_funcs, obj_Errors_methods, obj_Errors_metas, NULL, NULL, obj_Errors_constants, NULL, 1}, 2715 | { &(obj_type_Epoller), REG_OBJECT, obj_Epoller_pub_funcs, obj_Epoller_methods, obj_Epoller_metas, obj_Epoller_bases, obj_Epoller_fields, obj_Epoller_constants, obj_Epoller_implements, 0}, 2716 | {NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0} 2717 | }; 2718 | 2719 | 2720 | 2721 | 2722 | 2723 | #if LUAJIT_FFI 2724 | static const ffi_export_symbol epoll_ffi_export[] = { 2725 | {NULL, { NULL } } 2726 | }; 2727 | #endif 2728 | 2729 | 2730 | 2731 | 2732 | static const luaL_Reg submodule_libs[] = { 2733 | {NULL, NULL} 2734 | }; 2735 | 2736 | 2737 | 2738 | static void create_object_instance_cache(lua_State *L) { 2739 | lua_pushlightuserdata(L, obj_udata_weak_ref_key); /* key for weak table. */ 2740 | lua_rawget(L, LUA_REGISTRYINDEX); /* check if weak table exists already. */ 2741 | if(!lua_isnil(L, -1)) { 2742 | lua_pop(L, 1); /* pop weak table. */ 2743 | return; 2744 | } 2745 | lua_pop(L, 1); /* pop nil. */ 2746 | /* create weak table for object instance references. */ 2747 | lua_pushlightuserdata(L, obj_udata_weak_ref_key); /* key for weak table. */ 2748 | lua_newtable(L); /* weak table. */ 2749 | lua_newtable(L); /* metatable for weak table. */ 2750 | lua_pushliteral(L, "__mode"); 2751 | lua_pushliteral(L, "v"); 2752 | lua_rawset(L, -3); /* metatable.__mode = 'v' weak values. */ 2753 | lua_setmetatable(L, -2); /* add metatable to weak table. */ 2754 | lua_rawset(L, LUA_REGISTRYINDEX); /* create reference to weak table. */ 2755 | } 2756 | 2757 | LUA_NOBJ_API int luaopen_epoll(lua_State *L) { 2758 | const reg_sub_module *reg = reg_sub_modules; 2759 | const luaL_Reg *submodules = submodule_libs; 2760 | int priv_table = -1; 2761 | 2762 | /* register interfaces */ 2763 | obj_register_interfaces(L, obj_interfaces); 2764 | 2765 | /* private table to hold reference to object metatables. */ 2766 | lua_newtable(L); 2767 | priv_table = lua_gettop(L); 2768 | lua_pushlightuserdata(L, obj_udata_private_key); 2769 | lua_pushvalue(L, priv_table); 2770 | lua_rawset(L, LUA_REGISTRYINDEX); /* store private table in registry. */ 2771 | 2772 | /* create object cache. */ 2773 | create_object_instance_cache(L); 2774 | 2775 | /* module table. */ 2776 | #if REG_MODULES_AS_GLOBALS 2777 | luaL_register(L, "epoll", epoll_function); 2778 | #else 2779 | lua_newtable(L); 2780 | nobj_setfuncs(L, epoll_function, 0); 2781 | #endif 2782 | 2783 | /* register module constants. */ 2784 | obj_type_register_constants(L, epoll_constants, -1, 0); 2785 | 2786 | for(; submodules->func != NULL ; submodules++) { 2787 | lua_pushcfunction(L, submodules->func); 2788 | lua_pushstring(L, submodules->name); 2789 | lua_call(L, 1, 0); 2790 | } 2791 | 2792 | /* register objects */ 2793 | for(; reg->type != NULL ; reg++) { 2794 | lua_newtable(L); /* create public API table for object. */ 2795 | lua_pushvalue(L, -1); /* dup. object's public API table. */ 2796 | lua_setfield(L, -3, reg->type->name); /* module[""] = */ 2797 | #if REG_OBJECTS_AS_GLOBALS 2798 | lua_pushvalue(L, -1); /* dup value. */ 2799 | lua_setglobal(L, reg->type->name); /* global: = */ 2800 | #endif 2801 | obj_type_register(L, reg, priv_table); 2802 | } 2803 | 2804 | #if LUAJIT_FFI 2805 | if(nobj_check_ffi_support(L)) { 2806 | nobj_try_loading_ffi(L, "epoll.nobj.ffi.lua", epoll_ffi_lua_code, 2807 | epoll_ffi_export, priv_table); 2808 | } 2809 | #endif 2810 | 2811 | /* Cache reference to epoll.Errors table for errno->string convertion. */ 2812 | lua_pushlightuserdata(L, epoll_Errors_key); 2813 | lua_getfield(L, -2, "Errors"); 2814 | lua_rawset(L, LUA_REGISTRYINDEX); 2815 | 2816 | 2817 | 2818 | return 1; 2819 | } 2820 | 2821 | 2822 | -------------------------------------------------------------------------------- /tests/test_epoll.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2013 Robert G. Jakabosky 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in 11 | -- all copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | -- THE SOFTWARE. 20 | 21 | local epoll = require"epoll" 22 | 23 | local poller = epoll.new() 24 | 25 | -- stdin 26 | assert(poller:add(0, epoll.EPOLLIN, 0)) 27 | 28 | -- stdout 29 | assert(poller:add(1, epoll.EPOLLOUT, 1)) 30 | 31 | local fds = { } 32 | 33 | assert(poller:wait_callback(function(fd, ev) 34 | print("EPOLL: event for fd=", fd, ' event=', ev) 35 | fds[fd] = ev 36 | end, 1000)) 37 | 38 | assert(fds[0] ~= nil, "Failed to get event for stdin") 39 | assert(fds[1] ~= nil, "Failed to get event for stdout") 40 | 41 | assert(poller:del(0)) 42 | assert(poller:del(1)) 43 | 44 | poller:close() 45 | 46 | --------------------------------------------------------------------------------