From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 045896EC40; Thu, 1 Jul 2021 18:57:13 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 045896EC40 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1625155033; bh=I+lNAqUZBHbmXTuKK0W9BJJmiIDupvnhokET/hx2f88=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=RfTEYPzFRZR6WSN07XPl7MrGUoIhYk96TWbNuZdH+GLcuQ8ot0I/dVagp6V8+1OCs j0s5rmq/zwqRhLQ1q5bgL1cH/AGZ8/5X9plneBMRMKREifXqdMNmo4e+OZwBm5LKb/ m/G/N8l5GJjlu0YF0GvP0Rxdid1kXs4su5RGJa4I= Received: from smtp31.i.mail.ru (smtp31.i.mail.ru [94.100.177.91]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id F07CF6EC40 for ; Thu, 1 Jul 2021 18:55:21 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org F07CF6EC40 Received: by smtp31.i.mail.ru with esmtpa (envelope-from ) id 1lyz28-0006YJ-T6; Thu, 01 Jul 2021 18:55:21 +0300 To: tarantool-patches@dev.tarantool.org Date: Thu, 1 Jul 2021 18:54:47 +0300 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-4EC0790: 10 X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD954DFF1DC42D673FB96E19CC2B9345E2B1F8975EC27617E56182A05F5380850402102FE202ECC81E77E05EF5B44A6C3080B1E89947F6B7D54AF6457504D2BBDDF X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7BAE5222749FC9020C2099A533E45F2D0395957E7521B51C2CFCAF695D4D8E9FCEA1F7E6F0F101C6778DA827A17800CE789DCD78EC958A690EA1F7E6F0F101C6723150C8DA25C47586E58E00D9D99D84E1BDDB23E98D2D38BD6CF32B5F8F9D40489F04AA0C6F1FC9C1535C814D6852162CC7F00164DA146DAFE8445B8C89999728AA50765F7900637F6B57BC7E64490618DEB871D839B7333395957E7521B51C2DFABB839C843B9C08941B15DA834481F8AA50765F7900637F6B57BC7E6449061A352F6E88A58FB86F5D81C698A659EA73AA81AA40904B5D9A18204E546F3947CCBF6BC0891A06A85302FCEF25BFAB3454AD6D5ED66289B52698AB9A7B718F8C46E0066C2D8992A16725E5C173C3A84C3AB4674FCF129DEEB3AA81AA40904B5D9DBF02ECDB25306B2201CA6A4E26CD07C3BBE47FD9DD3FB595F5C1EE8F4F765FC72CEEB2601E22B093A03B725D353964B0B7D0EA88DDEDAC722CA9DD8327EE493B89ED3C7A628178124B591B534DDBB47C4224003CC83647689D4C264860C145E X-B7AD71C0: AC4F5C86D027EB782CDD5689AFBDA7A24209795067102C07E8F7B195E1C97831C3A611387EFBEF39D5EE6400B98F466E X-C1DE0DAB: C20DE7B7AB408E4181F030C43753B8186998911F362727C414F749A5E30D975CA007D7800FCDDA2793523131736F99012178D6549A8E78FF9C2B6934AE262D3EE7EAB7254005DCED7532B743992DF240BDC6A1CF3F042BAD6DF99611D93F60EFCCE3E035A672CDEE699F904B3F4130E343918A1A30D5E7FCCB5012B2E24CD356 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D34F3735C80F9F4B96DB623969908CB4FD4297C6039C41918F747197A1C1BEAEF4F461A9F168CDF6C9A1D7E09C32AA3244C48876D22A0E0A38E85F82D748CD77B03CE0B41342B755BCD83B48618A63566E0 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojbL9S8ysBdXgzbH4gLt0SRnQ36v+EDJs0 X-Mailru-Sender: EFA0F3A8419EF2166B053C73E674FFD52200F07866C9740A0E1091568CBB4E23E2527C969975515C67F54F2D6EFFC80BC77752E0C033A69E17841C44D9B5D58765F2F89A5AFDB6F16C18EFA0BB12DBB0 X-Mras: Ok Subject: [Tarantool-patches] [PATCH 4/7] fiber: add PoC for Lua parent backtrace X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Egor Elchinov via Tarantool-patches Reply-To: eelchinov@tarantool.org Cc: gorcunov@tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" From: Egor Elchinov For now Lua backtrace is fully collected at fiber creation moment and stored in a dynamically allocated buffer. Needed for: #4002 --- src/lib/core/fiber.h | 7 ++ src/lua/fiber.c | 168 ++++++++++++++++++++++++++++++++++++++++--- src/lua/fiber.h | 19 +++++ 3 files changed, 185 insertions(+), 9 deletions(-) diff --git a/src/lib/core/fiber.h b/src/lib/core/fiber.h index beed58866..ce1c83d11 100644 --- a/src/lib/core/fiber.h +++ b/src/lib/core/fiber.h @@ -528,6 +528,7 @@ struct txn; struct credentials; struct lua_State; struct ipc_wait_pad; +struct parent_bt_lua; struct fiber { coro_context ctx; @@ -634,6 +635,12 @@ struct fiber { * Optional fiber.storage Lua reference. */ int ref; +#if ENABLE_BACKTRACE + /** + * Lua parent backtrace (may be NULL) + */ + struct parent_bt_lua *parent_bt; +#endif /* ENABLE_BACKTRACE */ } lua; /** * Iproto sync. diff --git a/src/lua/fiber.c b/src/lua/fiber.c index 7b21361d4..026e30bc6 100644 --- a/src/lua/fiber.c +++ b/src/lua/fiber.c @@ -193,6 +193,18 @@ struct lua_fiber_tb_ctx { int tb_frame; }; +/** + * Lua parent traceback context. + */ +struct lua_parent_tb_ctx { + /* Lua stack to push values. */ + struct lua_State *L; + /* Lua parent backtrace. */ + struct parent_bt_lua *bt; + /* Count of traced frames (both C and Lua). */ + int tb_frame; +}; + #ifdef ENABLE_BACKTRACE static void dump_lua_frame(struct lua_State *L, lua_Debug *ar, int tb_frame) @@ -209,6 +221,22 @@ dump_lua_frame(struct lua_State *L, lua_Debug *ar, int tb_frame) lua_settable(L, -3); } +static void +dump_parent_lua_frame(struct lua_State *L, const char *name, const char *src, + int currentline, int tb_frame) +{ + char buf[512]; + snprintf(buf, sizeof(buf), "%s in %s at line %i", + name != NULL ? name : "(unnamed)", + src, currentline); + lua_pushnumber(L, tb_frame); + lua_newtable(L); + lua_pushstring(L, "L"); + lua_pushstring(L, buf); + lua_settable(L, -3); + lua_settable(L, -3); +} + static int fiber_backtrace_cb(int frameno, void *frameret, const char *func, size_t offset, void *cb_ctx) { @@ -260,7 +288,115 @@ fiber_backtrace_cb(int frameno, void *frameret, const char *func, size_t offset, lua_settable(L, -3); return 0; } -#endif + +static int +fiber_parent_backtrace_cb(int frameno, void *frameret, const char *func, + size_t offset, void *cb_ctx) +{ + int lua_frame = 0; + struct lua_parent_tb_ctx *tb_ctx = (struct lua_parent_tb_ctx *)cb_ctx; + struct parent_bt_lua *bt = tb_ctx->bt; + struct lua_State *L = tb_ctx->L; + /* + * There is impossible to get func == NULL until + * https://github.com/tarantool/tarantool/issues/5326 + * will not resolved, but is possible afterwards. + */ + if (bt != NULL && func != NULL && strstr(func, "lj_BC_FUNCC") == func) { + /* We are in the LUA vm. */ + while (lua_frame < bt->cnt) { + tb_ctx->tb_frame++; + dump_parent_lua_frame(L, bt->names[lua_frame], + bt->sources[lua_frame], + bt->lines[lua_frame], + tb_ctx->tb_frame); + lua_frame++; + } + } + char buf[512]; + int l = snprintf(buf, sizeof(buf), "#%-2d %p in ", frameno, frameret); + if (func) + snprintf(buf + l, sizeof(buf) - l, "%s+%zu", func, offset); + else + snprintf(buf + l, sizeof(buf) - l, "?"); + tb_ctx->tb_frame++; + lua_pushnumber(L, tb_ctx->tb_frame); + lua_newtable(L); + lua_pushstring(L, "C"); + lua_pushstring(L, buf); + lua_settable(L, -3); + lua_settable(L, -3); + return 0; +} + +static int +fiber_parent_bt_init(struct fiber *f, struct lua_State *L) +{ + int lua_frame = 0, tb_frame = 0; + lua_Debug ar; + struct parent_bt_lua *bt = NULL; + + bt = (struct parent_bt_lua *)malloc(sizeof(*bt)); + if (bt == NULL){ + diag_set(OutOfMemory, sizeof(*bt), "malloc", "bt"); + return 1; + } + + while (tb_frame < PARENT_BT_LUA_LEN_MAX && + lua_getstack(L, lua_frame, &ar) > 0) { + /* Skip all following C-frames. */ + lua_getinfo(L, "Sln", &ar); + if (*ar.what != 'C') + break; + if (ar.name != NULL) { + /* Dump frame if it is a C built-in call. */ + bt->lines[tb_frame] = ar.currentline; + memset(bt->names[tb_frame], 0, + PARENT_BT_LUA_NAME_MAX); + strncpy(bt->names[tb_frame], ar.name, + PARENT_BT_LUA_NAME_MAX - 1); + memset(bt->sources[tb_frame], 0, + PARENT_BT_LUA_NAME_MAX); + strncpy(bt->sources[tb_frame], ar.source, + PARENT_BT_LUA_NAME_MAX - 1); + tb_frame++; + } + lua_frame++; + } + while (tb_frame < PARENT_BT_LUA_LEN_MAX && + lua_getstack(L, lua_frame, &ar) > 0) { + /* Trace Lua frame. */ + lua_getinfo(L, "Sln", &ar); + if (*ar.what == 'C') + break; + bt->lines[tb_frame] = ar.currentline; + memset(bt->names[tb_frame], 0, PARENT_BT_LUA_NAME_MAX); + if (ar.name != NULL) { + strncpy(bt->names[tb_frame], ar.name, + PARENT_BT_LUA_NAME_MAX - 1); + } else { + strncpy(bt->names[tb_frame], "(unnamed)", + PARENT_BT_LUA_NAME_MAX - 1); + } + memset(bt->sources[tb_frame], 0, PARENT_BT_LUA_NAME_MAX); + strncpy(bt->sources[tb_frame], ar.source, + PARENT_BT_LUA_NAME_MAX - 1); + tb_frame++; + lua_frame++; + } + + bt->cnt = tb_frame; + f->storage.lua.parent_bt = bt; + + return 0; +} + +static void +fiber_parent_bt_free(struct fiber *f) +{ + free(f->storage.lua.parent_bt); +} +#endif /* ENABLE_BACKTRACE */ static int lbox_fiber_statof_map(struct fiber *f, void *cb_ctx, bool backtrace) @@ -299,6 +435,7 @@ lbox_fiber_statof_map(struct fiber *f, void *cb_ctx, bool backtrace) if (backtrace) { #ifdef ENABLE_BACKTRACE struct lua_fiber_tb_ctx tb_ctx; + struct lua_parent_tb_ctx parent_tb_ctx; tb_ctx.L = L; tb_ctx.R = f->storage.lua.stack; tb_ctx.lua_frame = 0; @@ -309,14 +446,14 @@ lbox_fiber_statof_map(struct fiber *f, void *cb_ctx, bool backtrace) f != fiber() ? &f->ctx : NULL, &tb_ctx); lua_settable(L, -3); - tb_ctx.lua_frame = 0; - tb_ctx.tb_frame = 0; - tb_ctx.R = NULL; + parent_tb_ctx.L = L; + parent_tb_ctx.bt = f->storage.lua.parent_bt; + parent_tb_ctx.tb_frame = 0; lua_pushstring(L, "backtrace_parent"); lua_newtable(L); - backtrace_foreach_ip(fiber_backtrace_cb, + backtrace_foreach_ip(fiber_parent_backtrace_cb, f->parent_bt_ip_buf, - FIBER_PARENT_BT_MAX, &tb_ctx); + FIBER_PARENT_BT_MAX, &parent_tb_ctx); lua_settable(L, -3); #endif /* ENABLE_BACKTRACE */ } @@ -481,10 +618,14 @@ lua_fiber_run_f(MAYBE_UNUSED va_list ap) * We can unref child stack here, * otherwise we have to unref child stack in join */ - if (f->flags & FIBER_IS_JOINABLE) + if (f->flags & FIBER_IS_JOINABLE) { lua_pushinteger(L, coro_ref); - else + } else { +#ifdef ENABLE_BACKTRACE + fiber_parent_bt_free(f); +#endif luaL_unref(L, LUA_REGISTRYINDEX, coro_ref); + } return result; } @@ -506,6 +647,11 @@ fiber_create(struct lua_State *L) luaT_error(L); } +#ifdef ENABLE_BACKTRACE + // TODO: error handling + fiber_parent_bt_init(f, L); +#endif + /* Move the arguments to the new coro */ lua_xmove(L, child_L, lua_gettop(L)); /* XXX: 'fiber' is leaked if this throws a Lua error. */ @@ -886,8 +1032,12 @@ lbox_fiber_join(struct lua_State *L) lua_xmove(child_L, L, num_ret); } } - if (child_L != NULL) + if (child_L != NULL) { +#ifdef ENABLE_BACKTRACE + fiber_parent_bt_free(fiber); +#endif luaL_unref(L, LUA_REGISTRYINDEX, coro_ref); + } return num_ret + 1; } diff --git a/src/lua/fiber.h b/src/lua/fiber.h index e29898706..450840fb0 100644 --- a/src/lua/fiber.h +++ b/src/lua/fiber.h @@ -36,6 +36,25 @@ extern "C" { struct lua_State; +/** + * Maximal name length (including '\0') + * and backtrace length. + */ +enum { + PARENT_BT_LUA_NAME_MAX = 64, + PARENT_BT_LUA_LEN_MAX = 8 +}; + +/** + * Stores lua parent backtrace for fiber. + */ +struct parent_bt_lua { + int cnt; + char names[PARENT_BT_LUA_LEN_MAX][PARENT_BT_LUA_NAME_MAX]; + char sources[PARENT_BT_LUA_LEN_MAX][PARENT_BT_LUA_NAME_MAX]; + int lines[PARENT_BT_LUA_LEN_MAX]; +}; + /** * Initialize box.fiber system */ -- 2.31.1