From fa5e0057283fc18745396638561272c6c0f9ee6a Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Thu, 21 Apr 2016 10:02:33 +0200
Subject: degesch: refactor Lua weak objects
---
degesch.c | 333 +++++++++++++++++++++-----------------------------------------
1 file changed, 111 insertions(+), 222 deletions(-)
diff --git a/degesch.c b/degesch.c
index f1eceb8..61355ef 100644
--- a/degesch.c
+++ b/degesch.c
@@ -8322,113 +8322,126 @@ lua_plugin_parse (lua_State *L)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-#define XLUA_USER_METATABLE "user" ///< Identifier for the Lua metatable
+// Lua code can use weakly referenced wrappers for internal objects.
-struct lua_user
+typedef struct weak_ref_link *
+ (*lua_weak_ref_fn) (void *object, destroy_cb_fn cb, void *user_data);
+typedef void (*lua_weak_unref_fn) (void *object, struct weak_ref_link **link);
+
+struct lua_weak_info
+{
+ const char *name; ///< Metatable name
+ lua_weak_ref_fn ref; ///< Weak link invalidator
+ lua_weak_unref_fn unref; ///< Weak link generator
+};
+
+struct lua_weak
{
struct lua_plugin *plugin; ///< The plugin we belong to
- struct user *user; ///< The user
+ void *object; ///< The object
struct weak_ref_link *weak_ref; ///< A weak reference link
};
static void
-lua_user_invalidate (void *object, void *user_data)
+lua_weak_invalidate (void *object, void *user_data)
{
- struct lua_user *wrapper = user_data;
- wrapper->user = NULL;
+ struct lua_weak *wrapper = user_data;
+ wrapper->object = NULL;
wrapper->weak_ref = NULL;
// This can in theory call the GC, order isn't arbitrary here
lua_cache_invalidate (wrapper->plugin->L, object);
}
static void
-lua_plugin_push_user (struct lua_plugin *plugin, struct user *user)
+lua_weak_push (struct lua_plugin *plugin, void *object,
+ struct lua_weak_info *info)
{
lua_State *L = plugin->L;
- if (lua_cache_get (L, user))
+ if (!object)
+ {
+ lua_pushnil (L);
+ return;
+ }
+ if (lua_cache_get (L, object))
return;
- struct lua_user *wrapper = lua_newuserdata (L, sizeof *wrapper);
- luaL_setmetatable (L, XLUA_USER_METATABLE);
+ struct lua_weak *wrapper = lua_newuserdata (L, sizeof *wrapper);
+ luaL_setmetatable (L, info->name);
wrapper->plugin = plugin;
- wrapper->user = user;
- wrapper->weak_ref = user_weak_ref (user, lua_user_invalidate, wrapper);
- lua_cache_store (L, user, -1);
+ wrapper->object = object;
+ wrapper->weak_ref = info->ref (object, lua_weak_invalidate, wrapper);
+ lua_cache_store (L, object, -1);
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-/// Identifier for the Lua metatable
-#define XLUA_CHANNEL_METATABLE "channel"
-
-struct lua_channel
+static int
+lua_weak_gc (lua_State *L, const struct lua_weak_info *info)
{
- struct lua_plugin *plugin; ///< The plugin we belong to
- struct channel *channel; ///< The channel
- struct weak_ref_link *weak_ref; ///< A weak reference link
-};
+ struct lua_weak *wrapper = luaL_checkudata (L, 1, info->name);
+ if (wrapper->object)
+ {
+ lua_cache_invalidate (L, wrapper->object);
+ info->unref (wrapper->object, &wrapper->weak_ref);
+ wrapper->object = NULL;
+ }
+ return 0;
+}
-static void
-lua_channel_invalidate (void *object, void *user_data)
+static struct lua_weak *
+lua_weak_deref (lua_State *L, const struct lua_weak_info *info)
{
- struct lua_channel *wrapper = user_data;
- wrapper->channel = NULL;
- wrapper->weak_ref = NULL;
- // This can in theory call the GC, order isn't arbitrary here
- lua_cache_invalidate (wrapper->plugin->L, object);
+ struct lua_weak *weak = luaL_checkudata (L, 1, info->name);
+ luaL_argcheck (L, weak->object, 1, "dead reference used");
+ return weak;
}
-static void
-lua_plugin_push_channel (struct lua_plugin *plugin, struct channel *channel)
-{
- lua_State *L = plugin->L;
- if (lua_cache_get (L, channel))
- return;
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- struct lua_channel *wrapper = lua_newuserdata (L, sizeof *wrapper);
- luaL_setmetatable (L, XLUA_CHANNEL_METATABLE);
- wrapper->plugin = plugin;
- wrapper->channel = channel;
- wrapper->weak_ref = channel_weak_ref
- (channel, lua_channel_invalidate, wrapper);
- lua_cache_store (L, channel, -1);
-}
+#define LUA_WEAK_DECLARE(id, metatable_id) \
+ static struct lua_weak_info lua_ ## id ## _info = \
+ { \
+ .name = metatable_id, \
+ .ref = (lua_weak_ref_fn) id ## _weak_ref, \
+ .unref = (lua_weak_unref_fn) id ## _weak_unref, \
+ };
+
+#define XLUA_USER_METATABLE "user" ///< Identifier for Lua metatable
+#define XLUA_CHANNEL_METATABLE "channel" ///< Identifier for Lua metatable
+#define XLUA_BUFFER_METATABLE "buffer" ///< Identifier for Lua metatable
+#define XLUA_SERVER_METATABLE "server" ///< Identifier for Lua metatable
+
+LUA_WEAK_DECLARE (user, XLUA_USER_METATABLE)
+LUA_WEAK_DECLARE (channel, XLUA_CHANNEL_METATABLE)
+LUA_WEAK_DECLARE (buffer, XLUA_BUFFER_METATABLE)
+LUA_WEAK_DECLARE (server, XLUA_SERVER_METATABLE)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static int
lua_user_gc (lua_State *L)
{
- struct lua_user *wrapper = luaL_checkudata (L, 1, XLUA_USER_METATABLE);
- if (wrapper->user)
- {
- lua_cache_invalidate (L, wrapper->user);
- user_weak_unref (wrapper->user, &wrapper->weak_ref);
- wrapper->user = NULL;
- }
- return 0;
+ return lua_weak_gc (L, &lua_user_info);
}
static int
lua_user_get_nickname (lua_State *L)
{
- struct lua_user *wrapper = luaL_checkudata (L, 1, XLUA_USER_METATABLE);
- luaL_argcheck (L, wrapper->user, 1, "dead reference used");
- lua_pushstring (L, wrapper->user->nickname);
+ struct lua_weak *wrapper = lua_weak_deref (L, &lua_user_info);
+ struct user *user = wrapper->object;
+ lua_pushstring (L, user->nickname);
return 1;
}
static int
lua_user_get_channels (lua_State *L)
{
- struct lua_user *wrapper = luaL_checkudata (L, 1, XLUA_USER_METATABLE);
- luaL_argcheck (L, wrapper->user, 1, "dead reference used");
+ struct lua_weak *wrapper = lua_weak_deref (L, &lua_user_info);
+ struct user *user = wrapper->object;
int i = 1;
lua_newtable (L);
- LIST_FOR_EACH (struct user_channel, iter, wrapper->user->channels)
+ LIST_FOR_EACH (struct user_channel, iter, user->channels)
{
- lua_plugin_push_channel (wrapper->plugin, iter->channel);
+ lua_weak_push (wrapper->plugin, iter->channel, &lua_channel_info);
lua_rawseti (L, -2, i++);
}
return 1;
@@ -8447,40 +8460,30 @@ static luaL_Reg lua_user_table[] =
static int
lua_channel_gc (lua_State *L)
{
- struct lua_channel *wrapper =
- luaL_checkudata (L, 1, XLUA_CHANNEL_METATABLE);
- if (wrapper->channel)
- {
- lua_cache_invalidate (L, wrapper->channel);
- channel_weak_unref (wrapper->channel, &wrapper->weak_ref);
- wrapper->channel = NULL;
- }
- return 0;
+ return lua_weak_gc (L, &lua_channel_info);
}
static int
lua_channel_get_name (lua_State *L)
{
- struct lua_channel *wrapper =
- luaL_checkudata (L, 1, XLUA_CHANNEL_METATABLE);
- luaL_argcheck (L, wrapper->channel, 1, "dead reference used");
- lua_pushstring (L, wrapper->channel->name);
+ struct lua_weak *wrapper = lua_weak_deref (L, &lua_channel_info);
+ struct channel *channel = wrapper->object;
+ lua_pushstring (L, channel->name);
return 1;
}
static int
lua_channel_get_users (lua_State *L)
{
- struct lua_channel *wrapper =
- luaL_checkudata (L, 1, XLUA_CHANNEL_METATABLE);
- luaL_argcheck (L, wrapper->channel, 1, "dead reference used");
+ struct lua_weak *wrapper = lua_weak_deref (L, &lua_channel_info);
+ struct channel *channel = wrapper->object;
int i = 1;
lua_newtable (L);
- LIST_FOR_EACH (struct channel_user, iter, wrapper->channel->users)
+ LIST_FOR_EACH (struct channel_user, iter, channel->users)
{
lua_createtable (L, 0, 2);
- lua_plugin_push_user (wrapper->plugin, iter->user);
+ lua_weak_push (wrapper->plugin, iter->user, &lua_user_info);
lua_setfield (L, -2, "user");
lua_plugin_kv (L, "prefixes", iter->prefixes.str);
@@ -8499,140 +8502,45 @@ static luaL_Reg lua_channel_table[] =
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-#define XLUA_BUFFER_METATABLE "buffer" ///< Identifier for the Lua metatable
-
-struct lua_buffer
-{
- struct lua_plugin *plugin; ///< The plugin we belong to
- struct buffer *buffer; ///< The buffer
- struct weak_ref_link *weak_ref; ///< A weak reference link
-};
-
-static void
-lua_buffer_invalidate (void *object, void *user_data)
-{
- struct lua_buffer *wrapper = user_data;
- wrapper->buffer = NULL;
- wrapper->weak_ref = NULL;
- // This can in theory call the GC, order isn't arbitrary here
- lua_cache_invalidate (wrapper->plugin->L, object);
-}
-
-static void
-lua_plugin_push_buffer (struct lua_plugin *plugin, struct buffer *buffer)
-{
- lua_State *L = plugin->L;
- if (lua_cache_get (L, buffer))
- return;
-
- struct lua_buffer *wrapper = lua_newuserdata (L, sizeof *wrapper);
- luaL_setmetatable (L, XLUA_BUFFER_METATABLE);
- wrapper->plugin = plugin;
- wrapper->buffer = buffer;
- wrapper->weak_ref = buffer_weak_ref
- (buffer, lua_buffer_invalidate, wrapper);
- lua_cache_store (L, buffer, -1);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-#define XLUA_SERVER_METATABLE "server" ///< Identifier for the Lua metatable
-
-struct lua_server
-{
- struct lua_plugin *plugin; ///< The plugin we belong to
- struct server *server; ///< The server
- struct weak_ref_link *weak_ref; ///< A weak reference link
-};
-
-static void
-lua_server_invalidate (void *object, void *user_data)
-{
- struct lua_server *wrapper = user_data;
- wrapper->server = NULL;
- wrapper->weak_ref = NULL;
- // This can in theory call the GC, order isn't arbitrary here
- lua_cache_invalidate (wrapper->plugin->L, object);
-}
-
-static void
-lua_plugin_push_server (struct lua_plugin *plugin, struct server *server)
-{
- lua_State *L = plugin->L;
- if (lua_cache_get (L, server))
- return;
-
- struct lua_server *wrapper = lua_newuserdata (L, sizeof *wrapper);
- luaL_setmetatable (L, XLUA_SERVER_METATABLE);
- wrapper->plugin = plugin;
- wrapper->server = server;
- wrapper->weak_ref = server_weak_ref
- (server, lua_server_invalidate, wrapper);
- lua_cache_store (L, server, -1);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
static int
lua_buffer_gc (lua_State *L)
{
- struct lua_buffer *wrapper = luaL_checkudata (L, 1, XLUA_BUFFER_METATABLE);
- if (wrapper->buffer)
- {
- lua_cache_invalidate (L, wrapper->buffer);
- buffer_weak_unref (wrapper->buffer, &wrapper->weak_ref);
- wrapper->buffer = NULL;
- }
- return 0;
+ return lua_weak_gc (L, &lua_buffer_info);
}
static int
lua_buffer_get_user (lua_State *L)
{
- struct lua_buffer *wrapper = luaL_checkudata (L, 1, XLUA_BUFFER_METATABLE);
- luaL_argcheck (L, wrapper->buffer, 1, "dead reference used");
-
- if (wrapper->buffer->user)
- lua_plugin_push_user (wrapper->plugin, wrapper->buffer->user);
- else
- lua_pushnil (L);
+ struct lua_weak *wrapper = lua_weak_deref (L, &lua_buffer_info);
+ struct buffer *buffer = wrapper->object;
+ lua_weak_push (wrapper->plugin, buffer->user, &lua_user_info);
return 1;
}
static int
lua_buffer_get_channel (lua_State *L)
{
- struct lua_buffer *wrapper = luaL_checkudata (L, 1, XLUA_BUFFER_METATABLE);
- luaL_argcheck (L, wrapper->buffer, 1, "dead reference used");
-
- if (wrapper->buffer->channel)
- lua_plugin_push_channel (wrapper->plugin, wrapper->buffer->channel);
- else
- lua_pushnil (L);
+ struct lua_weak *wrapper = lua_weak_deref (L, &lua_buffer_info);
+ struct buffer *buffer = wrapper->object;
+ lua_weak_push (wrapper->plugin, buffer->channel, &lua_channel_info);
return 1;
}
static int
lua_buffer_get_server (lua_State *L)
{
- struct lua_buffer *wrapper = luaL_checkudata (L, 1, XLUA_BUFFER_METATABLE);
- luaL_argcheck (L, wrapper->buffer, 1, "dead reference used");
-
- if (wrapper->buffer->server)
- lua_plugin_push_server (wrapper->plugin, wrapper->buffer->server);
- else
- lua_pushnil (L);
+ struct lua_weak *wrapper = lua_weak_deref (L, &lua_buffer_info);
+ struct buffer *buffer = wrapper->object;
+ lua_weak_push (wrapper->plugin, buffer->server, &lua_server_info);
return 1;
}
static int
lua_buffer_log (lua_State *L)
{
- struct lua_buffer *wrapper = luaL_checkudata (L, 1, XLUA_BUFFER_METATABLE);
- luaL_argcheck (L, wrapper->buffer, 1, "dead reference used");
+ struct lua_weak *wrapper = lua_weak_deref (L, &lua_buffer_info);
+ struct buffer *buffer = wrapper->object;
const char *message = lua_plugin_check_utf8 (L, 2);
-
- struct buffer *buffer = wrapper->buffer;
log_full (wrapper->plugin->ctx, buffer->server, buffer,
BUFFER_LINE_STATUS, "#s", message);
return 0;
@@ -8641,11 +8549,9 @@ lua_buffer_log (lua_State *L)
static int
lua_buffer_execute (lua_State *L)
{
- struct lua_buffer *wrapper = luaL_checkudata (L, 1, XLUA_BUFFER_METATABLE);
- luaL_argcheck (L, wrapper->buffer, 1, "dead reference used");
+ struct lua_weak *wrapper = lua_weak_deref (L, &lua_buffer_info);
+ struct buffer *buffer = wrapper->object;
const char *line = lua_plugin_check_utf8 (L, 2);
-
- struct buffer *buffer = wrapper->buffer;
process_input_utf8 (wrapper->plugin->ctx, buffer, line, 0);
return 0;
}
@@ -8667,50 +8573,33 @@ static luaL_Reg lua_buffer_table[] =
static int
lua_server_gc (lua_State *L)
{
- struct lua_server *wrapper = luaL_checkudata (L, 1, XLUA_SERVER_METATABLE);
- if (wrapper->server)
- {
- lua_cache_invalidate (L, wrapper->server);
- server_weak_unref (wrapper->server, &wrapper->weak_ref);
- wrapper->server = NULL;
- }
- return 0;
+ return lua_weak_gc (L, &lua_server_info);
}
static int
lua_server_get_user (lua_State *L)
{
- struct lua_server *wrapper = luaL_checkudata (L, 1, XLUA_SERVER_METATABLE);
- luaL_argcheck (L, wrapper->server, 1, "dead reference used");
-
- if (wrapper->server->irc_user)
- lua_plugin_push_user (wrapper->plugin, wrapper->server->irc_user);
- else
- lua_pushnil (L);
+ struct lua_weak *wrapper = lua_weak_deref (L, &lua_server_info);
+ struct server *server = wrapper->object;
+ lua_weak_push (wrapper->plugin, server->irc_user, &lua_user_info);
return 1;
}
static int
lua_server_get_buffer (lua_State *L)
{
- struct lua_server *wrapper = luaL_checkudata (L, 1, XLUA_SERVER_METATABLE);
- luaL_argcheck (L, wrapper->server, 1, "dead reference used");
-
- if (wrapper->server->buffer)
- lua_plugin_push_buffer (wrapper->plugin, wrapper->server->buffer);
- else
- lua_pushnil (L);
+ struct lua_weak *wrapper = lua_weak_deref (L, &lua_server_info);
+ struct server *server = wrapper->object;
+ lua_weak_push (wrapper->plugin, server->buffer, &lua_buffer_info);
return 1;
}
static int
lua_server_send (lua_State *L)
{
- struct lua_server *wrapper = luaL_checkudata (L, 1, XLUA_SERVER_METATABLE);
- luaL_argcheck (L, wrapper->server, 1, "dead reference used");
- const char *line = luaL_checkstring (L, 2);
-
- irc_send (wrapper->server, "%s", line);
+ struct lua_weak *wrapper = lua_weak_deref (L, &lua_server_info);
+ struct server *server = wrapper->object;
+ irc_send (server, "%s", luaL_checkstring (L, 2));
return 0;
}
@@ -8807,9 +8696,9 @@ lua_input_hook_filter (struct input_hook *self, struct buffer *buffer,
lua_State *L = plugin->L;
lua_rawgeti (L, LUA_REGISTRYINDEX, hook->ref_callback);
- lua_rawgetp (L, LUA_REGISTRYINDEX, hook); // 1: hook
- lua_plugin_push_buffer (plugin, buffer); // 2: buffer
- lua_pushstring (L, input); // 3: input
+ lua_rawgetp (L, LUA_REGISTRYINDEX, hook); // 1: hook
+ lua_weak_push (plugin, buffer, &lua_buffer_info); // 2: buffer
+ lua_pushstring (L, input); // 3: input
struct error *e = NULL;
if (lua_plugin_call (plugin, 3, 1, &e))
@@ -8838,9 +8727,9 @@ lua_irc_hook_filter (struct irc_hook *self, struct server *s, char *message)
lua_State *L = plugin->L;
lua_rawgeti (L, LUA_REGISTRYINDEX, hook->ref_callback);
- lua_rawgetp (L, LUA_REGISTRYINDEX, hook); // 1: hook
- lua_plugin_push_server (plugin, s); // 2: server
- lua_pushstring (L, message); // 3: message
+ lua_rawgetp (L, LUA_REGISTRYINDEX, hook); // 1: hook
+ lua_weak_push (plugin, s, &lua_server_info); // 2: server
+ lua_pushstring (L, message); // 3: message
struct error *e = NULL;
if (lua_plugin_call (plugin, 3, 1, &e))
@@ -8927,7 +8816,7 @@ lua_completion_hook_complete (struct completion_hook *self,
lua_rawgetp (L, LUA_REGISTRYINDEX, hook); // 1: hook
lua_plugin_push_completion (L, data); // 2: data
- lua_plugin_push_buffer (plugin, plugin->ctx->current_buffer);
+ lua_weak_push (plugin, plugin->ctx->current_buffer, &lua_buffer_info);
lua_setfield (L, -2, "buffer");
lua_pushstring (L, word); // 3: word
--
cgit v1.2.3-70-g09d2