mirror of
https://github.com/neovim/neovim.git
synced 2025-09-30 06:58:35 +00:00
libluv: use luv_set_callback to control callback execution
Disable the use of deferred API functions in a fast lua callback Correctly display error messages from a fast lua callback
This commit is contained in:
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "luv/luv.h"
|
||||
|
||||
static int in_fast_callback = 0;
|
||||
|
||||
typedef struct {
|
||||
Error err;
|
||||
String lua_err_str;
|
||||
@@ -110,6 +112,50 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void nlua_luv_error_event(void **argv)
|
||||
{
|
||||
char *error = (char *)argv[0];
|
||||
msg_ext_set_kind("lua_error");
|
||||
emsgf_multiline("Error executing luv callback:\n%s", error);
|
||||
xfree(error);
|
||||
}
|
||||
|
||||
static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult,
|
||||
int flags)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
int retval;
|
||||
|
||||
// luv callbacks might be executed at any os_breakcheck/line_breakcheck
|
||||
// call, so using the API directly here is not safe.
|
||||
in_fast_callback++;
|
||||
|
||||
int top = lua_gettop(lstate);
|
||||
int status = lua_pcall(lstate, nargs, nresult, 0);
|
||||
if (status) {
|
||||
if (status == LUA_ERRMEM && !(flags & LUVF_CALLBACK_NOEXIT)) {
|
||||
// consider out of memory errors unrecoverable, just like xmalloc()
|
||||
mch_errmsg(e_outofmem);
|
||||
mch_errmsg("\n");
|
||||
preserve_exit();
|
||||
}
|
||||
const char *error = lua_tostring(lstate, -1);
|
||||
|
||||
multiqueue_put(main_loop.events, nlua_luv_error_event,
|
||||
1, xstrdup(error));
|
||||
lua_pop(lstate, 1); // error mesage
|
||||
retval = -status;
|
||||
} else { // LUA_OK
|
||||
if (nresult == LUA_MULTRET) {
|
||||
nresult = lua_gettop(lstate) - top + nargs + 1;
|
||||
}
|
||||
retval = nresult;
|
||||
}
|
||||
|
||||
in_fast_callback--;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void nlua_schedule_event(void **argv)
|
||||
{
|
||||
LuaRef cb = (LuaRef)(ptrdiff_t)argv[0];
|
||||
@@ -180,6 +226,7 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
|
||||
|
||||
// vim.loop
|
||||
luv_set_loop(lstate, &main_loop.uv);
|
||||
luv_set_callback(lstate, nlua_luv_cfpcall);
|
||||
luaopen_luv(lstate);
|
||||
lua_setfield(lstate, -2, "loop");
|
||||
|
||||
@@ -546,6 +593,13 @@ Object executor_exec_lua_cb(LuaRef ref, const char *name, Array args,
|
||||
}
|
||||
}
|
||||
|
||||
/// check if the current execution context is safe for calling deferred API
|
||||
/// methods. Luv callbacks are unsafe as they are called inside the uv loop.
|
||||
bool nlua_is_deferred_safe(lua_State *lstate)
|
||||
{
|
||||
return in_fast_callback == 0;
|
||||
}
|
||||
|
||||
/// Run lua string
|
||||
///
|
||||
/// Used for :lua.
|
||||
|
@@ -172,11 +172,22 @@ local function __index(t, key)
|
||||
end
|
||||
end
|
||||
|
||||
--- Defers the wrapped callback until when the nvim API is safe to call.
|
||||
---
|
||||
--- See |vim-loop-callbacks|
|
||||
local function schedule_wrap(cb)
|
||||
return (function (...)
|
||||
local args = {...}
|
||||
vim.schedule(function() cb(unpack(args)) end)
|
||||
end)
|
||||
end
|
||||
|
||||
local module = {
|
||||
_update_package_paths = _update_package_paths,
|
||||
_os_proc_children = _os_proc_children,
|
||||
_os_proc_info = _os_proc_info,
|
||||
_system = _system,
|
||||
schedule_wrap = schedule_wrap,
|
||||
}
|
||||
|
||||
setmetatable(module, {
|
||||
|
Reference in New Issue
Block a user