Skip to content

Commit

Permalink
lua/fiber: do not raise on printing a dead fiber
Browse files Browse the repository at this point in the history
An attempt to print a dead fiber raised a fatal error, which is quite
unexpected. This patch updates __tostring metamethod of fiber_object so
that it pushes the "fiber: <fid> (dead)" string instead of the error.
The __serialize metamethod is patched similarly.

Closes tarantool#4265

NO_DOC=bugfix
  • Loading branch information
Gumix committed Sep 7, 2023
1 parent 307f3c5 commit 6a93581
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## bugfix/core

* An error is no longer raised on an attempt to print a dead fiber (gh-4265).
40 changes: 28 additions & 12 deletions src/lua/fiber.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,24 @@ lbox_pushfiber(struct lua_State *L, struct fiber *f)
lua_rawgeti(L, LUA_REGISTRYINDEX, fid_ref);
}

/**
* Returns fiber id for the fiber located at the given `index` on the Lua stack.
*/
static uint64_t
lbox_checkfiberid(struct lua_State *L, int index)
{
uint64_t *fid = luaL_checkudata(L, index, fiberlib_name);
return *fid;
}

static struct fiber *
lbox_checkfiber(struct lua_State *L, int index)
{
uint64_t fid;
if (lua_type(L, index) == LUA_TNUMBER) {
fid = luaL_touint64(L, index);
} else {
fid = *(uint64_t *)luaL_checkudata(L, index, fiberlib_name);
fid = lbox_checkfiberid(L, index);
}
struct fiber *f = fiber_find(fid);
if (f == NULL)
Expand All @@ -160,7 +170,7 @@ lbox_fiber_id(struct lua_State *L)
if (lua_gettop(L) == 0)
fid = fiber()->fid;
else
fid = *(uint64_t *)luaL_checkudata(L, 1, fiberlib_name);
fid = lbox_checkfiberid(L, 1);
luaL_pushuint64(L, fid);
return 1;
}
Expand Down Expand Up @@ -506,8 +516,8 @@ static struct fiber *
lbox_get_fiber(struct lua_State *L)
{
if (lua_gettop(L) != 0) {
uint64_t *fid = luaL_checkudata(L, 1, fiberlib_name);
return fiber_find(*fid);
uint64_t fid = lbox_checkfiberid(L, 1);
return fiber_find(fid);
} else {
return fiber();
}
Expand Down Expand Up @@ -726,12 +736,16 @@ lbox_fiber_cancel(struct lua_State *L)
static int
lbox_fiber_serialize(struct lua_State *L)
{
struct fiber *f = lbox_checkfiber(L, 1);
uint64_t fid = lbox_checkfiberid(L, 1);
struct fiber *f = fiber_find(fid);

lua_createtable(L, 0, 1);
luaL_pushuint64(L, f->fid);
luaL_pushuint64(L, fid);
lua_setfield(L, -2, "id");
lua_pushstring(L, fiber_name(f));
lua_setfield(L, -2, "name");
if (f != NULL) {
lua_pushstring(L, fiber_name(f));
lua_setfield(L, -2, "name");
}
lbox_fiber_status(L);
lua_setfield(L, -2, "status");
return 1;
Expand All @@ -740,10 +754,12 @@ lbox_fiber_serialize(struct lua_State *L)
static int
lbox_fiber_tostring(struct lua_State *L)
{
char buf[32];
struct fiber *f = lbox_checkfiber(L, 1);
snprintf(buf, sizeof(buf), "fiber: %llu",
(long long)f->fid);
char buf[35];
uint64_t fid = lbox_checkfiberid(L, 1);
bool is_dead = fiber_find(fid) == NULL;

snprintf(buf, sizeof(buf), "fiber: %llu%s", (long long)fid,
is_dead ? " (dead)" : "");
lua_pushstring(L, buf);
return 1;
}
Expand Down
36 changes: 36 additions & 0 deletions test/app-luatest/fiber_test.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
local fiber = require('fiber')
local t = require('luatest')
local g = t.group('fiber')

-- Test __serialize metamethod of the fiber.
g.test_serialize = function()
local f = fiber.new(function() end)
local fid = f:id()
f:name('test fiber')

-- Serialize a ready fiber.
t.assert_equals(f:__serialize(),
{ id = fid, name = 'test fiber', status = 'suspended' })

-- gh-4265: Serializing a finished fiber should not raise an error.
fiber.yield()
t.assert_equals(f:__serialize(), { id = fid, status = 'dead' })

-- Serialize a running fiber.
t.assert_equals(fiber.self():__serialize(),
{ id = fiber.self():id(),
name = 'luatest',
status = 'running' })
end

-- Test __tostring metamethod of the fiber.
g.test_tostring = function()
local f = fiber.new(function() end)
local fid = f:id()

t.assert_equals(tostring(f), "fiber: " .. fid)

-- gh-4265: Printing a finished fiber should not raise an error.
fiber.yield()
t.assert_equals(tostring(f), "fiber: " .. fid .. " (dead)")
end
3 changes: 1 addition & 2 deletions test/app/fiber.result
Original file line number Diff line number Diff line change
Expand Up @@ -961,9 +961,8 @@ fiber.create(function()end):name()
--
-- gh-1926
--
fiber.create(function() fiber.wakeup(fiber.self()) end)
_ = fiber.create(function() fiber.wakeup(fiber.self()) end)
---
- the fiber is dead
...
--
-- gh-2066 test for fiber wakeup
Expand Down
2 changes: 1 addition & 1 deletion test/app/fiber.test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ fiber.create(function()end):name()
--
-- gh-1926
--
fiber.create(function() fiber.wakeup(fiber.self()) end)
_ = fiber.create(function() fiber.wakeup(fiber.self()) end)

--
-- gh-2066 test for fiber wakeup
Expand Down

0 comments on commit 6a93581

Please sign in to comment.