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 29E156ECCC; Wed, 21 Oct 2026 20:42:40 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 29E156ECCC DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1792604560; bh=bTOtG6/A10JBCzp1JKp38j0Ps64QOgxrdvSyl9N/fIY=; h=To:Date:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=UiHHKsY1Ji65O08IzyAkwoks8Sl6QiC6ll+PQd8dhgCGRHAr28UzfoOzvNShc6RdN 5UB748yhl9z2TT1N2iFzvtoteMnE7oUlhM6FXaKwjofCezJOtiuHebA+bbOYzUlRqg 87Wre7u5KagEuJi7jByrITYGXcXmHmlbaoKY/19A= Received: from send127.i.mail.ru (send127.i.mail.ru [89.221.237.222]) (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 0E58D6ECCC for ; Wed, 21 Oct 2026 20:42:38 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 0E58D6ECCC Received: by exim-smtp-558c7cf579-wc5xf with esmtpa (envelope-from ) id 1xJaKi-00000000Rjw-3xJW; Wed, 21 Oct 2026 20:42:37 +0300 To: Sergey Kaplun , Sergey Bronnikov Date: Wed, 21 Oct 2026 20:42:33 +0300 Message-ID: <20261021174233.78149-1-e.temirgaleev@tarantool.org> X-Mailer: git-send-email 2.49.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Mailru-Src: smtp X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD989BA3B7790299D92CC5082B82906B6EF11B3E6117D502219182A05F53808504025FCBAEE100710253DE06ABAFEAF67051851A22C12D13258B6E5691EBA4FA414DAE10F9F46536182 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7BC08626EA5717D14EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637AC83A81C8FD4AD23D82A6BABE6F325AC2E85FA5F3EDFCBAA7353EFBB553375661E149F3A5221DB894946754A49F9D0316E603DF3977E3FE7D51BBC8947F74EC1389733CBF5DBD5E9D5E8D9A59859A8B636DA1BED736F9328CC7F00164DA146DA6F5DAA56C3B73B237318B6A418E8EAB8090A508E0FED6299176DF2183F8FC7C098EC00D919C1E4B6CD04E86FAF290E2DB606B96278B59C421DD303D21008E29813377AFFFEAFD269A417C69337E82CC2E827F84554CEF50127C277FBC8AE2E8BA83251EDC214901ED5E8D9A59859A8B66AF5326558468CE3089D37D7C0E48F6C5571747095F342E88FB05168BE4CE3AF X-C1DE0DAB: 0D63561A33F958A504ABE64C64DEA5C75002B1117B3ED696CE1A203AEACE81751A1B8FE1FED62FE8823CB91A9FED034534781492E4B8EEADCC19BF12C8264DFDC79554A2A72441328621D336A7BC284946AD531847A6065A535571D14F44ED41 X-C8649E89: 1C3962B70DF3F0AD73CAD6646DEDE191716CD42B3DD1D34C77DD89D51EBB774225B6776AC983F447FC0B9F89525902EE6F57B2FD27647F25E66C117BDB76D659CAAA3F6B65E700D72DCDB95E71DC740B8A271EB6146291AACDEE63BAC7C5065CBB5BE24186502E33B8341EE9D5BE9A0AEB581CA82A133D8F99860D27E05C4970BA5721BE2E656B26C7CEAA0681F5848F4C41F94D744909CEEF9E35A692215F79327F81E6EEE0AEB67A0F9F91F029B6AF33F2C28C22F508233FCF178C6DD14203 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu53w8ahmwBjZKM/YPHZyZHvz5uv+WouB9+ObcCpyrx6l7KImUglyhkEat/+ysWwi0gdhEs0JGjl6ggRWTy1haxBpVdbIX1nthFXOcIETfglQORZ0zpDET4Zrk3igikrdHlWPwxdzPKZVhNnNR0l9D9uPM= X-Mailru-Sender: 015BA6FC0EFA223A63A6570A1A0312859A30143D4980D93FB951B70A5BD4BD8EBA742331492EC14C83DC3CA5BA6FF409E62B12C1FE0372A178274A4A9E9E44FD2A114EDA040D8818F01FF9DF31C397A372D6B4FCE48DF648AE208404248635DF X-Mras: Ok Subject: [Tarantool-patches] [PATCH luajit] 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 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 last makes certain system calls, e.g. read() or wait(), restartable across signals [3]. The patch switches from signal() to sigaction() for POSIX systems. 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 --- Branch: https://github.com/tarantool/luajit/tree/tmr_g/lj-noticket-improve-cli-sig-handling-2 src/luajit.c | 23 +++++-- ...ket-fix-cli-posix-sigint-handling.test.lua | 17 +++++ .../script.lua | 25 ++++++++ .../script.sh | 28 +++++++++ test/tarantool-tests/utils/exec.lua | 63 +++++++++++++++---- 5 files changed, 141 insertions(+), 15 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 create mode 100644 test/tarantool-tests/lj-noticket-fix-cli-posix-sigint-handling/script.sh 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..4ea316d8 --- /dev/null +++ b/test/tarantool-tests/lj-noticket-fix-cli-posix-sigint-handling.test.lua @@ -0,0 +1,17 @@ +local tap = require('tap') +local test = tap.test('lj-noticket-fix-cli-posix-sigint-handling'):skipcond({ + ['Check LuaJIT CLI signal handling'] = _TARANTOOL, + ['Disabled on POSIX nonconformant OS'] = jit.os ~= 'BSD' and + jit.os ~= 'Linux' and + jit.os ~= 'OSX' and + jit.os ~= 'POSIX', +}) + +test:plan(1) +local utils = require('utils') +local script = utils.exec.makecmd_bash(arg, {t = test}) +local output = script( + utils.exec.luabin(arg), + utils.exec.test_data(arg, 'script.lua')) +test:is(output, 'OK') +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..0e6f4078 --- /dev/null +++ b/test/tarantool-tests/lj-noticket-fix-cli-posix-sigint-handling/script.lua @@ -0,0 +1,25 @@ +local ffi = require("ffi") + +ffi.cdef[[ + int fork(void); + unsigned int sleep(unsigned int seconds); + int waitpid(int pid, int *status, int options); +]] + +local pid = ffi.C.fork() + +if pid == 0 then + -- child. + ffi.C.sleep(10) +elseif pid > 0 then + -- parent. + local status = ffi.new("int[1]") + -- wait() system call: it restarts after signal is handled + -- if SA_RESTART flag is set for the handler in sigaction() + -- or if old signal() is used and it's OS specific implementation + -- is BSD-aware. + ffi.C.waitpid(pid, status, 0) +else + -- fork() failed. + os.exit(1) +end diff --git a/test/tarantool-tests/lj-noticket-fix-cli-posix-sigint-handling/script.sh b/test/tarantool-tests/lj-noticket-fix-cli-posix-sigint-handling/script.sh new file mode 100644 index 00000000..7fa3c019 --- /dev/null +++ b/test/tarantool-tests/lj-noticket-fix-cli-posix-sigint-handling/script.sh @@ -0,0 +1,28 @@ +LUA_BIN=$1 +SCRIPT_TO_RUN=$2 +$LUA_BIN $SCRIPT_TO_RUN 2>/dev/null & +pid=$! + +# Wait for proccess is started and running. +sleep 1.5 +if ! kill -0 "$pid" 2>/dev/null; then + echo 'ERR' + exit 1 +fi + +# Send SIGINT and wait for termination. +kill -INT "$pid" 2>/dev/null +sleep 1.5 + +# Terminated? OK, signal handled -- 'sigaction() behavior'. +if ! kill -0 "$pid" 2>/dev/null; then + wait "$pid" 2>/dev/null + echo 'OK' + exit 0 +fi + +# Not terminated -- 'signal() BSD-behavior'. +kill -KILL "$pid" 2>/dev/null +wait "$pid" 2>/dev/null +echo 'FAIL' +exit 0 diff --git a/test/tarantool-tests/utils/exec.lua b/test/tarantool-tests/utils/exec.lua index 49f8ef06..f19405a2 100644 --- a/test/tarantool-tests/utils/exec.lua +++ b/test/tarantool-tests/utils/exec.lua @@ -43,33 +43,74 @@ local function makeenv(tabenv) return table.concat(flatenv, ' ') end --- creates a command that runs %testname%/script.lua by --- with the given environment, launch options --- and CLI arguments. The function yields an object (i.e. table) --- with the aforementioned parameters. To launch the command just --- call the object. -function M.makecmd(arg, opts) +-- creates a command that runs given binary with the +-- given environment, launch options and zero or more permanent +-- arguments. +-- The function yields an object (i.e. table) with the aforementioned +-- parameters. To launch the command just call the object. Additional +-- arguments which may vary from call to call are the `__call` args. +-- Pass tap.test() object as opt.t for diagnostic. +function M.makecmd_exec(bin, opts) + assert(type(bin) == 'string') + assert(opts == nil or type(opts) == 'table') + local perm_args = opts and opts.args or {} + assert(type(perm_args) == 'table') return setmetatable({ - LUABIN = M.luacmd(arg), - SCRIPT = opts and opts.script or arg[0]:gsub('%.test%.lua$', '/script.lua'), + BIN = bin, ENV = opts and makeenv(opts.env) or '', REDIRECT = opts and opts.redirect or '', + PERMARGS = (' %s'):rep(#perm_args):format(unpack(perm_args)), + t = opts and opts.t, }, { __call = function(self, ...) -- This line just makes the command for by the -- following steps: -- 1. Replace the placeholders with the corresponding values - -- given to the command constructor (e.g. script, env). + -- given to the command constructor (e.g. bin, env). -- 2. Join all CLI arguments given to the __call metamethod. -- 3. Concatenate the results of step 1 and step 2 to obtain -- the resulting command. - local cmd = ('