├── .gitignore ├── COPYING ├── COPYING.LESSER ├── Makefile.in ├── PKGBUILD ├── README.markdown ├── bin ├── lem.c ├── libev.c ├── lua.c └── pool.c ├── config.guess ├── config.sub ├── configure ├── configure.ac ├── ev-config.h.in ├── include ├── lem-parsers.h └── lem.h ├── install-sh ├── lem.pc.in ├── lem ├── hathaway.lua ├── http.lua ├── http │ ├── client.lua │ ├── core.c │ ├── response.lua │ └── server.lua ├── io.lua ├── io │ ├── core.c │ ├── file.c │ ├── queue.lua │ ├── server.c │ ├── stream.c │ ├── tcp.c │ └── unix.c ├── lfs.lua ├── lfs │ └── core.c ├── parsers.lua ├── parsers │ └── core.c ├── queue.lua ├── repl.lua ├── signal.lua ├── signal │ └── core.c └── utils.c ├── libev ├── Changes ├── LICENSE ├── Makefile.am ├── Makefile.in ├── README ├── Symbols.ev ├── Symbols.event ├── aclocal.m4 ├── autogen.sh ├── compile ├── config.guess ├── config.h.in ├── config.sub ├── configure ├── configure.ac ├── depcomp ├── ev++.h ├── ev.3 ├── ev.c ├── ev.h ├── ev.pod ├── ev_epoll.c ├── ev_kqueue.c ├── ev_poll.c ├── ev_port.c ├── ev_select.c ├── ev_vars.h ├── ev_win32.c ├── ev_wrap.h ├── event.c ├── event.h ├── install-sh ├── libev.m4 ├── ltmain.sh ├── missing └── mkinstalldirs ├── lua ├── Makefile ├── lapi.c ├── lapi.h ├── lauxlib.c ├── lauxlib.h ├── lbaselib.c ├── lbitlib.c ├── lcode.c ├── lcode.h ├── lcorolib.c ├── lctype.c ├── lctype.h ├── ldblib.c ├── ldebug.c ├── ldebug.h ├── ldo.c ├── ldo.h ├── ldump.c ├── lfunc.c ├── lfunc.h ├── lgc.c ├── lgc.h ├── linit.c ├── liolib.c ├── llex.c ├── llex.h ├── llimits.h ├── lmathlib.c ├── lmem.c ├── lmem.h ├── loadlib.c ├── lobject.c ├── lobject.h ├── lopcodes.c ├── lopcodes.h ├── loslib.c ├── lparser.c ├── lparser.h ├── lprefix.h ├── lstate.c ├── lstate.h ├── lstring.c ├── lstring.h ├── lstrlib.c ├── ltable.c ├── ltable.h ├── ltablib.c ├── ltm.c ├── ltm.h ├── lua.c ├── lua.h ├── lua.hpp ├── luac.c ├── luaconf.h.in ├── lualib.h ├── lundump.c ├── lundump.h ├── lutf8lib.c ├── lvm.c ├── lvm.h ├── lzio.c └── lzio.h └── test ├── ctest.lua ├── download.lua ├── fclose.lua ├── fread.lua ├── fwrite.lua ├── hathawaytest.lua ├── httptest.lua ├── lfs.lua ├── lines.lua ├── multiplexing.lua ├── popen.lua ├── queue.lua ├── signal.lua ├── sleep.lua ├── stest.lua ├── test.lua └── test2.lua /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | bin/lem 4 | lua/luaconf.h 5 | libev/ev-config.h 6 | lem.pc 7 | config.status 8 | config.log 9 | Makefile 10 | aclocal.m4 11 | autom4te.cache 12 | *.pkg.tar.* 13 | src/ 14 | pkg/ 15 | .*sw? 16 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | # @configure_input@ 2 | CC = @CC@ 3 | CFLAGS = @CFLAGS@ 4 | CPPFLAGS = @CPPFLAGS@ 5 | CPPFLAGS += @CPPFLAGS_ADD@ 6 | LDFLAGS = @LDFLAGS@ 7 | SHARED = @SHARED@ 8 | LIBS = @LIBS@ 9 | 10 | INSTALL = @INSTALL@ 11 | SED = @SED@ 12 | STRIP = @STRIP@ 13 | 14 | prefix = @prefix@ 15 | exec_prefix = @exec_prefix@ 16 | bindir = @bindir@ 17 | includedir = @includedir@ 18 | libdir = @libdir@ 19 | datarootdir = @datarootdir@ 20 | pkgconfigdir = @pkgconfigdir@ 21 | lmoddir = @lmoddir@ 22 | cmoddir = @cmoddir@ 23 | 24 | headers = @headers@ 25 | objects = @objects@ 26 | 27 | llibs = \ 28 | lem/repl.lua \ 29 | lem/parsers.lua \ 30 | lem/io.lua \ 31 | lem/io/queue.lua \ 32 | lem/signal.lua \ 33 | lem/lfs.lua \ 34 | lem/http.lua \ 35 | lem/http/response.lua \ 36 | lem/http/server.lua \ 37 | lem/http/client.lua \ 38 | lem/queue.lua \ 39 | lem/hathaway.lua 40 | 41 | clibs = \ 42 | lem/utils.so \ 43 | lem/parsers/core.so \ 44 | lem/io/core.so \ 45 | lem/signal/core.so \ 46 | lem/lfs/core.so \ 47 | lem/http/core.so 48 | 49 | ifdef V 50 | E=@\# 51 | Q= 52 | else 53 | E=@echo 54 | Q=@ 55 | endif 56 | 57 | .PHONY: all strip install clean 58 | 59 | all: CPPFLAGS += -DNDEBUG 60 | all: bin/lem lem.pc $(clibs) 61 | 62 | debug: bin/lem lem.pc $(clibs) 63 | 64 | bin/libev.o: CFLAGS += -w 65 | include/lem.h: lua/luaconf.h 66 | bin/lua.o: lua/luaconf.h 67 | bin/lem.o: include/lem.h bin/pool.c 68 | bin/lem.o: CPPFLAGS += -D'LEM_LDIR="$(lmoddir)/"' 69 | lem/io/core.so: include/lem-parsers.h \ 70 | lem/io/file.c \ 71 | lem/io/stream.c \ 72 | lem/io/server.c \ 73 | lem/io/unix.c \ 74 | lem/io/tcp.c 75 | lem/parsers/core.so: include/lem-parsers.h 76 | lem/http/core.so: include/lem-parsers.h 77 | 78 | %.o: %.c 79 | $E ' CC $@' 80 | $Q$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ 81 | 82 | bin/lem: $(objects) 83 | $E ' LD $@' 84 | $Q$(CC) $^ -o $@ -rdynamic $(LDFLAGS) $(LIBS) 85 | 86 | %.so: %.c include/lem.h 87 | $E ' CCLD $@' 88 | $Q$(CC) $(CFLAGS) $(CPPFLAGS) -fPIC -nostartfiles $(SHARED) $< -o $@ $(LDFLAGS) 89 | 90 | lua/luaconf.h: lua/luaconf.h.in 91 | $E ' SED > $@' 92 | $Q$(SED) \ 93 | -e 's|@lmoddir[@]|$(lmoddir)|' \ 94 | -e 's|@cmoddir[@]|$(cmoddir)|' \ 95 | $< > $@ 96 | 97 | lem.pc: lem.pc.in 98 | $E ' SED > $@' 99 | $Q$(SED) \ 100 | -e 's|@lmoddir[@]|$(lmoddir)|' \ 101 | -e 's|@cmoddir[@]|$(cmoddir)|' \ 102 | -e 's|@includedir[@]|$(includedir)|' \ 103 | -e 's|@Lua_CFLAGS[@]|@Lua_CFLAGS@|' \ 104 | $< > $@ 105 | 106 | %-strip: % 107 | $E ' STRIP $<' 108 | $Q$(STRIP) $(STRIP_ARGS) $< 109 | 110 | strip: bin/lem-strip $(clibs:%=%-strip) 111 | 112 | $(DESTDIR)$(bindir)/%: bin/% 113 | $E ' INSTALL $@' 114 | $Q$(INSTALL) -d $(dir $@) 115 | $Q$(INSTALL) -m 755 $< $@ 116 | 117 | $(DESTDIR)$(includedir)/lem/%: lua/% 118 | $E ' INSTALL $@' 119 | $Q$(INSTALL) -d $(dir $@) 120 | $Q$(INSTALL) -m 644 $< $@ 121 | 122 | $(DESTDIR)$(includedir)/lem/%: libev/% 123 | $E ' INSTALL $@' 124 | $Q$(INSTALL) -d $(dir $@) 125 | $Q$(INSTALL) -m 644 $< $@ 126 | 127 | $(DESTDIR)$(includedir)/lem/%: include/% 128 | $E ' INSTALL $@' 129 | $Q$(INSTALL) -d $(dir $@) 130 | $Q$(INSTALL) -m 644 $< $@ 131 | 132 | $(DESTDIR)$(lmoddir)/% $(DESTDIR)$(cmoddir)/% $(DESTDIR)$(pkgconfigdir)/%: % 133 | $E ' INSTALL $@' 134 | $Q$(INSTALL) -d $(dir $@) 135 | $Q$(INSTALL) -m 644 $< $@ 136 | 137 | install: \ 138 | $(DESTDIR)$(bindir)/lem \ 139 | $(DESTDIR)$(pkgconfigdir)/lem.pc \ 140 | $(headers:%=$(DESTDIR)$(includedir)/lem/%) \ 141 | $(llibs:%=$(DESTDIR)$(lmoddir)/%) \ 142 | $(clibs:%=$(DESTDIR)$(cmoddir)/%) 143 | 144 | clean: 145 | rm -f bin/lem bin/*.o $(clibs) lua/luaconf.h lem.pc 146 | -------------------------------------------------------------------------------- /PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Emil Renner Berthing 2 | 3 | _lua='builtin' 4 | #_lua='lua' 5 | #_lua='lua5.1' # works, but not recommended 6 | #_lua='luajit' 7 | 8 | pkgname=lem 9 | pkgver=0.3 10 | pkgrel=1 11 | pkgdesc='A Lua Event Machine' 12 | arch=('i686' 'x86_64' 'armv5tel' 'armv7l') 13 | url='https://github.com/esmil/lem' 14 | license=('LGPL') 15 | case "$_lua" in 16 | builtin) depends=('glibc');; 17 | lua) depends=('lua');; 18 | lua5.1) depends=('lua51');; 19 | luajit) depends=('luajit');; 20 | esac 21 | source=() 22 | 23 | build() { 24 | cd "$startdir" 25 | 26 | ./configure --prefix=/usr --with-lua=$_lua 27 | make 28 | } 29 | 30 | package() { 31 | cd "$startdir" 32 | 33 | make DESTDIR="$pkgdir/" install 34 | } 35 | 36 | # vim:set ts=2 sw=2 et: 37 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | A Lua Event Machine 2 | =================== 3 | 4 | 5 | About 6 | ----- 7 | The Lua Event Machine is an attempt to make multitasking easier. 8 | It makes heavy use of Lua coroutines so code that does I/O 9 | can be suspended until data is ready. This allows you write code 10 | as if you're using blocking I/O, while still allowing code in other 11 | coroutines to run when you'd otherwise wait for I/O. 12 | 13 | Hovewer unlike traditional multithreading there is no need for locks since 14 | only one coroutine is running at a given time and you know exactly 15 | when control might switch to another coroutine. That is when you're 16 | doing I/O. 17 | 18 | Here is a minimal chat server: 19 | ```lua 20 | local io = require 'lem.io' 21 | local queue = require 'lem.io.queue' 22 | 23 | local socket = assert(io.tcp.listen('*', '5555')) 24 | local clients = {} 25 | 26 | socket:autospawn(function(client) 27 | client:write('What is your name?\r\n') 28 | local name = client:read('*l') 29 | if not name then 30 | client:close() 31 | return 32 | end 33 | name = name:match('[^\r]*') 34 | 35 | local self = queue.wrap(client) 36 | clients[self] = true 37 | 38 | while true do 39 | local line = client:read('*l') 40 | if not line then break end 41 | 42 | for c, _ in pairs(clients) do 43 | if c ~= self then 44 | c:write(string.format('%s : %s\r\n', name, line)) 45 | end 46 | end 47 | end 48 | 49 | clients[self] = nil 50 | client:close() 51 | end) 52 | ``` 53 | Use `telnet 5555` to connect to it. 54 | 55 | 56 | How It Works 57 | ------------ 58 | LEM is basically a [Lua][] interpreter with a built-in 59 | [libev][] main loop. 60 | 61 | All Lua code is run in coroutines so that modules can suspend the currently 62 | running code, register callbacks with the event loop and wait for events 63 | to happen before resuming the coroutine. 64 | 65 | This allows libraries to be written such that calls appear to be blocking, 66 | while still allowing other Lua coroutines to run. It also allows you to write 67 | libraries which automatically spawn new coroutines to handle incoming events. 68 | In the above example the autospawn method automatically spawns new coroutines 69 | to handle incoming connections, and the read and write methods suspends the 70 | the running coroutine while waiting for I/O. 71 | 72 | For this to work properly LEM modules needs to use non-blocking I/O. However, 73 | not all I/O can easily be done non-blocking. Filesystem operations is one example. 74 | Therefore LEM also includes a thread pool and an API to easily push work to a 75 | separate OS thread and receive an event when it's done. 76 | 77 | [Lua]: http://www.lua.org/ 78 | [libev]: http://libev.schmorp.de/ 79 | 80 | 81 | Getting Started 82 | --------------- 83 | Check out the sources 84 | 85 | $ git clone git://github.com/esmil/lem.git 86 | $ cd lem 87 | 88 | and do 89 | 90 | $ ./configure --prefix= 91 | $ make 92 | 93 | Now you can try out some of the test scripts. The test scripts also serve as examples. 94 | 95 | $ test/sleep.lua 96 | $ test/lfs.lua 97 | 98 | If you're happy with the result run 99 | 100 | $ make install 101 | 102 | to install the event machine to ``. 103 | 104 | Both the Lua 5.2.1 and libev 4.11 sources are included so having Lua or 105 | libev installed on your system is not required. 106 | However if you already have a Lua 5.1 or 5.2 library installed the configure 107 | script should find it and link against it. 108 | Use `./configure --with-lua=builtin` or `./configure --with-lua=` 109 | to use a specific version of Lua. 110 | Eg. to build against the [LuaJIT][] library I do 111 | 112 | $ ./configure --with-lua=luajit 113 | 114 | [LuaJIT]: http://luajit.org/luajit.html 115 | 116 | 117 | Usage 118 | ----- 119 | The `lem` interpreter will behave just like the normal standalone Lua 120 | interpreter except it doesn't take any command line options yet. 121 | All your normal Lua scripts should run with the LEM interpreter just fine. Type 122 | 123 | $ lem myscript.lua 124 | 125 | to run `myscript.lua` or make the script executable and add a hash-bang 126 | header as in 127 | 128 | ```lua 129 | #!/usr/bin/env lem 130 | 131 | local utils = require 'lem.utils' 132 | local io = require 'lem.io' 133 | 134 | (etc.) 135 | ``` 136 | 137 | Just like the normal stand-alone interpreter LEM stores command line 138 | arguments in the global table `arg` where `arg[-1]` is the interpreter, 139 | `arg[0]` is the script name and normal arguments begin at `arg[1]`. 140 | 141 | Running Lua scripts in the Lua Event Machine however, will allow you 142 | to load the LEM modules, which will fail in the normal interpreter. 143 | 144 | See the test folder for examples of how to use the different parts of LEM. 145 | 146 | License 147 | ------- 148 | The Lua Event Machine is free software. It is distributed under the terms 149 | of the [GNU Lesser General Public License][lgpl]. 150 | 151 | [lgpl]: http://www.gnu.org/licenses/lgpl.html 152 | 153 | 154 | Contact 155 | ------- 156 | Please send bug reports, patches, feature requests, praise and general gossip 157 | to me, Emil Renner Berthing . 158 | -------------------------------------------------------------------------------- /bin/libev.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of LEM, a Lua Event Machine. 3 | * Copyright 2011-2012 Emil Renner Berthing 4 | * 5 | * LEM is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as 7 | * published by the Free Software Foundation, either version 3 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * LEM is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with LEM. If not, see . 17 | */ 18 | 19 | #include "../libev/ev-config.h" 20 | #include "../libev/ev.c" 21 | -------------------------------------------------------------------------------- /bin/lua.c: -------------------------------------------------------------------------------- 1 | /* setup for luaconf.h */ 2 | #define LUA_CORE 3 | #define LUA_LIB 4 | #define lvm_c 5 | #include "luaconf.h" 6 | #include "lprefix.h" 7 | 8 | /* do not export internal symbols */ 9 | #undef LUAI_FUNC 10 | #undef LUAI_DDEC 11 | #undef LUAI_DDEF 12 | #define LUAI_FUNC static 13 | #define LUAI_DDEC static 14 | #define LUAI_DDEF static 15 | 16 | /* core -- used by all */ 17 | #include "../lua/lapi.c" 18 | #include "../lua/lcode.c" 19 | #include "../lua/lctype.c" 20 | #include "../lua/ldebug.c" 21 | #include "../lua/ldo.c" 22 | #include "../lua/ldump.c" 23 | #include "../lua/lfunc.c" 24 | #include "../lua/lgc.c" 25 | #include "../lua/llex.c" 26 | #include "../lua/lmem.c" 27 | #include "../lua/lobject.c" 28 | #include "../lua/lopcodes.c" 29 | #include "../lua/lparser.c" 30 | #include "../lua/lstate.c" 31 | #include "../lua/lstring.c" 32 | #include "../lua/ltable.c" 33 | #include "../lua/ltm.c" 34 | #include "../lua/lundump.c" 35 | #include "../lua/lvm.c" 36 | #include "../lua/lzio.c" 37 | 38 | /* auxiliary library -- used by all */ 39 | #include "../lua/lauxlib.c" 40 | 41 | /* standard library -- not used by luac */ 42 | #include "../lua/lbaselib.c" 43 | #if defined(LUA_COMPAT_BITLIB) 44 | #include "../lua/lbitlib.c" 45 | #endif 46 | #include "../lua/lcorolib.c" 47 | #include "../lua/ldblib.c" 48 | #include "../lua/liolib.c" 49 | #include "../lua/lmathlib.c" 50 | #include "../lua/loadlib.c" 51 | #include "../lua/loslib.c" 52 | #include "../lua/lstrlib.c" 53 | #include "../lua/ltablib.c" 54 | #include "../lua/lutf8lib.c" 55 | #include "../lua/linit.c" 56 | -------------------------------------------------------------------------------- /bin/pool.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of LEM, a Lua Event Machine. 3 | * Copyright 2012 Emil Renner Berthing 4 | * 5 | * LEM is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as 7 | * published by the Free Software Foundation, either version 3 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * LEM is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with LEM. If not, see . 17 | */ 18 | 19 | static unsigned int pool_jobs; 20 | static unsigned int pool_min; 21 | static unsigned int pool_max; 22 | static unsigned int pool_threads; 23 | static time_t pool_delay; 24 | static pthread_mutex_t pool_mutex; 25 | #if _POSIX_SPIN_LOCKS >= 200112L 26 | static pthread_spinlock_t pool_dlock; 27 | #define pool_done_init() pthread_spin_init(&pool_dlock, PTHREAD_PROCESS_PRIVATE) 28 | #define pool_done_lock() pthread_spin_lock(&pool_dlock) 29 | #define pool_done_unlock() pthread_spin_unlock(&pool_dlock) 30 | #else 31 | static pthread_mutex_t pool_dlock; 32 | #define pool_done_init() pthread_mutex_init(&pool_dlock, NULL) 33 | #define pool_done_lock() pthread_mutex_lock(&pool_dlock) 34 | #define pool_done_unlock() pthread_mutex_unlock(&pool_dlock) 35 | #endif 36 | static pthread_cond_t pool_cond; 37 | static struct lem_async *pool_head; 38 | static struct lem_async *pool_tail; 39 | static struct lem_async *pool_done; 40 | static struct ev_async pool_watch; 41 | 42 | static void * 43 | pool_threadfunc(void *arg) 44 | { 45 | struct lem_async *a; 46 | struct timespec ts; 47 | struct timeval tv; 48 | 49 | (void)arg; 50 | 51 | while (1) { 52 | gettimeofday(&tv, NULL); 53 | ts.tv_sec = tv.tv_sec + pool_delay; 54 | ts.tv_nsec = 1000*tv.tv_usec; 55 | 56 | pthread_mutex_lock(&pool_mutex); 57 | while ((a = pool_head) == NULL) { 58 | if (pool_threads <= pool_min) { 59 | pthread_cond_wait(&pool_cond, &pool_mutex); 60 | continue; 61 | } 62 | 63 | if (pthread_cond_timedwait(&pool_cond, &pool_mutex, &ts) 64 | && pool_threads > pool_min) 65 | goto out; 66 | } 67 | pool_head = a->next; 68 | pthread_mutex_unlock(&pool_mutex); 69 | 70 | lem_debug("Running job %p", a); 71 | a->work(a); 72 | lem_debug("Bye %p", a); 73 | 74 | pool_done_lock(); 75 | a->next = pool_done; 76 | pool_done = a; 77 | pool_done_unlock(); 78 | 79 | ev_async_send(LEM_ &pool_watch); 80 | } 81 | out: 82 | pool_threads--; 83 | pthread_mutex_unlock(&pool_mutex); 84 | return NULL; 85 | } 86 | 87 | static void 88 | pool_cb(EV_P_ struct ev_async *w, int revents) 89 | { 90 | struct lem_async *a; 91 | struct lem_async *next; 92 | 93 | (void)revents; 94 | 95 | pool_done_lock(); 96 | a = pool_done; 97 | pool_done = NULL; 98 | pool_done_unlock(); 99 | 100 | for (; a; a = next) { 101 | pool_jobs--; 102 | next = a->next; 103 | if (a->reap) 104 | a->reap(a); 105 | else 106 | free(a); 107 | } 108 | 109 | if (pool_jobs == 0) 110 | ev_async_stop(EV_A_ w); 111 | } 112 | 113 | #pragma GCC diagnostic push 114 | #pragma GCC diagnostic ignored "-Wstrict-aliasing" 115 | static inline void 116 | pool_watch_init(void) 117 | { 118 | ev_async_init(&pool_watch, pool_cb); 119 | } 120 | #pragma GCC diagnostic pop 121 | 122 | static int 123 | pool_init(void) 124 | { 125 | int ret; 126 | 127 | /* 128 | pool_jobs = 0; 129 | pool_min = 0; 130 | pool_threads = 0; 131 | */ 132 | pool_max = INT_MAX; 133 | pool_delay = 10; 134 | /* 135 | pool_head = NULL; 136 | pool_tail = NULL; 137 | pool_done = NULL; 138 | */ 139 | 140 | pool_watch_init(); 141 | 142 | ret = pthread_mutex_init(&pool_mutex, NULL); 143 | if (ret == 0) 144 | ret = pool_done_init(); 145 | if (ret) { 146 | lem_log_error("error initializing lock: %s", 147 | strerror(ret)); 148 | return -1; 149 | } 150 | 151 | ret = pthread_cond_init(&pool_cond, NULL); 152 | if (ret) { 153 | lem_log_error("error initializing cond: %s", 154 | strerror(ret)); 155 | return -1; 156 | } 157 | 158 | return 0; 159 | } 160 | 161 | static void 162 | pool_spawnthread(void) 163 | { 164 | pthread_attr_t attr; 165 | pthread_t thread; 166 | int ret; 167 | 168 | ret = pthread_attr_init(&attr); 169 | if (ret) 170 | goto error; 171 | 172 | ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 173 | if (ret) { 174 | pthread_attr_destroy(&attr); 175 | goto error; 176 | } 177 | 178 | ret = pthread_create(&thread, &attr, pool_threadfunc, NULL); 179 | pthread_attr_destroy(&attr); 180 | if (ret) 181 | goto error; 182 | 183 | return; 184 | error: 185 | lem_log_error("error spawning thread: %s", strerror(ret)); 186 | lem_exit(EXIT_FAILURE); 187 | } 188 | 189 | void 190 | lem_async_run(struct lem_async *a) 191 | { 192 | int spawn = 0; 193 | 194 | if (pool_jobs == 0) 195 | ev_async_start(LEM_ &pool_watch); 196 | pool_jobs++; 197 | 198 | a->next = NULL; 199 | 200 | pthread_mutex_lock(&pool_mutex); 201 | if (pool_head == NULL) { 202 | pool_head = a; 203 | pool_tail = a; 204 | } else { 205 | pool_tail->next = a; 206 | pool_tail = a; 207 | } 208 | if (pool_jobs > pool_threads && pool_threads < pool_max) { 209 | pool_threads++; 210 | spawn = 1; 211 | } 212 | pthread_mutex_unlock(&pool_mutex); 213 | pthread_cond_signal(&pool_cond); 214 | if (spawn) 215 | pool_spawnthread(); 216 | } 217 | 218 | void 219 | lem_async_config(int delay, int min, int max) 220 | { 221 | int spawn; 222 | 223 | pool_delay = (time_t)delay; 224 | pool_min = min; 225 | pool_max = max; 226 | 227 | pthread_mutex_lock(&pool_mutex); 228 | spawn = min - pool_threads; 229 | if (spawn > 0) 230 | pool_threads = min; 231 | pthread_mutex_unlock(&pool_mutex); 232 | 233 | for (; spawn > 0; spawn--) 234 | pool_spawnthread(); 235 | } 236 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.69]) 2 | AC_INIT([[lem]], [[0.3]], [[esmil@mailme.dk]]) 3 | builtin_lua_version='5.3' 4 | 5 | AC_LANG(C) 6 | 7 | AC_SUBST([headers], ['lem.h lem-parsers.h']) 8 | AC_SUBST([objects], ['bin/lem.o']) 9 | AC_SUBST([CPPFLAGS_ADD], ['-Iinclude']) 10 | AC_SUBST([SHARED], ['-shared']) 11 | 12 | AS_IF([test "x$CFLAGS" = 'x'], CFLAGS='-O2 -g -Wall -Wextra') 13 | 14 | AC_ARG_WITH([ev], 15 | [AS_HELP_STRING([--with-ev], 16 | [check or builtin @<:@default=check@:>@])], 17 | [], 18 | [with_ev=check]) 19 | 20 | AC_ARG_WITH([lua], 21 | [AS_HELP_STRING([--with-lua], 22 | [check, builtin or pkg-config name @<:@default=check@:>@])], 23 | [], 24 | [with_lua=check]) 25 | 26 | AC_SUBST([lmoddir]) 27 | AC_ARG_WITH([lmoddir], 28 | [AS_HELP_STRING([--with-lmoddir], 29 | [Lua module installation directory])], 30 | [lmoddir="$with_lmoddir"]) 31 | 32 | AC_SUBST([cmoddir]) 33 | AC_ARG_WITH([cmoddir], 34 | [AS_HELP_STRING([--with-cmoddir], 35 | [Lua C module installation directory])], 36 | [cmoddir="$with_cmoddir"]) 37 | 38 | PKG_INSTALLDIR 39 | AC_CANONICAL_TARGET 40 | 41 | # Checks for programs. 42 | AC_PROG_CC_C99 43 | AC_PROG_INSTALL 44 | AC_PROG_SED 45 | AC_PATH_TARGET_TOOL([STRIP],[strip]) 46 | PKG_PROG_PKG_CONFIG 47 | 48 | # Target specific fixes 49 | AS_CASE(["x$target_os"], 50 | [xdarwin*], 51 | [ac_cv_func_kqueue=no] # kqueue seems to be broken on OSX 52 | [SHARED='-dynamiclib -Wl,-undefined,dynamic_lookup'] 53 | [STRIP="$STRIP -x"]) 54 | 55 | # Check for pthread library 56 | AC_SEARCH_LIBS([pthread_create], [pthread]) 57 | 58 | # Checks for header files. 59 | AC_CHECK_HEADERS([stddef.h stdlib.h string.h unistd.h sys/time.h time.h pthread.h]) 60 | AC_CHECK_HEADERS([sys/eventfd.h sys/epoll.h sys/event.h]) 61 | 62 | # Configure libev 63 | AS_CASE(["x$with_ev"], 64 | [xbuiltin], 65 | [], 66 | [xcheck], 67 | [AC_SEARCH_LIBS([ev_run], [ev], [], [with_ev=builtin])], 68 | [AC_MSG_ERROR([--with-ev must be check or builtin, not '$with_ev'])]) 69 | 70 | AS_IF([test "x$with_ev" = 'xbuiltin'], 71 | [AC_CONFIG_HEADERS([libev/ev-config.h:ev-config.h.in])] 72 | [objects="bin/libev.o $objects"] 73 | [headers="ev-config.h ev.h $headers"] 74 | [CPPFLAGS_ADD="$CPPFLAGS_ADD -Ilibev"] 75 | 76 | [AS_IF([test "x$ac_cv_header_sys_eventfd_h" = 'xyes'], 77 | [AC_CHECK_FUNC([eventfd], 78 | [AC_DEFINE([EV_USE_EVENTFD], 1)], 79 | [AC_DEFINE([EV_USE_EVENTFD], 0)])], 80 | [AC_DEFINE([EV_USE_EVENTFD], 0)])] 81 | 82 | [AC_CHECK_FUNC([nanosleep], 83 | [AC_DEFINE([EV_USE_NANOSLEEP], 1)], 84 | [AC_DEFINE([EV_USE_NANOSLEEP], 0)])] 85 | 86 | [AC_CHECK_FUNCS([poll select epoll_ctl kqueue])] 87 | 88 | [AS_IF([test "x$ac_cv_func_epoll_ctl" = 'xyes'], 89 | [AC_DEFINE([EV_USE_SELECT], 0)] 90 | [AC_DEFINE([EV_USE_POLL], 0)] 91 | [AC_DEFINE([EV_USE_EPOLL], 1)] 92 | [AC_DEFINE([EV_USE_KQUEUE], 0)], 93 | [AS_IF([test "x$ac_cv_func_kqueue" = 'xyes'], 94 | [AC_DEFINE([EV_USE_SELECT], 0)] 95 | [AC_DEFINE([EV_USE_POLL], 0)] 96 | [AC_DEFINE([EV_USE_EPOLL], 0)] 97 | [AC_DEFINE([EV_USE_KQUEUE], 1)], 98 | [AS_IF([test "x$ac_cv_func_select" = 'xyes'], 99 | [AC_DEFINE([EV_USE_SELECT], 1)] 100 | [AC_DEFINE([EV_USE_POLL], 0)] 101 | [AC_DEFINE([EV_USE_EPOLL], 0)] 102 | [AC_DEFINE([EV_USE_KQUEUE], 0)], 103 | [AS_IF([test "x$ac_cv_func_poll" = 'xyes'], 104 | [AC_DEFINE([EV_USE_SELECT], 0)] 105 | [AC_DEFINE([EV_USE_POLL], 1)] 106 | [AC_DEFINE([EV_USE_EPOLL], 0)] 107 | [AC_DEFINE([EV_USE_KQUEUE], 0)], 108 | [AC_MSG_ERROR([neither poll or select found])])])])])]) 109 | 110 | # Configure Lua 111 | AS_CASE(["x$with_lua"], 112 | [xbuiltin], 113 | [], 114 | [xcheck], 115 | [PKG_CHECK_MODULES([Lua], [lua5.3], [with_lua=lua5.3], 116 | [PKG_CHECK_MODULES([Lua], [lua53], [with_lua=lua53], 117 | [PKG_CHECK_MODULES([Lua], [lua], 118 | [AS_IF([test "x$($PKG_CONFIG --variable=V lua)" = 'x5.3'], 119 | [with_lua=lua], 120 | [with_lua=builtin])], 121 | [with_lua=builtin])])])], 122 | [PKG_CHECK_MODULES([Lua], ["$with_lua"], [], 123 | [AC_MSG_ERROR([pkg-config package '$with_lua' not found])])]) 124 | 125 | AS_IF([test "x$with_lua" = 'xbuiltin'], 126 | [AC_SEARCH_LIBS([sin], [m])] 127 | [AC_SEARCH_LIBS([dlopen], [dl])] 128 | [objects="bin/lua.o $objects"] 129 | [headers="luaconf.h lua.h lauxlib.h $headers"] 130 | [CPPFLAGS_ADD="$CPPFLAGS_ADD -Ilua"] 131 | [Lua_CFLAGS=''] 132 | [Lua_LIBS=''] 133 | [ac_cv_func_luaL_traceback=yes] 134 | [AS_IF([test "x$lmoddir" = 'x'], [lmoddir="\${datarootdir}/lua/$builtin_lua_version"])] 135 | [AS_IF([test "x$cmoddir" = 'x'], [cmoddir="\${libdir}/lua/$builtin_lua_version"])]) 136 | 137 | CPPFLAGS_ADD="$CPPFLAGS_ADD $Lua_CFLAGS" 138 | LIBS="$Lua_LIBS $LIBS" 139 | AS_IF([test "x$lmoddir" = 'x'], [lmoddir="`$PKG_CONFIG --variable=INSTALL_LMOD $with_lua`"]) 140 | AS_IF([test "x$cmoddir" = 'x'], [cmoddir="`$PKG_CONFIG --variable=INSTALL_CMOD $with_lua`"]) 141 | 142 | AS_IF([test "x$lmoddir" = 'x'], 143 | [AC_MSG_ERROR([unable to deduce Lua module directory, please use --with-lmoddir=path])]) 144 | AS_IF([test "x$cmoddir" = 'x'], 145 | [AC_MSG_ERROR([unable to deduce Lua C module directory, please use --with-cmoddir=path])]) 146 | 147 | AC_CONFIG_FILES([Makefile]) 148 | AC_OUTPUT 149 | -------------------------------------------------------------------------------- /ev-config.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of LEM, a Lua Event Machine. 3 | * Copyright 2011-2012 Emil Renner Berthing 4 | * 5 | * LEM is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as 7 | * published by the Free Software Foundation, either version 3 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * LEM is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with LEM. If not, see . 17 | */ 18 | 19 | #define EV_STANDALONE 1 20 | #undef EV_USE_NANOSLEEP 21 | #undef EV_USE_EVENTFD 22 | 23 | #undef EV_USE_SELECT 24 | #undef EV_USE_POLL 25 | #undef EV_USE_EPOLL 26 | #undef EV_USE_KQUEUE 27 | #define EV_USE_PORT 0 28 | 29 | #define EV_MULTIPLICITY 0 30 | 31 | #define EV_PERIODIC_ENABLE 0 32 | #define EV_IDLE_ENABLE 1 33 | #define EV_EMBED_ENABLE 0 34 | #define EV_STAT_ENABLE 0 35 | #define EV_PREPARE_ENABLE 0 36 | #define EV_CHECK_ENABLE 0 37 | #define EV_FORK_ENABLE 0 38 | #define EV_SIGNAL_ENABLE 1 39 | #define EV_ASYNC_ENABLE 1 40 | #define EV_CHILD_ENABLE 1 41 | 42 | #define EV_MINPRI 0 43 | #define EV_MAXPRI 0 44 | -------------------------------------------------------------------------------- /include/lem-parsers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of LEM, a Lua Event Machine. 3 | * Copyright 2011-2013 Emil Renner Berthing 4 | * 5 | * LEM is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as 7 | * published by the Free Software Foundation, either version 3 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * LEM is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with LEM. If not, see . 17 | */ 18 | 19 | #ifndef _LEM_PARSERS_H 20 | #define _LEM_PARSERS_H 21 | 22 | #include 23 | 24 | #define LEM_INPUTBUF_PSIZE (4*sizeof(size_t)) 25 | #define LEM_INPUTBUF_SIZE 4096 26 | 27 | struct lem_inputbuf { 28 | unsigned int start; 29 | unsigned int end; 30 | char pstate[LEM_INPUTBUF_PSIZE]; 31 | char buf[LEM_INPUTBUF_SIZE]; 32 | }; 33 | 34 | enum lem_preason { 35 | LEM_PCLOSED, 36 | LEM_PERROR, 37 | }; 38 | 39 | struct lem_parser { 40 | void (*init)(lua_State *T, struct lem_inputbuf *b); 41 | int (*process)(lua_State *T, struct lem_inputbuf *b); 42 | int (*destroy)(lua_State *T, struct lem_inputbuf *b, enum lem_preason reason); 43 | }; 44 | 45 | static inline void 46 | lem_inputbuf_init(struct lem_inputbuf *buf) 47 | { 48 | buf->start = buf->end = 0; 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /include/lem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of LEM, a Lua Event Machine. 3 | * Copyright 2011-2012 Emil Renner Berthing 4 | * 5 | * LEM is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as 7 | * published by the Free Software Foundation, either version 3 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * LEM is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with LEM. If not, see . 17 | */ 18 | 19 | #ifndef _LEM_H 20 | #define _LEM_H 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | /* Support gcc's __FUNCTION__ for people using other compilers */ 27 | #if !defined(__GNUC__) && !defined(__FUNCTION__) 28 | # define __FUNCTION__ __func__ /* C99 */ 29 | #endif 30 | 31 | /* Built-time assertions */ 32 | #define LEM_BUILD_ASSERT__(prefix, line) prefix##line 33 | #define LEM_BUILD_ASSERT_(prefix, line) LEM_BUILD_ASSERT__(prefix, line) 34 | #define LEM_BUILD_ASSERT(x) \ 35 | typedef int LEM_BUILD_ASSERT_(lem_assert_, __LINE__)[(x) ? 1 : -1] 36 | 37 | #ifdef NDEBUG 38 | #define lem_debug(...) 39 | #else 40 | #define lem_debug(fmt, ...) do { \ 41 | printf("%s (%s:%u): " fmt "\n", \ 42 | __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__); \ 43 | fflush(stdout); } while (0) 44 | #endif 45 | 46 | #if EV_MINPRI == EV_MAXPRI 47 | # undef ev_priority 48 | # undef ev_set_priority 49 | # define ev_priority(pri) 50 | # define ev_set_priority(ev, pri) 51 | #endif 52 | 53 | #if EV_MULTIPLICITY 54 | extern struct ev_loop *lem_loop; 55 | # define LEM lem_loop 56 | # define LEM_ LEM, 57 | #else 58 | # define LEM 59 | # define LEM_ 60 | #endif 61 | 62 | struct lem_async { 63 | void (*work)(struct lem_async *a); 64 | void (*reap)(struct lem_async *a); 65 | struct lem_async *next; 66 | }; 67 | 68 | void *lem_xmalloc(size_t size); 69 | lua_State *lem_newthread(void); 70 | void lem_forgetthread(lua_State *T); 71 | void lem_queue(lua_State *T, int nargs); 72 | void lem_exit(int status); 73 | void lem_async_run(struct lem_async *a); 74 | void lem_async_config(int delay, int min, int max); 75 | 76 | static inline void 77 | lem_async_do(struct lem_async *a, 78 | void (*work)(struct lem_async *a), 79 | void (*reap)(struct lem_async *a)) 80 | { 81 | a->work = work; 82 | a->reap = reap; 83 | lem_async_run(a); 84 | } 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /lem.pc.in: -------------------------------------------------------------------------------- 1 | includedir=@includedir@/lem 2 | 3 | INSTALL_LMOD=@lmoddir@ 4 | INSTALL_CMOD=@cmoddir@ 5 | 6 | Name: lem 7 | Description: A Lua Event Machine 8 | Version: 0.3 9 | URL: https://github.com/esmil/lem 10 | Cflags: -I${includedir} @Lua_CFLAGS@ 11 | -------------------------------------------------------------------------------- /lem/hathaway.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- This file is part of LEM, a Lua Event Machine. 3 | -- Copyright 2011-2013 Emil Renner Berthing 4 | -- Copyright 2012-2013 Asbjørn Sloth Tønnesen 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | local format = string.format 21 | 22 | local httpserv = require 'lem.http.server' 23 | local httpresp = require 'lem.http.response' 24 | 25 | local M = {} 26 | 27 | function M.debug() end 28 | 29 | local Hathaway = {} 30 | Hathaway.__index = Hathaway 31 | M.Hathaway = Hathaway 32 | 33 | function Hathaway:GET(path, handler) 34 | local entry = self.lookup[path] 35 | if entry then 36 | entry['HEAD'] = handler 37 | entry['GET'] = handler 38 | else 39 | entry = { 40 | ['HEAD'] = handler, 41 | ['GET'] = handler, 42 | } 43 | self.lookup[path] = entry 44 | end 45 | end 46 | 47 | do 48 | local function static_setter(method) 49 | return function(self, path, handler) 50 | local entry = self.lookup[path] 51 | if entry then 52 | entry[method] = handler 53 | else 54 | self.lookup[path] = { [method] = handler } 55 | end 56 | end 57 | end 58 | 59 | Hathaway.POST = static_setter('POST') 60 | Hathaway.PUT = static_setter('PUT') 61 | Hathaway.DELETE = static_setter('DELETE') 62 | Hathaway.OPTIONS = static_setter('OPTIONS') 63 | end 64 | 65 | function Hathaway:GETM(pattern, handler) 66 | local i = 1 67 | while true do 68 | local entry = self.lookup[i] 69 | if entry == nil then 70 | self.lookup[i] = { pattern, 71 | ['GET'] = handler, 72 | ['HEAD'] = handler 73 | } 74 | break 75 | end 76 | if entry[1] == pattern then 77 | entry['GET'] = handler 78 | entry['HEAD'] = handler 79 | break 80 | end 81 | i = i + 1 82 | end 83 | end 84 | 85 | do 86 | local function match_setter(method) 87 | return function(self, pattern, handler) 88 | local i = 1 89 | while true do 90 | local entry = self.lookup[i] 91 | if entry == nil then 92 | self.lookup[i] = { pattern, [method] = handler } 93 | break 94 | end 95 | if entry[1] == pattern then 96 | entry[method] = handler 97 | break 98 | end 99 | i = i + 1 100 | end 101 | end 102 | end 103 | 104 | Hathaway.POSTM = match_setter('POST') 105 | Hathaway.PUTM = match_setter('PUT') 106 | Hathaway.DELETEM = match_setter('DELETE') 107 | Hathaway.OPTIONSM = match_setter('OPTIONS') 108 | end 109 | 110 | local function check_match(entry, req, res, ok, ...) 111 | if not ok then return false end 112 | local handler = entry[req.method] 113 | if handler then 114 | handler(req, res, ok, ...) 115 | else 116 | httpresp.method_not_allowed(req, res) 117 | end 118 | return true 119 | end 120 | 121 | local function handle(self, req, res) 122 | local method, path = req.method, req.path 123 | self.debug('info', format("%s %s HTTP/%s", method, req.uri, req.version)) 124 | local lookup = self.lookup 125 | local entry = lookup[path] 126 | if entry then 127 | local handler = entry[method] 128 | if handler then 129 | handler(req, res) 130 | else 131 | httpresp.method_not_allowed(req, res) 132 | end 133 | else 134 | local i = 0 135 | repeat 136 | i = i + 1 137 | local entry = lookup[i] 138 | if not entry then 139 | httpresp.not_found(req, res) 140 | break 141 | end 142 | until check_match(entry, req, res, path:match(entry[1])) 143 | end 144 | end 145 | Hathaway.handle = handle 146 | 147 | function Hathaway:run(host, port) 148 | local server, err 149 | if port then 150 | server, err = httpserv.new(host, port, self.handler) 151 | else 152 | server, err = httpserv.new(host, self.handler) 153 | end 154 | if not server then self.debug('new', err) return nil, err end 155 | 156 | self.server = server 157 | server.debug = self.debug 158 | 159 | local ok, err = server:run() 160 | if not ok and err ~= 'interrupted' then 161 | self.debug('run', err) 162 | return nil, err 163 | end 164 | return true 165 | end 166 | 167 | function Hathaway:import(env) 168 | if not env then 169 | env = _G 170 | end 171 | 172 | env.GET = function(...) self:GET(...) end 173 | env.POST = function(...) self:POST(...) end 174 | env.PUT = function(...) self:PUT(...) end 175 | env.DELETE = function(...) self:DELETE(...) end 176 | env.OPTIONS = function(...) self:OPTIONS(...) end 177 | env.GETM = function(...) self:GETM(...) end 178 | env.POSTM = function(...) self:POSTM(...) end 179 | env.PUTM = function(...) self:PUTM(...) end 180 | env.DELETEM = function(...) self:DELETEM(...) end 181 | env.OPTIONSM = function(...) self:OPTIONSM(...) end 182 | env.Hathaway = function(...) self:run(...) end 183 | end 184 | 185 | local function new() 186 | local self = { 187 | lookup = {}, 188 | debug = M.debug 189 | } 190 | self.handler = function(...) return handle(self, ...) end 191 | return setmetatable(self, Hathaway) 192 | end 193 | M.new = new 194 | 195 | function M.import(...) 196 | return new():import(...) 197 | end 198 | 199 | return M 200 | 201 | -- vim: ts=2 sw=2 noet: 202 | -------------------------------------------------------------------------------- /lem/http.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- This file is part of LEM, a Lua Event Machine. 3 | -- Copyright 2011-2013 Emil Renner Berthing 4 | -- 5 | -- LEM is free software: you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as 7 | -- published by the Free Software Foundation, either version 3 of 8 | -- the License, or (at your option) any later version. 9 | -- 10 | -- LEM is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU Lesser General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public 16 | -- License along with LEM. If not, see . 17 | -- 18 | 19 | local http = require 'lem.http.core' 20 | local parsers = require 'lem.parsers' 21 | 22 | parsers.lookup['HTTPRequest'] = http.HTTPRequest 23 | http.HTTPRequest = nil 24 | parsers.lookup['HTTPResponse'] = http.HTTPResponse 25 | http.HTTPResponse = nil 26 | 27 | return http 28 | 29 | -- vim: ts=2 sw=2 noet: 30 | -------------------------------------------------------------------------------- /lem/http/client.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- This file is part of LEM, a Lua Event Machine. 3 | -- Copyright 2013 Emil Renner Berthing 4 | -- 5 | -- LEM is free software: you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as 7 | -- published by the Free Software Foundation, either version 3 of 8 | -- the License, or (at your option) any later version. 9 | -- 10 | -- LEM is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU Lesser General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public 16 | -- License along with LEM. If not, see . 17 | -- 18 | 19 | local setmetatable = setmetatable 20 | local tonumber = tonumber 21 | local concat = table.concat 22 | 23 | local io = require 'lem.io' 24 | require 'lem.http' 25 | 26 | local M = {} 27 | 28 | local Response = {} 29 | Response.__index = Response 30 | M.Response = Response 31 | 32 | function Response:body_chunked() 33 | if self._body then return self._body end 34 | 35 | local conn = self.conn 36 | local rope, i = {}, 0 37 | local line, err 38 | while true do 39 | line, err = conn:read('*l') 40 | if not line then return nil, err end 41 | 42 | local len = tonumber(line, 16) 43 | if not len then return nil, 'expectation failed' end 44 | if len == 0 then break end 45 | 46 | local data, err = conn:read(len) 47 | if not data then return nil, err end 48 | 49 | i = i + 1 50 | rope[i] = data 51 | 52 | line, err = conn:read('*l') 53 | if not line then return nil, err end 54 | end 55 | 56 | line, err = conn:read('*l') 57 | if not line then return nil, err end 58 | 59 | rope = concat(rope) 60 | self._body = rope 61 | return rope 62 | end 63 | 64 | function Response:body() 65 | if self._body then return self._body end 66 | if self.headers['transfer-encoding'] == 'chunked' then 67 | return self:body_chunked() 68 | end 69 | 70 | local len, body, err = self.headers['content-length'] 71 | if len then 72 | len = tonumber(len) 73 | if not len then return nil, 'invalid content length' end 74 | body, err = self.conn:read(len) 75 | else 76 | if self.headers['connection'] == 'close' then 77 | body, err = self.client:read('*a') 78 | else 79 | return nil, 'no content length specified' 80 | end 81 | end 82 | if not body then return nil, err end 83 | 84 | self._body = body 85 | return body 86 | end 87 | 88 | local Client = {} 89 | Client.__index = Client 90 | M.Client = Client 91 | 92 | function M.new() 93 | return setmetatable({ 94 | proto = false, 95 | domain = false, 96 | conn = false, 97 | }, Client) 98 | end 99 | 100 | local req_get = "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n\r\n" 101 | --local req_get = "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n" 102 | 103 | local function close(self) 104 | local c = self.conn 105 | if c then 106 | self.conn = false 107 | return c:close() 108 | end 109 | return true 110 | end 111 | Client.close = close 112 | 113 | local function fail(self, err) 114 | self.proto = false 115 | close(self) 116 | return nil, err 117 | end 118 | 119 | function Client:get(url) 120 | local proto, domain, uri = url:match('([a-zA-Z0-9]+)://([a-zA-Z0-9.]+)(/.*)') 121 | if not proto then 122 | error('Invalid URL', 2) 123 | end 124 | 125 | local c, err 126 | local req = req_get:format(uri, domain) 127 | local res 128 | if proto == self.proto and domain == self.domain then 129 | c = self.conn 130 | if c:write(req) then 131 | res = c:read('HTTPResponse') 132 | end 133 | end 134 | 135 | if not res then 136 | c = self.conn 137 | if c then 138 | c:close() 139 | end 140 | 141 | if proto == 'http' then 142 | c, err = io.tcp.connect(domain, '80') 143 | elseif proto == 'https' then 144 | local ssl = self.ssl 145 | if not ssl then 146 | error('No ssl context defined', 2) 147 | end 148 | c, err = ssl:connect(domain, '443') 149 | else 150 | error('Unknown protocol', 2) 151 | end 152 | if not c then return fail(self, err) end 153 | 154 | local ok 155 | ok, err = c:write(req) 156 | if not ok then return fail(self, err) end 157 | 158 | res, err = c:read('HTTPResponse') 159 | if not res then return fail(self, err) end 160 | end 161 | 162 | res.conn = c 163 | setmetatable(res, Response) 164 | 165 | self.proto = proto 166 | self.domain = domain 167 | self.conn = c 168 | return res 169 | end 170 | 171 | function Client:download(url, filename) 172 | local res, err = self:get(url) 173 | if not res then return res, err end 174 | 175 | local file 176 | file, err = io.open(filename, 'w') 177 | if not file then return file, err end 178 | 179 | local ok 180 | ok, err = file:write(res.body) 181 | if not ok then return ok, err end 182 | ok, err = file:close() 183 | if not ok then return ok, err end 184 | 185 | return true 186 | end 187 | 188 | return M 189 | 190 | -- vim: set ts=2 sw=2 noet: 191 | -------------------------------------------------------------------------------- /lem/http/response.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- This file is part of LEM, a Lua Event Machine. 3 | -- Copyright 2011-2013 Emil Renner Berthing 4 | -- Copyright 2013 Halfdan Mouritzen 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | local setmetatable = setmetatable 21 | local tostring = tostring 22 | local tonumber = tonumber 23 | local pairs = pairs 24 | local type = type 25 | local date = os.date 26 | local format = string.format 27 | local concat = table.concat 28 | local remove = table.remove 29 | 30 | local M = {} 31 | 32 | local status_string = { 33 | -- 1xx Informational 34 | [100] = '100 Continue', 35 | [101] = '101 Switching Protocols', 36 | [102] = '102 Processing', -- WebDAV 37 | 38 | -- 2xx Success 39 | [200] = '200 OK', 40 | [201] = '201 Created', 41 | [202] = '202 Accepted', 42 | [203] = '203 Non-Authoritative Information', 43 | [204] = '204 No Content', 44 | [205] = '205 Reset Content', 45 | [206] = '206 Partial Content', 46 | [207] = '207 Multi-Status', -- WebDAV 47 | [208] = '208 Already Reported', -- WebDAV 48 | [226] = '226 IM Used', 49 | [230] = '230 Authentication Successfull', 50 | 51 | -- 3xx Redirection 52 | [300] = '300 Multiple Choices', 53 | [301] = '301 Moved Permanently', 54 | [302] = '302 Found', 55 | [303] = '303 See Other', 56 | [304] = '304 Not Modified', 57 | [305] = '305 Use Proxy', 58 | [306] = '306 Switch Proxy', 59 | [307] = '307 Temporary Redirect', 60 | [308] = '308 Permanent Redirect', 61 | 62 | -- 4xx Client Error 63 | [400] = '400 Bad Request', 64 | [401] = '401 Unauthorized', 65 | [402] = '402 Payment Required', 66 | [403] = '403 Forbidden', 67 | [404] = '404 Not Found', 68 | [405] = '405 Method Not Allowed', 69 | [406] = '406 Not Acceptable', 70 | [407] = '407 Proxy Authentication Required', 71 | [408] = '408 Request Timeout', 72 | [409] = '409 Conflict', 73 | [410] = '410 Gone', 74 | [411] = '411 Length Required', 75 | [412] = '412 Precondition Failed', 76 | [413] = '413 Request Entity Too Large', 77 | [414] = '414 Request-URI Too Long', 78 | [415] = '415 Unsupported Media Type', 79 | [416] = '416 Requested Range Not Satisfiable', 80 | [417] = '417 Expectation Failed', 81 | -- ... 82 | [422] = '422 Unprocessable Entity', -- WebDAV 83 | [423] = '423 Locked', -- WebDAV 84 | [424] = '424 Failed Dependency', -- WebDAV 85 | -- ... 86 | [426] = '426 Upgrade Required', 87 | [428] = '428 Precondition Required', 88 | [429] = '429 Too Many Requests', 89 | [431] = '431 Request Header Fields Too Large', 90 | 91 | -- 5xx Server Error 92 | [500] = '500 Internal Server Error', 93 | [501] = '501 Not Implemented', 94 | [502] = '502 Bad Gateway', 95 | [503] = '503 Service Unavailable', 96 | [504] = '504 Gateway Timeout', 97 | [505] = '505 HTTP Version Not Supported', 98 | [506] = '506 Variant Also Negotiates', 99 | [507] = '507 Insufficient Storage', -- WebDAV 100 | [508] = '508 Loop Detected', -- WebDAV 101 | -- ... 102 | [510] = '510 Not Extended', 103 | [511] = '511 Network Authentication Required', 104 | [531] = '531 Access Denied', 105 | } 106 | 107 | M.status_string = status_string 108 | 109 | function M.not_found(req, res) 110 | if req.headers['expect'] ~= '100-continue' then 111 | req:body() 112 | end 113 | 114 | res.status = 404 115 | res.headers['Content-Type'] = 'text/html; charset=UTF-8' 116 | res:add([[ 117 | 118 | 119 | 120 | Not Found 121 | 122 | 123 |

