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 89AA96EC44; Thu, 12 Nov 2026 12:31:22 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 89AA96EC44 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1794475882; bh=hryWOxGQe7QpdwoA4cY5Ri1W82rqT4/PkMn+o+z4zUw=; h=Date:To:Cc:References:In-Reply-To:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=lodopAF4OPeybxEIl6AeHX9f1V/iPNAOB8nJraQ9seemQQ4pbEAkiH7Y5CHfoOQ6/ xYRiPJi9Q4WfRKDjAZZlhQ6rBorFAStvrEe7QhdNV8H+iOpUDiGMHBcSviYShBDNZS B+UAU1y/WqY3jb8B0LFLylNPi1EKpPaqu+37AAnE= Received: from send240.i.mail.ru (send240.i.mail.ru [95.163.59.79]) (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 BB4196EC44 for ; Thu, 12 Nov 2026 12:31:20 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org BB4196EC44 Received: by exim-smtp-bccb94844-drcvq with esmtpa (envelope-from ) id 1xRR9L-00000000Gfq-2WNE; Thu, 12 Nov 2026 12:31:20 +0300 Message-ID: Date: Thu, 12 Nov 2026 12:31:19 +0300 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird To: Evgeniy Temirgaleev , Sergey Kaplun Cc: tarantool-patches@dev.tarantool.org References: <68d8da9f72cbf7237b0e21f9c643789d36fa82a8.1793574664.git.e.temirgaleev@tarantool.org> Content-Language: en-US In-Reply-To: <68d8da9f72cbf7237b0e21f9c643789d36fa82a8.1793574664.git.e.temirgaleev@tarantool.org> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Mailru-Src: smtp X-4EC0790: 10 X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD9CC39C64ECE24C2D7E46AFCFF31E72140D7017F1BC49F495F182A05F538085040D8F44F8FE6EC61063DE06ABAFEAF6705E10B12FE8E0726FFD321476F809595F492B1A6A82314B74A X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7548C33FFD72831AFEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637AC83A81C8FD4AD23D82A6BABE6F325AC2E85FA5F3EDFCBAA7353EFBB553375661F398E59D6539FAAEAB0CDFCD74922EB411A80A0661A3BA326B1FCC7A1F40419389733CBF5DBD5E9D5E8D9A59859A8B636DA1BED736F9328CC7F00164DA146DA6F5DAA56C3B73B237318B6A418E8EAB8090A508E0FED6299176DF2183F8FC7C02A79E8FE808DD2C2CD04E86FAF290E2DB606B96278B59C421DD303D21008E29813377AFFFEAFD269A417C69337E82CC2E827F84554CEF50127C277FBC8AE2E8BA83251EDC214901ED5E8D9A59859A8B61F2C8E835678F328089D37D7C0E48F6C5571747095F342E88FB05168BE4CE3AF X-C1DE0DAB: 0D63561A33F958A593E0A2FB6B78D56A5002B1117B3ED696CA864A5C79F79CE3E772F934B9BCD185823CB91A9FED034534781492E4B8EEADCF86CE9B81855096 X-C8649E89: 1C3962B70DF3F0AD73CAD6646DEDE191716CD42B3DD1D34CAB70F9BE574AE9C625B6776AC983F447FC0B9F89525902EE6F57B2FD27647F25E66C117BDB76D65985B236A3AD9ED33B59B6B77EEF49A16FFC975F90D9E247955ADCBA1E567D7F483E7F98B80BCE1AACB8341EE9D5BE9A0A4E9B1F8900C0CFF76877C9C183AFC5334B350AA3BFAFC71E6536EB022892E5344C41F94D744909CE2512F26BEC029E55448553D2254B8D95CD72808BE417F3B9E0E7457915DAA85F X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu53w8ahmwBjZKM/YPHZyZHvz5uv+WouB9+ObcCpyrx6l7KImUglyhkEat/+ysWwi0gdhEs0JGjl6ggRWTy1haxBpVdbIX1nthFXOcIETfglQORZ0zpDET4Zrk3igikrdHlWF3H8WlxFMKhsl0Q2O/NArY= X-Mailru-Sender: C4F68CFF4024C8867DFDF7C7F2588458CC0AE41635472216582B80AE0CC32409D6DCADBF6BB649423B0BF030481DD0BC645D15D82EE4B272BD6E4642A116CA93524AA66B5ACBE6721EF430B9A63E2A504198E0F3ECE9B5443453F38A29522196 X-Mras: Ok Subject: Re: [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: Sergey Bronnikov via Tarantool-patches Reply-To: Sergey Bronnikov Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" Hi, Evgeniy, thanks for the fixes! See my comments below. Sergey On 11/2/26 02:59, Evgeniy Temirgaleev wrote: > 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 s/the the/the/ (typo in the patch on the branch) > +-- 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, The skip reason "Disabled due to Tarantool uses it's own signal handling" -> "Disabled because Tarantool uses its own signal handling". > + ['Disabled on POSIX nonconformant OS'] = jit.os ~= 'BSD' and The "Disabled on POSIX nonconformant OS" reads as if a POSIX system did not conform, while the check is a whitelist of supported `jit.os` values; maybe "Disabled on non-POSIX systems"? > + 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) The suite skips signal/timing-sensitive tests under Valgrind via `os.getenv('LUAJIT_TEST_USE_VALGRIND')`, while this one still does not. The Valgrind CI job runs the whole `tarantool-tests` suite, and here the child is spawned through `luacmd()`, so it is wrapped in Valgrind as well, which makes startup and signal delivery slower. I could not check this locally (no Valgrind in this environment). Is running this test under Valgrind intentional, or would the usual skip condition be safer? > +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') > + the version at the branch contains a comment missed here: > +-- The script runs via 'popen()' with closed pipe read-end, > +-- and the stdin is not guaranteed to be connected somewhere. > +-- Reading from it may result in EOF. Maybe: "The child's stdin is inherited from the test process and may be `/dev/null` or closed, so a read from it can return EOF immediately. Hence a new pipe is created and its read end will block."? Also `read-end` -> `read end`. > +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)