Tarantool development patches archive
 help / color / mirror / Atom feed
* [Tarantool-patches] [PATCH luajit v3 0/2] Improve CLI signal handling on POSIX.
@ 2026-11-01 23:59 Evgeniy Temirgaleev via Tarantool-patches
  2026-11-01 23:59 ` [Tarantool-patches] [PATCH luajit v3 1/2] test: refactored utils.exec.makecmd Evgeniy Temirgaleev via Tarantool-patches
  2026-11-01 23:59 ` [Tarantool-patches] [PATCH luajit v3 2/2] Improve CLI signal handling on POSIX Evgeniy Temirgaleev via Tarantool-patches
  0 siblings, 2 replies; 3+ messages in thread
From: Evgeniy Temirgaleev via Tarantool-patches @ 2026-11-01 23:59 UTC (permalink / raw)
  To: Sergey Kaplun, Sergey Bronnikov; +Cc: tarantool-patches

The changes from v2:
* the patch was splitted into two patches;
* other fixes and suggestions from Sergey Bronnikov's letter at 10/26/26 3:59 PM (https://lists.tarantool.org/pipermail/tarantool-patches/2026-October/030876.html) was applied.

The first patch contains test utils refactoring for the tests in the second patch. The second patch is the target 'Improve CLI signal handling on POSIX.' patch.

Mike Pall (1):
  Improve CLI signal handling on POSIX.

Temir Galeev (1):
  test: refactored utils.exec.makecmd

---

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 | 64 +++++++++++++++++++
 .../script.lua                                | 26 ++++++++
 test/tarantool-tests/utils/exec.lua           | 56 ++++++++++++----
 4 files changed, 154 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

-- 
2.49.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [Tarantool-patches] [PATCH luajit v3 1/2] test: refactored utils.exec.makecmd
  2026-11-01 23:59 [Tarantool-patches] [PATCH luajit v3 0/2] Improve CLI signal handling on POSIX Evgeniy Temirgaleev via Tarantool-patches
@ 2026-11-01 23:59 ` Evgeniy Temirgaleev via Tarantool-patches
  2026-11-01 23:59 ` [Tarantool-patches] [PATCH luajit v3 2/2] Improve CLI signal handling on POSIX Evgeniy Temirgaleev via Tarantool-patches
  1 sibling, 0 replies; 3+ messages in thread
From: Evgeniy Temirgaleev via Tarantool-patches @ 2026-11-01 23:59 UTC (permalink / raw)
  To: Sergey Kaplun, Sergey Bronnikov; +Cc: tarantool-patches

From: Temir Galeev <temir.galeev@bk.ru>

The 'utils.exec.makecmd()' was refactored to allow executing of the
arbitrary commands. Also, the diagnostic messages may be enabled
if the test object is supplied. See the example below.

Initially this patch was prepared for tests in the follows up
'Improve CLI signal handling on POSIX' patch. After the test
simplification the shell script helper was wiped out, but the
refactoring was already done.

How to use new 'utils.exec.makecmd_exec()' to run arbitrary
shell script:

```
local tap = require('tap')
local test = tap.test('example')
local utils = require('utils')
local script = utils.exec.makecmd_exec('/bin/sh', {
  args = {'-c'},
  redirect = '2>&1',
  t = test, -- shows cmd and it's output for diagnostic
})

test:plan(2)
local output
output = script("'echo 1'")
test:is(output, '1')
output = script("'echo 2'")
test:is(output, '23') -- see the on-failure output
test:done(true)
```
---
 test/tarantool-tests/utils/exec.lua | 56 +++++++++++++++++++++++------
 1 file changed, 45 insertions(+), 11 deletions(-)

diff --git a/test/tarantool-tests/utils/exec.lua b/test/tarantool-tests/utils/exec.lua
index 49f8ef06..b435e084 100644
--- a/test/tarantool-tests/utils/exec.lua
+++ b/test/tarantool-tests/utils/exec.lua
@@ -43,33 +43,67 @@ local function makeenv(tabenv)
   return table.concat(flatenv, ' ')
 end
 
--- <makecmd> creates a command that runs %testname%/script.lua by
--- <LUAJIT_TEST_BINARY> 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)
+-- <makecmd_exec> 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 opts.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 <io.popen> 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 = ('<ENV> <LUABIN> <REDIRECT> <SCRIPT>'):gsub('%<(%w+)>', self)
+      local cmd = ('<ENV> <BIN> <REDIRECT> <PERMARGS>'):gsub('%<(%w+)>', self)
                   .. (' %s'):rep(select('#', ...)):format(...)
+      if self.t ~= nil then self.t:diag('cmd: '..cmd) end
       -- Trim both leading and trailing whitespace from the output
       -- produced by the child process.
-      return io.popen(cmd):read('*all'):gsub('^%s+', ''):gsub('%s+$', '')
+      local output = io.popen(cmd):
+        read('*all'):gsub('^%s+', ''):gsub('%s+$', '')
+      if self.t ~= nil then self.t:diag('output: '..output) end
+      return output
     end
   })
 end
 
+-- Makes a file name for running test's data file in
+-- '%testname%' directory.
+function M.test_data(arg, name)
+  local fname, matches = arg[0]:gsub('%.test%.lua$', '/'..name)
+  assert(matches == 1, 'unexpected test filename')
+  return fname
+end
+
+-- <makecmd> creates a command that runs %testname%/script.lua by
+-- <LUAJIT_TEST_BINARY> with the given environment, launch options
+-- and CLI arguments.
+function M.makecmd(arg, opts)
+  local luabin = M.luacmd(arg)
+  local script = opts and opts.script or M.test_data(arg, 'script.lua')
+  return M.makecmd_exec(luabin, {
+    env = opts and opts.env or nil,
+    redirect = opts and opts.redirect or nil,
+    args = {script},
+    t = opts and opts.t or nil,
+  })
+end
+
 return M
-- 
2.49.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [Tarantool-patches] [PATCH luajit v3 2/2] Improve CLI signal handling on POSIX.
  2026-11-01 23:59 [Tarantool-patches] [PATCH luajit v3 0/2] Improve CLI signal handling on POSIX Evgeniy Temirgaleev via Tarantool-patches
  2026-11-01 23:59 ` [Tarantool-patches] [PATCH luajit v3 1/2] test: refactored utils.exec.makecmd Evgeniy Temirgaleev via Tarantool-patches
@ 2026-11-01 23:59 ` Evgeniy Temirgaleev via Tarantool-patches
  1 sibling, 0 replies; 3+ messages in thread
From: Evgeniy Temirgaleev via Tarantool-patches @ 2026-11-01 23:59 UTC (permalink / raw)
  To: Sergey Kaplun, Sergey Bronnikov; +Cc: tarantool-patches

From: Mike Pall <mike>

(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 <signal.h>
+
+#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


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-11-02  0:01 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-01 23:59 [Tarantool-patches] [PATCH luajit v3 0/2] Improve CLI signal handling on POSIX Evgeniy Temirgaleev via Tarantool-patches
2026-11-01 23:59 ` [Tarantool-patches] [PATCH luajit v3 1/2] test: refactored utils.exec.makecmd Evgeniy Temirgaleev via Tarantool-patches
2026-11-01 23:59 ` [Tarantool-patches] [PATCH luajit v3 2/2] Improve CLI signal handling on POSIX Evgeniy Temirgaleev via Tarantool-patches

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox