From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
To: Igor Munkin <imun@tarantool.org>
Cc: tarantool-patches@dev.tarantool.org
Subject: Re: [Tarantool-patches] [PATCH v2 1/3] fiber: introduce schedule_task() internal function
Date: Fri, 20 Mar 2020 01:00:34 +0100 [thread overview]
Message-ID: <9d071039-e834-10d1-62b3-a562abea6f5b@tarantool.org> (raw)
In-Reply-To: <20200319145257.GJ6392@tarantool.org>
Hi! Thanks for the review!
On 19/03/2020 15:52, Igor Munkin wrote:
> Vlad,
>
> Thanks for the patch! Please consider several minor comments I left.
>
> On 03.03.20, Vladislav Shpilevoy wrote:
>> fiber._internal.schedule_task() is an API for a singleton fiber
>> worker object. It serves for not urgent delayed execution of
>> functions. Main purpose - schedule execution of a function, which
>> is going to yield, from a context, where a yield is not allowed.
>> Such as an FFI object's GC callback.
>>
>> It will be used by SWIM and by fio, whose destruction yields, but
>> they need to use ffi.gc hook, where a yield is not allowed.
>
> Minor: AFAIR __gc metamethod[1] also obligues the one to avoid
> coroutine/fiber switch[2]. Thereby GC finalizer looks to be more
> accurate term here.
You know better. Changed 'ffi.gc hook' -> 'GC finalizer'.
>>
>> Part of #4727
>> ---
>> src/lua/fiber.c | 15 +++++++++
>> src/lua/fiber.lua | 60 ++++++++++++++++++++++++++++++++++
>> test/app/fiber.result | 72 +++++++++++++++++++++++++++++++++++++++++
>> test/app/fiber.test.lua | 41 +++++++++++++++++++++++
>> 4 files changed, 188 insertions(+)
>>
>> diff --git a/src/lua/fiber.c b/src/lua/fiber.c
>> index 575a020d0..ddf827ab6 100644
>> --- a/src/lua/fiber.c
>> +++ b/src/lua/fiber.c
>> @@ -828,6 +828,19 @@ lbox_fiber_set_joinable(struct lua_State *L)
>> return 0;
>> }
>>
>> +/**
>> + * Alternative to fiber.sleep(infinite) which does not participate
>> + * in an event loop at all until an explicit wakeup. This is less
>> + * overhead. Useful for fibers sleeping most of the time.
>> + */
>
> Minor: I guess <lbox_fiber_stall> and <fiber.stall> are good names for
> this API. Feel free to ignore.
Yeah, sounds much better.
====================
diff --git a/src/lua/fiber.c b/src/lua/fiber.c
index ddf827ab6..03b1b959c 100644
--- a/src/lua/fiber.c
+++ b/src/lua/fiber.c
@@ -834,7 +834,7 @@ lbox_fiber_set_joinable(struct lua_State *L)
* overhead. Useful for fibers sleeping most of the time.
*/
static int
-lbox_fiber_sleep_infinite(struct lua_State *L)
+lbox_fiber_stall(struct lua_State *L)
{
(void) L;
fiber_yield();
@@ -879,7 +879,7 @@ static const struct luaL_Reg fiberlib[] = {
{"status", lbox_fiber_status},
{"name", lbox_fiber_name},
/* Internal functions, to hide in fiber.lua. */
- {"sleep_infinite", lbox_fiber_sleep_infinite},
+ {"stall", lbox_fiber_stall},
{NULL, NULL}
};
diff --git a/src/lua/fiber.lua b/src/lua/fiber.lua
index d0b765b60..fa53403d0 100644
--- a/src/lua/fiber.lua
+++ b/src/lua/fiber.lua
@@ -35,8 +35,8 @@ fiber.time64 = fiber_time64
fiber.clock = fiber_clock
fiber.clock64 = fiber_clock64
-local sleep_infinite = fiber.sleep_infinite
-fiber.sleep_infinite = nil
+local stall = fiber.stall
+fiber.stall = nil
local worker_next_task = nil
local worker_last_task = nil
@@ -56,7 +56,7 @@ local function worker_f()
if task then
break
end
- sleep_infinite()
+ stall()
end
worker_next_task = task.next
task.f(task.arg)
====================
>> diff --git a/src/lua/fiber.lua b/src/lua/fiber.lua
>> index 8712ee0d6..d0b765b60 100644
>> --- a/src/lua/fiber.lua
>> +++ b/src/lua/fiber.lua
>> @@ -34,4 +34,64 @@ fiber.time = fiber_time
>> fiber.time64 = fiber_time64
>> fiber.clock = fiber_clock
>> fiber.clock64 = fiber_clock64
>> +
>> +local sleep_infinite = fiber.sleep_infinite
>> +fiber.sleep_infinite = nil
>> +
>> +local worker_next_task = nil
>> +local worker_last_task = nil
>> +local worker_fiber = nil
>> +
>> +--
>> +-- Worker is a singleton fiber for not urgent delayed execution of
>> +-- functions. Main purpose - schedule execution of a function,
>> +-- which is going to yield, from a context, where a yield is not
>> +-- allowed. Such as an FFI object's GC callback.
>> +--
>> +local function worker_f()
>> + local task
>> + while true do
>> + while true do
>> + task = worker_next_task
>> + if task then
>> + break
>> + end
>> + sleep_infinite()
>> + end
>> + worker_next_task = task.next
>> + task.f(task.arg)
>> + fiber.sleep(0)
>> + end
>> +end
>> +
>> +local function worker_safe_f()
>> + pcall(worker_f)
>> + -- This fiber is probably canceled and now is not able to
>> + -- sleep, create a new one.
>
> Minor: I guess it worth mentioning the fact that <worker_f> doesn't
> return. It would definitely make the comment clearer.
Done.
====================
diff --git a/src/lua/fiber.lua b/src/lua/fiber.lua
index fa53403d0..89c17f63d 100644
--- a/src/lua/fiber.lua
+++ b/src/lua/fiber.lua
@@ -66,8 +66,9 @@ end
local function worker_safe_f()
pcall(worker_f)
- -- This fiber is probably canceled and now is not able to
- -- sleep, create a new one.
+ -- Worker_f never returns. If the execution is here, this
+ -- fiber is probably canceled and now is not able to sleep.
+ -- Create a new one.
worker_fiber = fiber.new(worker_safe_f)
end
====================
>> + worker_fiber = fiber.new(worker_safe_f)
>> +end
>> +
>> +worker_fiber = fiber.new(worker_safe_f)
>> +
>> +local function worker_schedule_task(f, arg)
>> + local task = {f = f, arg = arg}
>> + if not worker_next_task then
>> + worker_next_task = task
>> + else
>
> Minor: It would be great to add an assert here, since nothing except the
> current implementation prevents us from indexing a nil value. Feel free
> to ignore.
The assertion will explode with the same error at an attempt
to index nil - no information will be lost, but the assert
would be executed even in Release. Lets better omit it.
>> + worker_last_task.next = task
>> + end
>> + worker_last_task = task
>> + worker_fiber:wakeup()
>> +end
>> +
>> diff --git a/test/app/fiber.test.lua b/test/app/fiber.test.lua
>> index 6df210d9c..f10782d1f 100644
>> --- a/test/app/fiber.test.lua
>> +++ b/test/app/fiber.test.lua
>> @@ -688,6 +688,47 @@ tbl.time > 0
>> fiber.top_disable()
>> fiber.top()
>>
>> +--
>> +-- fiber._internal.schedule_task() - API for internal usage for
>> +-- delayed execution of a function.
>> +--
>> +glob_arg = {}
>> +count = 0
>> +function task_f(arg) \
>> + count = count + 1 \
>> + table.insert(glob_arg, arg) \
>> + arg = arg + 1 \
>> + if arg <= 3 then \
>> + fiber._internal.schedule_task(task_f, arg) \
>> + else \
>> + fiber.self():cancel() \
>> + error('Worker is broken') \
>> + end \
>> +end
>> +for i = 1, 3 do \
>> + local csw1 = fiber.info()[fiber.id()].csw \
>> + fiber._internal.schedule_task(task_f, i) \
>> + local csw2 = fiber.info()[fiber.id()].csw \
>> + assert(csw1 == csw2 and csw1 ~= nil) \
>
> Minor: IMHO it's better to check that csw1 is a 'number'. Feel free to
> ignore.
I don't mind.
====================
diff --git a/test/app/fiber.result b/test/app/fiber.result
index bd60e1483..0e1ca815c 100644
--- a/test/app/fiber.result
+++ b/test/app/fiber.result
@@ -1588,7 +1588,7 @@ for i = 1, 3 do
local csw1 = fiber.info()[fiber.id()].csw \
fiber._internal.schedule_task(task_f, i) \
local csw2 = fiber.info()[fiber.id()].csw \
- assert(csw1 == csw2 and csw1 ~= nil) \
+ assert(csw1 == csw2 and type(csw1) == 'number') \
end
---
...
diff --git a/test/app/fiber.test.lua b/test/app/fiber.test.lua
index f10782d1f..f01144f49 100644
--- a/test/app/fiber.test.lua
+++ b/test/app/fiber.test.lua
@@ -709,7 +709,7 @@ for i = 1, 3 do
local csw1 = fiber.info()[fiber.id()].csw \
fiber._internal.schedule_task(task_f, i) \
local csw2 = fiber.info()[fiber.id()].csw \
- assert(csw1 == csw2 and csw1 ~= nil) \
+ assert(csw1 == csw2 and type(csw1) == 'number') \
end
old_count = count
test_run:wait_cond(function() \
====================
next prev parent reply other threads:[~2020-03-20 0:00 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-03-02 23:29 [Tarantool-patches] [PATCH v2 0/3] fio: close unused descriptors automatically Vladislav Shpilevoy
2020-03-02 23:29 ` [Tarantool-patches] [PATCH v2 1/3] fiber: introduce schedule_task() internal function Vladislav Shpilevoy
2020-03-19 14:52 ` Igor Munkin
2020-03-20 0:00 ` Vladislav Shpilevoy [this message]
2020-03-20 10:48 ` Igor Munkin
2020-03-02 23:29 ` [Tarantool-patches] [PATCH v2 2/3] fio: close unused descriptors automatically Vladislav Shpilevoy
2020-03-19 14:53 ` Igor Munkin
2020-03-19 22:53 ` Igor Munkin
2020-03-20 0:00 ` Vladislav Shpilevoy
2020-03-20 10:48 ` Igor Munkin
2020-03-20 21:28 ` Vladislav Shpilevoy
2020-03-20 21:28 ` Igor Munkin
2020-03-02 23:29 ` [Tarantool-patches] [PATCH v2 3/3] swim: use fiber._internal.schedule_task() for GC Vladislav Shpilevoy
2020-03-19 14:53 ` Igor Munkin
2020-03-26 1:08 ` [Tarantool-patches] [PATCH v2 0/3] fio: close unused descriptors automatically Nikita Pettik
2020-03-26 12:56 ` Kirill Yukhin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=9d071039-e834-10d1-62b3-a562abea6f5b@tarantool.org \
--to=v.shpilevoy@tarantool.org \
--cc=imun@tarantool.org \
--cc=tarantool-patches@dev.tarantool.org \
--subject='Re: [Tarantool-patches] [PATCH v2 1/3] fiber: introduce schedule_task() internal function' \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox