Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spawn callback #9

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4f3e67e
changed function used for spawning processes
jerojasro Jan 14, 2011
550a681
test callback handler
jerojasro Jan 17, 2011
c878e88
added docs for lua callback handling
jerojasro Jan 20, 2011
94fd0ac
add callback handling infrastructure
jerojasro Jan 21, 2011
1c9070c
add simple Lua callback handling
jerojasro Jan 23, 2011
1a56e59
TODOs for callback handling
jerojasro Jan 23, 2011
2bbb3ff
made definition of callback optional - check func. type
jerojasro Jan 23, 2011
9d672f9
pass termination status to Lua callback function
jerojasro Jan 24, 2011
3d71d5f
TODO added
jerojasro Jan 24, 2011
046be68
expose codes for types of process finalization to lua side
jerojasro Jan 24, 2011
be234e9
changed callback data to pass std{out,err} file descriptors
Jan 24, 2011
b12644f
added missing free() calls
Jan 24, 2011
e80b1ee
moved identical memory releases to a single location
Jan 24, 2011
b0fe8e2
async-callback: added support for passing stdin and stdout to the lua…
jerojasro Feb 21, 2011
8178c18
usage example for lua callbacks
jerojasro Feb 21, 2011
908d77c
Revert "async-callback: added support for passing stdin and stdout to…
Mar 14, 2011
3f642b6
Revert "added missing free() calls"
Mar 14, 2011
90513ac
Revert "changed callback data to pass std{out,err} file descriptors"
Mar 14, 2011
5ef55e1
spawn_callback - added docs
Mar 14, 2011
0de43e7
spawn_async - use lua_pcall to execute the callback
jerojasro Mar 15, 2011
eadeb55
spawn_async - updated lua usage example
jerojasro Mar 15, 2011
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions common/tokenize.list
Expand Up @@ -114,3 +114,6 @@ webview
window
windows
xid
PROC_TERM_EXIT
PROC_TERM_SIGNAL
PROC_TERM_UNKNOWN
1 change: 1 addition & 0 deletions globalconf.h.in
Expand Up @@ -23,6 +23,7 @@

#define LUAKIT_INSTALL_PATH "/usr/local/share/luakit"
#define LUAKIT_OBJECT_REGISTRY_KEY "luakit.object.registry"
#define LUAKIT_CALLBACKS_REGISTRY_KEY "luakit.callbacks.registry"

#include <glib/gtypes.h>
#include <lua.h>
Expand Down
16 changes: 16 additions & 0 deletions lib/async_call_example.lua
@@ -0,0 +1,16 @@
local buf = lousy.bind.buf
local key = lousy.bind.key
add_binds("normal",
{
key({}, "a", function (w)
luakit.spawn("touch /tmp/luakit_iat_test",
function(exit_type, exit_num)
if exit_num == 0 then
w:warning("OK")
else
w:warning("Not OK")
end
end)
end),
})

104 changes: 102 additions & 2 deletions luah.c
Expand Up @@ -19,7 +19,9 @@
*
*/

#include <glib/gprintf.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <webkit/webkit.h>
Expand Down Expand Up @@ -527,22 +529,103 @@ luaH_luakit_spawn_sync(lua_State *L)
return 3;
}

/* Calls the Lua function defined as callback for a (async) spawned process
*
* \param pid The PID of the process that has just finished
* \param status status information about the spawned process. See waitpid(2)
* \param data pointer to the Lua VM state
*
* The called Lua function receives 2 arguments:
*
* Exit type: one of: TERM_EXIT (normal exit), TERM_SIGNAL (terminated by
* signal), TERM_UNKNOWN (another reason)
* Exit number: When normal exit happened, the exit code of the process. When
* finished by a signal, the signal number. -1 otherwise.
*/
void async_callback_handler(GPid pid, gint status, gpointer data) {
lua_State *L = (lua_State *)data;

// fetch callbacks table
lua_pushliteral(L, LUAKIT_CALLBACKS_REGISTRY_KEY);
lua_rawget(L, LUA_REGISTRYINDEX);

// get callback function for the given PID (callbacks[pid])
lua_pushlightuserdata(L, (void *)pid);
lua_rawget(L, -2);

proc_exit_status_t exit_type;
int exit_num = 0;
if (WIFEXITED(status)) {
exit_type = TERM_EXIT;
exit_num = WEXITSTATUS(status);
} else if (WIFSIGNALED(status)) {
exit_type = TERM_SIGNAL;
exit_num = WTERMSIG(status);
} else {
exit_type = TERM_UNKNOWN;
exit_num = -1;
}
lua_pushinteger(L, exit_type);
lua_pushinteger(L, exit_num);
if (lua_pcall(L, 2, 0, 0)) {
g_fprintf(stderr, "%s\n", lua_tostring(L, -1));
}

// free callbacks[pid]
lua_pushlightuserdata(L, (void *)pid);
lua_pushnil(L);
lua_rawset(L, -3);

// stack cleanup - remove callbacks table from it
lua_remove(L, -1);

g_spawn_close_pid(pid);
}

