From 09c13aa2fdf3b2f05986e121cc182a63b4956031 Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Wed, 30 Nov 2011 08:28:03 -0800 Subject: [PATCH] Use table to cache Error number to string conversion. --- src/error.nobj.lua | 274 ++++++++++++++++++++++++++++++++++++++++++++- zmq.nobj.lua | 37 ------ 2 files changed, 269 insertions(+), 42 deletions(-) diff --git a/src/error.nobj.lua b/src/error.nobj.lua index 4e353f3..8797281 100644 --- a/src/error.nobj.lua +++ b/src/error.nobj.lua @@ -18,26 +18,290 @@ -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. +-- E* error values. +meta_object "ZErrors" { + export_definitions { + -- Native 0MQ error codes. + "EFSM", + "ENOCOMPATPROTO", + "ETERM", + "EMTHREAD", + + "EPERM", -- Operation not permitted + "ENOENT", -- No such file or directory + "ESRCH", -- No such process + "EINTR", -- Interrupted system call + "EIO", -- I/O error + "ENXIO", -- No such device or address + "E2BIG", -- Argument list too long + "ENOEXEC", -- Exec format error + "EBADF", -- Bad file number + "ECHILD", -- No child processes + "EAGAIN", -- Try again + "ENOMEM", -- Out of memory + "EACCES", -- Permission denied + "EFAULT", -- Bad address + "ENOTBLK", -- Block device required + "EBUSY", -- Device or resource busy + "EEXIST", -- File exists + "EXDEV", -- Cross-device link + "ENODEV", -- No such device + "ENOTDIR", -- Not a directory + "EISDIR", -- Is a directory + "EINVAL", -- Invalid argument + "ENFILE", -- File table overflow + "EMFILE", -- Too many open files + "ENOTTY", -- Not a typewriter + "ETXTBSY", -- Text file busy + "EFBIG", -- File too large + "ENOSPC", -- No space left on device + "ESPIPE", -- Illegal seek + "EROFS", -- Read-only file system + "EMLINK", -- Too many links + "EPIPE", -- Broken pipe + "EDOM", -- Math argument out of domain of func + "ERANGE", -- Math result not representable + + "EDEADLK", -- Resource deadlock would occur + "EDEADLOCK", -- EDEADLK + "ENAMETOOLONG", -- File name too long + "ENOLCK", -- No record locks available + "ENOSYS", -- Function not implemented + "ENOTEMPTY", -- Directory not empty + "ELOOP", -- Too many symbolic links encountered + "EWOULDBLOCK", -- Operation would block + "ENOMSG", -- No message of desired type + "EIDRM", -- Identifier removed + "ECHRNG", -- Channel number out of range + "EL2NSYNC", -- Level 2 not synchronized + "EL3HLT", -- Level 3 halted + "EL3RST", -- Level 3 reset + "ELNRNG", -- Link number out of range + "EUNATCH", -- Protocol driver not attached + "ENOCSI", -- No CSI structure available + "EL2HLT", -- Level 2 halted + "EBADE", -- Invalid exchange + "EBADR", -- Invalid request descriptor + "EXFULL", -- Exchange full + "ENOANO", -- No anode + "EBADRQC", -- Invalid request code + "EBADSLT", -- Invalid slot + + "EBFONT", -- Bad font file format + "ENOSTR", -- Device not a stream + "ENODATA", -- No data available + "ETIME", -- Timer expired + "ENOSR", -- Out of streams resources + "ENONET", -- Machine is not on the network + "ENOPKG", -- Package not installed + "EREMOTE", -- Object is remote + "ENOLINK", -- Link has been severed + "EADV", -- Advertise error + "ESRMNT", -- Srmount error + "ECOMM", -- Communication error on send + "EPROTO", -- Protocol error + "EMULTIHOP", -- Multihop attempted + "EDOTDOT", -- RFS specific error + "EBADMSG", -- Not a data message + "EOVERFLOW", -- Value too large for defined data type + "ENOTUNIQ", -- Name not unique on network + "EBADFD", -- File descriptor in bad state + "EREMCHG", -- Remote address changed + "ELIBACC", -- Can not access a needed shared library + "ELIBBAD", -- Accessing a corrupted shared library + "ELIBSCN", -- .lib section in a.out corrupted + "ELIBMAX", -- Attempting to link in too many shared libraries + "ELIBEXEC", -- Cannot exec a shared library directly + "EILSEQ", -- Illegal byte sequence + "ERESTART", -- Interrupted system call should be restarted + "ESTRPIPE", -- Streams pipe error + "EUSERS", -- Too many users + "ENOTSOCK", -- Socket operation on non-socket + "EDESTADDRREQ", -- Destination address required + "EMSGSIZE", -- Message too long + "EPROTOTYPE", -- Protocol wrong type for socket + "ENOPROTOOPT", -- Protocol not available + "EPROTONOSUPPORT", -- Protocol not supported + "ESOCKTNOSUPPORT", -- Socket type not supported + "EOPNOTSUPP", -- Operation not supported on transport endpoint + "EPFNOSUPPORT", -- Protocol family not supported + "EAFNOSUPPORT", -- Address family not supported by protocol + "EADDRINUSE", -- Address already in use + "EADDRNOTAVAIL", -- Cannot assign requested address + "ENETDOWN", -- Network is down + "ENETUNREACH", -- Network is unreachable + "ENETRESET", -- Network dropped connection because of reset + "ECONNABORTED", -- Software caused connection abort + "ECONNRESET", -- Connection reset by peer + "ENOBUFS", -- No buffer space available + "EISCONN", -- Transport endpoint is already connected + "ENOTCONN", -- Transport endpoint is not connected + "ESHUTDOWN", -- Cannot send after transport endpoint shutdown + "ETOOMANYREFS", -- Too many references: cannot splice + "ETIMEDOUT", -- Connection timed out + "ECONNREFUSED", -- Connection refused + "EHOSTDOWN", -- Host is down + "EHOSTUNREACH", -- No route to host + "EALREADY", -- Operation already in progress + "EINPROGRESS", -- Operation now in progress + "ESTALE", -- Stale NFS file handle + "EUCLEAN", -- Structure needs cleaning + "ENOTNAM", -- Not a XENIX named type file + "ENAVAIL", -- No XENIX semaphores available + "EISNAM", -- Is a named type file + "EREMOTEIO", -- Remote I/O error + "EDQUOT", -- Quota exceeded + + "ENOMEDIUM", -- No medium found + "EMEDIUMTYPE", -- Wrong medium type + "ECANCELED", -- Operation Canceled + "ENOKEY", -- Required key not available + "EKEYEXPIRED", -- Key has expired + "EKEYREVOKED", -- Key has been revoked + "EKEYREJECTED", -- Key was rejected by service + + -- for robust mutexes + "EOWNERDEAD", -- Owner died + "ENOTRECOVERABLE", -- State not recoverable + + "ERFKILL", -- Operation not possible due to RF-kill + }, + + method "description" { + var_in{ "", "err" }, + var_out{ "const char *", "msg" }, + c_source "pre" [[ + int err_type; + int err_num = -1; +]], + c_source[[ + err_type = lua_type(L, ${err::idx}); + if(err_type == LUA_TSTRING) { + lua_pushvalue(L, ${err::idx}); + lua_rawget(L, ${this::idx}); + if(lua_isnumber(L, -1)) { + err_num = lua_tointeger(L, -1); + } + lua_pop(L, 1); + } else if(err_type == LUA_TNUMBER) { + err_num = lua_tointeger(L, ${err::idx}); + } else { + return luaL_argerror(L, ${err::idx}, "expected string/number"); + } + if(err_num < 0) { + lua_pushnil(L); + lua_pushliteral(L, "UNKNOWN ERROR"); + return 2; + } + ${msg} = strerror(err_num); +]], + }, + + method "__index" { + var_in{ "int", "err" }, + var_out{ "const char *", "msg" }, + c_source[[ + switch(${err}) { + case EAGAIN: + ${msg} = "timeout"; + break; + case EINTR: + ${msg} = "interrupted"; + break; +#if defined(ETERM) + case ETERM: + ${msg} = "closed"; + break; +#endif + default: + ${msg} = zmq_strerror(${err}); + break; + } + lua_pushvalue(L, ${err::idx}); + lua_pushstring(L, ${msg}); + lua_rawset(L, ${this::idx}); +]], + }, +} + +ffi_source "ffi_src" [[ +-- get ZErrors table to map errno to error name. +local ZError_names = _M.ZErrors + +local function get_zmq_strerror() + return ZError_names[C.zmq_errno()] +end +]] + +ffi_source "ffi_src" [[ +]] + +c_source "extra_code" [[ +static char *zmq_ZErrors_key = "zmq_ZErrors_key"; +/* + * This wrapper function is to make the EAGAIN/ETERM error messages more like + * what is returned by LuaSocket. + */ +static const char *get_zmq_strerror() { + int err = zmq_errno(); + switch(err) { + case EAGAIN: + return "timeout"; + break; + case EINTR: + return "interrupted"; + break; +#if defined(ETERM) + case ETERM: + return "closed"; + break; +#endif + default: + break; + } + return zmq_strerror(err); +} + +]] + +c_source "module_init_src" [[ + /* Cache reference to zmq.ZErrors table for errno->string convertion. */ + lua_pushlightuserdata(L, zmq_ZErrors_key); + lua_getfield(L, -2, "ZErrors"); + lua_rawset(L, LUA_REGISTRYINDEX); +]] + -- Convert ZMQ Error codes into strings. -- -- This is an error code wrapper object, it converts C-style 'int' return error code -- into Lua-style 'nil, "Error message"' return values. -- error_code "ZMQ_Error" "int" { - ffi_cdef[[ -typedef int ZMQ_Error; -]], + ffi_type = "int", is_error_check = function(rec) return "(-1 == ${" .. rec.name .. "})" end, ffi_is_error_check = function(rec) return "(-1 == ${" .. rec.name .. "})" end, default = "0", c_source [[ if(-1 == err) { - err_str = get_zmq_strerror(); + /* get ZErrors table. */ + lua_pushlightuserdata(L, zmq_ZErrors_key); + lua_rawget(L, LUA_REGISTRYINDEX); + /* convert zmq_errno to string. */ + lua_rawgeti(L, -1, zmq_errno()); + /* remove ZErrors table. */ + lua_remove(L, -2); + if(!lua_isnil(L, -1)) { + /* found error. */ + return; + } + /* Unknown error. */ + lua_pop(L, 1); + err_str = "UNKNOWN ERROR"; } ]], ffi_source [[ if(-1 == err) then - err_str = get_zmq_strerror(); + err_str = ZError_names[C.zmq_errno()] end ]], } diff --git a/zmq.nobj.lua b/zmq.nobj.lua index ad31b33..0d521bd 100644 --- a/zmq.nobj.lua +++ b/zmq.nobj.lua @@ -35,43 +35,6 @@ ffi_load { Windows = "libzmq", -- lib name for on windows. }, -c_source[[ -/* - * This wrapper function is to make the EAGAIN/ETERM error messages more like - * what is returned by LuaSocket. - */ -static const char *get_zmq_strerror() { - int err = zmq_errno(); - switch(err) { - case EAGAIN: - return "timeout"; - break; - case EINTR: - return "interrupted"; - break; -#if defined(ETERM) - case ETERM: - return "closed"; - break; -#endif - default: - break; - } - return zmq_strerror(err); -} - -]], - --- export helper function 'get_zmq_strerror' to FFI code. -ffi_export_function "const char *" "get_zmq_strerror" "()", -ffi_source[[ -local C_get_zmq_strerror = get_zmq_strerror --- make nicer wrapper for exported error function. -local function get_zmq_strerror() - return ffi.string(C_get_zmq_strerror()) -end -]], - -- -- Module constants --