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 41E056EC44; Mon, 2 Nov 2026 03:01:05 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 41E056EC44 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1793577665; bh=aS7PIbr5kkccH9gv2wkjynMexN7o2dydUK/GU1JqWME=; 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=R1C9I7w7WTnQ0pOyRSOwJ/c5C6oUZFs1qyKBU7f/8KJCrhTuiqTHQf1DLatzyUK6S +vHQ09Chb2Bc9WVePyCPgTngK113GqLgoFGbC+fe/jii1yfSjVa9Bw2JOJTMhI6t4L x0AyGXLUfVC1vgJhQl8kQ4LfCa3CxUxRxBwJC9zs= Received: from send103.i.mail.ru (send103.i.mail.ru [89.221.237.198]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id DB2986EC44 for ; Mon, 2 Nov 2026 03:00:07 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org DB2986EC44 Received: by exim-smtp-675c6798c6-rgnsv with esmtpa (envelope-from ) id 1xNfT4-00000000HuQ-35iW; Mon, 02 Nov 2026 03:00:07 +0300 To: Sergey Kaplun , Sergey Bronnikov Date: Mon, 2 Nov 2026 02:59:59 +0300 Message-ID: <68d8da9f72cbf7237b0e21f9c643789d36fa82a8.1793574664.git.e.temirgaleev@tarantool.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Mailru-Src: smtp X-4EC0790: 10 X-7564579A: B8F34718100C35BD X-77F55803: 4F1203BC0FB41BD995934D660C27459BD3DB3CB4AEDE6BDC48D61C87D2BE5E8C182A05F53808504039F55BFD4502C0AD3DE06ABAFEAF67057346E3F3CB20CE3C4C29320517C55D9028006A18B89A7669 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7B9D6DADD6B53929DEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637AC83A81C8FD4AD23D82A6BABE6F325AC2E85FA5F3EDFCBAA7353EFBB553375667B1596EEF16A891D83FE3E4BFC4AF6BE2C765D022272A437F8C00A644A25E964389733CBF5DBD5E9D5E8D9A59859A8B6E5E764EB5D94DBD4CC7F00164DA146DA6F5DAA56C3B73B237318B6A418E8EAB8090A508E0FED6299176DF2183F8FC7C0D62E3522C432C21CCD04E86FAF290E2DB606B96278B59C421DD303D21008E29813377AFFFEAFD269A417C69337E82CC2E827F84554CEF50127C277FBC8AE2E8BA83251EDC214901ED5E8D9A59859A8B628CE318A6C97A486089D37D7C0E48F6C5571747095F342E88FB05168BE4CE3AF X-C1DE0DAB: 0D63561A33F958A5CF72CD2B74F99D9D5002B1117B3ED696B170A98F0E9602961A1B8FE1FED62FE8823CB91A9FED034534781492E4B8EEAD42E5C09891E4E6C3F36E2E0160E5C55395B8A2A0B6518DF68C46860778A80D54AF47762AB4810619 X-C8649E89: 1C3962B70DF3F0AD73CAD6646DEDE191716CD42B3DD1D34CAB70F9BE574AE9C625B6776AC983F447FC0B9F89525902EE6F57B2FD27647F25E66C117BDB76D659136714615C55314DB5858DF08E384293E1AD40302EFA28811AC4C82D1974988BA7F682DA9E98879FB8341EE9D5BE9A0A37CB301F06E6248FB9E1BF928990B3572E1A353EC59BF1A6C7CEAA0681F5848F4C41F94D744909CEEF9E35A692215F79327F81E6EEE0AEB67A0F9F91F029B6AF33F2C28C22F508233FCF178C6DD14203 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu53w8ahmwBjZKM/YPHZyZHvz5uv+WouB9+ObcCpyrx6l7KImUglyhkEat/+ysWwi0gdhEs0JGjl6ggRWTy1haxBpVdbIX1nthFXOcIETfglQORZ0zpDET4Zrk3igikrdHlWCxBJZBkFf8inNR0l9D9uPM= X-Mailru-Sender: 015BA6FC0EFA223A63A6570A1A03128574DD9A4EF7A1A6DCB951B70A5BD4BD8E1981DF50C982989E83DC3CA5BA6FF409E62B12C1FE0372A178274A4A9E9E44FD2A114EDA040D8818F01FF9DF31C397A372D6B4FCE48DF648AE208404248635DF X-Mras: Ok Subject: [Tarantool-patches] [PATCH luajit v3 2/2] Improve CLI signal handling on POSIX. 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: Evgeniy Temirgaleev via Tarantool-patches Reply-To: Evgeniy Temirgaleev Cc: tarantool-patches@dev.tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" From: Mike Pall (cherry picked from commit 423ac2144b0447c925596f4d93e073ce501ed4e1) An obsolete signal() function in glibc is implemented as a wrapper for POSIX sigaction() call with BSD semantic. In particular, it provides an SA_RESTART flag for SIGINT handler [1-2]. The latter makes certain system calls, e.g. read() or wait(), restartable across signals [3]. The patch switches from signal() to sigaction() for POSIX systems to obtain an explicit control of the signal flag set, which must not contain SA_RESTART flag. (Actually, the empty flag set is used.) 1. https://man7.org/linux/man-pages/man2/signal.2.html 2. https://ftp.gnu.org/gnu/glibc/glibc-2.44.tar.xz (sysdeps/posix/signal.c, line 44) 3. https://man7.org/linux/man-pages/man2/sigaction.2.html Temir Galeev: * added the description and the test for the problem Part of tarantool/tarantool#13442 --- src/luajit.c | 23 +++++-- ...ket-fix-cli-posix-sigint-handling.test.lua | 64 +++++++++++++++++++ .../script.lua | 26 ++++++++ 3 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 test/tarantool-tests/lj-noticket-fix-cli-posix-sigint-handling.test.lua create mode 100644 test/tarantool-tests/lj-noticket-fix-cli-posix-sigint-handling/script.lua diff --git a/src/luajit.c b/src/luajit.c index d9d85361..d35bea54 100644 --- a/src/luajit.c +++ b/src/luajit.c @@ -35,6 +35,21 @@ #if !LJ_TARGET_CONSOLE #include + +#if LJ_TARGET_POSIX +/* Improve signal handling on POSIX. Try CTRL-C on: luajit -e 'io.read()' */ +static void signal_set(int sig, void (*h)(int)) +{ + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = h; + sigemptyset(&sa.sa_mask); + sigaction(sig, &sa, NULL); +} +#else +#define signal_set signal +#endif + #endif static lua_State *globalL = NULL; @@ -54,8 +69,8 @@ static void lstop(lua_State *L, lua_Debug *ar) static void laction(int i) { - signal(i, SIG_DFL); /* if another SIGINT happens before lstop, - terminate process (default action) */ + /* Terminate process if another SIGINT happens (double CTRL-C). */ + signal_set(i, SIG_DFL); lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); } #endif @@ -129,11 +144,11 @@ static int docall(lua_State *L, int narg, int clear) lua_pushcfunction(L, traceback); /* push traceback function */ lua_insert(L, base); /* put it under chunk and args */ #if !LJ_TARGET_CONSOLE - signal(SIGINT, laction); + signal_set(SIGINT, laction); #endif status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); #if !LJ_TARGET_CONSOLE - signal(SIGINT, SIG_DFL); + signal_set(SIGINT, SIG_DFL); #endif lua_remove(L, base); /* remove traceback function */ /* force a complete garbage collection in case of errors */ diff --git a/test/tarantool-tests/lj-noticket-fix-cli-posix-sigint-handling.test.lua b/test/tarantool-tests/lj-noticket-fix-cli-posix-sigint-handling.test.lua new file mode 100644 index 00000000..5b235660 --- /dev/null +++ b/test/tarantool-tests/lj-noticket-fix-cli-posix-sigint-handling.test.lua @@ -0,0 +1,64 @@ +local tap = require('tap') + +-- The test checks that luajit CLI stop hook is executed on +-- SIGINT on a blocking system call (read(), waitpid(), etc.). +-- +-- The test runs luajit CLI with a script, which prints it's PID +-- as a ready marker and blocks on a read() call. After the +-- child's PID number is read from child's pipe, the test send +-- SIGINT to the child. +-- With a patch applied (no SA_RESTART flag for SIGINT handler) +-- read() call is interrupted and the CLI's Lua stop hook +-- executed. +-- Without a patch (SA_RESTART flag is present for SIGINT +-- handler) read() call is restarted, the test and the child is +-- blocked on a pipe read until the child is terminated by +-- SIGALRM. The test reads nothing from the child and fails. + +local test = tap.test('lj-noticket-fix-cli-posix-sigint-handling'):skipcond({ + -- The patched code is not present in Tarantool binary: + ["Disabled due to Tarantool uses it's own signal handling"] = _TARANTOOL, + ['Disabled on POSIX nonconformant OS'] = jit.os ~= 'BSD' and + jit.os ~= 'Linux' and + jit.os ~= 'OSX' and + jit.os ~= 'POSIX', +}) + +local ffi = require('ffi') +ffi.cdef[[ + int kill(int pid, int sig); +]] +local SIGINT = 2 + +test:plan(1) +local utils = require('utils') +local script = utils.exec.test_data(arg, 'script.lua') +local cmd = ('exec %s %s 2>&1'):format(utils.exec.luacmd(arg), script) +local proc = io.popen(cmd) + +local MARKER = 'CHILD_PID:' +local RMARKER = '^'..MARKER..'(%d+)$' +-- The child prints its PID after the CLI has installed the SIGINT +-- handler, so it is a readiness marker. Skip possible noise +-- lines, collect pre-marker output for error reporting. +local lines_for_diag = {'child output:'} +local pid, line +repeat + line = proc:read('*l') + if line ~= nil then + table.insert(lines_for_diag, line) + local match = line:match(RMARKER) + if match ~= nil then pid = tonumber(match) end + end +until line == nil or pid ~= nil +if pid == nil then + test:diag(table.concat(lines_for_diag, '\n')) +end +assert(pid ~= nil, 'the child process must report its PID') + +local res = ffi.C.kill(pid, SIGINT) +assert(res == 0, 'SIGINT delivery failed') +local output = proc:read('*a') +proc:close() +test:like(output, 'interrupted!', 'SIGINT interrupts the blocking call') +test:done(true) diff --git a/test/tarantool-tests/lj-noticket-fix-cli-posix-sigint-handling/script.lua b/test/tarantool-tests/lj-noticket-fix-cli-posix-sigint-handling/script.lua new file mode 100644 index 00000000..d2430a52 --- /dev/null +++ b/test/tarantool-tests/lj-noticket-fix-cli-posix-sigint-handling/script.lua @@ -0,0 +1,26 @@ +local ffi = require('ffi') + +ffi.cdef[[ + int pipe(int *fds); + int getpid(void); + long read(int fd, void *buf, size_t count); + unsigned int alarm(unsigned int seconds); +]] + +local fds = ffi.new('int[2]') +assert(ffi.C.pipe(fds) == 0) + +-- Fail instead of hanging forever if SIGINT does not break +-- the call. (SIGALRM isn't handled by CLI.) +ffi.C.alarm(10) + +-- The CLI installs the SIGINT handler before the script +-- starts, so this line is the readiness marker for the test. +local MARKER = 'CHILD_PID:' +io.write(MARKER, ffi.C.getpid(), '\n') +io.flush() + +-- Block in read(2) until SIGINT. Without SA_RESTART it returns +-- EINTR and the CLI runs the Lua hook, which raises +-- "interrupted!". +ffi.C.read(fds[0], ffi.new('char[1]'), 1) -- 2.49.0