Not found

124 | 125 | 126 | ]]) 127 | end 128 | 129 | function M.htmlerror(num, text) 130 | local str = format([[ 131 | 132 | 133 | 134 | %s 135 | 136 | 137 |

%s

138 | 139 | 140 | ]], text, text) 141 | return function(req, res) 142 | res.status = num 143 | res.headers['Content-Type'] = 'text/html; charset=UTF-8' 144 | res.headers['Connection'] = 'close' 145 | res:add(str) 146 | end 147 | end 148 | 149 | M.method_not_allowed = M.htmlerror(405, 'Method Not Allowed') 150 | M.expectation_failed = M.htmlerror(417, 'Expectation Failed') 151 | M.version_not_supported = M.htmlerror(505, 'HTTP Version Not Supported') 152 | M.bad_request = M.htmlerror(400, 'Bad Request') 153 | 154 | local Response = {} 155 | Response.__index = Response 156 | M.Response = Response 157 | 158 | function Response:contentlength() 159 | local len = 0 160 | for i = 1, #self do 161 | len = len + #self[i] 162 | end 163 | return len 164 | end 165 | 166 | function Response:appendheader(rope, i, size) 167 | if not size then size = 0 end 168 | local line 169 | for k, v in pairs(self.headers) do 170 | line = format('%s: %s\r\n', k, tostring(v)) 171 | i = i + 1 172 | rope[i] = line 173 | size = size + #line 174 | end 175 | i = i + 1 176 | rope[i] = '\r\n' 177 | size = size + 2 178 | return i, size 179 | end 180 | 181 | function Response:appendbody(rope, i, size) 182 | if not size then size = 0 end 183 | local chunk 184 | for j = 1, #self do 185 | chunk = self[j] 186 | i = i + 1 187 | rope[i] = chunk 188 | size = size + #chunk 189 | end 190 | return i, size 191 | end 192 | 193 | function M.new(req) 194 | local n = 0 195 | return setmetatable({ 196 | headers = {}, 197 | version = req and req.version or nil, 198 | add = function(self, fmt, first, ...) 199 | n = n + 1 200 | if first then 201 | self[n] = format(fmt, first, ...) 202 | else 203 | self[n] = fmt 204 | end 205 | end 206 | }, Response) 207 | end 208 | 209 | return M 210 | 211 | -- vim: ts=2 sw=2 noet: 212 | -------------------------------------------------------------------------------- /lem/http/server.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- This file is part of LEM, a Lua Event Machine. 3 | -- Copyright 2011-2013 Emil Renner Berthing 4 | -- Copyright 2013 Halfdan Mouritzen 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | local setmetatable = setmetatable 21 | local tostring = tostring 22 | local tonumber = tonumber 23 | local pairs = pairs 24 | local type = type 25 | local date = os.date 26 | local format = string.format 27 | local concat = table.concat 28 | local remove = table.remove 29 | 30 | local io = require 'lem.io' 31 | require 'lem.http' 32 | local response = require 'lem.http.response' 33 | 34 | local M = {} 35 | 36 | function M.debug() end 37 | 38 | local Request = {} 39 | Request.__index = Request 40 | M.Request = Request 41 | 42 | function Request:body(maxsize) 43 | local len, body = self.headers['content-length'], '' 44 | if not len then return body end 45 | 46 | len = tonumber(len) 47 | if len <= 0 then return body end 48 | 49 | if maxsize and len > maxsize then 50 | return nil, 'oversized' 51 | end 52 | 53 | if self.headers['expect'] == '100-continue' then 54 | local ok, err = self.client:write('HTTP/1.1 100 Continue\r\n\r\n') 55 | if not ok then return nil, err end 56 | end 57 | 58 | local err 59 | body, err = self.client:read(len) 60 | if not body then return nil, err end 61 | 62 | return body 63 | end 64 | 65 | do 66 | local gsub, char, tonumber = string.gsub, string.char, tonumber 67 | 68 | local function tochar(str) 69 | return char(tonumber(str, 16)) 70 | end 71 | 72 | function M.urldecode(str) 73 | return gsub(gsub(str, '+', ' '), '%%(%x%x)', tochar) 74 | end 75 | end 76 | 77 | local function check_match(entry, req, res, ok, ...) 78 | if not ok then return false end 79 | local handler = entry[req.method] 80 | if handler then 81 | handler(req, res, ok, ...) 82 | else 83 | response.method_not_allowed(req, res) 84 | end 85 | return true 86 | end 87 | 88 | local urldecode = M.urldecode 89 | local newresponse = response.new 90 | 91 | local function handleHTTP(self, client) 92 | repeat 93 | local req, err = client:read('HTTPRequest') 94 | if not req then self.debug('read', err) break end 95 | local method, uri, version = req.method, req.uri, req.version 96 | 97 | setmetatable(req, Request) 98 | req.client = client 99 | req.path = urldecode(uri:match('^([^?]*)')) 100 | 101 | local res = newresponse(req) 102 | 103 | if version ~= '1.0' and version ~= '1.1' then 104 | response.version_not_supported(req, res) 105 | version = '1.1' 106 | else 107 | local expect = req.headers['expect'] 108 | if expect and expect ~= '100-continue' then 109 | response.expectation_failed(req, res) 110 | else 111 | self.handler(req, res) 112 | end 113 | end 114 | 115 | local headers = res.headers 116 | local file, close = res.file, false 117 | if type(file) == 'string' then 118 | file, err = io.open(file) 119 | if file then 120 | close = true 121 | else 122 | self.debug('open', err) 123 | res = newresponse(req) 124 | headers = res.headers 125 | response.not_found(req, res) 126 | end 127 | end 128 | 129 | if not res.status then 130 | if #res == 0 and file == nil then 131 | res.status = 204 132 | else 133 | res.status = 200 134 | end 135 | end 136 | 137 | if headers['Content-Length'] == nil and res.status ~= 204 then 138 | local len 139 | if file then 140 | len = file:size() 141 | else 142 | len = 0 143 | for i = 1, #res do 144 | len = len + #res[i] 145 | end 146 | end 147 | 148 | headers['Content-Length'] = len 149 | end 150 | 151 | if headers['Date'] == nil then 152 | headers['Date'] = date('!%a, %d %b %Y %H:%M:%S GMT') 153 | end 154 | 155 | if headers['Server'] == nil then 156 | headers['Server'] = 'Hathaway/0.1 LEM/0.3' 157 | end 158 | 159 | if req.headers['connection'] == 'close' and headers['Connection'] == nil then 160 | headers['Connection'] = 'close' 161 | end 162 | 163 | local rope = {} 164 | do 165 | local status = res.status 166 | if type(status) == 'number' then 167 | status = response.status_string[status] 168 | end 169 | 170 | rope[1] = format('HTTP/%s %s\r\n', version, status) 171 | end 172 | 173 | res:appendheader(rope, 1) 174 | 175 | client:cork() 176 | 177 | local ok, err = client:write(concat(rope)) 178 | if not ok then self.debug('write', err) break end 179 | 180 | if method ~= 'HEAD' then 181 | if file then 182 | ok, err = client:sendfile(file, headers['Content-Length']) 183 | if close then file:close() end 184 | else 185 | local body = concat(res) 186 | if #body > 0 then 187 | ok, err = client:write(body) 188 | end 189 | end 190 | if not ok then self.debug('write', err) break end 191 | end 192 | 193 | client:uncork() 194 | 195 | until version == '1.0' or headers['Connection'] == 'close' 196 | 197 | client:close() 198 | end 199 | 200 | local Server = {} 201 | Server.__index = Server 202 | M.Server = Server 203 | 204 | function Server:run() 205 | return self.socket:autospawn(function(...) return handleHTTP(self, ...) end) 206 | end 207 | 208 | function Server:close() 209 | return self.socket:close() 210 | end 211 | 212 | local type, setmetatable = type, setmetatable 213 | 214 | function M.new(host, port, handler) 215 | local socket, err 216 | if type(host) == 'string' then 217 | socket, err = io.tcp.listen(host, port) 218 | if not socket then 219 | return nil, err 220 | end 221 | else 222 | socket = host 223 | handler = port 224 | end 225 | 226 | return setmetatable({ 227 | socket = socket, 228 | handler = handler, 229 | debug = M.debug 230 | }, Server) 231 | end 232 | 233 | return M 234 | 235 | -- vim: ts=2 sw=2 noet: 236 | -------------------------------------------------------------------------------- /lem/io.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- This file is part of LEM, a Lua Event Machine. 3 | -- Copyright 2011-2013 Emil Renner Berthing 4 | -- 5 | -- LEM is free software: you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as 7 | -- published by the Free Software Foundation, either version 3 of 8 | -- the License, or (at your option) any later version. 9 | -- 10 | -- LEM is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU Lesser General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public 16 | -- License along with LEM. If not, see . 17 | -- 18 | 19 | local utils = require 'lem.utils' 20 | local io = require 'lem.io.core' 21 | 22 | local type = type 23 | local assert = assert 24 | local error = error 25 | 26 | do 27 | local parsers = require 'lem.parsers' 28 | 29 | io.Stream.read = parsers.newreader(io.Stream.readp) 30 | io.File.read = parsers.newreader(io.File.readp) 31 | end 32 | 33 | do 34 | local stdin = io.stdin 35 | 36 | function io.input(file) 37 | if not file then return stdin end 38 | if type(file) == 'string' then 39 | stdin = assert(io.open(file)) 40 | else 41 | stdin = file 42 | end 43 | end 44 | 45 | function io.read(...) 46 | return stdin:read(...) 47 | end 48 | 49 | local streamfile, error = io.streamfile, error 50 | function io.lines(filename, fmt) 51 | if not filename then return stdin:lines(fmt) end 52 | if not fmt then fmt = '*l' end 53 | local file, err = streamfile(filename) 54 | if not file then error(err, 2) end 55 | return function(s) 56 | local line = s:read(fmt) 57 | if not line then s:close() end 58 | return line 59 | end, file 60 | end 61 | end 62 | 63 | do 64 | local stdout = io.stdout 65 | 66 | function io.output(file) 67 | if not file then return stdout end 68 | if type(file) == 'string' then 69 | stdout = assert(io.open(file)) 70 | else 71 | stdout = file 72 | end 73 | end 74 | 75 | function io.write(...) 76 | return stdout:write(...) 77 | end 78 | 79 | function io.close(file) 80 | if not file then file = stdout end 81 | return file:close() 82 | end 83 | end 84 | 85 | function io.File:lines(fmt) 86 | if not fmt then fmt = '*l' end 87 | return function(s) 88 | return s:read(fmt) 89 | end, self 90 | end 91 | io.Stream.lines = io.File.lines 92 | 93 | if not io.Stream.cork then 94 | function io.Stream:cork() 95 | return nil, 'Operation not supported' 96 | end 97 | io.Stream.uncork = io.Stream.cork 98 | end 99 | 100 | do 101 | local MultiServer = {} 102 | MultiServer.__index = MultiServer 103 | io.MultiServer = MultiServer 104 | 105 | function MultiServer:interrupt() 106 | return self[1]:interrupt() 107 | end 108 | 109 | function MultiServer:close() 110 | local rok, rerr = true 111 | for i = 1, #self do 112 | local ok, err = self[i]:close() 113 | if not ok then 114 | rok, rerr = ok, err 115 | end 116 | end 117 | return rok, rerr 118 | end 119 | 120 | 121 | local function autospawn(self, i, handler) 122 | local ok, err = self[i]:autospawn(handler) 123 | if self.running then 124 | self.running, self.ok, self.err = false, ok, err 125 | end 126 | for i = 1, #self do 127 | self[i]:interrupt() 128 | end 129 | end 130 | 131 | local spawn = utils.spawn 132 | 133 | function MultiServer:autospawn(handler) 134 | local n = #self 135 | 136 | self.running = true 137 | for i = 1, n-1 do 138 | spawn(autospawn, self, i, handler) 139 | end 140 | autospawn(self, n, handler) 141 | 142 | return self.ok, self.err 143 | end 144 | 145 | local setmetatable = setmetatable 146 | local listen4, listen6 = io.tcp.listen4, io.tcp.listen6 147 | 148 | function io.tcp.listen(host, port) 149 | if host:match(':') then 150 | return listen6(host, port) 151 | end 152 | 153 | local s6, err = listen6(host, port) 154 | if s6 then 155 | local s4 = listen4(host, port) 156 | if s4 then 157 | return setmetatable({ s6, s4 }, MultiServer) 158 | end 159 | return s6 160 | else 161 | return listen4(host, port) 162 | end 163 | end 164 | end 165 | 166 | return io 167 | 168 | -- vim: ts=2 sw=2 noet: 169 | -------------------------------------------------------------------------------- /lem/io/queue.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- This file is part of LEM, a Lua Event Machine. 3 | -- Copyright 2011-2012 Emil Renner Berthing 4 | -- 5 | -- LEM is free software: you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as 7 | -- published by the Free Software Foundation, either version 3 of 8 | -- the License, or (at your option) any later version. 9 | -- 10 | -- LEM is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU Lesser General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public 16 | -- License along with LEM. If not, see . 17 | -- 18 | 19 | local utils = require 'lem.utils' 20 | 21 | local setmetatable = setmetatable 22 | local thisthread, suspend, resume 23 | = utils.thisthread, utils.suspend, utils.resume 24 | 25 | local Stream = {} 26 | Stream.__index = Stream 27 | 28 | function Stream:closed(...) 29 | return self.stream:closed(...) 30 | end 31 | 32 | function Stream:close(...) 33 | return self.stream:close(...) 34 | end 35 | 36 | function Stream:write(...) 37 | local nxt = self.next 38 | if nxt == 0 then 39 | nxt = 1 40 | self.next = 1 41 | else 42 | local me = nxt 43 | 44 | self[me] = thisthread() 45 | nxt = #self+1 46 | self.next = nxt 47 | suspend() 48 | self[me] = nil 49 | end 50 | 51 | local ok, err = self.stream:write(...) 52 | 53 | nxt = self[nxt] 54 | if nxt then 55 | resume(nxt) 56 | else 57 | self.next = 0 58 | end 59 | 60 | if not ok then return nil, err end 61 | return ok 62 | end 63 | 64 | local function wrap(stream, ...) 65 | if not stream then return stream, ... end 66 | return setmetatable({ stream = stream, next = 0 }, Stream) 67 | end 68 | 69 | return { 70 | Stream = Stream, 71 | wrap = wrap, 72 | } 73 | 74 | -- vim: set ts=2 sw=2 noet: 75 | -------------------------------------------------------------------------------- /lem/io/unix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of LEM, a Lua Event Machine. 3 | * Copyright 2013 Emil Renner Berthing 4 | * 5 | * LEM is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as 7 | * published by the Free Software Foundation, either version 3 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * LEM is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with LEM. If not, see . 17 | */ 18 | 19 | struct unix_create { 20 | struct lem_async a; 21 | lua_State *T; 22 | const char *path; 23 | size_t len; 24 | int sock; 25 | int err; 26 | }; 27 | 28 | static void 29 | unix_connect_work(struct lem_async *a) 30 | { 31 | struct unix_create *u = (struct unix_create *)a; 32 | struct sockaddr_un addr; 33 | int sock; 34 | 35 | sock = socket(AF_UNIX, 36 | #ifdef SOCK_CLOEXEC 37 | SOCK_CLOEXEC | 38 | #endif 39 | SOCK_STREAM, 0); 40 | if (sock < 0) { 41 | u->sock = -1; 42 | u->err = errno; 43 | return; 44 | } 45 | #ifndef SOCK_CLOEXEC 46 | if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) { 47 | u->sock = -1; 48 | u->err = errno; 49 | goto error; 50 | } 51 | #endif 52 | addr.sun_family = AF_UNIX; 53 | memcpy(addr.sun_path, u->path, u->len+1); 54 | 55 | if (connect(sock, (struct sockaddr *)&addr, 56 | offsetof(struct sockaddr_un, sun_path) + u->len)) { 57 | u->sock = -2; 58 | u->err = errno; 59 | goto error; 60 | } 61 | 62 | /* make the socket non-blocking */ 63 | if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) { 64 | u->sock = -1; 65 | u->err = errno; 66 | goto error; 67 | } 68 | 69 | u->sock = sock; 70 | return; 71 | 72 | error: 73 | close(sock); 74 | } 75 | 76 | static void 77 | unix_connect_reap(struct lem_async *a) 78 | { 79 | struct unix_create *u = (struct unix_create *)a; 80 | lua_State *T = u->T; 81 | int sock = u->sock; 82 | 83 | if (sock >= 0) { 84 | free(u); 85 | 86 | stream_new(T, sock, 2); 87 | lem_queue(T, 1); 88 | return; 89 | } 90 | 91 | lua_pushnil(T); 92 | switch (-sock) { 93 | case 1: 94 | lua_pushfstring(T, "error creating socket: %s", 95 | strerror(u->err)); 96 | break; 97 | case 2: 98 | lua_pushfstring(T, "error connecting to '%s': %s", 99 | u->path, strerror(u->err)); 100 | break; 101 | } 102 | lem_queue(T, 2); 103 | free(u); 104 | } 105 | 106 | static int 107 | unix_connect(lua_State *T) 108 | { 109 | size_t len; 110 | const char *path = luaL_checklstring(T, 1, &len); 111 | struct unix_create *u; 112 | 113 | if (len >= UNIX_PATH_MAX) 114 | return luaL_argerror(T, 1, "path too long"); 115 | 116 | u = lem_xmalloc(sizeof(struct unix_create)); 117 | u->T = T; 118 | u->path = path; 119 | u->len = len; 120 | lem_async_do(&u->a, unix_connect_work, unix_connect_reap); 121 | 122 | lua_settop(T, 1); 123 | lua_pushvalue(T, lua_upvalueindex(1)); 124 | return lua_yield(T, 2); 125 | } 126 | 127 | static void 128 | unix_listen_work(struct lem_async *a) 129 | { 130 | struct unix_create *u = (struct unix_create *)a; 131 | struct sockaddr_un addr; 132 | int sock; 133 | 134 | sock = socket(AF_UNIX, 135 | #ifdef SOCK_CLOEXEC 136 | SOCK_CLOEXEC | 137 | #endif 138 | SOCK_STREAM, 0); 139 | if (sock < 0) { 140 | u->sock = -1; 141 | u->err = errno; 142 | return; 143 | } 144 | #ifndef SOCK_CLOEXEC 145 | if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) { 146 | u->sock = -1; 147 | u->err = errno; 148 | goto error; 149 | } 150 | #endif 151 | addr.sun_family = AF_UNIX; 152 | memcpy(addr.sun_path, u->path, u->len+1); 153 | 154 | if (bind(sock, (struct sockaddr *)&addr, 155 | offsetof(struct sockaddr_un, sun_path) + u->len)) { 156 | u->sock = -2; 157 | u->err = errno; 158 | goto error; 159 | } 160 | 161 | if (u->sock >= 0 && chmod(u->path, u->sock)) { 162 | u->sock = -3; 163 | u->err = errno; 164 | goto error; 165 | } 166 | 167 | if (listen(sock, u->err)) { 168 | u->sock = -4; 169 | u->err = errno; 170 | goto error; 171 | } 172 | 173 | /* make the socket non-blocking */ 174 | if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) { 175 | u->sock = -1; 176 | u->err = errno; 177 | goto error; 178 | } 179 | 180 | u->sock = sock; 181 | return; 182 | 183 | error: 184 | close(sock); 185 | } 186 | 187 | static void 188 | unix_listen_reap(struct lem_async *a) 189 | { 190 | struct unix_create *u = (struct unix_create *)a; 191 | lua_State *T = u->T; 192 | int sock = u->sock; 193 | 194 | if (sock >= 0) { 195 | free(u); 196 | server_new(T, sock, 2); 197 | lem_queue(T, 1); 198 | return; 199 | } 200 | 201 | lua_pushnil(T); 202 | switch (-sock) { 203 | case 1: 204 | lua_pushfstring(T, "error creating socket: %s", 205 | strerror(u->err)); 206 | break; 207 | case 2: 208 | lua_pushfstring(T, "error binding to '%s': %s", 209 | u->path, strerror(u->err)); 210 | break; 211 | case 3: 212 | lua_pushfstring(T, "error setting permissions on '%s': %s", 213 | u->path, strerror(u->err)); 214 | break; 215 | case 4: 216 | lua_pushfstring(T, "error listening on '%s': %s", 217 | u->path, strerror(u->err)); 218 | break; 219 | } 220 | lem_queue(T, 2); 221 | free(u); 222 | } 223 | 224 | static int 225 | unix_listen(lua_State *T) 226 | { 227 | size_t len; 228 | const char *path = luaL_checklstring(T, 1, &len); 229 | int perm = io_optperm(T, 2); 230 | int backlog = (int)luaL_optnumber(T, 3, MAXPENDING); 231 | struct unix_create *u; 232 | 233 | if (len >= UNIX_PATH_MAX) 234 | return luaL_argerror(T, 1, "path too long"); 235 | 236 | u = lem_xmalloc(sizeof(struct unix_create)); 237 | u->T = T; 238 | u->path = path; 239 | u->len = len; 240 | u->sock = perm; 241 | u->err = backlog; 242 | lem_async_do(&u->a, unix_listen_work, unix_listen_reap); 243 | 244 | lua_settop(T, 1); 245 | lua_pushvalue(T, lua_upvalueindex(1)); 246 | return lua_yield(T, 2); 247 | } 248 | -------------------------------------------------------------------------------- /lem/lfs.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- This file is part of LEM, a Lua Event Machine. 3 | -- Copyright 2012 Emil Renner Berthing 4 | -- 5 | -- LEM is free software: you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as 7 | -- published by the Free Software Foundation, either version 3 of 8 | -- the License, or (at your option) any later version. 9 | -- 10 | -- LEM is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU Lesser General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public 16 | -- License along with LEM. If not, see . 17 | -- 18 | 19 | local lfs = require 'lem.lfs.core' 20 | 21 | function lfs.lock(file, ...) 22 | return file:lock(...) 23 | end 24 | 25 | function lfs.unlock(file, ...) 26 | return file:lock('u', ...) 27 | end 28 | 29 | function lfs.setmode() 30 | return 'binary' 31 | end 32 | 33 | do 34 | local setmetatable, remove, link = setmetatable, lfs.remove, lfs.link 35 | 36 | local Lock = { __index = true, free = true } 37 | Lock.__index = Lock 38 | 39 | function Lock:free() 40 | return remove(self.filename) 41 | end 42 | 43 | function lfs.lock_dir(path) 44 | local filename = path .. '/lockfile.lfs' 45 | local ok, err = link('lock', filename, true) 46 | if not ok then return ok, err end 47 | 48 | return setmetatable({ filename = filename }, Lock) 49 | end 50 | end 51 | 52 | return lfs 53 | 54 | -- vim: ts=2 sw=2 noet: 55 | -------------------------------------------------------------------------------- /lem/parsers.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- This file is part of LEM, a Lua Event Machine. 3 | -- Copyright 2012-2013 Emil Renner Berthing 4 | -- 5 | -- LEM is free software: you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as 7 | -- published by the Free Software Foundation, either version 3 of 8 | -- the License, or (at your option) any later version. 9 | -- 10 | -- LEM is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU Lesser General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public 16 | -- License along with LEM. If not, see . 17 | -- 18 | 19 | local parsers = require 'lem.parsers.core' 20 | 21 | local type = type 22 | local error = error 23 | 24 | local lookup = parsers.lookup 25 | local available = lookup.available 26 | lookup.available = nil 27 | local target = lookup.target 28 | lookup.target = nil 29 | 30 | function parsers.newreader(readp) 31 | return function(self, fmt, ...) 32 | if fmt == nil then 33 | return readp(self, available) 34 | end 35 | if type(fmt) == 'number' then 36 | return readp(self, target, fmt) 37 | end 38 | local parser = lookup[fmt] 39 | if parser == nil then 40 | error('invalid format', 2) 41 | end 42 | return readp(self, parser, ...) 43 | end 44 | end 45 | 46 | return parsers 47 | 48 | -- vim: ts=2 sw=2 noet: 49 | -------------------------------------------------------------------------------- /lem/queue.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- This file is part of LEM, a Lua Event Machine. 3 | -- Copyright 2013 Emil Renner Berthing 4 | -- 5 | -- LEM is free software: you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as 7 | -- published by the Free Software Foundation, either version 3 of 8 | -- the License, or (at your option) any later version. 9 | -- 10 | -- LEM is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU Lesser General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public 16 | -- License along with LEM. If not, see . 17 | -- 18 | 19 | local utils = require 'lem.utils' 20 | 21 | local M = {} 22 | 23 | local Queue = {} 24 | Queue.__index = Queue 25 | M.Queue = Queue 26 | 27 | local remove = table.remove 28 | local thisthread, suspend, resume = 29 | utils.thisthread, utils.suspend, utils.resume 30 | 31 | function Queue:put(v) 32 | local n = self.n + 1 33 | self.n = n 34 | 35 | if n >= 1 then 36 | self[n] = v 37 | else 38 | resume(remove(self, 1), v) 39 | end 40 | end 41 | 42 | function Queue:signal(...) 43 | local n = self.n 44 | if n < 0 then 45 | for i = 1, -n do 46 | resume(self[i], ...) 47 | self[i] = nil 48 | end 49 | self.n = 0 50 | end 51 | end 52 | 53 | function Queue:get() 54 | local n = self.n - 1 55 | self.n = n 56 | 57 | if n >= 0 then 58 | return remove(self, 1) 59 | end 60 | 61 | self[-n] = thisthread() 62 | return suspend() 63 | end 64 | 65 | function Queue:reset() 66 | self:signal(nil, 'reset') 67 | for i = self.n, 1, -1 do 68 | self[i] = nil 69 | end 70 | self.n = 0 71 | end 72 | 73 | local get = Queue.get 74 | function Queue:consume() 75 | return get, self 76 | end 77 | 78 | function Queue:empty() 79 | return self.n <= 0 80 | end 81 | 82 | function M.new() 83 | return setmetatable({ n = 0 }, Queue) 84 | end 85 | 86 | return M 87 | 88 | -- vim: ts=2 sw=2 noet: 89 | -------------------------------------------------------------------------------- /lem/repl.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- This file is part of LEM, a Lua Event Machine. 3 | -- Copyright 2011-2013 Emil Renner Berthing 4 | -- 5 | -- LEM is free software: you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as 7 | -- published by the Free Software Foundation, either version 3 of 8 | -- the License, or (at your option) any later version. 9 | -- 10 | -- LEM is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU Lesser General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public 16 | -- License along with LEM. If not, see . 17 | -- 18 | 19 | local load = load 20 | 21 | local format = string.format 22 | local concat = table.concat 23 | local tostring = tostring 24 | local select = select 25 | 26 | local function repl(name, ins, outs) 27 | name = '=' .. name 28 | 29 | local function onreturn(ok, ...) 30 | if not ok then 31 | local ok, err = outs:write(format("%s\n", select(1, ...))) 32 | if not ok then return nil, err end 33 | return true 34 | end 35 | 36 | local args = select('#', ...) 37 | if args == 0 then return true end 38 | 39 | local rstr 40 | do 41 | local t = { ... } 42 | for i = 1, args - 1 do 43 | t[i] = tostring(t[i]) 44 | end 45 | t[args] = tostring(t[args])..'\n' 46 | 47 | rstr = concat(t, '\t') 48 | end 49 | 50 | local ok, err = outs:write(rstr) 51 | if not ok then return nil, err end 52 | 53 | return true 54 | end 55 | 56 | while true do 57 | local res, err = outs:write('> ') 58 | if not res then return nil, err end 59 | 60 | res, err = ins:read('*l') 61 | if not res then return nil, err end 62 | 63 | local line = res:gsub('^=', 'return ') 64 | 65 | while true do 66 | res, err = load(line, name) 67 | if res then 68 | res, err = onreturn(pcall(res)) 69 | if not res then return nil, err end 70 | break 71 | end 72 | 73 | if not err:match("") then 74 | res, err = outs:write(format("%s\n", err)) 75 | if not res then return nil, err end 76 | break 77 | end 78 | 79 | res, err = outs:write('>> ') 80 | if not res then return nil, err end 81 | 82 | res, err = ins:read('*l') 83 | if not res then return nil, err end 84 | 85 | line = line .. ('\n' .. res) 86 | end 87 | end 88 | end 89 | 90 | -- if not run directly just return the module table 91 | if not arg or arg[0] then 92 | return { repl = repl } 93 | end 94 | 95 | local io = require 'lem.io' 96 | 97 | io.stdout:write([[ 98 | A Lua Event Machine 0.3 Copyright 2011-2013 Emil Renner Berthing 99 | ]]) 100 | 101 | local _, err = repl('stdin', io.stdin, io.stdout) 102 | print(err or '') 103 | 104 | -- vim: ts=2 sw=2 noet: 105 | -------------------------------------------------------------------------------- /lem/signal.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- This file is part of LEM, a Lua Event Machine. 3 | -- Copyright 2013 Asbjørn Sloth Tønnesen 4 | -- 5 | -- LEM is free software: you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as 7 | -- published by the Free Software Foundation, either version 3 of 8 | -- the License, or (at your option) any later version. 9 | -- 10 | -- LEM is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU Lesser General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public 16 | -- License along with LEM. If not, see . 17 | -- 18 | 19 | local core = require 'lem.signal.core' 20 | 21 | local queues = {} 22 | 23 | local function fire(signal, ...) 24 | local queue = queues[signal] 25 | for i = 1, #queue do 26 | queue[i](signal, ...) 27 | end 28 | end 29 | 30 | local install_signal_handler 31 | do 32 | local installed = false 33 | function install_signal_handler() 34 | if not installed then 35 | core.sethandler(function(signal, ...) 36 | fire(signal, ...) 37 | end) 38 | installed = true 39 | end 40 | end 41 | end 42 | 43 | local signal_install, signal_uninstall 44 | do 45 | local installed = {} 46 | 47 | function signal_install(sig) 48 | if installed[sig] then 49 | return true 50 | end 51 | 52 | install_signal_handler() 53 | 54 | local ret, err = core.watch(sig) 55 | if not ret then return nil, err end 56 | 57 | installed[sig] = true 58 | return true 59 | end 60 | 61 | function signal_uninstall(sig) 62 | if not installed[sig] then 63 | return true 64 | end 65 | 66 | local ret, err = core.unwatch(sig) 67 | if not ret then return nil, err end 68 | 69 | installed[sig] = nil 70 | return true 71 | end 72 | end 73 | 74 | local function lookup(signal) 75 | if type(signal) == 'string' then 76 | if string.sub(signal, 1, 3):upper() == 'SIG' then 77 | signal = string.sub(signal, 4) 78 | end 79 | return core.tonumber(signal:upper()) 80 | else 81 | local ret = core.tostring(signal) 82 | if not ret then return nil end 83 | 84 | return 'SIG' .. ret 85 | end 86 | end 87 | 88 | local M = {} 89 | M.lookup = lookup 90 | 91 | function M.register(signal, func) 92 | assert(type(signal) == 'string', 'signal should be a string') 93 | local signum = lookup(signal) 94 | if not signum then return nil, 'unknown signal' end 95 | 96 | local queue = queues[signum] 97 | if queue == nil then 98 | queue = {} 99 | queues[signum] = queue 100 | end 101 | table.insert(queue, func) 102 | return signal_install(signum) 103 | end 104 | 105 | function M.unregister(signal, func) 106 | assert(type(signal) == 'string', 'signal should be a string') 107 | local signum = lookup(signal) 108 | if not signum then return nil, 'unknown signal' end 109 | 110 | local queue = queues[signum] 111 | if queue then 112 | for i = 1, #queue do 113 | if queue[i] == func then 114 | table.remove(queue, i) 115 | end 116 | end 117 | if #queue == 0 then 118 | return signal_uninstall(signum) 119 | end 120 | end 121 | return true 122 | end 123 | 124 | return M 125 | 126 | -- vim: ts=2 sw=2 noet: 127 | -------------------------------------------------------------------------------- /libev/LICENSE: -------------------------------------------------------------------------------- 1 | All files in libev are 2 | Copyright (c)2007,2008,2009,2010,2011,2012,2013 Marc Alexander Lehmann. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | Alternatively, the contents of this package may be used under the terms 29 | of the GNU General Public License ("GPL") version 2 or any later version, 30 | in which case the provisions of the GPL are applicable instead of the 31 | above. If you wish to allow the use of your version of this package only 32 | under the terms of the GPL and not to allow others to use your version of 33 | this file under the BSD license, indicate your decision by deleting the 34 | provisions above and replace them with the notice and other provisions 35 | required by the GPL in this and the other files of this package. If you do 36 | not delete the provisions above, a recipient may use your version of this 37 | file under either the BSD or the GPL. 38 | -------------------------------------------------------------------------------- /libev/Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = foreign 2 | 3 | VERSION_INFO = 4:0:0 4 | 5 | EXTRA_DIST = LICENSE Changes libev.m4 autogen.sh \ 6 | ev_vars.h ev_wrap.h \ 7 | ev_epoll.c ev_select.c ev_poll.c ev_kqueue.c ev_port.c ev_win32.c \ 8 | ev.3 ev.pod Symbols.ev Symbols.event 9 | 10 | man_MANS = ev.3 11 | 12 | include_HEADERS = ev.h ev++.h event.h 13 | 14 | lib_LTLIBRARIES = libev.la 15 | 16 | libev_la_SOURCES = ev.c event.c 17 | libev_la_LDFLAGS = -version-info $(VERSION_INFO) 18 | 19 | ev.3: ev.pod 20 | pod2man -n LIBEV -r "libev-$(VERSION)" -c "libev - high performance full featured event loop" -s3 <$< >$@ 21 | -------------------------------------------------------------------------------- /libev/README: -------------------------------------------------------------------------------- 1 | libev is a high-performance event loop/event model with lots of features. 2 | (see benchmark at http://libev.schmorp.de/bench.html) 3 | 4 | 5 | ABOUT 6 | 7 | Homepage: http://software.schmorp.de/pkg/libev 8 | Mailinglist: libev@lists.schmorp.de 9 | http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev 10 | Library Documentation: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod 11 | 12 | Libev is modelled (very losely) after libevent and the Event perl 13 | module, but is faster, scales better and is more correct, and also more 14 | featureful. And also smaller. Yay. 15 | 16 | Some of the specialties of libev not commonly found elsewhere are: 17 | 18 | - extensive and detailed, readable documentation (not doxygen garbage). 19 | - fully supports fork, can detect fork in various ways and automatically 20 | re-arms kernel mechanisms that do not support fork. 21 | - highly optimised select, poll, epoll, kqueue and event ports backends. 22 | - filesystem object (path) watching (with optional linux inotify support). 23 | - wallclock-based times (using absolute time, cron-like). 24 | - relative timers/timeouts (handle time jumps). 25 | - fast intra-thread communication between multiple 26 | event loops (with optional fast linux eventfd backend). 27 | - extremely easy to embed (fully documented, no dependencies, 28 | autoconf supported but optional). 29 | - very small codebase, no bloated library, simple code. 30 | - fully extensible by being able to plug into the event loop, 31 | integrate other event loops, integrate other event loop users. 32 | - very little memory use (small watchers, small event loop data). 33 | - optional C++ interface allowing method and function callbacks 34 | at no extra memory or runtime overhead. 35 | - optional Perl interface with similar characteristics (capable 36 | of running Glib/Gtk2 on libev). 37 | - support for other languages (multiple C++ interfaces, D, Ruby, 38 | Python) available from third-parties. 39 | 40 | Examples of programs that embed libev: the EV perl module, node.js, 41 | auditd, rxvt-unicode, gvpe (GNU Virtual Private Ethernet), the 42 | Deliantra MMORPG server (http://www.deliantra.net/), Rubinius (a 43 | next-generation Ruby VM), the Ebb web server, the Rev event toolkit. 44 | 45 | 46 | CONTRIBUTORS 47 | 48 | libev was written and designed by Marc Lehmann and Emanuele Giaquinta. 49 | 50 | The following people sent in patches or made other noteworthy 51 | contributions to the design (for minor patches, see the Changes 52 | file. If I forgot to include you, please shout at me, it was an 53 | accident): 54 | 55 | W.C.A. Wijngaards 56 | Christopher Layne 57 | Chris Brody 58 | 59 | -------------------------------------------------------------------------------- /libev/Symbols.ev: -------------------------------------------------------------------------------- 1 | ev_async_send 2 | ev_async_start 3 | ev_async_stop 4 | ev_backend 5 | ev_break 6 | ev_check_start 7 | ev_check_stop 8 | ev_child_start 9 | ev_child_stop 10 | ev_cleanup_start 11 | ev_cleanup_stop 12 | ev_clear_pending 13 | ev_default_loop 14 | ev_default_loop_ptr 15 | ev_depth 16 | ev_embed_start 17 | ev_embed_stop 18 | ev_embed_sweep 19 | ev_embeddable_backends 20 | ev_feed_event 21 | ev_feed_fd_event 22 | ev_feed_signal 23 | ev_feed_signal_event 24 | ev_fork_start 25 | ev_fork_stop 26 | ev_idle_start 27 | ev_idle_stop 28 | ev_invoke 29 | ev_invoke_pending 30 | ev_io_start 31 | ev_io_stop 32 | ev_iteration 33 | ev_loop_destroy 34 | ev_loop_fork 35 | ev_loop_new 36 | ev_now 37 | ev_now_update 38 | ev_once 39 | ev_pending_count 40 | ev_periodic_again 41 | ev_periodic_start 42 | ev_periodic_stop 43 | ev_prepare_start 44 | ev_prepare_stop 45 | ev_recommended_backends 46 | ev_ref 47 | ev_resume 48 | ev_run 49 | ev_set_allocator 50 | ev_set_invoke_pending_cb 51 | ev_set_io_collect_interval 52 | ev_set_loop_release_cb 53 | ev_set_syserr_cb 54 | ev_set_timeout_collect_interval 55 | ev_set_userdata 56 | ev_signal_start 57 | ev_signal_stop 58 | ev_sleep 59 | ev_stat_start 60 | ev_stat_stat 61 | ev_stat_stop 62 | ev_supported_backends 63 | ev_suspend 64 | ev_time 65 | ev_timer_again 66 | ev_timer_remaining 67 | ev_timer_start 68 | ev_timer_stop 69 | ev_unref 70 | ev_userdata 71 | ev_verify 72 | ev_version_major 73 | ev_version_minor 74 | -------------------------------------------------------------------------------- /libev/Symbols.event: -------------------------------------------------------------------------------- 1 | event_active 2 | event_add 3 | event_base_dispatch 4 | event_base_free 5 | event_base_get_method 6 | event_base_loop 7 | event_base_loopexit 8 | event_base_new 9 | event_base_once 10 | event_base_priority_init 11 | event_base_set 12 | event_del 13 | event_dispatch 14 | event_get_callback 15 | event_get_method 16 | event_get_version 17 | event_init 18 | event_loop 19 | event_loopexit 20 | event_once 21 | event_pending 22 | event_priority_init 23 | event_priority_set 24 | event_set 25 | -------------------------------------------------------------------------------- /libev/autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | autoreconf --install --symlink --force 4 | -------------------------------------------------------------------------------- /libev/config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define to 1 if you have the `clock_gettime' function. */ 4 | #undef HAVE_CLOCK_GETTIME 5 | 6 | /* Define to 1 to use the syscall interface for clock_gettime */ 7 | #undef HAVE_CLOCK_SYSCALL 8 | 9 | /* Define to 1 if you have the header file. */ 10 | #undef HAVE_DLFCN_H 11 | 12 | /* Define to 1 if you have the `epoll_ctl' function. */ 13 | #undef HAVE_EPOLL_CTL 14 | 15 | /* Define to 1 if you have the `eventfd' function. */ 16 | #undef HAVE_EVENTFD 17 | 18 | /* Define to 1 if the floor function is available */ 19 | #undef HAVE_FLOOR 20 | 21 | /* Define to 1 if you have the `inotify_init' function. */ 22 | #undef HAVE_INOTIFY_INIT 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #undef HAVE_INTTYPES_H 26 | 27 | /* Define to 1 if you have the `kqueue' function. */ 28 | #undef HAVE_KQUEUE 29 | 30 | /* Define to 1 if you have the `rt' library (-lrt). */ 31 | #undef HAVE_LIBRT 32 | 33 | /* Define to 1 if you have the header file. */ 34 | #undef HAVE_MEMORY_H 35 | 36 | /* Define to 1 if you have the `nanosleep' function. */ 37 | #undef HAVE_NANOSLEEP 38 | 39 | /* Define to 1 if you have the `poll' function. */ 40 | #undef HAVE_POLL 41 | 42 | /* Define to 1 if you have the header file. */ 43 | #undef HAVE_POLL_H 44 | 45 | /* Define to 1 if you have the `port_create' function. */ 46 | #undef HAVE_PORT_CREATE 47 | 48 | /* Define to 1 if you have the header file. */ 49 | #undef HAVE_PORT_H 50 | 51 | /* Define to 1 if you have the `select' function. */ 52 | #undef HAVE_SELECT 53 | 54 | /* Define to 1 if you have the `signalfd' function. */ 55 | #undef HAVE_SIGNALFD 56 | 57 | /* Define to 1 if you have the header file. */ 58 | #undef HAVE_STDINT_H 59 | 60 | /* Define to 1 if you have the header file. */ 61 | #undef HAVE_STDLIB_H 62 | 63 | /* Define to 1 if you have the header file. */ 64 | #undef HAVE_STRINGS_H 65 | 66 | /* Define to 1 if you have the header file. */ 67 | #undef HAVE_STRING_H 68 | 69 | /* Define to 1 if you have the header file. */ 70 | #undef HAVE_SYS_EPOLL_H 71 | 72 | /* Define to 1 if you have the header file. */ 73 | #undef HAVE_SYS_EVENTFD_H 74 | 75 | /* Define to 1 if you have the header file. */ 76 | #undef HAVE_SYS_EVENT_H 77 | 78 | /* Define to 1 if you have the header file. */ 79 | #undef HAVE_SYS_INOTIFY_H 80 | 81 | /* Define to 1 if you have the header file. */ 82 | #undef HAVE_SYS_SELECT_H 83 | 84 | /* Define to 1 if you have the header file. */ 85 | #undef HAVE_SYS_SIGNALFD_H 86 | 87 | /* Define to 1 if you have the header file. */ 88 | #undef HAVE_SYS_STAT_H 89 | 90 | /* Define to 1 if you have the header file. */ 91 | #undef HAVE_SYS_TYPES_H 92 | 93 | /* Define to 1 if you have the header file. */ 94 | #undef HAVE_UNISTD_H 95 | 96 | /* Define to the sub-directory in which libtool stores uninstalled libraries. 97 | */ 98 | #undef LT_OBJDIR 99 | 100 | /* Name of package */ 101 | #undef PACKAGE 102 | 103 | /* Define to the address where bug reports for this package should be sent. */ 104 | #undef PACKAGE_BUGREPORT 105 | 106 | /* Define to the full name of this package. */ 107 | #undef PACKAGE_NAME 108 | 109 | /* Define to the full name and version of this package. */ 110 | #undef PACKAGE_STRING 111 | 112 | /* Define to the one symbol short name of this package. */ 113 | #undef PACKAGE_TARNAME 114 | 115 | /* Define to the home page for this package. */ 116 | #undef PACKAGE_URL 117 | 118 | /* Define to the version of this package. */ 119 | #undef PACKAGE_VERSION 120 | 121 | /* Define to 1 if you have the ANSI C header files. */ 122 | #undef STDC_HEADERS 123 | 124 | /* Version number of package */ 125 | #undef VERSION 126 | -------------------------------------------------------------------------------- /libev/configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT 2 | 3 | orig_CFLAGS="$CFLAGS" 4 | 5 | AC_CONFIG_SRCDIR([ev_epoll.c]) 6 | 7 | dnl also update ev.h! 8 | AM_INIT_AUTOMAKE(libev,4.22) 9 | AC_CONFIG_HEADERS([config.h]) 10 | AM_MAINTAINER_MODE 11 | 12 | AC_PROG_CC 13 | 14 | dnl Supply default CFLAGS, if not specified 15 | if test -z "$orig_CFLAGS"; then 16 | if test x$GCC = xyes; then 17 | CFLAGS="-g -O3" 18 | fi 19 | fi 20 | 21 | AC_PROG_INSTALL 22 | AC_PROG_LIBTOOL 23 | 24 | m4_include([libev.m4]) 25 | 26 | AC_CONFIG_FILES([Makefile]) 27 | AC_OUTPUT 28 | -------------------------------------------------------------------------------- /libev/ev_poll.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libev poll fd activity backend 3 | * 4 | * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modifica- 8 | * tion, are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 19 | * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 21 | * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 25 | * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | * OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | * Alternatively, the contents of this file may be used under the terms of 29 | * the GNU General Public License ("GPL") version 2 or any later version, 30 | * in which case the provisions of the GPL are applicable instead of 31 | * the above. If you wish to allow the use of your version of this file 32 | * only under the terms of the GPL and not to allow others to use your 33 | * version of this file under the BSD license, indicate your decision 34 | * by deleting the provisions above and replace them with the notice 35 | * and other provisions required by the GPL. If you do not delete the 36 | * provisions above, a recipient may use your version of this file under 37 | * either the BSD or the GPL. 38 | */ 39 | 40 | #include 41 | 42 | void inline_size 43 | pollidx_init (int *base, int count) 44 | { 45 | /* consider using memset (.., -1, ...), which is practically guaranteed 46 | * to work on all systems implementing poll */ 47 | while (count--) 48 | *base++ = -1; 49 | } 50 | 51 | static void 52 | poll_modify (EV_P_ int fd, int oev, int nev) 53 | { 54 | int idx; 55 | 56 | if (oev == nev) 57 | return; 58 | 59 | array_needsize (int, pollidxs, pollidxmax, fd + 1, pollidx_init); 60 | 61 | idx = pollidxs [fd]; 62 | 63 | if (idx < 0) /* need to allocate a new pollfd */ 64 | { 65 | pollidxs [fd] = idx = pollcnt++; 66 | array_needsize (struct pollfd, polls, pollmax, pollcnt, EMPTY2); 67 | polls [idx].fd = fd; 68 | } 69 | 70 | assert (polls [idx].fd == fd); 71 | 72 | if (nev) 73 | polls [idx].events = 74 | (nev & EV_READ ? POLLIN : 0) 75 | | (nev & EV_WRITE ? POLLOUT : 0); 76 | else /* remove pollfd */ 77 | { 78 | pollidxs [fd] = -1; 79 | 80 | if (expect_true (idx < --pollcnt)) 81 | { 82 | polls [idx] = polls [pollcnt]; 83 | pollidxs [polls [idx].fd] = idx; 84 | } 85 | } 86 | } 87 | 88 | static void 89 | poll_poll (EV_P_ ev_tstamp timeout) 90 | { 91 | struct pollfd *p; 92 | int res; 93 | 94 | EV_RELEASE_CB; 95 | res = poll (polls, pollcnt, timeout * 1e3); 96 | EV_ACQUIRE_CB; 97 | 98 | if (expect_false (res < 0)) 99 | { 100 | if (errno == EBADF) 101 | fd_ebadf (EV_A); 102 | else if (errno == ENOMEM && !syserr_cb) 103 | fd_enomem (EV_A); 104 | else if (errno != EINTR) 105 | ev_syserr ("(libev) poll"); 106 | } 107 | else 108 | for (p = polls; res; ++p) 109 | { 110 | assert (("libev: poll() returned illegal result, broken BSD kernel?", p < polls + pollcnt)); 111 | 112 | if (expect_false (p->revents)) /* this expect is debatable */ 113 | { 114 | --res; 115 | 116 | if (expect_false (p->revents & POLLNVAL)) 117 | fd_kill (EV_A_ p->fd); 118 | else 119 | fd_event ( 120 | EV_A_ 121 | p->fd, 122 | (p->revents & (POLLOUT | POLLERR | POLLHUP) ? EV_WRITE : 0) 123 | | (p->revents & (POLLIN | POLLERR | POLLHUP) ? EV_READ : 0) 124 | ); 125 | } 126 | } 127 | } 128 | 129 | int inline_size 130 | poll_init (EV_P_ int flags) 131 | { 132 | backend_mintime = 1e-3; 133 | backend_modify = poll_modify; 134 | backend_poll = poll_poll; 135 | 136 | pollidxs = 0; pollidxmax = 0; 137 | polls = 0; pollmax = 0; pollcnt = 0; 138 | 139 | return EVBACKEND_POLL; 140 | } 141 | 142 | void inline_size 143 | poll_destroy (EV_P) 144 | { 145 | ev_free (pollidxs); 146 | ev_free (polls); 147 | } 148 | 149 | -------------------------------------------------------------------------------- /libev/ev_win32.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libev win32 compatibility cruft (_not_ a backend) 3 | * 4 | * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modifica- 8 | * tion, are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 19 | * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 21 | * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 25 | * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | * OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | * Alternatively, the contents of this file may be used under the terms of 29 | * the GNU General Public License ("GPL") version 2 or any later version, 30 | * in which case the provisions of the GPL are applicable instead of 31 | * the above. If you wish to allow the use of your version of this file 32 | * only under the terms of the GPL and not to allow others to use your 33 | * version of this file under the BSD license, indicate your decision 34 | * by deleting the provisions above and replace them with the notice 35 | * and other provisions required by the GPL. If you do not delete the 36 | * provisions above, a recipient may use your version of this file under 37 | * either the BSD or the GPL. 38 | */ 39 | 40 | #ifdef _WIN32 41 | 42 | /* note: the comment below could not be substantiated, but what would I care */ 43 | /* MSDN says this is required to handle SIGFPE */ 44 | /* my wild guess would be that using something floating-pointy is required */ 45 | /* for the crt to do something about it */ 46 | volatile double SIGFPE_REQ = 0.0f; 47 | 48 | static SOCKET 49 | ev_tcp_socket (void) 50 | { 51 | #if EV_USE_WSASOCKET 52 | return WSASocket (AF_INET, SOCK_STREAM, 0, 0, 0, 0); 53 | #else 54 | return socket (AF_INET, SOCK_STREAM, 0); 55 | #endif 56 | } 57 | 58 | /* oh, the humanity! */ 59 | static int 60 | ev_pipe (int filedes [2]) 61 | { 62 | struct sockaddr_in addr = { 0 }; 63 | int addr_size = sizeof (addr); 64 | struct sockaddr_in adr2; 65 | int adr2_size = sizeof (adr2); 66 | SOCKET listener; 67 | SOCKET sock [2] = { -1, -1 }; 68 | 69 | if ((listener = ev_tcp_socket ()) == INVALID_SOCKET) 70 | return -1; 71 | 72 | addr.sin_family = AF_INET; 73 | addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); 74 | addr.sin_port = 0; 75 | 76 | if (bind (listener, (struct sockaddr *)&addr, addr_size)) 77 | goto fail; 78 | 79 | if (getsockname (listener, (struct sockaddr *)&addr, &addr_size)) 80 | goto fail; 81 | 82 | if (listen (listener, 1)) 83 | goto fail; 84 | 85 | if ((sock [0] = ev_tcp_socket ()) == INVALID_SOCKET) 86 | goto fail; 87 | 88 | if (connect (sock [0], (struct sockaddr *)&addr, addr_size)) 89 | goto fail; 90 | 91 | /* TODO: returns INVALID_SOCKET on winsock accept, not < 0. fix it */ 92 | /* when convenient, probably by just removing error checking altogether? */ 93 | if ((sock [1] = accept (listener, 0, 0)) < 0) 94 | goto fail; 95 | 96 | /* windows vista returns fantasy port numbers for sockets: 97 | * example for two interconnected tcp sockets: 98 | * 99 | * (Socket::unpack_sockaddr_in getsockname $sock0)[0] == 53364 100 | * (Socket::unpack_sockaddr_in getpeername $sock0)[0] == 53363 101 | * (Socket::unpack_sockaddr_in getsockname $sock1)[0] == 53363 102 | * (Socket::unpack_sockaddr_in getpeername $sock1)[0] == 53365 103 | * 104 | * wow! tridirectional sockets! 105 | * 106 | * this way of checking ports seems to work: 107 | */ 108 | if (getpeername (sock [0], (struct sockaddr *)&addr, &addr_size)) 109 | goto fail; 110 | 111 | if (getsockname (sock [1], (struct sockaddr *)&adr2, &adr2_size)) 112 | goto fail; 113 | 114 | errno = WSAEINVAL; 115 | if (addr_size != adr2_size 116 | || addr.sin_addr.s_addr != adr2.sin_addr.s_addr /* just to be sure, I mean, it's windows */ 117 | || addr.sin_port != adr2.sin_port) 118 | goto fail; 119 | 120 | closesocket (listener); 121 | 122 | #if EV_SELECT_IS_WINSOCKET 123 | filedes [0] = EV_WIN32_HANDLE_TO_FD (sock [0]); 124 | filedes [1] = EV_WIN32_HANDLE_TO_FD (sock [1]); 125 | #else 126 | /* when select isn't winsocket, we also expect socket, connect, accept etc. 127 | * to work on fds */ 128 | filedes [0] = sock [0]; 129 | filedes [1] = sock [1]; 130 | #endif 131 | 132 | return 0; 133 | 134 | fail: 135 | closesocket (listener); 136 | 137 | if (sock [0] != INVALID_SOCKET) closesocket (sock [0]); 138 | if (sock [1] != INVALID_SOCKET) closesocket (sock [1]); 139 | 140 | return -1; 141 | } 142 | 143 | #undef pipe 144 | #define pipe(filedes) ev_pipe (filedes) 145 | 146 | #define EV_HAVE_EV_TIME 1 147 | ev_tstamp 148 | ev_time (void) 149 | { 150 | FILETIME ft; 151 | ULARGE_INTEGER ui; 152 | 153 | GetSystemTimeAsFileTime (&ft); 154 | ui.u.LowPart = ft.dwLowDateTime; 155 | ui.u.HighPart = ft.dwHighDateTime; 156 | 157 | /* msvc cannot convert ulonglong to double... yes, it is that sucky */ 158 | return (LONGLONG)(ui.QuadPart - 116444736000000000) * 1e-7; 159 | } 160 | 161 | #endif 162 | 163 | -------------------------------------------------------------------------------- /libev/libev.m4: -------------------------------------------------------------------------------- 1 | dnl this file is part of libev, do not make local modifications 2 | dnl http://software.schmorp.de/pkg/libev 3 | 4 | dnl libev support 5 | AC_CHECK_HEADERS(sys/inotify.h sys/epoll.h sys/event.h port.h poll.h sys/select.h sys/eventfd.h sys/signalfd.h) 6 | 7 | AC_CHECK_FUNCS(inotify_init epoll_ctl kqueue port_create poll select eventfd signalfd) 8 | 9 | AC_CHECK_FUNCS(clock_gettime, [], [ 10 | dnl on linux, try syscall wrapper first 11 | if test $(uname) = Linux; then 12 | AC_MSG_CHECKING(for clock_gettime syscall) 13 | AC_LINK_IFELSE([AC_LANG_PROGRAM( 14 | [#include 15 | #include 16 | #include ], 17 | [struct timespec ts; int status = syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts)])], 18 | [ac_have_clock_syscall=1 19 | AC_DEFINE(HAVE_CLOCK_SYSCALL, 1, Define to 1 to use the syscall interface for clock_gettime) 20 | AC_MSG_RESULT(yes)], 21 | [AC_MSG_RESULT(no)]) 22 | fi 23 | if test -z "$LIBEV_M4_AVOID_LIBRT" && test -z "$ac_have_clock_syscall"; then 24 | AC_CHECK_LIB(rt, clock_gettime) 25 | unset ac_cv_func_clock_gettime 26 | AC_CHECK_FUNCS(clock_gettime) 27 | fi 28 | ]) 29 | 30 | AC_CHECK_FUNCS(nanosleep, [], [ 31 | if test -z "$LIBEV_M4_AVOID_LIBRT"; then 32 | AC_CHECK_LIB(rt, nanosleep) 33 | unset ac_cv_func_nanosleep 34 | AC_CHECK_FUNCS(nanosleep) 35 | fi 36 | ]) 37 | 38 | if test -z "$LIBEV_M4_AVOID_LIBM"; then 39 | LIBM=m 40 | fi 41 | AC_SEARCH_LIBS(floor, $LIBM, [AC_DEFINE(HAVE_FLOOR, 1, Define to 1 if the floor function is available)]) 42 | 43 | -------------------------------------------------------------------------------- /libev/mkinstalldirs: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # mkinstalldirs --- make directory hierarchy 3 | 4 | scriptversion=2009-04-28.21; # UTC 5 | 6 | # Original author: Noah Friedman 7 | # Created: 1993-05-16 8 | # Public domain. 9 | # 10 | # This file is maintained in Automake, please report 11 | # bugs to or send patches to 12 | # . 13 | 14 | nl=' 15 | ' 16 | IFS=" "" $nl" 17 | errstatus=0 18 | dirmode= 19 | 20 | usage="\ 21 | Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... 22 | 23 | Create each directory DIR (with mode MODE, if specified), including all 24 | leading file name components. 25 | 26 | Report bugs to ." 27 | 28 | # process command line arguments 29 | while test $# -gt 0 ; do 30 | case $1 in 31 | -h | --help | --h*) # -h for help 32 | echo "$usage" 33 | exit $? 34 | ;; 35 | -m) # -m PERM arg 36 | shift 37 | test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } 38 | dirmode=$1 39 | shift 40 | ;; 41 | --version) 42 | echo "$0 $scriptversion" 43 | exit $? 44 | ;; 45 | --) # stop option processing 46 | shift 47 | break 48 | ;; 49 | -*) # unknown option 50 | echo "$usage" 1>&2 51 | exit 1 52 | ;; 53 | *) # first non-opt arg 54 | break 55 | ;; 56 | esac 57 | done 58 | 59 | for file 60 | do 61 | if test -d "$file"; then 62 | shift 63 | else 64 | break 65 | fi 66 | done 67 | 68 | case $# in 69 | 0) exit 0 ;; 70 | esac 71 | 72 | # Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and 73 | # mkdir -p a/c at the same time, both will detect that a is missing, 74 | # one will create a, then the other will try to create a and die with 75 | # a "File exists" error. This is a problem when calling mkinstalldirs 76 | # from a parallel make. We use --version in the probe to restrict 77 | # ourselves to GNU mkdir, which is thread-safe. 78 | case $dirmode in 79 | '') 80 | if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then 81 | echo "mkdir -p -- $*" 82 | exec mkdir -p -- "$@" 83 | else 84 | # On NextStep and OpenStep, the 'mkdir' command does not 85 | # recognize any option. It will interpret all options as 86 | # directories to create, and then abort because '.' already 87 | # exists. 88 | test -d ./-p && rmdir ./-p 89 | test -d ./--version && rmdir ./--version 90 | fi 91 | ;; 92 | *) 93 | if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && 94 | test ! -d ./--version; then 95 | echo "mkdir -m $dirmode -p -- $*" 96 | exec mkdir -m "$dirmode" -p -- "$@" 97 | else 98 | # Clean up after NextStep and OpenStep mkdir. 99 | for d in ./-m ./-p ./--version "./$dirmode"; 100 | do 101 | test -d $d && rmdir $d 102 | done 103 | fi 104 | ;; 105 | esac 106 | 107 | for file 108 | do 109 | case $file in 110 | /*) pathcomp=/ ;; 111 | *) pathcomp= ;; 112 | esac 113 | oIFS=$IFS 114 | IFS=/ 115 | set fnord $file 116 | shift 117 | IFS=$oIFS 118 | 119 | for d 120 | do 121 | test "x$d" = x && continue 122 | 123 | pathcomp=$pathcomp$d 124 | case $pathcomp in 125 | -*) pathcomp=./$pathcomp ;; 126 | esac 127 | 128 | if test ! -d "$pathcomp"; then 129 | echo "mkdir $pathcomp" 130 | 131 | mkdir "$pathcomp" || lasterr=$? 132 | 133 | if test ! -d "$pathcomp"; then 134 | errstatus=$lasterr 135 | else 136 | if test ! -z "$dirmode"; then 137 | echo "chmod $dirmode $pathcomp" 138 | lasterr= 139 | chmod "$dirmode" "$pathcomp" || lasterr=$? 140 | 141 | if test ! -z "$lasterr"; then 142 | errstatus=$lasterr 143 | fi 144 | fi 145 | fi 146 | fi 147 | 148 | pathcomp=$pathcomp/ 149 | done 150 | done 151 | 152 | exit $errstatus 153 | 154 | # Local Variables: 155 | # mode: shell-script 156 | # sh-indentation: 2 157 | # eval: (add-hook 'write-file-hooks 'time-stamp) 158 | # time-stamp-start: "scriptversion=" 159 | # time-stamp-format: "%:y-%02m-%02d.%02H" 160 | # time-stamp-time-zone: "UTC" 161 | # time-stamp-end: "; # UTC" 162 | # End: 163 | -------------------------------------------------------------------------------- /lua/lapi.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lapi.h,v 2.9 2015/03/06 19:49:50 roberto Exp $ 3 | ** Auxiliary functions from Lua API 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lapi_h 8 | #define lapi_h 9 | 10 | 11 | #include "llimits.h" 12 | #include "lstate.h" 13 | 14 | #define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ 15 | "stack overflow");} 16 | 17 | #define adjustresults(L,nres) \ 18 | { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } 19 | 20 | #define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ 21 | "not enough elements in the stack") 22 | 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /lua/lbitlib.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lbitlib.c,v 1.30 2015/11/11 19:08:09 roberto Exp $ 3 | ** Standard library for bitwise operations 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lbitlib_c 8 | #define LUA_LIB 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include "lua.h" 14 | 15 | #include "lauxlib.h" 16 | #include "lualib.h" 17 | 18 | 19 | #if defined(LUA_COMPAT_BITLIB) /* { */ 20 | 21 | 22 | #define pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) 23 | #define checkunsigned(L,i) ((lua_Unsigned)luaL_checkinteger(L,i)) 24 | 25 | 26 | /* number of bits to consider in a number */ 27 | #if !defined(LUA_NBITS) 28 | #define LUA_NBITS 32 29 | #endif 30 | 31 | 32 | /* 33 | ** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must 34 | ** be made in two parts to avoid problems when LUA_NBITS is equal to the 35 | ** number of bits in a lua_Unsigned.) 36 | */ 37 | #define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) 38 | 39 | 40 | /* macro to trim extra bits */ 41 | #define trim(x) ((x) & ALLONES) 42 | 43 | 44 | /* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */ 45 | #define mask(n) (~((ALLONES << 1) << ((n) - 1))) 46 | 47 | 48 | 49 | static lua_Unsigned andaux (lua_State *L) { 50 | int i, n = lua_gettop(L); 51 | lua_Unsigned r = ~(lua_Unsigned)0; 52 | for (i = 1; i <= n; i++) 53 | r &= checkunsigned(L, i); 54 | return trim(r); 55 | } 56 | 57 | 58 | static int b_and (lua_State *L) { 59 | lua_Unsigned r = andaux(L); 60 | pushunsigned(L, r); 61 | return 1; 62 | } 63 | 64 | 65 | static int b_test (lua_State *L) { 66 | lua_Unsigned r = andaux(L); 67 | lua_pushboolean(L, r != 0); 68 | return 1; 69 | } 70 | 71 | 72 | static int b_or (lua_State *L) { 73 | int i, n = lua_gettop(L); 74 | lua_Unsigned r = 0; 75 | for (i = 1; i <= n; i++) 76 | r |= checkunsigned(L, i); 77 | pushunsigned(L, trim(r)); 78 | return 1; 79 | } 80 | 81 | 82 | static int b_xor (lua_State *L) { 83 | int i, n = lua_gettop(L); 84 | lua_Unsigned r = 0; 85 | for (i = 1; i <= n; i++) 86 | r ^= checkunsigned(L, i); 87 | pushunsigned(L, trim(r)); 88 | return 1; 89 | } 90 | 91 | 92 | static int b_not (lua_State *L) { 93 | lua_Unsigned r = ~checkunsigned(L, 1); 94 | pushunsigned(L, trim(r)); 95 | return 1; 96 | } 97 | 98 | 99 | static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) { 100 | if (i < 0) { /* shift right? */ 101 | i = -i; 102 | r = trim(r); 103 | if (i >= LUA_NBITS) r = 0; 104 | else r >>= i; 105 | } 106 | else { /* shift left */ 107 | if (i >= LUA_NBITS) r = 0; 108 | else r <<= i; 109 | r = trim(r); 110 | } 111 | pushunsigned(L, r); 112 | return 1; 113 | } 114 | 115 | 116 | static int b_lshift (lua_State *L) { 117 | return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2)); 118 | } 119 | 120 | 121 | static int b_rshift (lua_State *L) { 122 | return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2)); 123 | } 124 | 125 | 126 | static int b_arshift (lua_State *L) { 127 | lua_Unsigned r = checkunsigned(L, 1); 128 | lua_Integer i = luaL_checkinteger(L, 2); 129 | if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1)))) 130 | return b_shift(L, r, -i); 131 | else { /* arithmetic shift for 'negative' number */ 132 | if (i >= LUA_NBITS) r = ALLONES; 133 | else 134 | r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */ 135 | pushunsigned(L, r); 136 | return 1; 137 | } 138 | } 139 | 140 | 141 | static int b_rot (lua_State *L, lua_Integer d) { 142 | lua_Unsigned r = checkunsigned(L, 1); 143 | int i = d & (LUA_NBITS - 1); /* i = d % NBITS */ 144 | r = trim(r); 145 | if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */ 146 | r = (r << i) | (r >> (LUA_NBITS - i)); 147 | pushunsigned(L, trim(r)); 148 | return 1; 149 | } 150 | 151 | 152 | static int b_lrot (lua_State *L) { 153 | return b_rot(L, luaL_checkinteger(L, 2)); 154 | } 155 | 156 | 157 | static int b_rrot (lua_State *L) { 158 | return b_rot(L, -luaL_checkinteger(L, 2)); 159 | } 160 | 161 | 162 | /* 163 | ** get field and width arguments for field-manipulation functions, 164 | ** checking whether they are valid. 165 | ** ('luaL_error' called without 'return' to avoid later warnings about 166 | ** 'width' being used uninitialized.) 167 | */ 168 | static int fieldargs (lua_State *L, int farg, int *width) { 169 | lua_Integer f = luaL_checkinteger(L, farg); 170 | lua_Integer w = luaL_optinteger(L, farg + 1, 1); 171 | luaL_argcheck(L, 0 <= f, farg, "field cannot be negative"); 172 | luaL_argcheck(L, 0 < w, farg + 1, "width must be positive"); 173 | if (f + w > LUA_NBITS) 174 | luaL_error(L, "trying to access non-existent bits"); 175 | *width = (int)w; 176 | return (int)f; 177 | } 178 | 179 | 180 | static int b_extract (lua_State *L) { 181 | int w; 182 | lua_Unsigned r = trim(checkunsigned(L, 1)); 183 | int f = fieldargs(L, 2, &w); 184 | r = (r >> f) & mask(w); 185 | pushunsigned(L, r); 186 | return 1; 187 | } 188 | 189 | 190 | static int b_replace (lua_State *L) { 191 | int w; 192 | lua_Unsigned r = trim(checkunsigned(L, 1)); 193 | lua_Unsigned v = trim(checkunsigned(L, 2)); 194 | int f = fieldargs(L, 3, &w); 195 | lua_Unsigned m = mask(w); 196 | r = (r & ~(m << f)) | ((v & m) << f); 197 | pushunsigned(L, r); 198 | return 1; 199 | } 200 | 201 | 202 | static const luaL_Reg bitlib[] = { 203 | {"arshift", b_arshift}, 204 | {"band", b_and}, 205 | {"bnot", b_not}, 206 | {"bor", b_or}, 207 | {"bxor", b_xor}, 208 | {"btest", b_test}, 209 | {"extract", b_extract}, 210 | {"lrotate", b_lrot}, 211 | {"lshift", b_lshift}, 212 | {"replace", b_replace}, 213 | {"rrotate", b_rrot}, 214 | {"rshift", b_rshift}, 215 | {NULL, NULL} 216 | }; 217 | 218 | 219 | 220 | LUAMOD_API int luaopen_bit32 (lua_State *L) { 221 | luaL_newlib(L, bitlib); 222 | return 1; 223 | } 224 | 225 | 226 | #else /* }{ */ 227 | 228 | 229 | LUAMOD_API int luaopen_bit32 (lua_State *L) { 230 | return luaL_error(L, "library 'bit32' has been deprecated"); 231 | } 232 | 233 | #endif /* } */ 234 | -------------------------------------------------------------------------------- /lua/lcode.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lcode.h,v 1.63 2013/12/30 20:47:58 roberto Exp $ 3 | ** Code generator for Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lcode_h 8 | #define lcode_h 9 | 10 | #include "llex.h" 11 | #include "lobject.h" 12 | #include "lopcodes.h" 13 | #include "lparser.h" 14 | 15 | 16 | /* 17 | ** Marks the end of a patch list. It is an invalid value both as an absolute 18 | ** address, and as a list link (would link an element to itself). 19 | */ 20 | #define NO_JUMP (-1) 21 | 22 | 23 | /* 24 | ** grep "ORDER OPR" if you change these enums (ORDER OP) 25 | */ 26 | typedef enum BinOpr { 27 | OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW, 28 | OPR_DIV, 29 | OPR_IDIV, 30 | OPR_BAND, OPR_BOR, OPR_BXOR, 31 | OPR_SHL, OPR_SHR, 32 | OPR_CONCAT, 33 | OPR_EQ, OPR_LT, OPR_LE, 34 | OPR_NE, OPR_GT, OPR_GE, 35 | OPR_AND, OPR_OR, 36 | OPR_NOBINOPR 37 | } BinOpr; 38 | 39 | 40 | typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; 41 | 42 | 43 | #define getcode(fs,e) ((fs)->f->code[(e)->u.info]) 44 | 45 | #define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) 46 | 47 | #define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) 48 | 49 | #define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) 50 | 51 | LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); 52 | LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); 53 | LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k); 54 | LUAI_FUNC void luaK_fixline (FuncState *fs, int line); 55 | LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); 56 | LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); 57 | LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); 58 | LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); 59 | LUAI_FUNC int luaK_intK (FuncState *fs, lua_Integer n); 60 | LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); 61 | LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); 62 | LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); 63 | LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); 64 | LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); 65 | LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); 66 | LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); 67 | LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); 68 | LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); 69 | LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); 70 | LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); 71 | LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); 72 | LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); 73 | LUAI_FUNC int luaK_jump (FuncState *fs); 74 | LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); 75 | LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); 76 | LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); 77 | LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level); 78 | LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); 79 | LUAI_FUNC int luaK_getlabel (FuncState *fs); 80 | LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); 81 | LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); 82 | LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, 83 | expdesc *v2, int line); 84 | LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); 85 | 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /lua/lcorolib.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lcorolib.c,v 1.9 2014/11/02 19:19:04 roberto Exp $ 3 | ** Coroutine Library 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lcorolib_c 8 | #define LUA_LIB 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "lauxlib.h" 18 | #include "lualib.h" 19 | 20 | 21 | static lua_State *getco (lua_State *L) { 22 | lua_State *co = lua_tothread(L, 1); 23 | luaL_argcheck(L, co, 1, "thread expected"); 24 | return co; 25 | } 26 | 27 | 28 | static int auxresume (lua_State *L, lua_State *co, int narg) { 29 | int status; 30 | if (!lua_checkstack(co, narg)) { 31 | lua_pushliteral(L, "too many arguments to resume"); 32 | return -1; /* error flag */ 33 | } 34 | if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) { 35 | lua_pushliteral(L, "cannot resume dead coroutine"); 36 | return -1; /* error flag */ 37 | } 38 | lua_xmove(L, co, narg); 39 | status = lua_resume(co, L, narg); 40 | if (status == LUA_OK || status == LUA_YIELD) { 41 | int nres = lua_gettop(co); 42 | if (!lua_checkstack(L, nres + 1)) { 43 | lua_pop(co, nres); /* remove results anyway */ 44 | lua_pushliteral(L, "too many results to resume"); 45 | return -1; /* error flag */ 46 | } 47 | lua_xmove(co, L, nres); /* move yielded values */ 48 | return nres; 49 | } 50 | else { 51 | lua_xmove(co, L, 1); /* move error message */ 52 | return -1; /* error flag */ 53 | } 54 | } 55 | 56 | 57 | static int luaB_coresume (lua_State *L) { 58 | lua_State *co = getco(L); 59 | int r; 60 | r = auxresume(L, co, lua_gettop(L) - 1); 61 | if (r < 0) { 62 | lua_pushboolean(L, 0); 63 | lua_insert(L, -2); 64 | return 2; /* return false + error message */ 65 | } 66 | else { 67 | lua_pushboolean(L, 1); 68 | lua_insert(L, -(r + 1)); 69 | return r + 1; /* return true + 'resume' returns */ 70 | } 71 | } 72 | 73 | 74 | static int luaB_auxwrap (lua_State *L) { 75 | lua_State *co = lua_tothread(L, lua_upvalueindex(1)); 76 | int r = auxresume(L, co, lua_gettop(L)); 77 | if (r < 0) { 78 | if (lua_isstring(L, -1)) { /* error object is a string? */ 79 | luaL_where(L, 1); /* add extra info */ 80 | lua_insert(L, -2); 81 | lua_concat(L, 2); 82 | } 83 | return lua_error(L); /* propagate error */ 84 | } 85 | return r; 86 | } 87 | 88 | 89 | static int luaB_cocreate (lua_State *L) { 90 | lua_State *NL; 91 | luaL_checktype(L, 1, LUA_TFUNCTION); 92 | NL = lua_newthread(L); 93 | lua_pushvalue(L, 1); /* move function to top */ 94 | lua_xmove(L, NL, 1); /* move function from L to NL */ 95 | return 1; 96 | } 97 | 98 | 99 | static int luaB_cowrap (lua_State *L) { 100 | luaB_cocreate(L); 101 | lua_pushcclosure(L, luaB_auxwrap, 1); 102 | return 1; 103 | } 104 | 105 | 106 | static int luaB_yield (lua_State *L) { 107 | return lua_yield(L, lua_gettop(L)); 108 | } 109 | 110 | 111 | static int luaB_costatus (lua_State *L) { 112 | lua_State *co = getco(L); 113 | if (L == co) lua_pushliteral(L, "running"); 114 | else { 115 | switch (lua_status(co)) { 116 | case LUA_YIELD: 117 | lua_pushliteral(L, "suspended"); 118 | break; 119 | case LUA_OK: { 120 | lua_Debug ar; 121 | if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ 122 | lua_pushliteral(L, "normal"); /* it is running */ 123 | else if (lua_gettop(co) == 0) 124 | lua_pushliteral(L, "dead"); 125 | else 126 | lua_pushliteral(L, "suspended"); /* initial state */ 127 | break; 128 | } 129 | default: /* some error occurred */ 130 | lua_pushliteral(L, "dead"); 131 | break; 132 | } 133 | } 134 | return 1; 135 | } 136 | 137 | 138 | static int luaB_yieldable (lua_State *L) { 139 | lua_pushboolean(L, lua_isyieldable(L)); 140 | return 1; 141 | } 142 | 143 | 144 | static int luaB_corunning (lua_State *L) { 145 | int ismain = lua_pushthread(L); 146 | lua_pushboolean(L, ismain); 147 | return 2; 148 | } 149 | 150 | 151 | static const luaL_Reg co_funcs[] = { 152 | {"create", luaB_cocreate}, 153 | {"resume", luaB_coresume}, 154 | {"running", luaB_corunning}, 155 | {"status", luaB_costatus}, 156 | {"wrap", luaB_cowrap}, 157 | {"yield", luaB_yield}, 158 | {"isyieldable", luaB_yieldable}, 159 | {NULL, NULL} 160 | }; 161 | 162 | 163 | 164 | LUAMOD_API int luaopen_coroutine (lua_State *L) { 165 | luaL_newlib(L, co_funcs); 166 | return 1; 167 | } 168 | 169 | -------------------------------------------------------------------------------- /lua/lctype.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lctype.c,v 1.12 2014/11/02 19:19:04 roberto Exp $ 3 | ** 'ctype' functions for Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lctype_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include "lctype.h" 14 | 15 | #if !LUA_USE_CTYPE /* { */ 16 | 17 | #include 18 | 19 | LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { 20 | 0x00, /* EOZ */ 21 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ 22 | 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ 24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 25 | 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ 26 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 27 | 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ 28 | 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 29 | 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ 30 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 31 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ 32 | 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, 33 | 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ 34 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 35 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ 36 | 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */ 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */ 40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */ 42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */ 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */ 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */ 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */ 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */ 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 | }; 54 | 55 | #endif /* } */ 56 | -------------------------------------------------------------------------------- /lua/lctype.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $ 3 | ** 'ctype' functions for Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lctype_h 8 | #define lctype_h 9 | 10 | #include "lua.h" 11 | 12 | 13 | /* 14 | ** WARNING: the functions defined here do not necessarily correspond 15 | ** to the similar functions in the standard C ctype.h. They are 16 | ** optimized for the specific needs of Lua 17 | */ 18 | 19 | #if !defined(LUA_USE_CTYPE) 20 | 21 | #if 'A' == 65 && '0' == 48 22 | /* ASCII case: can use its own tables; faster and fixed */ 23 | #define LUA_USE_CTYPE 0 24 | #else 25 | /* must use standard C ctype */ 26 | #define LUA_USE_CTYPE 1 27 | #endif 28 | 29 | #endif 30 | 31 | 32 | #if !LUA_USE_CTYPE /* { */ 33 | 34 | #include 35 | 36 | #include "llimits.h" 37 | 38 | 39 | #define ALPHABIT 0 40 | #define DIGITBIT 1 41 | #define PRINTBIT 2 42 | #define SPACEBIT 3 43 | #define XDIGITBIT 4 44 | 45 | 46 | #define MASK(B) (1 << (B)) 47 | 48 | 49 | /* 50 | ** add 1 to char to allow index -1 (EOZ) 51 | */ 52 | #define testprop(c,p) (luai_ctype_[(c)+1] & (p)) 53 | 54 | /* 55 | ** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_' 56 | */ 57 | #define lislalpha(c) testprop(c, MASK(ALPHABIT)) 58 | #define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT))) 59 | #define lisdigit(c) testprop(c, MASK(DIGITBIT)) 60 | #define lisspace(c) testprop(c, MASK(SPACEBIT)) 61 | #define lisprint(c) testprop(c, MASK(PRINTBIT)) 62 | #define lisxdigit(c) testprop(c, MASK(XDIGITBIT)) 63 | 64 | /* 65 | ** this 'ltolower' only works for alphabetic characters 66 | */ 67 | #define ltolower(c) ((c) | ('A' ^ 'a')) 68 | 69 | 70 | /* two more entries for 0 and -1 (EOZ) */ 71 | LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2]; 72 | 73 | 74 | #else /* }{ */ 75 | 76 | /* 77 | ** use standard C ctypes 78 | */ 79 | 80 | #include 81 | 82 | 83 | #define lislalpha(c) (isalpha(c) || (c) == '_') 84 | #define lislalnum(c) (isalnum(c) || (c) == '_') 85 | #define lisdigit(c) (isdigit(c)) 86 | #define lisspace(c) (isspace(c)) 87 | #define lisprint(c) (isprint(c)) 88 | #define lisxdigit(c) (isxdigit(c)) 89 | 90 | #define ltolower(c) (tolower(c)) 91 | 92 | #endif /* } */ 93 | 94 | #endif 95 | 96 | -------------------------------------------------------------------------------- /lua/ldebug.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ldebug.h,v 2.14 2015/05/22 17:45:56 roberto Exp $ 3 | ** Auxiliary functions from Debug Interface module 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ldebug_h 8 | #define ldebug_h 9 | 10 | 11 | #include "lstate.h" 12 | 13 | 14 | #define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) 15 | 16 | #define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : -1) 17 | 18 | #define resethookcount(L) (L->hookcount = L->basehookcount) 19 | 20 | 21 | LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, 22 | const char *opname); 23 | LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, 24 | const TValue *p2); 25 | LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1, 26 | const TValue *p2, 27 | const char *msg); 28 | LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1, 29 | const TValue *p2); 30 | LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, 31 | const TValue *p2); 32 | LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); 33 | LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, 34 | TString *src, int line); 35 | LUAI_FUNC l_noret luaG_errormsg (lua_State *L); 36 | LUAI_FUNC void luaG_traceexec (lua_State *L); 37 | 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /lua/ldo.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ldo.h,v 2.28 2015/11/23 11:29:43 roberto Exp $ 3 | ** Stack and Call structure of Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ldo_h 8 | #define ldo_h 9 | 10 | 11 | #include "lobject.h" 12 | #include "lstate.h" 13 | #include "lzio.h" 14 | 15 | 16 | /* 17 | ** Macro to check stack size and grow stack if needed. Parameters 18 | ** 'pre'/'pos' allow the macro to preserve a pointer into the 19 | ** stack across reallocations, doing the work only when needed. 20 | ** 'condmovestack' is used in heavy tests to force a stack reallocation 21 | ** at every check. 22 | */ 23 | #define luaD_checkstackaux(L,n,pre,pos) \ 24 | if (L->stack_last - L->top <= (n)) \ 25 | { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); } 26 | 27 | /* In general, 'pre'/'pos' are empty (nothing to save) */ 28 | #define luaD_checkstack(L,n) luaD_checkstackaux(L,n,,) 29 | 30 | 31 | 32 | #define savestack(L,p) ((char *)(p) - (char *)L->stack) 33 | #define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) 34 | 35 | 36 | /* type of protected functions, to be ran by 'runprotected' */ 37 | typedef void (*Pfunc) (lua_State *L, void *ud); 38 | 39 | LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, 40 | const char *mode); 41 | LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); 42 | LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); 43 | LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); 44 | LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); 45 | LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, 46 | ptrdiff_t oldtop, ptrdiff_t ef); 47 | LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, 48 | int nres); 49 | LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); 50 | LUAI_FUNC void luaD_growstack (lua_State *L, int n); 51 | LUAI_FUNC void luaD_shrinkstack (lua_State *L); 52 | LUAI_FUNC void luaD_inctop (lua_State *L); 53 | 54 | LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); 55 | LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); 56 | 57 | #endif 58 | 59 | -------------------------------------------------------------------------------- /lua/ldump.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ldump.c,v 2.37 2015/10/08 15:53:49 roberto Exp $ 3 | ** save precompiled Lua chunks 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define ldump_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "lobject.h" 18 | #include "lstate.h" 19 | #include "lundump.h" 20 | 21 | 22 | typedef struct { 23 | lua_State *L; 24 | lua_Writer writer; 25 | void *data; 26 | int strip; 27 | int status; 28 | } DumpState; 29 | 30 | 31 | /* 32 | ** All high-level dumps go through DumpVector; you can change it to 33 | ** change the endianness of the result 34 | */ 35 | #define DumpVector(v,n,D) DumpBlock(v,(n)*sizeof((v)[0]),D) 36 | 37 | #define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D) 38 | 39 | 40 | static void DumpBlock (const void *b, size_t size, DumpState *D) { 41 | if (D->status == 0 && size > 0) { 42 | lua_unlock(D->L); 43 | D->status = (*D->writer)(D->L, b, size, D->data); 44 | lua_lock(D->L); 45 | } 46 | } 47 | 48 | 49 | #define DumpVar(x,D) DumpVector(&x,1,D) 50 | 51 | 52 | static void DumpByte (int y, DumpState *D) { 53 | lu_byte x = (lu_byte)y; 54 | DumpVar(x, D); 55 | } 56 | 57 | 58 | static void DumpInt (int x, DumpState *D) { 59 | DumpVar(x, D); 60 | } 61 | 62 | 63 | static void DumpNumber (lua_Number x, DumpState *D) { 64 | DumpVar(x, D); 65 | } 66 | 67 | 68 | static void DumpInteger (lua_Integer x, DumpState *D) { 69 | DumpVar(x, D); 70 | } 71 | 72 | 73 | static void DumpString (const TString *s, DumpState *D) { 74 | if (s == NULL) 75 | DumpByte(0, D); 76 | else { 77 | size_t size = tsslen(s) + 1; /* include trailing '\0' */ 78 | const char *str = getstr(s); 79 | if (size < 0xFF) 80 | DumpByte(cast_int(size), D); 81 | else { 82 | DumpByte(0xFF, D); 83 | DumpVar(size, D); 84 | } 85 | DumpVector(str, size - 1, D); /* no need to save '\0' */ 86 | } 87 | } 88 | 89 | 90 | static void DumpCode (const Proto *f, DumpState *D) { 91 | DumpInt(f->sizecode, D); 92 | DumpVector(f->code, f->sizecode, D); 93 | } 94 | 95 | 96 | static void DumpFunction(const Proto *f, TString *psource, DumpState *D); 97 | 98 | static void DumpConstants (const Proto *f, DumpState *D) { 99 | int i; 100 | int n = f->sizek; 101 | DumpInt(n, D); 102 | for (i = 0; i < n; i++) { 103 | const TValue *o = &f->k[i]; 104 | DumpByte(ttype(o), D); 105 | switch (ttype(o)) { 106 | case LUA_TNIL: 107 | break; 108 | case LUA_TBOOLEAN: 109 | DumpByte(bvalue(o), D); 110 | break; 111 | case LUA_TNUMFLT: 112 | DumpNumber(fltvalue(o), D); 113 | break; 114 | case LUA_TNUMINT: 115 | DumpInteger(ivalue(o), D); 116 | break; 117 | case LUA_TSHRSTR: 118 | case LUA_TLNGSTR: 119 | DumpString(tsvalue(o), D); 120 | break; 121 | default: 122 | lua_assert(0); 123 | } 124 | } 125 | } 126 | 127 | 128 | static void DumpProtos (const Proto *f, DumpState *D) { 129 | int i; 130 | int n = f->sizep; 131 | DumpInt(n, D); 132 | for (i = 0; i < n; i++) 133 | DumpFunction(f->p[i], f->source, D); 134 | } 135 | 136 | 137 | static void DumpUpvalues (const Proto *f, DumpState *D) { 138 | int i, n = f->sizeupvalues; 139 | DumpInt(n, D); 140 | for (i = 0; i < n; i++) { 141 | DumpByte(f->upvalues[i].instack, D); 142 | DumpByte(f->upvalues[i].idx, D); 143 | } 144 | } 145 | 146 | 147 | static void DumpDebug (const Proto *f, DumpState *D) { 148 | int i, n; 149 | n = (D->strip) ? 0 : f->sizelineinfo; 150 | DumpInt(n, D); 151 | DumpVector(f->lineinfo, n, D); 152 | n = (D->strip) ? 0 : f->sizelocvars; 153 | DumpInt(n, D); 154 | for (i = 0; i < n; i++) { 155 | DumpString(f->locvars[i].varname, D); 156 | DumpInt(f->locvars[i].startpc, D); 157 | DumpInt(f->locvars[i].endpc, D); 158 | } 159 | n = (D->strip) ? 0 : f->sizeupvalues; 160 | DumpInt(n, D); 161 | for (i = 0; i < n; i++) 162 | DumpString(f->upvalues[i].name, D); 163 | } 164 | 165 | 166 | static void DumpFunction (const Proto *f, TString *psource, DumpState *D) { 167 | if (D->strip || f->source == psource) 168 | DumpString(NULL, D); /* no debug info or same source as its parent */ 169 | else 170 | DumpString(f->source, D); 171 | DumpInt(f->linedefined, D); 172 | DumpInt(f->lastlinedefined, D); 173 | DumpByte(f->numparams, D); 174 | DumpByte(f->is_vararg, D); 175 | DumpByte(f->maxstacksize, D); 176 | DumpCode(f, D); 177 | DumpConstants(f, D); 178 | DumpUpvalues(f, D); 179 | DumpProtos(f, D); 180 | DumpDebug(f, D); 181 | } 182 | 183 | 184 | static void DumpHeader (DumpState *D) { 185 | DumpLiteral(LUA_SIGNATURE, D); 186 | DumpByte(LUAC_VERSION, D); 187 | DumpByte(LUAC_FORMAT, D); 188 | DumpLiteral(LUAC_DATA, D); 189 | DumpByte(sizeof(int), D); 190 | DumpByte(sizeof(size_t), D); 191 | DumpByte(sizeof(Instruction), D); 192 | DumpByte(sizeof(lua_Integer), D); 193 | DumpByte(sizeof(lua_Number), D); 194 | DumpInteger(LUAC_INT, D); 195 | DumpNumber(LUAC_NUM, D); 196 | } 197 | 198 | 199 | /* 200 | ** dump Lua function as precompiled chunk 201 | */ 202 | int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, 203 | int strip) { 204 | DumpState D; 205 | D.L = L; 206 | D.writer = w; 207 | D.data = data; 208 | D.strip = strip; 209 | D.status = 0; 210 | DumpHeader(&D); 211 | DumpByte(f->sizeupvalues, &D); 212 | DumpFunction(f, NULL, &D); 213 | return D.status; 214 | } 215 | 216 | -------------------------------------------------------------------------------- /lua/lfunc.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lfunc.c,v 2.45 2014/11/02 19:19:04 roberto Exp $ 3 | ** Auxiliary functions to manipulate prototypes and closures 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lfunc_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "lfunc.h" 18 | #include "lgc.h" 19 | #include "lmem.h" 20 | #include "lobject.h" 21 | #include "lstate.h" 22 | 23 | 24 | 25 | CClosure *luaF_newCclosure (lua_State *L, int n) { 26 | GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n)); 27 | CClosure *c = gco2ccl(o); 28 | c->nupvalues = cast_byte(n); 29 | return c; 30 | } 31 | 32 | 33 | LClosure *luaF_newLclosure (lua_State *L, int n) { 34 | GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n)); 35 | LClosure *c = gco2lcl(o); 36 | c->p = NULL; 37 | c->nupvalues = cast_byte(n); 38 | while (n--) c->upvals[n] = NULL; 39 | return c; 40 | } 41 | 42 | /* 43 | ** fill a closure with new closed upvalues 44 | */ 45 | void luaF_initupvals (lua_State *L, LClosure *cl) { 46 | int i; 47 | for (i = 0; i < cl->nupvalues; i++) { 48 | UpVal *uv = luaM_new(L, UpVal); 49 | uv->refcount = 1; 50 | uv->v = &uv->u.value; /* make it closed */ 51 | setnilvalue(uv->v); 52 | cl->upvals[i] = uv; 53 | } 54 | } 55 | 56 | 57 | UpVal *luaF_findupval (lua_State *L, StkId level) { 58 | UpVal **pp = &L->openupval; 59 | UpVal *p; 60 | UpVal *uv; 61 | lua_assert(isintwups(L) || L->openupval == NULL); 62 | while (*pp != NULL && (p = *pp)->v >= level) { 63 | lua_assert(upisopen(p)); 64 | if (p->v == level) /* found a corresponding upvalue? */ 65 | return p; /* return it */ 66 | pp = &p->u.open.next; 67 | } 68 | /* not found: create a new upvalue */ 69 | uv = luaM_new(L, UpVal); 70 | uv->refcount = 0; 71 | uv->u.open.next = *pp; /* link it to list of open upvalues */ 72 | uv->u.open.touched = 1; 73 | *pp = uv; 74 | uv->v = level; /* current value lives in the stack */ 75 | if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ 76 | L->twups = G(L)->twups; /* link it to the list */ 77 | G(L)->twups = L; 78 | } 79 | return uv; 80 | } 81 | 82 | 83 | void luaF_close (lua_State *L, StkId level) { 84 | UpVal *uv; 85 | while (L->openupval != NULL && (uv = L->openupval)->v >= level) { 86 | lua_assert(upisopen(uv)); 87 | L->openupval = uv->u.open.next; /* remove from 'open' list */ 88 | if (uv->refcount == 0) /* no references? */ 89 | luaM_free(L, uv); /* free upvalue */ 90 | else { 91 | setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ 92 | uv->v = &uv->u.value; /* now current value lives here */ 93 | luaC_upvalbarrier(L, uv); 94 | } 95 | } 96 | } 97 | 98 | 99 | Proto *luaF_newproto (lua_State *L) { 100 | GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto)); 101 | Proto *f = gco2p(o); 102 | f->k = NULL; 103 | f->sizek = 0; 104 | f->p = NULL; 105 | f->sizep = 0; 106 | f->code = NULL; 107 | f->cache = NULL; 108 | f->sizecode = 0; 109 | f->lineinfo = NULL; 110 | f->sizelineinfo = 0; 111 | f->upvalues = NULL; 112 | f->sizeupvalues = 0; 113 | f->numparams = 0; 114 | f->is_vararg = 0; 115 | f->maxstacksize = 0; 116 | f->locvars = NULL; 117 | f->sizelocvars = 0; 118 | f->linedefined = 0; 119 | f->lastlinedefined = 0; 120 | f->source = NULL; 121 | return f; 122 | } 123 | 124 | 125 | void luaF_freeproto (lua_State *L, Proto *f) { 126 | luaM_freearray(L, f->code, f->sizecode); 127 | luaM_freearray(L, f->p, f->sizep); 128 | luaM_freearray(L, f->k, f->sizek); 129 | luaM_freearray(L, f->lineinfo, f->sizelineinfo); 130 | luaM_freearray(L, f->locvars, f->sizelocvars); 131 | luaM_freearray(L, f->upvalues, f->sizeupvalues); 132 | luaM_free(L, f); 133 | } 134 | 135 | 136 | /* 137 | ** Look for n-th local variable at line 'line' in function 'func'. 138 | ** Returns NULL if not found. 139 | */ 140 | const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { 141 | int i; 142 | for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) { 143 | if (pc < f->locvars[i].endpc) { /* is variable active? */ 144 | local_number--; 145 | if (local_number == 0) 146 | return getstr(f->locvars[i].varname); 147 | } 148 | } 149 | return NULL; /* not found */ 150 | } 151 | 152 | -------------------------------------------------------------------------------- /lua/lfunc.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lfunc.h,v 2.15 2015/01/13 15:49:11 roberto Exp $ 3 | ** Auxiliary functions to manipulate prototypes and closures 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lfunc_h 8 | #define lfunc_h 9 | 10 | 11 | #include "lobject.h" 12 | 13 | 14 | #define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ 15 | cast(int, sizeof(TValue)*((n)-1))) 16 | 17 | #define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ 18 | cast(int, sizeof(TValue *)*((n)-1))) 19 | 20 | 21 | /* test whether thread is in 'twups' list */ 22 | #define isintwups(L) (L->twups != L) 23 | 24 | 25 | /* 26 | ** maximum number of upvalues in a closure (both C and Lua). (Value 27 | ** must fit in a VM register.) 28 | */ 29 | #define MAXUPVAL 255 30 | 31 | 32 | /* 33 | ** Upvalues for Lua closures 34 | */ 35 | struct UpVal { 36 | TValue *v; /* points to stack or to its own value */ 37 | lu_mem refcount; /* reference counter */ 38 | union { 39 | struct { /* (when open) */ 40 | UpVal *next; /* linked list */ 41 | int touched; /* mark to avoid cycles with dead threads */ 42 | } open; 43 | TValue value; /* the value (when closed) */ 44 | } u; 45 | }; 46 | 47 | #define upisopen(up) ((up)->v != &(up)->u.value) 48 | 49 | 50 | LUAI_FUNC Proto *luaF_newproto (lua_State *L); 51 | LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems); 52 | LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems); 53 | LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); 54 | LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); 55 | LUAI_FUNC void luaF_close (lua_State *L, StkId level); 56 | LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); 57 | LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, 58 | int pc); 59 | 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /lua/lgc.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lgc.h,v 2.90 2015/10/21 18:15:15 roberto Exp $ 3 | ** Garbage Collector 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lgc_h 8 | #define lgc_h 9 | 10 | 11 | #include "lobject.h" 12 | #include "lstate.h" 13 | 14 | /* 15 | ** Collectable objects may have one of three colors: white, which 16 | ** means the object is not marked; gray, which means the 17 | ** object is marked, but its references may be not marked; and 18 | ** black, which means that the object and all its references are marked. 19 | ** The main invariant of the garbage collector, while marking objects, 20 | ** is that a black object can never point to a white one. Moreover, 21 | ** any gray object must be in a "gray list" (gray, grayagain, weak, 22 | ** allweak, ephemeron) so that it can be visited again before finishing 23 | ** the collection cycle. These lists have no meaning when the invariant 24 | ** is not being enforced (e.g., sweep phase). 25 | */ 26 | 27 | 28 | 29 | /* how much to allocate before next GC step */ 30 | #if !defined(GCSTEPSIZE) 31 | /* ~100 small strings */ 32 | #define GCSTEPSIZE (cast_int(100 * sizeof(TString))) 33 | #endif 34 | 35 | 36 | /* 37 | ** Possible states of the Garbage Collector 38 | */ 39 | #define GCSpropagate 0 40 | #define GCSatomic 1 41 | #define GCSswpallgc 2 42 | #define GCSswpfinobj 3 43 | #define GCSswptobefnz 4 44 | #define GCSswpend 5 45 | #define GCScallfin 6 46 | #define GCSpause 7 47 | 48 | 49 | #define issweepphase(g) \ 50 | (GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend) 51 | 52 | 53 | /* 54 | ** macro to tell when main invariant (white objects cannot point to black 55 | ** ones) must be kept. During a collection, the sweep 56 | ** phase may break the invariant, as objects turned white may point to 57 | ** still-black objects. The invariant is restored when sweep ends and 58 | ** all objects are white again. 59 | */ 60 | 61 | #define keepinvariant(g) ((g)->gcstate <= GCSatomic) 62 | 63 | 64 | /* 65 | ** some useful bit tricks 66 | */ 67 | #define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) 68 | #define setbits(x,m) ((x) |= (m)) 69 | #define testbits(x,m) ((x) & (m)) 70 | #define bitmask(b) (1<<(b)) 71 | #define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) 72 | #define l_setbit(x,b) setbits(x, bitmask(b)) 73 | #define resetbit(x,b) resetbits(x, bitmask(b)) 74 | #define testbit(x,b) testbits(x, bitmask(b)) 75 | 76 | 77 | /* Layout for bit use in 'marked' field: */ 78 | #define WHITE0BIT 0 /* object is white (type 0) */ 79 | #define WHITE1BIT 1 /* object is white (type 1) */ 80 | #define BLACKBIT 2 /* object is black */ 81 | #define FINALIZEDBIT 3 /* object has been marked for finalization */ 82 | /* bit 7 is currently used by tests (luaL_checkmemory) */ 83 | 84 | #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) 85 | 86 | 87 | #define iswhite(x) testbits((x)->marked, WHITEBITS) 88 | #define isblack(x) testbit((x)->marked, BLACKBIT) 89 | #define isgray(x) /* neither white nor black */ \ 90 | (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) 91 | 92 | #define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) 93 | 94 | #define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) 95 | #define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) 96 | #define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) 97 | 98 | #define changewhite(x) ((x)->marked ^= WHITEBITS) 99 | #define gray2black(x) l_setbit((x)->marked, BLACKBIT) 100 | 101 | #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) 102 | 103 | 104 | /* 105 | ** Does one step of collection when debt becomes positive. 'pre'/'pos' 106 | ** allows some adjustments to be done only when needed. macro 107 | ** 'condchangemem' is used only for heavy tests (forcing a full 108 | ** GC cycle on every opportunity) 109 | */ 110 | #define luaC_condGC(L,pre,pos) \ 111 | { if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \ 112 | condchangemem(L,pre,pos); } 113 | 114 | /* more often than not, 'pre'/'pos' are empty */ 115 | #define luaC_checkGC(L) luaC_condGC(L,,) 116 | 117 | 118 | #define luaC_barrier(L,p,v) ( \ 119 | (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ 120 | luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0)) 121 | 122 | #define luaC_barrierback(L,p,v) ( \ 123 | (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ 124 | luaC_barrierback_(L,p) : cast_void(0)) 125 | 126 | #define luaC_objbarrier(L,p,o) ( \ 127 | (isblack(p) && iswhite(o)) ? \ 128 | luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) 129 | 130 | #define luaC_upvalbarrier(L,uv) ( \ 131 | (iscollectable((uv)->v) && !upisopen(uv)) ? \ 132 | luaC_upvalbarrier_(L,uv) : cast_void(0)) 133 | 134 | LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); 135 | LUAI_FUNC void luaC_freeallobjects (lua_State *L); 136 | LUAI_FUNC void luaC_step (lua_State *L); 137 | LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); 138 | LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); 139 | LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); 140 | LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); 141 | LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o); 142 | LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv); 143 | LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); 144 | LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv); 145 | 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /lua/linit.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: linit.c,v 1.38 2015/01/05 13:48:33 roberto Exp $ 3 | ** Initialization of libraries for lua.c and other clients 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #define linit_c 9 | #define LUA_LIB 10 | 11 | /* 12 | ** If you embed Lua in your program and need to open the standard 13 | ** libraries, call luaL_openlibs in your program. If you need a 14 | ** different set of libraries, copy this file to your project and edit 15 | ** it to suit your needs. 16 | ** 17 | ** You can also *preload* libraries, so that a later 'require' can 18 | ** open the library, which is already linked to the application. 19 | ** For that, do the following code: 20 | ** 21 | ** luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); 22 | ** lua_pushcfunction(L, luaopen_modname); 23 | ** lua_setfield(L, -2, modname); 24 | ** lua_pop(L, 1); // remove _PRELOAD table 25 | */ 26 | 27 | #include "lprefix.h" 28 | 29 | 30 | #include 31 | 32 | #include "lua.h" 33 | 34 | #include "lualib.h" 35 | #include "lauxlib.h" 36 | 37 | 38 | /* 39 | ** these libs are loaded by lua.c and are readily available to any Lua 40 | ** program 41 | */ 42 | static const luaL_Reg loadedlibs[] = { 43 | {"_G", luaopen_base}, 44 | {LUA_LOADLIBNAME, luaopen_package}, 45 | {LUA_COLIBNAME, luaopen_coroutine}, 46 | {LUA_TABLIBNAME, luaopen_table}, 47 | {LUA_IOLIBNAME, luaopen_io}, 48 | {LUA_OSLIBNAME, luaopen_os}, 49 | {LUA_STRLIBNAME, luaopen_string}, 50 | {LUA_MATHLIBNAME, luaopen_math}, 51 | {LUA_UTF8LIBNAME, luaopen_utf8}, 52 | {LUA_DBLIBNAME, luaopen_debug}, 53 | #if defined(LUA_COMPAT_BITLIB) 54 | {LUA_BITLIBNAME, luaopen_bit32}, 55 | #endif 56 | {NULL, NULL} 57 | }; 58 | 59 | 60 | LUALIB_API void luaL_openlibs (lua_State *L) { 61 | const luaL_Reg *lib; 62 | /* "require" functions from 'loadedlibs' and set results to global table */ 63 | for (lib = loadedlibs; lib->func; lib++) { 64 | luaL_requiref(L, lib->name, lib->func, 1); 65 | lua_pop(L, 1); /* remove lib */ 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /lua/llex.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: llex.h,v 1.78 2014/10/29 15:38:24 roberto Exp $ 3 | ** Lexical Analyzer 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef llex_h 8 | #define llex_h 9 | 10 | #include "lobject.h" 11 | #include "lzio.h" 12 | 13 | 14 | #define FIRST_RESERVED 257 15 | 16 | 17 | #if !defined(LUA_ENV) 18 | #define LUA_ENV "_ENV" 19 | #endif 20 | 21 | 22 | /* 23 | * WARNING: if you change the order of this enumeration, 24 | * grep "ORDER RESERVED" 25 | */ 26 | enum RESERVED { 27 | /* terminal symbols denoted by reserved words */ 28 | TK_AND = FIRST_RESERVED, TK_BREAK, 29 | TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, 30 | TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, 31 | TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, 32 | /* other terminal symbols */ 33 | TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, 34 | TK_SHL, TK_SHR, 35 | TK_DBCOLON, TK_EOS, 36 | TK_FLT, TK_INT, TK_NAME, TK_STRING 37 | }; 38 | 39 | /* number of reserved words */ 40 | #define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) 41 | 42 | 43 | typedef union { 44 | lua_Number r; 45 | lua_Integer i; 46 | TString *ts; 47 | } SemInfo; /* semantics information */ 48 | 49 | 50 | typedef struct Token { 51 | int token; 52 | SemInfo seminfo; 53 | } Token; 54 | 55 | 56 | /* state of the lexer plus state of the parser when shared by all 57 | functions */ 58 | typedef struct LexState { 59 | int current; /* current character (charint) */ 60 | int linenumber; /* input line counter */ 61 | int lastline; /* line of last token 'consumed' */ 62 | Token t; /* current token */ 63 | Token lookahead; /* look ahead token */ 64 | struct FuncState *fs; /* current function (parser) */ 65 | struct lua_State *L; 66 | ZIO *z; /* input stream */ 67 | Mbuffer *buff; /* buffer for tokens */ 68 | Table *h; /* to avoid collection/reuse strings */ 69 | struct Dyndata *dyd; /* dynamic structures used by the parser */ 70 | TString *source; /* current source name */ 71 | TString *envn; /* environment variable name */ 72 | char decpoint; /* locale decimal point */ 73 | } LexState; 74 | 75 | 76 | LUAI_FUNC void luaX_init (lua_State *L); 77 | LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, 78 | TString *source, int firstchar); 79 | LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); 80 | LUAI_FUNC void luaX_next (LexState *ls); 81 | LUAI_FUNC int luaX_lookahead (LexState *ls); 82 | LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s); 83 | LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); 84 | 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /lua/lmem.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lmem.c,v 1.91 2015/03/06 19:45:54 roberto Exp $ 3 | ** Interface to Memory Manager 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lmem_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "ldebug.h" 18 | #include "ldo.h" 19 | #include "lgc.h" 20 | #include "lmem.h" 21 | #include "lobject.h" 22 | #include "lstate.h" 23 | 24 | 25 | 26 | /* 27 | ** About the realloc function: 28 | ** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); 29 | ** ('osize' is the old size, 'nsize' is the new size) 30 | ** 31 | ** * frealloc(ud, NULL, x, s) creates a new block of size 's' (no 32 | ** matter 'x'). 33 | ** 34 | ** * frealloc(ud, p, x, 0) frees the block 'p' 35 | ** (in this specific case, frealloc must return NULL); 36 | ** particularly, frealloc(ud, NULL, 0, 0) does nothing 37 | ** (which is equivalent to free(NULL) in ISO C) 38 | ** 39 | ** frealloc returns NULL if it cannot create or reallocate the area 40 | ** (any reallocation to an equal or smaller size cannot fail!) 41 | */ 42 | 43 | 44 | 45 | #define MINSIZEARRAY 4 46 | 47 | 48 | void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, 49 | int limit, const char *what) { 50 | void *newblock; 51 | int newsize; 52 | if (*size >= limit/2) { /* cannot double it? */ 53 | if (*size >= limit) /* cannot grow even a little? */ 54 | luaG_runerror(L, "too many %s (limit is %d)", what, limit); 55 | newsize = limit; /* still have at least one free place */ 56 | } 57 | else { 58 | newsize = (*size)*2; 59 | if (newsize < MINSIZEARRAY) 60 | newsize = MINSIZEARRAY; /* minimum size */ 61 | } 62 | newblock = luaM_reallocv(L, block, *size, newsize, size_elems); 63 | *size = newsize; /* update only when everything else is OK */ 64 | return newblock; 65 | } 66 | 67 | 68 | l_noret luaM_toobig (lua_State *L) { 69 | luaG_runerror(L, "memory allocation error: block too big"); 70 | } 71 | 72 | 73 | 74 | /* 75 | ** generic allocation routine. 76 | */ 77 | void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { 78 | void *newblock; 79 | global_State *g = G(L); 80 | size_t realosize = (block) ? osize : 0; 81 | lua_assert((realosize == 0) == (block == NULL)); 82 | #if defined(HARDMEMTESTS) 83 | if (nsize > realosize && g->gcrunning) 84 | luaC_fullgc(L, 1); /* force a GC whenever possible */ 85 | #endif 86 | newblock = (*g->frealloc)(g->ud, block, osize, nsize); 87 | if (newblock == NULL && nsize > 0) { 88 | lua_assert(nsize > realosize); /* cannot fail when shrinking a block */ 89 | if (g->version) { /* is state fully built? */ 90 | luaC_fullgc(L, 1); /* try to free some memory... */ 91 | newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ 92 | } 93 | if (newblock == NULL) 94 | luaD_throw(L, LUA_ERRMEM); 95 | } 96 | lua_assert((nsize == 0) == (newblock == NULL)); 97 | g->GCdebt = (g->GCdebt + nsize) - realosize; 98 | return newblock; 99 | } 100 | 101 | -------------------------------------------------------------------------------- /lua/lmem.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lmem.h,v 1.43 2014/12/19 17:26:14 roberto Exp $ 3 | ** Interface to Memory Manager 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lmem_h 8 | #define lmem_h 9 | 10 | 11 | #include 12 | 13 | #include "llimits.h" 14 | #include "lua.h" 15 | 16 | 17 | /* 18 | ** This macro reallocs a vector 'b' from 'on' to 'n' elements, where 19 | ** each element has size 'e'. In case of arithmetic overflow of the 20 | ** product 'n'*'e', it raises an error (calling 'luaM_toobig'). Because 21 | ** 'e' is always constant, it avoids the runtime division MAX_SIZET/(e). 22 | ** 23 | ** (The macro is somewhat complex to avoid warnings: The 'sizeof' 24 | ** comparison avoids a runtime comparison when overflow cannot occur. 25 | ** The compiler should be able to optimize the real test by itself, but 26 | ** when it does it, it may give a warning about "comparison is always 27 | ** false due to limited range of data type"; the +1 tricks the compiler, 28 | ** avoiding this warning but also this optimization.) 29 | */ 30 | #define luaM_reallocv(L,b,on,n,e) \ 31 | (((sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e)) \ 32 | ? luaM_toobig(L) : cast_void(0)) , \ 33 | luaM_realloc_(L, (b), (on)*(e), (n)*(e))) 34 | 35 | /* 36 | ** Arrays of chars do not need any test 37 | */ 38 | #define luaM_reallocvchar(L,b,on,n) \ 39 | cast(char *, luaM_realloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char))) 40 | 41 | #define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) 42 | #define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) 43 | #define luaM_freearray(L, b, n) luaM_realloc_(L, (b), (n)*sizeof(*(b)), 0) 44 | 45 | #define luaM_malloc(L,s) luaM_realloc_(L, NULL, 0, (s)) 46 | #define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) 47 | #define luaM_newvector(L,n,t) \ 48 | cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t))) 49 | 50 | #define luaM_newobject(L,tag,s) luaM_realloc_(L, NULL, tag, (s)) 51 | 52 | #define luaM_growvector(L,v,nelems,size,t,limit,e) \ 53 | if ((nelems)+1 > (size)) \ 54 | ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) 55 | 56 | #define luaM_reallocvector(L, v,oldn,n,t) \ 57 | ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) 58 | 59 | LUAI_FUNC l_noret luaM_toobig (lua_State *L); 60 | 61 | /* not to be called directly */ 62 | LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, 63 | size_t size); 64 | LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, 65 | size_t size_elem, int limit, 66 | const char *what); 67 | 68 | #endif 69 | 70 | -------------------------------------------------------------------------------- /lua/lopcodes.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lopcodes.c,v 1.55 2015/01/05 13:48:33 roberto Exp $ 3 | ** Opcodes for Lua virtual machine 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lopcodes_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lopcodes.h" 16 | 17 | 18 | /* ORDER OP */ 19 | 20 | LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { 21 | "MOVE", 22 | "LOADK", 23 | "LOADKX", 24 | "LOADBOOL", 25 | "LOADNIL", 26 | "GETUPVAL", 27 | "GETTABUP", 28 | "GETTABLE", 29 | "SETTABUP", 30 | "SETUPVAL", 31 | "SETTABLE", 32 | "NEWTABLE", 33 | "SELF", 34 | "ADD", 35 | "SUB", 36 | "MUL", 37 | "MOD", 38 | "POW", 39 | "DIV", 40 | "IDIV", 41 | "BAND", 42 | "BOR", 43 | "BXOR", 44 | "SHL", 45 | "SHR", 46 | "UNM", 47 | "BNOT", 48 | "NOT", 49 | "LEN", 50 | "CONCAT", 51 | "JMP", 52 | "EQ", 53 | "LT", 54 | "LE", 55 | "TEST", 56 | "TESTSET", 57 | "CALL", 58 | "TAILCALL", 59 | "RETURN", 60 | "FORLOOP", 61 | "FORPREP", 62 | "TFORCALL", 63 | "TFORLOOP", 64 | "SETLIST", 65 | "CLOSURE", 66 | "VARARG", 67 | "EXTRAARG", 68 | NULL 69 | }; 70 | 71 | 72 | #define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) 73 | 74 | LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { 75 | /* T A B C mode opcode */ 76 | opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ 77 | ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ 78 | ,opmode(0, 1, OpArgN, OpArgN, iABx) /* OP_LOADKX */ 79 | ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ 80 | ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_LOADNIL */ 81 | ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ 82 | ,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */ 83 | ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ 84 | ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABUP */ 85 | ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ 86 | ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ 87 | ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ 88 | ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ 89 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ 90 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ 91 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ 92 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ 93 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ 94 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ 95 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_IDIV */ 96 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BAND */ 97 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BOR */ 98 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BXOR */ 99 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHL */ 100 | ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHR */ 101 | ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ 102 | ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_BNOT */ 103 | ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ 104 | ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ 105 | ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ 106 | ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ 107 | ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ 108 | ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ 109 | ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ 110 | ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TEST */ 111 | ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ 112 | ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ 113 | ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ 114 | ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ 115 | ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ 116 | ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ 117 | ,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */ 118 | ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */ 119 | ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ 120 | ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ 121 | ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ 122 | ,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */ 123 | }; 124 | 125 | -------------------------------------------------------------------------------- /lua/lparser.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lparser.h,v 1.74 2014/10/25 11:50:46 roberto Exp $ 3 | ** Lua Parser 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lparser_h 8 | #define lparser_h 9 | 10 | #include "llimits.h" 11 | #include "lobject.h" 12 | #include "lzio.h" 13 | 14 | 15 | /* 16 | ** Expression descriptor 17 | */ 18 | 19 | typedef enum { 20 | VVOID, /* no value */ 21 | VNIL, 22 | VTRUE, 23 | VFALSE, 24 | VK, /* info = index of constant in 'k' */ 25 | VKFLT, /* nval = numerical float value */ 26 | VKINT, /* nval = numerical integer value */ 27 | VNONRELOC, /* info = result register */ 28 | VLOCAL, /* info = local register */ 29 | VUPVAL, /* info = index of upvalue in 'upvalues' */ 30 | VINDEXED, /* t = table register/upvalue; idx = index R/K */ 31 | VJMP, /* info = instruction pc */ 32 | VRELOCABLE, /* info = instruction pc */ 33 | VCALL, /* info = instruction pc */ 34 | VVARARG /* info = instruction pc */ 35 | } expkind; 36 | 37 | 38 | #define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXED) 39 | #define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL) 40 | 41 | typedef struct expdesc { 42 | expkind k; 43 | union { 44 | struct { /* for indexed variables (VINDEXED) */ 45 | short idx; /* index (R/K) */ 46 | lu_byte t; /* table (register or upvalue) */ 47 | lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ 48 | } ind; 49 | int info; /* for generic use */ 50 | lua_Number nval; /* for VKFLT */ 51 | lua_Integer ival; /* for VKINT */ 52 | } u; 53 | int t; /* patch list of 'exit when true' */ 54 | int f; /* patch list of 'exit when false' */ 55 | } expdesc; 56 | 57 | 58 | /* description of active local variable */ 59 | typedef struct Vardesc { 60 | short idx; /* variable index in stack */ 61 | } Vardesc; 62 | 63 | 64 | /* description of pending goto statements and label statements */ 65 | typedef struct Labeldesc { 66 | TString *name; /* label identifier */ 67 | int pc; /* position in code */ 68 | int line; /* line where it appeared */ 69 | lu_byte nactvar; /* local level where it appears in current block */ 70 | } Labeldesc; 71 | 72 | 73 | /* list of labels or gotos */ 74 | typedef struct Labellist { 75 | Labeldesc *arr; /* array */ 76 | int n; /* number of entries in use */ 77 | int size; /* array size */ 78 | } Labellist; 79 | 80 | 81 | /* dynamic structures used by the parser */ 82 | typedef struct Dyndata { 83 | struct { /* list of active local variables */ 84 | Vardesc *arr; 85 | int n; 86 | int size; 87 | } actvar; 88 | Labellist gt; /* list of pending gotos */ 89 | Labellist label; /* list of active labels */ 90 | } Dyndata; 91 | 92 | 93 | /* control of blocks */ 94 | struct BlockCnt; /* defined in lparser.c */ 95 | 96 | 97 | /* state needed to generate code for a given function */ 98 | typedef struct FuncState { 99 | Proto *f; /* current function header */ 100 | struct FuncState *prev; /* enclosing function */ 101 | struct LexState *ls; /* lexical state */ 102 | struct BlockCnt *bl; /* chain of current blocks */ 103 | int pc; /* next position to code (equivalent to 'ncode') */ 104 | int lasttarget; /* 'label' of last 'jump label' */ 105 | int jpc; /* list of pending jumps to 'pc' */ 106 | int nk; /* number of elements in 'k' */ 107 | int np; /* number of elements in 'p' */ 108 | int firstlocal; /* index of first local var (in Dyndata array) */ 109 | short nlocvars; /* number of elements in 'f->locvars' */ 110 | lu_byte nactvar; /* number of active local variables */ 111 | lu_byte nups; /* number of upvalues */ 112 | lu_byte freereg; /* first free register */ 113 | } FuncState; 114 | 115 | 116 | LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, 117 | Dyndata *dyd, const char *name, int firstchar); 118 | 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /lua/lprefix.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lprefix.h,v 1.2 2014/12/29 16:54:13 roberto Exp $ 3 | ** Definitions for Lua code that must come before any other header file 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lprefix_h 8 | #define lprefix_h 9 | 10 | 11 | /* 12 | ** Allows POSIX/XSI stuff 13 | */ 14 | #if !defined(LUA_USE_C89) /* { */ 15 | 16 | #if !defined(_XOPEN_SOURCE) 17 | #define _XOPEN_SOURCE 600 18 | #elif _XOPEN_SOURCE == 0 19 | #undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ 20 | #endif 21 | 22 | /* 23 | ** Allows manipulation of large files in gcc and some other compilers 24 | */ 25 | #if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) 26 | #define _LARGEFILE_SOURCE 1 27 | #define _FILE_OFFSET_BITS 64 28 | #endif 29 | 30 | #endif /* } */ 31 | 32 | 33 | /* 34 | ** Windows stuff 35 | */ 36 | #if defined(_WIN32) /* { */ 37 | 38 | #if !defined(_CRT_SECURE_NO_WARNINGS) 39 | #define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ 40 | #endif 41 | 42 | #endif /* } */ 43 | 44 | #endif 45 | 46 | -------------------------------------------------------------------------------- /lua/lstring.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lstring.h,v 1.61 2015/11/03 15:36:01 roberto Exp $ 3 | ** String table (keep all strings handled by Lua) 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lstring_h 8 | #define lstring_h 9 | 10 | #include "lgc.h" 11 | #include "lobject.h" 12 | #include "lstate.h" 13 | 14 | 15 | #define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char)) 16 | 17 | #define sizeludata(l) (sizeof(union UUdata) + (l)) 18 | #define sizeudata(u) sizeludata((u)->len) 19 | 20 | #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ 21 | (sizeof(s)/sizeof(char))-1)) 22 | 23 | 24 | /* 25 | ** test whether a string is a reserved word 26 | */ 27 | #define isreserved(s) ((s)->tt == LUA_TSHRSTR && (s)->extra > 0) 28 | 29 | 30 | /* 31 | ** equality for short strings, which are always internalized 32 | */ 33 | #define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b)) 34 | 35 | 36 | LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); 37 | LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts); 38 | LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); 39 | LUAI_FUNC void luaS_resize (lua_State *L, int newsize); 40 | LUAI_FUNC void luaS_clearcache (global_State *g); 41 | LUAI_FUNC void luaS_init (lua_State *L); 42 | LUAI_FUNC void luaS_remove (lua_State *L, TString *ts); 43 | LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s); 44 | LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); 45 | LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); 46 | LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l); 47 | 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /lua/ltable.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ltable.h,v 2.21 2015/11/03 15:47:30 roberto Exp $ 3 | ** Lua tables (hash) 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ltable_h 8 | #define ltable_h 9 | 10 | #include "lobject.h" 11 | 12 | 13 | #define gnode(t,i) (&(t)->node[i]) 14 | #define gval(n) (&(n)->i_val) 15 | #define gnext(n) ((n)->i_key.nk.next) 16 | 17 | 18 | /* 'const' to avoid wrong writings that can mess up field 'next' */ 19 | #define gkey(n) cast(const TValue*, (&(n)->i_key.tvk)) 20 | 21 | /* 22 | ** writable version of 'gkey'; allows updates to individual fields, 23 | ** but not to the whole (which has incompatible type) 24 | */ 25 | #define wgkey(n) (&(n)->i_key.nk) 26 | 27 | #define invalidateTMcache(t) ((t)->flags = 0) 28 | 29 | 30 | /* returns the key, given the value of a table entry */ 31 | #define keyfromval(v) \ 32 | (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val)))) 33 | 34 | 35 | LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); 36 | LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, 37 | TValue *value); 38 | LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); 39 | LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); 40 | LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); 41 | LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key); 42 | LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); 43 | LUAI_FUNC Table *luaH_new (lua_State *L); 44 | LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, 45 | unsigned int nhsize); 46 | LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize); 47 | LUAI_FUNC void luaH_free (lua_State *L, Table *t); 48 | LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); 49 | LUAI_FUNC int luaH_getn (Table *t); 50 | 51 | 52 | #if defined(LUA_DEBUG) 53 | LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); 54 | LUAI_FUNC int luaH_isdummy (Node *n); 55 | #endif 56 | 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /lua/ltm.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ltm.c,v 2.36 2015/11/03 15:47:30 roberto Exp $ 3 | ** Tag methods 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define ltm_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "ldebug.h" 18 | #include "ldo.h" 19 | #include "lobject.h" 20 | #include "lstate.h" 21 | #include "lstring.h" 22 | #include "ltable.h" 23 | #include "ltm.h" 24 | #include "lvm.h" 25 | 26 | 27 | static const char udatatypename[] = "userdata"; 28 | 29 | LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { 30 | "no value", 31 | "nil", "boolean", udatatypename, "number", 32 | "string", "table", "function", udatatypename, "thread", 33 | "proto" /* this last case is used for tests only */ 34 | }; 35 | 36 | 37 | void luaT_init (lua_State *L) { 38 | static const char *const luaT_eventname[] = { /* ORDER TM */ 39 | "__index", "__newindex", 40 | "__gc", "__mode", "__len", "__eq", 41 | "__add", "__sub", "__mul", "__mod", "__pow", 42 | "__div", "__idiv", 43 | "__band", "__bor", "__bxor", "__shl", "__shr", 44 | "__unm", "__bnot", "__lt", "__le", 45 | "__concat", "__call" 46 | }; 47 | int i; 48 | for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); 50 | luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ 51 | } 52 | } 53 | 54 | 55 | /* 56 | ** function to be used with macro "fasttm": optimized for absence of 57 | ** tag methods 58 | */ 59 | const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { 60 | const TValue *tm = luaH_getshortstr(events, ename); 61 | lua_assert(event <= TM_EQ); 62 | if (ttisnil(tm)) { /* no tag method? */ 63 | events->flags |= cast_byte(1u<metatable; 75 | break; 76 | case LUA_TUSERDATA: 77 | mt = uvalue(o)->metatable; 78 | break; 79 | default: 80 | mt = G(L)->mt[ttnov(o)]; 81 | } 82 | return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject); 83 | } 84 | 85 | 86 | void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, 87 | const TValue *p2, TValue *p3, int hasres) { 88 | ptrdiff_t result = savestack(L, p3); 89 | StkId func = L->top; 90 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ 91 | setobj2s(L, func + 1, p1); /* 1st argument */ 92 | setobj2s(L, func + 2, p2); /* 2nd argument */ 93 | L->top += 3; 94 | if (!hasres) /* no result? 'p3' is third argument */ 95 | setobj2s(L, L->top++, p3); /* 3rd argument */ 96 | /* metamethod may yield only when called from Lua code */ 97 | if (isLua(L->ci)) 98 | luaD_call(L, func, hasres); 99 | else 100 | luaD_callnoyield(L, func, hasres); 101 | if (hasres) { /* if has result, move it to its place */ 102 | p3 = restorestack(L, result); 103 | setobjs2s(L, p3, --L->top); 104 | } 105 | } 106 | 107 | 108 | int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, 109 | StkId res, TMS event) { 110 | const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ 111 | if (ttisnil(tm)) 112 | tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ 113 | if (ttisnil(tm)) return 0; 114 | luaT_callTM(L, tm, p1, p2, res, 1); 115 | return 1; 116 | } 117 | 118 | 119 | void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, 120 | StkId res, TMS event) { 121 | if (!luaT_callbinTM(L, p1, p2, res, event)) { 122 | switch (event) { 123 | case TM_CONCAT: 124 | luaG_concaterror(L, p1, p2); 125 | /* call never returns, but to avoid warnings: *//* FALLTHROUGH */ 126 | case TM_BAND: case TM_BOR: case TM_BXOR: 127 | case TM_SHL: case TM_SHR: case TM_BNOT: { 128 | lua_Number dummy; 129 | if (tonumber(p1, &dummy) && tonumber(p2, &dummy)) 130 | luaG_tointerror(L, p1, p2); 131 | else 132 | luaG_opinterror(L, p1, p2, "perform bitwise operation on"); 133 | } 134 | /* calls never return, but to avoid warnings: *//* FALLTHROUGH */ 135 | default: 136 | luaG_opinterror(L, p1, p2, "perform arithmetic on"); 137 | } 138 | } 139 | } 140 | 141 | 142 | int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, 143 | TMS event) { 144 | if (!luaT_callbinTM(L, p1, p2, L->top, event)) 145 | return -1; /* no metamethod */ 146 | else 147 | return !l_isfalse(L->top); 148 | } 149 | 150 | -------------------------------------------------------------------------------- /lua/ltm.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ltm.h,v 2.21 2014/10/25 11:50:46 roberto Exp $ 3 | ** Tag methods 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ltm_h 8 | #define ltm_h 9 | 10 | 11 | #include "lobject.h" 12 | 13 | 14 | /* 15 | * WARNING: if you change the order of this enumeration, 16 | * grep "ORDER TM" and "ORDER OP" 17 | */ 18 | typedef enum { 19 | TM_INDEX, 20 | TM_NEWINDEX, 21 | TM_GC, 22 | TM_MODE, 23 | TM_LEN, 24 | TM_EQ, /* last tag method with fast access */ 25 | TM_ADD, 26 | TM_SUB, 27 | TM_MUL, 28 | TM_MOD, 29 | TM_POW, 30 | TM_DIV, 31 | TM_IDIV, 32 | TM_BAND, 33 | TM_BOR, 34 | TM_BXOR, 35 | TM_SHL, 36 | TM_SHR, 37 | TM_UNM, 38 | TM_BNOT, 39 | TM_LT, 40 | TM_LE, 41 | TM_CONCAT, 42 | TM_CALL, 43 | TM_N /* number of elements in the enum */ 44 | } TMS; 45 | 46 | 47 | 48 | #define gfasttm(g,et,e) ((et) == NULL ? NULL : \ 49 | ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) 50 | 51 | #define fasttm(l,et,e) gfasttm(G(l), et, e) 52 | 53 | #define ttypename(x) luaT_typenames_[(x) + 1] 54 | #define objtypename(x) ttypename(ttnov(x)) 55 | 56 | LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; 57 | 58 | 59 | LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); 60 | LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, 61 | TMS event); 62 | LUAI_FUNC void luaT_init (lua_State *L); 63 | 64 | LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, 65 | const TValue *p2, TValue *p3, int hasres); 66 | LUAI_FUNC int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, 67 | StkId res, TMS event); 68 | LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, 69 | StkId res, TMS event); 70 | LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, 71 | const TValue *p2, TMS event); 72 | 73 | 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /lua/lua.hpp: -------------------------------------------------------------------------------- 1 | // lua.hpp 2 | // Lua header files for C++ 3 | // <> not supplied automatically because Lua also compiles as C++ 4 | 5 | extern "C" { 6 | #include "lua.h" 7 | #include "lualib.h" 8 | #include "lauxlib.h" 9 | } 10 | -------------------------------------------------------------------------------- /lua/lualib.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $ 3 | ** Lua standard libraries 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef lualib_h 9 | #define lualib_h 10 | 11 | #include "lua.h" 12 | 13 | 14 | 15 | LUAMOD_API int (luaopen_base) (lua_State *L); 16 | 17 | #define LUA_COLIBNAME "coroutine" 18 | LUAMOD_API int (luaopen_coroutine) (lua_State *L); 19 | 20 | #define LUA_TABLIBNAME "table" 21 | LUAMOD_API int (luaopen_table) (lua_State *L); 22 | 23 | #define LUA_IOLIBNAME "io" 24 | LUAMOD_API int (luaopen_io) (lua_State *L); 25 | 26 | #define LUA_OSLIBNAME "os" 27 | LUAMOD_API int (luaopen_os) (lua_State *L); 28 | 29 | #define LUA_STRLIBNAME "string" 30 | LUAMOD_API int (luaopen_string) (lua_State *L); 31 | 32 | #define LUA_UTF8LIBNAME "utf8" 33 | LUAMOD_API int (luaopen_utf8) (lua_State *L); 34 | 35 | #define LUA_BITLIBNAME "bit32" 36 | LUAMOD_API int (luaopen_bit32) (lua_State *L); 37 | 38 | #define LUA_MATHLIBNAME "math" 39 | LUAMOD_API int (luaopen_math) (lua_State *L); 40 | 41 | #define LUA_DBLIBNAME "debug" 42 | LUAMOD_API int (luaopen_debug) (lua_State *L); 43 | 44 | #define LUA_LOADLIBNAME "package" 45 | LUAMOD_API int (luaopen_package) (lua_State *L); 46 | 47 | 48 | /* open all previous libraries */ 49 | LUALIB_API void (luaL_openlibs) (lua_State *L); 50 | 51 | 52 | 53 | #if !defined(lua_assert) 54 | #define lua_assert(x) ((void)0) 55 | #endif 56 | 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /lua/lundump.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lundump.h,v 1.45 2015/09/08 15:41:05 roberto Exp $ 3 | ** load precompiled Lua chunks 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lundump_h 8 | #define lundump_h 9 | 10 | #include "llimits.h" 11 | #include "lobject.h" 12 | #include "lzio.h" 13 | 14 | 15 | /* data to catch conversion errors */ 16 | #define LUAC_DATA "\x19\x93\r\n\x1a\n" 17 | 18 | #define LUAC_INT 0x5678 19 | #define LUAC_NUM cast_num(370.5) 20 | 21 | #define MYINT(s) (s[0]-'0') 22 | #define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)) 23 | #define LUAC_FORMAT 0 /* this is the official format */ 24 | 25 | /* load one chunk; from lundump.c */ 26 | LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); 27 | 28 | /* dump one chunk; from ldump.c */ 29 | LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, 30 | void* data, int strip); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /lua/lvm.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lvm.h,v 2.39 2015/09/09 13:44:07 roberto Exp $ 3 | ** Lua virtual machine 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lvm_h 8 | #define lvm_h 9 | 10 | 11 | #include "ldo.h" 12 | #include "lobject.h" 13 | #include "ltm.h" 14 | 15 | 16 | #if !defined(LUA_NOCVTN2S) 17 | #define cvt2str(o) ttisnumber(o) 18 | #else 19 | #define cvt2str(o) 0 /* no conversion from numbers to strings */ 20 | #endif 21 | 22 | 23 | #if !defined(LUA_NOCVTS2N) 24 | #define cvt2num(o) ttisstring(o) 25 | #else 26 | #define cvt2num(o) 0 /* no conversion from strings to numbers */ 27 | #endif 28 | 29 | 30 | /* 31 | ** You can define LUA_FLOORN2I if you want to convert floats to integers 32 | ** by flooring them (instead of raising an error if they are not 33 | ** integral values) 34 | */ 35 | #if !defined(LUA_FLOORN2I) 36 | #define LUA_FLOORN2I 0 37 | #endif 38 | 39 | 40 | #define tonumber(o,n) \ 41 | (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n)) 42 | 43 | #define tointeger(o,i) \ 44 | (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I)) 45 | 46 | #define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) 47 | 48 | #define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2) 49 | 50 | 51 | /* 52 | ** fast track for 'gettable': 1 means 'aux' points to resulted value; 53 | ** 0 means 'aux' is metamethod (if 't' is a table) or NULL. 'f' is 54 | ** the raw get function to use. 55 | */ 56 | #define luaV_fastget(L,t,k,aux,f) \ 57 | (!ttistable(t) \ 58 | ? (aux = NULL, 0) /* not a table; 'aux' is NULL and result is 0 */ \ 59 | : (aux = f(hvalue(t), k), /* else, do raw access */ \ 60 | !ttisnil(aux) ? 1 /* result not nil? 'aux' has it */ \ 61 | : (aux = fasttm(L, hvalue(t)->metatable, TM_INDEX), /* get metamethod */\ 62 | aux != NULL ? 0 /* has metamethod? must call it */ \ 63 | : (aux = luaO_nilobject, 1)))) /* else, final result is nil */ 64 | 65 | /* 66 | ** standard implementation for 'gettable' 67 | */ 68 | #define luaV_gettable(L,t,k,v) { const TValue *aux; \ 69 | if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \ 70 | else luaV_finishget(L,t,k,v,aux); } 71 | 72 | 73 | /* 74 | ** Fast track for set table. If 't' is a table and 't[k]' is not nil, 75 | ** call GC barrier, do a raw 't[k]=v', and return true; otherwise, 76 | ** return false with 'slot' equal to NULL (if 't' is not a table) or 77 | ** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro 78 | ** returns true, there is no need to 'invalidateTMcache', because the 79 | ** call is not creating a new entry. 80 | */ 81 | #define luaV_fastset(L,t,k,slot,f,v) \ 82 | (!ttistable(t) \ 83 | ? (slot = NULL, 0) \ 84 | : (slot = f(hvalue(t), k), \ 85 | ttisnil(slot) ? 0 \ 86 | : (luaC_barrierback(L, hvalue(t), v), \ 87 | setobj2t(L, cast(TValue *,slot), v), \ 88 | 1))) 89 | 90 | 91 | #define luaV_settable(L,t,k,v) { const TValue *slot; \ 92 | if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ 93 | luaV_finishset(L,t,k,v,slot); } 94 | 95 | 96 | 97 | LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); 98 | LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); 99 | LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); 100 | LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); 101 | LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode); 102 | LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, 103 | StkId val, const TValue *tm); 104 | LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, 105 | StkId val, const TValue *oldval); 106 | LUAI_FUNC void luaV_finishOp (lua_State *L); 107 | LUAI_FUNC void luaV_execute (lua_State *L); 108 | LUAI_FUNC void luaV_concat (lua_State *L, int total); 109 | LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y); 110 | LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y); 111 | LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y); 112 | LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb); 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /lua/lzio.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lzio.c,v 1.37 2015/09/08 15:41:05 roberto Exp $ 3 | ** Buffered streams 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lzio_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "llimits.h" 18 | #include "lmem.h" 19 | #include "lstate.h" 20 | #include "lzio.h" 21 | 22 | 23 | int luaZ_fill (ZIO *z) { 24 | size_t size; 25 | lua_State *L = z->L; 26 | const char *buff; 27 | lua_unlock(L); 28 | buff = z->reader(L, z->data, &size); 29 | lua_lock(L); 30 | if (buff == NULL || size == 0) 31 | return EOZ; 32 | z->n = size - 1; /* discount char being returned */ 33 | z->p = buff; 34 | return cast_uchar(*(z->p++)); 35 | } 36 | 37 | 38 | void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { 39 | z->L = L; 40 | z->reader = reader; 41 | z->data = data; 42 | z->n = 0; 43 | z->p = NULL; 44 | } 45 | 46 | 47 | /* --------------------------------------------------------------- read --- */ 48 | size_t luaZ_read (ZIO *z, void *b, size_t n) { 49 | while (n) { 50 | size_t m; 51 | if (z->n == 0) { /* no bytes in buffer? */ 52 | if (luaZ_fill(z) == EOZ) /* try to read more */ 53 | return n; /* no more input; return number of missing bytes */ 54 | else { 55 | z->n++; /* luaZ_fill consumed first byte; put it back */ 56 | z->p--; 57 | } 58 | } 59 | m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ 60 | memcpy(b, z->p, m); 61 | z->n -= m; 62 | z->p += m; 63 | b = (char *)b + m; 64 | n -= m; 65 | } 66 | return 0; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /lua/lzio.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lzio.h,v 1.31 2015/09/08 15:41:05 roberto Exp $ 3 | ** Buffered streams 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef lzio_h 9 | #define lzio_h 10 | 11 | #include "lua.h" 12 | 13 | #include "lmem.h" 14 | 15 | 16 | #define EOZ (-1) /* end of stream */ 17 | 18 | typedef struct Zio ZIO; 19 | 20 | #define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) 21 | 22 | 23 | typedef struct Mbuffer { 24 | char *buffer; 25 | size_t n; 26 | size_t buffsize; 27 | } Mbuffer; 28 | 29 | #define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) 30 | 31 | #define luaZ_buffer(buff) ((buff)->buffer) 32 | #define luaZ_sizebuffer(buff) ((buff)->buffsize) 33 | #define luaZ_bufflen(buff) ((buff)->n) 34 | 35 | #define luaZ_buffremove(buff,i) ((buff)->n -= (i)) 36 | #define luaZ_resetbuffer(buff) ((buff)->n = 0) 37 | 38 | 39 | #define luaZ_resizebuffer(L, buff, size) \ 40 | ((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \ 41 | (buff)->buffsize, size), \ 42 | (buff)->buffsize = size) 43 | 44 | #define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) 45 | 46 | 47 | LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, 48 | void *data); 49 | LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ 50 | 51 | 52 | 53 | /* --------- Private Part ------------------ */ 54 | 55 | struct Zio { 56 | size_t n; /* bytes still unread */ 57 | const char *p; /* current position in buffer */ 58 | lua_Reader reader; /* reader function */ 59 | void *data; /* additional data */ 60 | lua_State *L; /* Lua state (for reader) */ 61 | }; 62 | 63 | 64 | LUAI_FUNC int luaZ_fill (ZIO *z); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /test/ctest.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2011-2012 Emil Renner Berthing 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | print('Entered ' .. arg[0]) 21 | 22 | package.path = '?.lua' 23 | package.cpath = '?.so' 24 | 25 | local utils = require 'lem.utils' 26 | local io = require 'lem.io' 27 | 28 | local conn = assert(io.tcp.connect('localhost', arg[1] or '8080')) 29 | 30 | for i = 1, 10 do 31 | assert(conn:write('ping\n')) 32 | 33 | local line, err = conn:read('*l') 34 | if not line then 35 | if err == 'closed' then 36 | print("Server closed connection") 37 | return 38 | end 39 | 40 | error(err) 41 | end 42 | 43 | print("Server answered: '" .. line .. "'") 44 | end 45 | 46 | conn:write('quit\n') 47 | 48 | print('Exiting ' .. arg[0]) 49 | 50 | -- vim: syntax=lua ts=2 sw=2 noet: 51 | -------------------------------------------------------------------------------- /test/download.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2013 Emil Renner Berthing 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | package.path = '?.lua' 21 | package.cpath = '?.so' 22 | 23 | local utils = require 'lem.utils' 24 | local io = require 'lem.io' 25 | local client = require 'lem.http.client' 26 | 27 | local write, format = io.write, string.format 28 | local function printf(...) 29 | return write(format(...)) 30 | end 31 | 32 | local url = arg[1] or 'http://ompldr.org/vODFnOA/Birgit%20Lystager%20-%20Birger.mp3' 33 | local filename = arg[2] or 'birger.mp3' 34 | local stop = false 35 | 36 | utils.spawn(function() 37 | local c = client.new() 38 | 39 | assert(c:download(url, filename)) 40 | assert(c:close()) 41 | stop = true 42 | end) 43 | 44 | local sleeper = utils.newsleeper() 45 | repeat 46 | write('.') 47 | sleeper:sleep(0.001) 48 | until stop 49 | 50 | -- vim: set ts=2 sw=2 noet: 51 | -------------------------------------------------------------------------------- /test/fclose.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2013 Ico Doornekamp 5 | -- Copyright 2013 Emil Renner Berthing 6 | -- 7 | -- LEM is free software: you can redistribute it and/or modify it 8 | -- under the terms of the GNU Lesser General Public License as 9 | -- published by the Free Software Foundation, either version 3 of 10 | -- the License, or (at your option) any later version. 11 | -- 12 | -- LEM is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | -- GNU Lesser General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU Lesser General Public 18 | -- License along with LEM. If not, see . 19 | -- 20 | 21 | package.path = '?.lua' 22 | package.cpath = '?.so' 23 | 24 | local utils = require 'lem.utils' 25 | local io = require 'lem.io' 26 | 27 | local done = false 28 | 29 | utils.spawn(function() 30 | local s, now, format = utils.newsleeper(), utils.now, string.format 31 | local t1, t2 = now(), 0 32 | repeat 33 | s:sleep(0.1) 34 | t2 = now() 35 | print(format("Tick after %uus", (t2 - t1)*1000000)) 36 | t1 = t2 37 | until done 38 | end) 39 | 40 | local file = assert(io.open('file.txt', 'w')) 41 | local b = string.rep("a", 1024*1024) 42 | for i = 1, 150 do 43 | file:write(b) 44 | end 45 | print("Closing file") 46 | file:close() 47 | print("Write done") 48 | 49 | utils.newsleeper():sleep(1) 50 | done = true 51 | 52 | -- vim: set ts=2 sw=2 noet: 53 | -------------------------------------------------------------------------------- /test/fread.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2012 Emil Renner Berthing 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | package.path = '?.lua' 21 | package.cpath = '?.so' 22 | 23 | local utils = require 'lem.utils' 24 | local io = require 'lem.io' 25 | 26 | local write = io.write 27 | 28 | print("Press enter to read '" .. (arg[1] or arg[0]) .. "'") 29 | io.read() 30 | 31 | local threads = 2 32 | for i = 1, threads do 33 | utils.spawn(function() 34 | local file = assert(io.open(arg[1] or arg[0])) 35 | assert(getmetatable(file) == io.File, "Hmm...") 36 | 37 | ---[[ 38 | local chunk, err 39 | while true do 40 | chunk, err = file:read() 41 | if not chunk then break end 42 | write('|') 43 | --print(chunk) 44 | end 45 | assert(err == 'eof', "Hmm..") 46 | --[=[ 47 | --]] 48 | local line, err 49 | while true do 50 | line, err = file:read('*l') 51 | if not line then break end 52 | print(line) 53 | end 54 | --]=] 55 | 56 | threads = threads - 1 57 | end) 58 | end 59 | 60 | local yield = utils.yield 61 | while threads > 0 do 62 | write('.') 63 | yield() 64 | end 65 | 66 | print "\nDone. Press enter to continue." 67 | io.read() 68 | 69 | -- vim: set ts=2 sw=2 noet: 70 | -------------------------------------------------------------------------------- /test/fwrite.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2012-2013 Emil Renner Berthing 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | package.path = '?.lua' 21 | package.cpath = '?.so' 22 | 23 | local utils = require 'lem.utils' 24 | local io = require 'lem.io' 25 | 26 | local write = io.write 27 | 28 | print("Press enter to read '" .. (arg[1] or arg[0]) .. "'") 29 | io.read() 30 | 31 | local threads = 2 32 | for i = 1, threads do 33 | utils.spawn(function(n) 34 | local file = assert(io.open('file' .. tostring(n) .. '.txt', 'w')) 35 | assert(getmetatable(file) == io.File, "Hmm...") 36 | 37 | print(tostring(n) .. '-1') 38 | assert(file:write('Hej', ' ', 'med', ' ', 'dig', '!\n')) 39 | print(tostring(n) .. '-2') 40 | assert(file:write(tostring(n))) 41 | print(tostring(n) .. '-3') 42 | assert(file:write('\n')) 43 | print(tostring(n) .. '-4') 44 | print(assert(file:seek("cur", -2))) 45 | print(tostring(n) .. '-5') 46 | assert(file:write('Dav!')) 47 | print(tostring(n) .. '-6') 48 | 49 | threads = threads - 1 50 | end, i) 51 | end 52 | 53 | local yield = utils.yield 54 | while threads > 0 do 55 | write('.') 56 | yield() 57 | end 58 | 59 | print "\nDone. Press enter to continue." 60 | io.read() 61 | 62 | -- vim: set ts=2 sw=2 noet: 63 | -------------------------------------------------------------------------------- /test/hathawaytest.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2011-2012 Emil Renner Berthing 5 | -- Copyright 2013 Asbjørn Sloth Tønnesen 6 | -- 7 | -- LEM is free software: you can redistribute it and/or modify it 8 | -- under the terms of the GNU Lesser General Public License as 9 | -- published by the Free Software Foundation, either version 3 of 10 | -- the License, or (at your option) any later version. 11 | -- 12 | -- LEM is distributed in the hope that it will be useful, but 13 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | -- GNU Lesser General Public License for more details. 16 | -- 17 | -- You should have received a copy of the GNU Lesser General Public 18 | -- License along with LEM. If not, see . 19 | -- 20 | 21 | package.path = '?.lua' 22 | package.cpath = '?.so' 23 | 24 | local utils = require 'lem.utils' 25 | local io = require 'lem.io' 26 | local hathaway = require 'lem.hathaway' 27 | 28 | hathaway.debug = print -- must be set before import() 29 | hathaway.import() -- when using single instance API 30 | 31 | GET('/', function(req, res) 32 | print(req.client:getpeer()) 33 | res.status = 302 34 | res.headers['Location'] = '/dump' 35 | end) 36 | 37 | GET('/hello', function(req, res) 38 | res.headers['Content-Type'] = 'text/plain' 39 | res:add('Hello, World!\n') 40 | end) 41 | 42 | GET('/self', function(req, res) 43 | res.headers['Content-Type'] = 'text/plain' 44 | res.file = arg[0] 45 | end) 46 | 47 | GET('/dump', function(req, res) 48 | local accept = req.headers['accept'] 49 | if accept and accept:match('application/xhtml%+xml') then 50 | res.headers['Content-Type'] = 'application/xhtml+xml' 51 | else 52 | res.headers['Content-Type'] = 'text/html' 53 | end 54 | res:add([[ 55 | 56 | 57 | 58 | Hathaway HTTP dump 59 | 62 | 63 | 64 | 65 |

