fix(dirmonitor): deadlock if error handler jumps somewhere else (#1647)
* fix: deadlock if error handler jumps somewhere else * docs(dirmonitor): fix wrong data type in error callback * docs(dirmonitor): clarify coroutines and deadlocks * docs(dirmonitor): wording Co-authored-by: Guldoman <giulio.lettieri@gmail.com> --------- Co-authored-by: Guldoman <giulio.lettieri@gmail.com>
This commit is contained in:
parent
05e7fc4e43
commit
6370968494
|
@ -91,6 +91,7 @@ end
|
||||||
-- designed to be run inside a coroutine.
|
-- designed to be run inside a coroutine.
|
||||||
function dirwatch:check(change_callback, scan_time, wait_time)
|
function dirwatch:check(change_callback, scan_time, wait_time)
|
||||||
local had_change = false
|
local had_change = false
|
||||||
|
local last_error
|
||||||
self.monitor:check(function(id)
|
self.monitor:check(function(id)
|
||||||
had_change = true
|
had_change = true
|
||||||
if self.monitor:mode() == "single" then
|
if self.monitor:mode() == "single" then
|
||||||
|
@ -102,7 +103,10 @@ function dirwatch:check(change_callback, scan_time, wait_time)
|
||||||
elseif self.reverse_watched[id] then
|
elseif self.reverse_watched[id] then
|
||||||
change_callback(self.reverse_watched[id])
|
change_callback(self.reverse_watched[id])
|
||||||
end
|
end
|
||||||
|
end, function(err)
|
||||||
|
last_error = err
|
||||||
end)
|
end)
|
||||||
|
if last_error ~= nil then error(last_error) end
|
||||||
local start_time = system.get_time()
|
local start_time = system.get_time()
|
||||||
for directory, old_modified in pairs(self.scanned) do
|
for directory, old_modified in pairs(self.scanned) do
|
||||||
if old_modified then
|
if old_modified then
|
||||||
|
|
|
@ -45,10 +45,14 @@ function dirmonitor:unwatch(fd_or_path) end
|
||||||
---edited, removed or added. A file descriptor will be passed to the
|
---edited, removed or added. A file descriptor will be passed to the
|
||||||
---callback in "multiple" mode or a path in "single" mode.
|
---callback in "multiple" mode or a path in "single" mode.
|
||||||
---
|
---
|
||||||
|
---If an error occurred during the callback execution, the error callback will be called with the error object.
|
||||||
|
---This callback should not manipulate coroutines to avoid deadlocks.
|
||||||
|
---
|
||||||
---@param callback dirmonitor.callback
|
---@param callback dirmonitor.callback
|
||||||
|
---@param error_callback fun(error: any): nil
|
||||||
---
|
---
|
||||||
---@return boolean? changes True when changes were detected.
|
---@return boolean? changes True when changes were detected.
|
||||||
function dirmonitor:check(callback) end
|
function dirmonitor:check(callback, error_callback) end
|
||||||
|
|
||||||
---
|
---
|
||||||
---Get the working mode for the current file system monitoring backend.
|
---Get the working mode for the current file system monitoring backend.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "api.h"
|
#include "api.h"
|
||||||
|
#include "lua.h"
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -25,13 +26,16 @@ int get_mode_dirmonitor();
|
||||||
|
|
||||||
|
|
||||||
static int f_check_dir_callback(int watch_id, const char* path, void* L) {
|
static int f_check_dir_callback(int watch_id, const char* path, void* L) {
|
||||||
lua_pushvalue(L, -1);
|
// using absolute indices from f_dirmonitor_check (2: callback, 3: error_callback)
|
||||||
|
lua_pushvalue(L, 2);
|
||||||
if (path)
|
if (path)
|
||||||
lua_pushlstring(L, path, watch_id);
|
lua_pushlstring(L, path, watch_id);
|
||||||
else
|
else
|
||||||
lua_pushnumber(L, watch_id);
|
lua_pushnumber(L, watch_id);
|
||||||
lua_call(L, 1, 1);
|
|
||||||
int result = lua_toboolean(L, -1);
|
int result = 0;
|
||||||
|
if (lua_pcall(L, 1, 1, 3) == LUA_OK)
|
||||||
|
result = lua_toboolean(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
return !result;
|
return !result;
|
||||||
}
|
}
|
||||||
|
@ -95,8 +99,20 @@ static int f_dirmonitor_unwatch(lua_State *L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int f_noop(lua_State *L) { return 0; }
|
||||||
|
|
||||||
|
|
||||||
static int f_dirmonitor_check(lua_State* L) {
|
static int f_dirmonitor_check(lua_State* L) {
|
||||||
struct dirmonitor* monitor = luaL_checkudata(L, 1, API_TYPE_DIRMONITOR);
|
struct dirmonitor* monitor = luaL_checkudata(L, 1, API_TYPE_DIRMONITOR);
|
||||||
|
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||||
|
if (!lua_isnoneornil(L, 3)) {
|
||||||
|
luaL_checktype(L, 3, LUA_TFUNCTION);
|
||||||
|
} else {
|
||||||
|
lua_settop(L, 2);
|
||||||
|
lua_pushcfunction(L, f_noop);
|
||||||
|
}
|
||||||
|
lua_settop(L, 3);
|
||||||
|
|
||||||
SDL_LockMutex(monitor->mutex);
|
SDL_LockMutex(monitor->mutex);
|
||||||
if (monitor->length < 0)
|
if (monitor->length < 0)
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
|
|
Loading…
Reference in New Issue