/* Spawns a command.
* \param L The Lua VM state.
* \param L The Lua VM state. Contains a Lua function, the callback handler to use
* when the command finishes.
* \return The number of elements pushed on stack (0).
*/
static gint
luaH_luakit_spawn(lua_State *L)
{
GError *e = NULL;
GPid pid = 0;
const gchar *command = luaL_checkstring(L, 1);
g_spawn_command_line_async(command, &e);
gint argc = 0;
gchar **argv = NULL;
g_shell_parse_argv(command, &argc, &argv, &e);
if (e) {
lua_pushstring(L, e->message);
g_clear_error(&e);
g_strfreev(argv);
lua_error(L);
}
g_spawn_async(NULL, argv, NULL,
G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH, NULL, NULL, &pid,
&e);
g_strfreev(argv);
if(e)
{
lua_pushstring(L, e->message);
g_clear_error(&e);
lua_error(L);
}
int CB_FUNC_IDX = 2;

int cb_type = lua_type(L, CB_FUNC_IDX);
if (cb_type == LUA_TNONE) return 0;

if (cb_type != LUA_TFUNCTION)
luaL_typerror(L, CB_FUNC_IDX, lua_typename(L, LUA_TFUNCTION));

lua_pushliteral(L, LUAKIT_CALLBACKS_REGISTRY_KEY);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pushlightuserdata(L, (void *)pid);
lua_pushvalue(L, CB_FUNC_IDX);
lua_rawset(L, -3);
g_child_watch_add(pid, async_callback_handler, L);
return 0;
}

Expand Down Expand Up @@ -599,6 +682,10 @@ luaH_luakit_index(lua_State *L)
PI_CASE(WEBKIT_USER_AGENT_MAJOR_VERSION, WEBKIT_USER_AGENT_MAJOR_VERSION)
PI_CASE(WEBKIT_USER_AGENT_MINOR_VERSION, WEBKIT_USER_AGENT_MINOR_VERSION)

PI_CASE(PROC_TERM_EXIT, TERM_EXIT)
PI_CASE(PROC_TERM_SIGNAL, TERM_SIGNAL)
PI_CASE(PROC_TERM_UNKNOWN, TERM_UNKNOWN)

case L_TK_WINDOWS:
lua_newtable(L);
for (guint i = 0; i < globalconf.windows->len; i++) {
Expand Down Expand Up @@ -723,6 +810,18 @@ luaH_dofunction_on_error(lua_State *L)
return 1;
}

/* creates a table (with an empty metatable) in the Lua registry to store the
* Lua callback functions associtated to processes spawned via
* luaH_luakit_spawn */
void
luaH_processcallbacks_setup(lua_State *L) {
lua_pushliteral(L, LUAKIT_CALLBACKS_REGISTRY_KEY);
lua_newtable(L);
lua_newtable(L);
lua_setmetatable(L, -2);
lua_rawset(L, LUA_REGISTRYINDEX);
}

void
luaH_init(void)
{
Expand Down Expand Up @@ -752,6 +851,7 @@ luaH_init(void)
luaH_fixups(L);

luaH_object_setup(L);
luaH_processcallbacks_setup(L);

/* Export luakit lib */
luaH_openlib(L, "luakit", luakit_lib, luakit_lib);
Expand Down
6 changes: 6 additions & 0 deletions luah.h
Expand Up @@ -27,6 +27,12 @@
#include "common/luaobject.h"
#include "common/lualib.h"

typedef enum {
TERM_EXIT = 1,
TERM_SIGNAL,
TERM_UNKNOWN
} proc_exit_status_t;

#define luaH_deprecate(L, repl) \
do { \
luaH_warn(L, "%s: This function is deprecated and will be removed, see %s", \
Expand Down