From c3733d869d4ba5caf0e0a4cf42c860bbbd94f769 Mon Sep 17 00:00:00 2001 From: Georgy Moshkin <gmoshkin@picodata.io> Date: Mon, 9 Oct 2023 14:13:39 +0300 Subject: [PATCH] fiber: basic api exports Closes #9237 Add exports for fiber_set_name_n, fiber_name, fiber_id, fiber_csw & fiber_find. Also make fiber_set_joinable, fiber_set_ctx & fiber_get_ctx interpret NULL as the current fiber. @TarantoolBot document Title: add basic fiber api to ffi exports. 5 basic functions can now be used via ffi api, which were previously only accessible via lua api: fiber_set_name_n, fiber_name, fiber_id, fiber_csw & fiber_find. fiber_set_joinable now interprets NULL as current fiber. --- changelogs/unreleased/fiber-basic-api.md | 6 ++ extra/exports | 6 +- src/lib/core/fiber.c | 39 +++++++++++-- src/lib/core/fiber.h | 72 ++++++++++++++++-------- test/app-tap/module_api.c | 58 +++++++++++++++++++ test/app-tap/module_api.test.lua | 2 +- 6 files changed, 153 insertions(+), 30 deletions(-) create mode 100644 changelogs/unreleased/fiber-basic-api.md diff --git a/changelogs/unreleased/fiber-basic-api.md b/changelogs/unreleased/fiber-basic-api.md new file mode 100644 index 0000000000..6b7b255437 --- /dev/null +++ b/changelogs/unreleased/fiber-basic-api.md @@ -0,0 +1,6 @@ +## feature/fiber + +* Exported `fiber_set_name_n`, `fiber_name`, `fiber_id`, `fiber_csw` and + `fiber_find` into the public C API and usable via FFI as well. +* Make `fiber_set_joinable`, `fiber_set_ctx` and `fiber_get_ctx` + treat the NULL argument as the current fiber. diff --git a/extra/exports b/extra/exports index 3eaaae0ab4..1c780e1719 100644 --- a/extra/exports +++ b/extra/exports @@ -232,10 +232,14 @@ fiber_cond_new fiber_cond_signal fiber_cond_wait fiber_cond_wait_timeout +fiber_csw +fiber_find fiber_get_ctx +fiber_id fiber_is_cancelled fiber_join fiber_join_timeout +fiber_name fiber_new fiber_new_ex fiber_reschedule @@ -243,6 +247,7 @@ fiber_self fiber_set_cancellable fiber_set_ctx fiber_set_joinable +fiber_set_name_n fiber_sleep fiber_start fiber_time @@ -655,7 +660,6 @@ coio_readn_ahead coio_read_ahead_timeout coio_write_timeout -fiber_set_name_n authenticate user_auth_method_name port_c_create diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c index b3074e1b1d..6e1a8e1ee2 100644 --- a/src/lib/core/fiber.c +++ b/src/lib/core/fiber.c @@ -586,12 +586,16 @@ fiber_make_ready(struct fiber *f) void fiber_set_ctx(struct fiber *f, void *f_arg) { + if (f == NULL) + f = fiber(); f->f_arg = f_arg; } void * fiber_get_ctx(struct fiber *f) { + if (f == NULL) + f = fiber(); return f->f_arg; } @@ -649,6 +653,9 @@ fiber_is_cancelled(void) void fiber_set_joinable(struct fiber *fiber, bool yesno) { + if (fiber == NULL) + fiber = fiber(); + /* * The C fiber API does not allow to report any error to the caller. At * the same time using the function in some conditions is unsafe. So in @@ -1201,15 +1208,11 @@ fiber_loop(MAYBE_UNUSED void *data) } } -inline void -fiber_set_name(struct fiber *fiber, const char *name) -{ - fiber_set_name_n(fiber, name, strlen(name)); -} - void fiber_set_name_n(struct fiber *fiber, const char *name, uint32_t len) { + if (fiber == NULL) + fiber = fiber(); size_t size = len + 1; if (size <= FIBER_NAME_INLINE) { if (fiber->name != fiber->inline_name) { @@ -1233,6 +1236,30 @@ fiber_set_name_n(struct fiber *fiber, const char *name, uint32_t len) fiber->name[size] = 0; } +const char * +fiber_name(const struct fiber *fiber) +{ + if (fiber == NULL) + fiber = fiber(); + return fiber->name; +} + +uint64_t +fiber_id(const struct fiber *fiber) +{ + if (fiber == NULL) + fiber = fiber(); + return fiber->fid; +} + +uint64_t +fiber_csw(const struct fiber *fiber) +{ + if (fiber == NULL) + fiber = fiber(); + return fiber->csw; +} + static inline void * page_align_down(void *ptr) { diff --git a/src/lib/core/fiber.h b/src/lib/core/fiber.h index c3f80686a8..afe8c2dba8 100644 --- a/src/lib/core/fiber.h +++ b/src/lib/core/fiber.h @@ -299,6 +299,7 @@ fiber_start(struct fiber *callee, ...); * fiber_start which means no yields. * * \param f fiber to set the context for + * if NULL, the current fiber is used * \param f_arg context for the fiber function */ API_EXPORT void @@ -307,6 +308,7 @@ fiber_set_ctx(struct fiber *f, void *f_arg); /** * Get the context for the fiber which was set via the fiber_set_ctx * function. Can be used to avoid calling fiber_start which means no yields. + * If \a f is NULL, the current fiber is used. * * \retval context for the fiber function set by fiber_set_ctx function * @@ -354,6 +356,8 @@ fiber_set_cancellable(bool yesno); * @pre the fiber is not dead (panic if not). * @pre the fiber is not joined yet (panic if not). * + * \param fiber to (un)set the joinable property. + * If set to NULL, the current fiber is used. * \param yesno status to set */ API_EXPORT void @@ -443,6 +447,49 @@ fiber_clock64(void); API_EXPORT void fiber_reschedule(void); +/** + * Set fiber name. + * @param fiber Target fiber, if it's NULL the current fiber is used. + * @param name A new name of @a fiber. + * @param len Length of the string pointed to by @a name. + */ +API_EXPORT void +fiber_set_name_n(struct fiber *fiber, const char *name, uint32_t len); + +/** + * Get fiber name. + * @param fiber Target fiber, if it's NULL the current fiber is used. + * @return pointer to a nul-terminated string. + */ +API_EXPORT const char * +fiber_name(const struct fiber *fiber); + +/** + * Get fiber id. + * @param fiber Target fiber, if it's NULL the current fiber is used. + */ +API_EXPORT uint64_t +fiber_id(const struct fiber *fiber); + +/** + * Get number of context switches of the given fiber. + * @param fiber Target fiber, if it's NULL the current fiber is used. + */ +API_EXPORT uint64_t +fiber_csw(const struct fiber *fiber); + +/** + * Get a pointer to a live fiber in the current cord by the given fiber id, + * which may be used for getting other info about the fiber (name, csw, etc.). + * + * @param fid Target fiber id. + * @return fiber on success, NULL if fiber was not found. + * + * @sa fiber_name, fiber_csw, fiber_id + */ +API_EXPORT struct fiber * +fiber_find(uint64_t fid); + /** * Return slab_cache suitable to use with tarantool/small library */ @@ -967,26 +1014,10 @@ fiber_signal_reset(void); * @param fiber Fiber to set name for. * @param name A new name of @a fiber. */ -void -fiber_set_name(struct fiber *fiber, const char *name); - -/** \cond public */ - -/** - * Set fiber name providing a length for it. - * @param fiber Fiber to set name for. - * @param name A new name of @a fiber. - * @param len Length of the string pointed to by @a name. - */ -void -fiber_set_name_n(struct fiber *fiber, const char *name, uint32_t len); - -/** \endcond public */ - -static inline const char * -fiber_name(struct fiber *f) +static inline void +fiber_set_name(struct fiber *fiber, const char *name) { - return f->name; + fiber_set_name_n(fiber, name, strlen(name)); } /** Helper function to check if slice is valid. */ @@ -1125,9 +1156,6 @@ fiber_destroy_all(struct cord *cord); void fiber_call(struct fiber *callee); -struct fiber * -fiber_find(uint64_t fid); - void fiber_schedule_cb(ev_loop * /* loop */, ev_watcher *watcher, int revents); diff --git a/test/app-tap/module_api.c b/test/app-tap/module_api.c index f7443a9311..230e540e13 100644 --- a/test/app-tap/module_api.c +++ b/test/app-tap/module_api.c @@ -326,6 +326,12 @@ fiber_set_ctx_test_func(va_list va) static int test_fiber_set_ctx(lua_State *L) { + /* Set context for the current fiber. */ + fiber_set_ctx(NULL, (void *)0xCAFEBABEDEADF00D); + uint64_t ctx = (uint64_t)fiber_get_ctx(NULL); + fail_unless(ctx == 0xCAFEBABEDEADF00D); + + /* Set context for a child fiber. */ struct fiber *fiber = fiber_new("test fiber", fiber_set_ctx_test_func); fiber_set_joinable(fiber, true); char data[3] = { '?', '!', '\0' }; @@ -3328,6 +3334,57 @@ test_box_iproto_override_reset(struct lua_State *L) /* }}} Helpers for `box_iproto_override` Lua/C API test cases */ +static int +fiber_basic_api_func(va_list va) +{ + (void)va; + const char *name = "oppenheimer"; + /* fiber_set_joinable now works with NULL. (Consistency!) */ + fiber_set_joinable(NULL, true); + fiber_set_name_n(fiber_self(), name, strlen(name)); + return 0; +} + +static int +test_fiber_basic_api(lua_State *L) +{ + uint64_t self_id = fiber_id(NULL); + struct fiber *t = fiber_find(self_id); + fail_unless(fiber_self() == t); + + /* Set/get name of self works. */ + const char *name = "parent"; + fiber_set_name_n(NULL, name, strlen(name)); + string_check_equal(fiber_name(NULL), name); + + /* No such fiber. */ + t = fiber_find((uint64_t)-1); + fail_unless(t == NULL); + + /* Fiber is created and is immediately accessible via fiber_find. */ + struct fiber *fiber = fiber_new("barbie", fiber_basic_api_func); + string_check_equal(fiber_name(fiber), "barbie"); + uint64_t f_id = fiber_id(fiber); + t = fiber_find(f_id); + fail_unless(fiber == t); + + /* Check that csw is increased because fiber_start yields. */ + uint64_t csw0_parent = fiber_csw(NULL); + uint64_t csw0_child = fiber_csw(fiber); + fiber_start(fiber); + uint64_t csw1_parent = fiber_csw(NULL); + uint64_t csw1_child = fiber_csw(fiber); + fail_unless(csw1_parent == csw0_parent + 1); + fail_unless(csw1_child == csw0_child + 1); + + string_check_equal(fiber_name(fiber), "oppenheimer"); + /* At this point fiber is recycled. */ + fiber_join(fiber); + + lua_pushboolean(L, 1); + return 1; +} + static int test_box_auth_data_prepare(struct lua_State *L) { @@ -3644,6 +3701,7 @@ luaopen_module_api(lua_State *L) {"test_fiber", test_fiber }, {"test_fiber_set_ctx", test_fiber_set_ctx }, {"test_cord", test_cord }, + {"test_fiber_basic_api", test_fiber_basic_api }, {"pushcdata", test_pushcdata }, {"checkcdata", test_checkcdata }, {"test_clock", test_clock }, diff --git a/test/app-tap/module_api.test.lua b/test/app-tap/module_api.test.lua index 29e28a765c..e22a3b716b 100755 --- a/test/app-tap/module_api.test.lua +++ b/test/app-tap/module_api.test.lua @@ -746,7 +746,7 @@ local function test_box_access_check_space(test) end require('tap').test("module_api", function(test) - test:plan(57) + test:plan(58) local status, module = pcall(require, 'module_api') test:is(status, true, "module") test:ok(status, "module is loaded") -- GitLab