Permalink
Browse files

lua libuv bindings

  • Loading branch information...
1 parent f488b6a commit 21c24dc3dfc0bbb43f86aa45d11ba4a83f089d79 @bnoordhuis committed Sep 19, 2011
Showing with 614 additions and 0 deletions.
  1. +50 −0 Makefile
  2. +52 −0 src/core.c
  3. +208 −0 src/lua_uv.c
  4. +46 −0 src/lua_uv.h
  5. +258 −0 src/tcp.c
View
@@ -0,0 +1,50 @@
+B ?= build
+
+CFLAGS = -pthread -Wall -Wextra -Wno-unused-parameter -Ideps/http_parser -Ideps/libuv/include
+LDFLAGS = -lpthread
+
+LUA_DIR ?= /usr
+LUA_LIBDIR = $(LUA_DIR)/lib/lua/5.1
+LUA_SHAREDIR = $(LUA_DIR)/share/lua/5.1
+
+SOURCES = \
+ src/lua_uv.c \
+ src/core.c \
+ src/tcp.c \
+
+override CFLAGS += \
+ $(shell pkg-config --cflags lua5.1 --silence-errors || pkg-config --cflags lua-5.1 --silence-errors || pkg-config --cflags lua) \
+ $(shell apr-1-config --cflags --cppflags --includes 2>/dev/null || pkg-config --cflags apr-1) \
+ $(shell apu-1-config --includes 2>/dev/null || pkg-config --cflags apr-util-1)
+
+override LDFLAGS += \
+ $(shell apr-1-config --link-ld --libs 2>/dev/null || pkg-config --libs apr-1) \
+ $(shell apu-1-config --link-ld --libs --ldap-libs 2>/dev/null || pkg-config --libs apr-util-1)
+
+ifdef DEBUG
+ override CFLAGS += -g -O0
+else
+ override CFLAGS += -O2 -DNDEBUG
+endif
+
+.PHONY: prereqs clean
+
+OBJECTS = $(patsubst src/%.c,$(B)/%.o,$(SOURCES))
+
+$(B)/uv.so: prereqs $(OBJECTS) $(B)/http_parser.o deps/libuv/uv.a
+ $(CC) -shared -o $@ $(OBJECTS) deps/libuv/uv.a $(LDFLAGS)
+
+$(B)/http_parser.o: deps/http_parser/http_parser.c deps/http_parser/http_parser.h
+ $(CC) -c $(CFLAGS) -fPIC $< -o $@
+
+$(OBJECTS): $(B)/%.o: src/%.c src/lua_uv.h Makefile
+ $(CC) -c $(CFLAGS) -fPIC $< -o $@
+
+prereqs:
+ [ -d $(B) ] || mkdir $(B)
+
+clean:
+ rm -rf $(B)
+
+deps/libuv/uv.a:
+ $(MAKE) -C deps/libuv CFLAGS+=-fPIC
View
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2011, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "lua_uv.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+
+
+static int core_run(lua_State* L) {
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+ assert(L == loop->data);
+
+ r = uv_run(loop);
+ lua_pushinteger(L, r);
+
+ return 1;
+}
+
+
+static luaL_reg functions[] = {
+ { "run", core_run },
+ { NULL, NULL }
+};
+
+
+void luaopen_uv_core(lua_State *L) {
+ /* Don't create a table, let our functions spill into
+ * the library's global symbol table.
+ */
+ luaL_register(L, NULL, functions);
+}
View
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2011, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "lua_uv.h"
+#include <assert.h>
+
+
+static char object_registry[0];
+
+
+static int traceback(lua_State *L) {
+ if (!lua_isstring(L, 1)) return 1;
+
+ lua_getfield(L, LUA_GLOBALSINDEX, "debug");
+ if (!lua_istable(L, -1)) {
+ lua_pop(L, 1);
+ return 1;
+ }
+
+ lua_getfield(L, -1, "traceback");
+ if (!lua_isfunction(L, -1)) {
+ lua_pop(L, 2);
+ return 1;
+ }
+
+ lua_pushvalue(L, 1); /* pass error message */
+ lua_pushinteger(L, 2); /* skip this function and traceback */
+ lua_call(L, 2, 1); /* call debug.traceback */
+
+ return 1;
+}
+
+
+/**
+ *
+ * Function signature: [-0, +0, ?]
+ */
+static void create_object_registry(lua_State* L) {
+ lua_pushlightuserdata(L, object_registry);
+ lua_newtable(L);
+
+ /* Make registry values weak. Allows the Lua GC
+ * to clean up our stale objects for us.
+ */
+ lua_createtable(L, 0, 1);
+ lua_pushstring(L, "v");
+ lua_setfield(L, -2, "__mode");
+
+ lua_setmetatable(L, -2);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+}
+
+
+/**
+ *
+ * Function signature: [-0, +1, ?]
+ */
+void* new_object(lua_State* L, size_t size, const char* clazz) {
+ void* object;
+
+ /* Create object with metatable. */
+ object = lua_newuserdata(L, size);
+ luaL_getmetatable(L, clazz);
+ lua_setmetatable(L, -2);
+
+ /* Create storage for callbacks. */
+ lua_createtable(L, 1, 0);
+ lua_setfenv(L, -2);
+
+ push_registry(L);
+
+ /* Associate our object with the Lua object. */
+ lua_pushlightuserdata(L, object);
+ lua_pushvalue(L, -3); /* object */
+ lua_rawset(L, -3); /* registry */
+
+ /* Pop our object registry from the stack. */
+ lua_pop(L, 1);
+
+ return object;
+}
+
+
+/**
+ * Set callback.
+ *
+ * `name` is the key to save the callback under.
+ * `index` is the stack index of the Lua callback.
+ *
+ * This function assumes that the first element on the stack
+ * is the Lua object to attach the callback to.
+ *
+ * Function signature: [-0, +0, ?]
+ */
+void set_callback(lua_State* L, const char* name, int index) {
+ index = abs_index(L, index);
+ luaL_checktype(L, index, LUA_TFUNCTION);
+
+ lua_getfenv(L, 1);
+ lua_pushstring(L, name);
+ lua_pushvalue(L, index);
+ lua_rawset(L, -3);
+ lua_pop(L, 1);
+}
+
+
+void clear_callback(lua_State* L, const char* name, void* object) {
+ push_object(L, object);
+ lua_getfenv(L, -1);
+ lua_pushstring(L, name);
+ lua_pushnil(L);
+ lua_rawset(L, -3);
+ lua_pop(L, 2);
+}
+
+
+/**
+ * Push our object registry onto the stack.
+ *
+ * Function signature: [-0, +1, ?]
+ */
+void push_registry(lua_State* L) {
+ /* Push our object registry onto the stack. */
+ lua_pushlightuserdata(L, object_registry);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ assert(lua_istable(L, -1));
+}
+
+
+/**
+ * Find Lua object by handle and push it onto the stack.
+ *
+ * Function signature: [-0, +1, ?]
+ */
+void push_object(lua_State* L, void* object) {
+ /* Push our object registry onto the stack. */
+ lua_pushlightuserdata(L, object_registry);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ assert(lua_istable(L, -1));
+
+ /* Look up the Lua object associated with this handle. */
+ lua_pushlightuserdata(L, object);
+ lua_rawget(L, -2);
+
+ /* STACK: <registry> <object> */
+ lua_remove(L, -2);
+ /* STACK: <object> */
+}
+
+
+/**
+ * Pushes "<traceback> <callback> <object>" onto the stack.
+ *
+ * Function signature: [-0, +3, ?]
+ */
+void push_callback(lua_State* L, void* object, const char* name) {
+ lua_pushcfunction(L, traceback);
+
+ push_object(L, object);
+
+ /* Get the callback table. */
+ lua_getfenv(L, -1);
+ assert(lua_istable(L, -1));
+
+ /* Look up callback. */
+ lua_pushstring(L, name);
+ lua_rawget(L, -2);
+ assert(lua_isfunction(L, -1));
+
+ /* STACK: <object> <table> <callback> */
+ lua_remove(L, -2);
+ /* STACK: <object> <callback> */
+
+ /* STACK: <object> <callback> */
+ lua_pushvalue(L, -2);
+ lua_remove(L, -3);
+ /* STACK: <callback> <object> */
+}
+
+
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+int luaopen_uv(lua_State *L) {
+ luaL_reg functions[] = {{NULL, NULL}};
+
+ uv_default_loop()->data = L;
+ create_object_registry(L);
+
+ luaL_register(L, "uv", functions);
+ luaopen_uv_core(L);
+ luaopen_uv_tcp(L);
+
+ return 1;
+}
View
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef LUV_H_
+#define LUV_H_
+
+#include "uv.h"
+
+#include <stddef.h> /* offsetof */
+
+#include <lua.h>
+#include <lauxlib.h>
+
+/* Lifted from the Lua source. Make stack index absolute. */
+#define abs_index(L, i) \
+ ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1)
+
+#define container_of(ptr, type, member) \
+ ((type *) ((char *) (ptr) - offsetof(type, member)))
+
+#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
+
+void luaopen_uv_core(lua_State *L);
+void luaopen_uv_tcp(lua_State *L);
+
+void* new_object(lua_State* L, size_t size, const char* clazz);
+void set_callback(lua_State* L, const char* name, int index);
+void clear_callback(lua_State* L, const char* name, void* object);
+void push_registry(lua_State* L);
+void push_object(lua_State* L, void* object);
+void push_callback(lua_State* L, void* object, const char* name);
+
+#endif /* lua_uv.h */
Oops, something went wrong.

0 comments on commit 21c24dc

Please sign in to comment.