Request

66 | 67 | 68 | 69 | 70 |
Method:%s
Uri:%s
Version:%s
71 | 72 |

Headers

73 | 74 | ]], req.method or '', req.uri or '', req.version) 75 | 76 | for k, v in pairs(req.headers) do 77 | res:add(' \n', k, v) 78 | end 79 | 80 | res:add([[ 81 |
%s%s
82 | 83 |

Body

84 |
85 |

86 |
87 | 88 |

89 |
90 | 91 |
92 |

93 | 94 | 95 |

96 |
97 | 98 | 99 | 100 | ]]) 101 | end) 102 | 103 | local function urldecode(str) 104 | return str:gsub('+', ' '):gsub('%%(%x%x)', function (str) 105 | return string.char(tonumber(str, 16)) 106 | end) 107 | end 108 | 109 | local function parseform(str) 110 | local t = {} 111 | for k, v in str:gmatch('([^&]+)=([^&]*)') do 112 | t[urldecode(k)] = urldecode(v) 113 | end 114 | return t 115 | end 116 | 117 | POST('/form', function(req, res) 118 | res.headers['Content-Type'] = 'text/plain' 119 | local body =req:body() 120 | res:add("You sent:\n%s\n", body) 121 | res:add('{\n') 122 | for k, v in pairs(parseform(body)) do 123 | res:add(" ['%s'] = '%s'\n", k, v) 124 | end 125 | res:add('}\n') 126 | end) 127 | 128 | GET('/close', function(req, res) 129 | res.headers['Content-Type'] = 'text/plain' 130 | res.headers['Connection'] = 'close' 131 | res:add('This connection should close\n') 132 | end) 133 | 134 | POST('/quit', function(req, res) 135 | local body = req:body() 136 | 137 | res.headers['Content-Type'] = 'text/plain' 138 | 139 | if body == 'quit=secret' then 140 | res:add("Bye o/\n") 141 | hathaway.server:close() 142 | else 143 | res:add("You didn't supply the right value...\n") 144 | end 145 | end) 146 | 147 | GETM('^/hello/([^/]+)$', function(req, res, name) 148 | res.headers['Content-Type'] = 'text/plain' 149 | res:add('Hello, %s!\n', name) 150 | end) 151 | 152 | if arg[1] == 'socket' then 153 | local sock = assert(io.unix.listen('socket', 666)) 154 | Hathaway(sock) 155 | else 156 | Hathaway('*', arg[1] or '8080') 157 | end 158 | utils.exit(0) -- otherwise open connections will keep us running 159 | 160 | -- vim: syntax=lua ts=2 sw=2 noet: 161 | -------------------------------------------------------------------------------- /test/httptest.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2011-2012 Emil Renner Berthing 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | package.path = '?.lua' 21 | package.cpath = '?.so' 22 | 23 | local utils = require 'lem.utils' 24 | local io = require 'lem.io' 25 | local client = require 'lem.http.client' 26 | 27 | local write, format = io.write, string.format 28 | local function printf(...) 29 | return write(format(...)) 30 | end 31 | 32 | local url = arg[1] or 'http://www.google.com/' 33 | local running = 0 34 | 35 | local function get(n, close) 36 | running = running + 1 37 | 38 | local c = client.new() 39 | 40 | local res = assert(c:get(url)) 41 | 42 | printf('\n%d: HTTP/%s %d %s\n', n, res.version, res.status, res.text) 43 | for k, v in pairs(res.headers) do 44 | printf('%d: %s: %s\n', n, k, v) 45 | end 46 | 47 | local body = assert(res:body()) 48 | printf('\n%d: #body = %d\n', n, #body) 49 | 50 | assert(c:close()) 51 | running = running - 1 52 | end 53 | 54 | for i = 1, 2 do 55 | utils.spawn(get, i, (i % 2) == 0) 56 | end 57 | 58 | local sleeper = utils.newsleeper() 59 | repeat 60 | write('.') 61 | sleeper:sleep(0.001) 62 | until running == 0 63 | 64 | -- vim: set ts=2 sw=2 noet: 65 | -------------------------------------------------------------------------------- /test/lfs.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2012 Emil Renner Berthing 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | package.path = '?.lua' 21 | package.cpath = '?.so' 22 | 23 | local utils = require 'lem.utils' 24 | local io = require 'lem.io' 25 | local lfs = require 'lem.lfs' 26 | 27 | local testdir = 'testdir' 28 | local testfile = 'testfile' 29 | 30 | local spawnticker, stopticker 31 | do 32 | local write, yield = io.write, utils.yield 33 | local stop = true 34 | 35 | local function ticker() 36 | stop = false 37 | repeat 38 | write('.') 39 | yield() 40 | until stop 41 | end 42 | 43 | function spawnticker() 44 | utils.spawn(ticker) 45 | end 46 | 47 | function stopticker() 48 | stop = true 49 | end 50 | end 51 | 52 | local sleeper = utils.newsleeper() 53 | local attr 54 | 55 | io.write('Current directory: '.. lfs.currentdir() ..'\n') 56 | 57 | spawnticker() 58 | 59 | for name in lfs.dir('.') do 60 | io.write('\n"' .. name .. '"\n') 61 | end 62 | 63 | io.write('\nCreating testdir\n') 64 | assert(lfs.mkdir(testdir)) 65 | io.write('\nLocking directory\n') 66 | local lock = assert(lfs.lock_dir(testdir)) 67 | io.write('\nGetting attributes\n') 68 | attr = assert(lfs.attributes(testdir)) 69 | io.write('\nAttributes:\n') 70 | for k, v in pairs(attr) do 71 | print(k, v) 72 | end 73 | io.write('\nUnlocking testdir\n') 74 | assert(lock:free()) 75 | io.write('\nRemoving testdir\n') 76 | assert(lfs.rmdir(testdir)) 77 | io.write('\nCreating testfile\n') 78 | local file = assert(io.open(testfile, 'w')) 79 | io.write('\nLocking testfile\n') 80 | assert(lfs.lock(file, 'w')) 81 | io.write('\nGetting change time\n') 82 | attr = assert(lfs.attributes(testfile, 'change')) 83 | io.write('\nChange time: ' .. attr .. '\n') 84 | stopticker() 85 | io.write('\nSleeping two seconds..\n') 86 | sleeper:sleep(2) 87 | spawnticker() 88 | io.write('\nTouching testfile\n') 89 | assert(lfs.touch(testfile)) 90 | io.write('\nGetting change time\n') 91 | attr = assert(lfs.attributes(testfile, 'change')) 92 | io.write('\nChange time: ' .. attr .. '\n') 93 | io.write('\nRenaming testfile\n') 94 | assert(lfs.rename(testfile, testfile..'2')) 95 | io.write('\nRemoving testfile\n') 96 | assert(lfs.remove(testfile..'2')) 97 | io.write('\nDone\n') 98 | stopticker() 99 | 100 | -- vim: syntax=lua ts=2 sw=2 noet: 101 | -------------------------------------------------------------------------------- /test/lines.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2013 Emil Renner Berthing 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | package.path = '?.lua' 21 | package.cpath = '?.so' 22 | 23 | local utils = require 'lem.utils' 24 | local io = require 'lem.io' 25 | 26 | local format, write = string.format, io.write 27 | 28 | local n = 0 29 | 30 | if not arg[1] then 31 | io.stderr:write("I need a file..\n") 32 | utils.exit(1) 33 | end 34 | 35 | ---[[ 36 | local file, err = io.streamfile(arg[1]) 37 | --local file, err = io.open(arg[1]) 38 | 39 | if not file then 40 | io.stderr:write(format("Error opening '%s': %s\n", arg[1], err)) 41 | utils.exit(1) 42 | end 43 | 44 | for line in file:lines() do 45 | n = n+1 46 | end 47 | --[=[ 48 | --]] 49 | for line in io.lines(arg[1]) do 50 | n = n+1 51 | end 52 | --]=] 53 | 54 | write(format('%d lines\n', n)) 55 | 56 | -- vim: syntax=lua ts=2 sw=2 noet: 57 | -------------------------------------------------------------------------------- /test/multiplexing.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2011-2012 Emil Renner Berthing 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | package.path = '?.lua' 21 | package.cpath = '?.so' 22 | 23 | local utils = require 'lem.utils' 24 | local io = require 'lem.io' 25 | local queue = require 'lem.io.queue' 26 | 27 | local exit = false 28 | local ticker = utils.newsleeper() 29 | local stdout = queue.wrap(io.stdout) 30 | 31 | do 32 | local format = string.format 33 | function queue.Stream:printf(...) 34 | return self:write(format(...)) 35 | end 36 | end 37 | 38 | -- this function just reads lines from a 39 | -- stream and prints them to stdout 40 | local function poll(stream, name) 41 | repeat 42 | local line, err = stream:read('*l') 43 | if not line then 44 | stdout:printf('%s: %s\n', name, err) 45 | break 46 | end 47 | 48 | stdout:printf('%s: %s\n', name, line) 49 | until line == 'quit' 50 | 51 | exit = true 52 | ticker:wakeup() 53 | end 54 | 55 | -- type 'mkfifo pipe' to create a named pipe for this script 56 | -- and do 'cat > pipe' (in another terminal) to write to it 57 | local pipe = assert(io.open(arg[1] or 'pipe', 'r')) 58 | 59 | -- spawn coroutines to read from stdin and the pipe 60 | utils.spawn(poll, io.stdin, 'stdin') 61 | utils.spawn(poll, pipe, 'pipe') 62 | 63 | do 64 | --local out = io.stderr 65 | local out = stdout 66 | local sound 67 | 68 | repeat 69 | if sound == 'tick\n' then 70 | sound = 'tock\n' 71 | else 72 | sound = 'tick\n' 73 | end 74 | out:write(sound) 75 | ticker:sleep(1.0) 76 | until exit 77 | end 78 | 79 | io.stdin:close() 80 | pipe:close() 81 | 82 | -- vim: syntax=lua ts=2 sw=2 noet: 83 | -------------------------------------------------------------------------------- /test/popen.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2013 Emil Renner Berthing 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | package.path = '?.lua' 21 | package.cpath = '?.so' 22 | 23 | local utils = require 'lem.utils' 24 | local io = require 'lem.io' 25 | 26 | local write, format = io.write, string.format 27 | 28 | local p = assert(io.popen('telnet localhost 8080', 'rw')) 29 | 30 | assert(p:write('GET / HTTP/1.0')) 31 | assert(p:write('\n')) 32 | assert(p:write('\n')) 33 | 34 | local n = 0 35 | for line in p:lines() do 36 | n = n+1 37 | write(format('%4d: %s\n', n, line)) 38 | end 39 | 40 | -- vim: syntax=lua ts=2 sw=2 noet: 41 | -------------------------------------------------------------------------------- /test/queue.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2011-2012 Emil Renner Berthing 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | package.path = '?.lua' 21 | package.cpath = '?.so' 22 | 23 | local utils = require 'lem.utils' 24 | local queue = require 'lem.queue' 25 | 26 | local consumers = 0 27 | local function consumer(q, id) 28 | consumers = consumers + 1 29 | local sleeper = utils.newsleeper() 30 | for v in q:consume() do 31 | print(string.format('thread %d, n = %2d, received "%s"', 32 | id, q.n, tostring(v))) 33 | sleeper:sleep(0.04) 34 | end 35 | consumers = consumers - 1 36 | end 37 | 38 | local q, sleeper = queue.new(), utils.newsleeper() 39 | 40 | print "One consumer:\n" 41 | for i = 1, 5 do 42 | q:put(i) 43 | end 44 | 45 | utils.spawn(consumer, q, 1) 46 | utils.yield() 47 | assert(consumers == 1) 48 | 49 | for i = 6, 10 do 50 | q:put(i) 51 | sleeper:sleep(0.1) 52 | end 53 | 54 | assert(q:empty()) 55 | 56 | assert(consumers == 1) 57 | q:reset() 58 | utils.yield() 59 | assert(consumers == 0) 60 | 61 | print "\nFive consumers:\n" 62 | 63 | for i = 1, 10 do 64 | q:put(i) 65 | end 66 | 67 | for i = 1, 5 do 68 | utils.spawn(consumer, q, i) 69 | end 70 | utils.yield() 71 | assert(consumers == 5) 72 | 73 | for i = 11, 20 do 74 | q:put(i) 75 | sleeper:sleep(0.1) 76 | end 77 | 78 | assert(q:empty()) 79 | assert(consumers == 5) 80 | 81 | q:signal(nil) 82 | utils.yield() 83 | assert(consumers == 0) 84 | 85 | -- vim: syntax=lua ts=2 sw=2 noet: 86 | -------------------------------------------------------------------------------- /test/signal.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2013 Asbjørn Sloth Tønnesen 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | package.path = '?.lua' 21 | package.cpath = '?.so' 22 | 23 | local signal = require 'lem.signal' 24 | local utils = require 'lem.utils' 25 | local io = require 'lem.io' 26 | 27 | local sleeper = utils.newsleeper() 28 | 29 | assert(signal.register('sigchld', function(signum, ev) 30 | if ev.type == 'exited' then 31 | print('child ' .. ev.rpid .. ' ' .. ev.type .. ' with status ' .. ev.status) 32 | end 33 | end)) 34 | 35 | local cmd = 'sleep 0.5' 36 | print('starting child: `'..cmd..'`'); 37 | io.popen(cmd) 38 | 39 | sleeper:sleep(1) 40 | 41 | local function handler(signum) 42 | print('got ' .. signal.lookup(signum)) 43 | end 44 | 45 | print('catch sigint') 46 | assert(signal.register('SIGINT', handler)) 47 | 48 | sleeper:sleep(5) 49 | 50 | print('restore sigint') 51 | assert(signal.unregister('SIGINT', handler)) 52 | 53 | sleeper:sleep(5) 54 | 55 | print('catch sigint') 56 | assert(signal.register('SIGINT', handler)) 57 | 58 | sleeper:sleep(5) 59 | print('exiting') 60 | 61 | -- vim: ts=2 sw=2 noet: 62 | -------------------------------------------------------------------------------- /test/sleep.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2011-2012 Emil Renner Berthing 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | package.path = '?.lua' 21 | package.cpath = '?.so' 22 | 23 | local utils = require 'lem.utils' 24 | 25 | local sum, coros, n = 0, 0, 0 26 | local done = utils.newsleeper() 27 | 28 | local function test(t) 29 | local sleeper = utils.newsleeper() 30 | local diff = utils.now() 31 | sleeper:sleep(t) 32 | diff = utils.now() - diff 33 | 34 | print(string.format('%fs, %fms off', diff, 1000*(diff - t))) 35 | sum = sum + math.abs(diff - t) 36 | n = n + 1 37 | if n == coros then done:wakeup() end 38 | end 39 | 40 | for t = 0, 3, 0.1 do 41 | coros = coros + 1 42 | utils.spawn(test, t) 43 | end 44 | 45 | done:sleep() 46 | 47 | print(string.format('%fms off on average', 1000*sum / n)) 48 | 49 | -- vim: syntax=lua ts=2 sw=2 noet: 50 | -------------------------------------------------------------------------------- /test/stest.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2011-2012 Emil Renner Berthing 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | print('Entered ' .. arg[0]) 21 | 22 | package.path = '?.lua' 23 | package.cpath = '?.so' 24 | 25 | local utils = require 'lem.utils' 26 | local io = require 'lem.io' 27 | 28 | local server = assert(io.tcp.listen('*', arg[1] or '8080')) 29 | 30 | --timer(10, function() exit(0) end) 31 | utils.spawn(function() 32 | utils.newsleeper():sleep(10) 33 | print 'Closing server' 34 | server:close() 35 | end) 36 | 37 | local ok, err = server:autospawn(function(client) 38 | print 'Accepted a connection' 39 | local sleeper = utils.newsleeper() 40 | 41 | while true do 42 | local line, err = client:read('*l') 43 | if not line then 44 | if err == 'closed' then 45 | print("Client closed connection") 46 | return 47 | end 48 | 49 | error(err) 50 | end 51 | 52 | print("Client sent: '" .. line .. "'") 53 | if line ~= 'ping' then break end 54 | 55 | sleeper:sleep(0.4) 56 | assert(client:write('pong\n')) 57 | end 58 | 59 | print "Ok, I'm out" 60 | assert(client:close()) 61 | end) 62 | 63 | if not ok and err ~= 'interrupted' then error(err) end 64 | 65 | print('Exiting ' .. arg[0]) 66 | 67 | -- vim: syntax=lua ts=2 sw=2 noet: 68 | -------------------------------------------------------------------------------- /test/test.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2011-2012 Emil Renner Berthing 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | package.path = '?.lua' 21 | package.cpath = '?.so' 22 | 23 | local utils = require 'lem.utils' 24 | 25 | local function sleep(n) 26 | utils.newsleeper():sleep(n) 27 | end 28 | 29 | local function timer(n, f, ...) 30 | utils.spawn(function(...) 31 | sleep(n) 32 | return f(...) 33 | end, ...) 34 | end 35 | 36 | --print('package.cpath = ', package.cpath) 37 | 38 | print 'Saying booh in 2.5 seconds' 39 | 40 | timer(2.5, function() print 'Booh!' end) 41 | 42 | print 'Sleeping 5 seconds' 43 | 44 | sleep(5) 45 | 46 | print 'Done sleeping' 47 | 48 | print 'Spawning new thread..' 49 | utils.spawn(function(s) print(s) end, "I'm the new thread!") 50 | 51 | print 'Yielding..' 52 | utils.yield() 53 | 54 | print 'Back.' 55 | 56 | print 'Bye!' 57 | 58 | -- vim: syntax=lua ts=3 sw=3 et: 59 | -------------------------------------------------------------------------------- /test/test2.lua: -------------------------------------------------------------------------------- 1 | #!bin/lem 2 | -- 3 | -- This file is part of LEM, a Lua Event Machine. 4 | -- Copyright 2011-2012 Emil Renner Berthing 5 | -- 6 | -- LEM is free software: you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as 8 | -- published by the Free Software Foundation, either version 3 of 9 | -- the License, or (at your option) any later version. 10 | -- 11 | -- LEM is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU Lesser General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public 17 | -- License along with LEM. If not, see . 18 | -- 19 | 20 | print('Entered ' .. arg[0]) 21 | 22 | package.path = '?.lua' 23 | package.cpath = '?.so' 24 | 25 | local utils = require 'lem.utils' 26 | 27 | local function sleep(n) 28 | utils.newsleeper():sleep(n) 29 | end 30 | 31 | print 'Saying "Fee!" in 1 second' 32 | utils.spawn(function() 33 | sleep(1) 34 | print 'Fee!' 35 | end) 36 | 37 | print 'Saying "Fo!" in 3 seconds' 38 | utils.spawn(function() 39 | sleep(3) 40 | print 'Fo!' 41 | end) 42 | 43 | print 'Sleeping for 2 seconds, then saying "Fi!" before the script ends' 44 | sleep(2) 45 | print 'Fi!' 46 | 47 | -- vim: syntax=lua ts=3 sw=3 et: 48 | --------------------------------------------------------------------------------