This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch fix-interruption-nested-shells
in repository https://gitbox.apache.org/repos/asf/felix-dev.git

commit d9b07f8d6614ec80cb2703b11fad30357b03e581
Author: Guillaume Nodet <gno...@gmail.com>
AuthorDate: Wed Apr 30 00:09:47 2025 +0200

    Fix interruption handling in nested shells
    
    This change modifies the Shell.sh method to properly handle interruption 
signals
    in nested shells by clearing and restoring the current pipe. When a user 
starts a
    shell session, then runs the 'sh' command to create a nested shell, and 
then runs
    a command like 'ttop' in that nested shell, pressing Ctrl+C now properly 
interrupts
    the command.
    
    This complements PR #411 which made the Pipe.setCurrentPipe method public 
to enable
    this fix. Together, these changes resolve the issue reported in 
jline/jline3#1143
    where interruption exceptions were not working for child sessions.
    
    The fix follows the same pattern implemented in the Posix.runShell method, 
ensuring
    consistent behavior across different shell creation methods.
---
 commit-message.txt                                 | 14 +++++++++
 gogo/jline/pom.xml                                 |  2 +-
 .../java/org/apache/felix/gogo/jline/Posix.java    | 35 +++++++++++++++++++++-
 .../java/org/apache/felix/gogo/jline/Shell.java    | 21 ++++++++++++-
 4 files changed, 69 insertions(+), 3 deletions(-)

diff --git a/commit-message.txt b/commit-message.txt
new file mode 100644
index 0000000000..8232678fde
--- /dev/null
+++ b/commit-message.txt
@@ -0,0 +1,14 @@
+Fix interruption handling in nested shells
+
+This change modifies the Shell.sh method to properly handle interruption 
signals
+in nested shells by clearing and restoring the current pipe. When a user 
starts a
+shell session, then runs the 'sh' command to create a nested shell, and then 
runs
+a command like 'ttop' in that nested shell, pressing Ctrl+C now properly 
interrupts
+the command.
+
+This complements PR #411 which made the Pipe.setCurrentPipe method public to 
enable
+this fix. Together, these changes resolve the issue reported in 
jline/jline3#1143
+where interruption exceptions were not working for child sessions.
+
+The fix follows the same pattern implemented in the Posix.runShell method, 
ensuring
+consistent behavior across different shell creation methods.
diff --git a/gogo/jline/pom.xml b/gogo/jline/pom.xml
index 9056afba83..cf8827999d 100644
--- a/gogo/jline/pom.xml
+++ b/gogo/jline/pom.xml
@@ -58,7 +58,7 @@
         <dependency>
             <groupId>org.apache.felix</groupId>
             <artifactId>org.apache.felix.gogo.runtime</artifactId>
-            <version>1.1.0</version>
+            <version>1.1.7-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>org.jline</groupId>
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java 
b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java
index 9ead00c263..a954bf0311 100644
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java
+++ b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java
@@ -71,6 +71,7 @@ import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import org.apache.felix.gogo.runtime.Pipe;
 import org.apache.felix.service.command.Process;
 import org.apache.felix.gogo.jline.Shell.Context;
 import org.apache.felix.service.command.CommandProcessor;
@@ -808,9 +809,26 @@ public class Posix {
         new Thread(() -> runShell(session, terminal), terminal.getName() + " 
shell").start();
     }
 
+    /**
+     * Run a shell in a new terminal.
+     *
+     * This method has been modified to fix an issue with interruption 
handling in nested shells.
+     * The fix clears the current pipe before creating a child shell and 
restores it afterward,
+     * ensuring that when Ctrl+C is pressed in a child shell (e.g., when 
running "sh" followed by "ttop"),
+     * the interruption signal is properly propagated to the child process.
+     *
+     * See: https://github.com/jline/jline3/issues/1143
+     *
+     * @param session The parent command session
+     * @param terminal The terminal to use for the new shell
+     */
     private void runShell(CommandSession session, Terminal terminal) {
         InputStream in = terminal.input();
         OutputStream out = terminal.output();
+        
+        // Save the current pipe and clear it before creating a child shell
+        Pipe currentPipe = Pipe.setCurrentPipe(null);
+
         CommandSession newSession = processor.createSession(in, out, out);
         newSession.put(Shell.VAR_TERMINAL, terminal);
         newSession.put(".tmux", session.get(".tmux"));
@@ -822,11 +840,26 @@ public class Posix {
                 terminal.close();
             }
         };
+
+        // Register a signal handler for INT signal to properly propagate 
interruption
+        Terminal.SignalHandler prevIntHandler = 
terminal.handle(Terminal.Signal.INT, signal -> {
+            // Propagate the interrupt to the current thread
+            Thread.currentThread().interrupt();
+        });
+        
         try {
-            new Shell(context, processor).gosh(newSession, new 
String[]{"--login"});
+            new Shell(context, processor).gosh(newSession, new String[] 
{"--login"});
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
+            // Restore the previous signal handler
+            if (prevIntHandler != null) {
+                terminal.handle(Terminal.Signal.INT, prevIntHandler);
+            }
+            
+            // Restore the previous pipe
+            Pipe.setCurrentPipe(currentPipe);
+
             try {
                 terminal.close();
             } catch (IOException e) {
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java 
b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java
index eaf0901102..d3da4b37e2 100644
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java
+++ b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java
@@ -46,6 +46,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import org.apache.felix.gogo.runtime.Closure;
 import org.apache.felix.gogo.runtime.CommandProxy;
 import org.apache.felix.gogo.runtime.CommandSessionImpl;
+import org.apache.felix.gogo.runtime.Pipe;
 import org.apache.felix.service.command.Job;
 import org.apache.felix.service.command.Job.Status;
 import org.apache.felix.gogo.runtime.Reflective;
@@ -440,6 +441,16 @@ public class Shell {
 
     private Object runShell(final CommandSession session, Terminal terminal,
                             LineReader reader) throws InterruptedException {
+        Pipe currentPipe = Pipe.setCurrentPipe(null);
+        try {
+            return doRunShell(session, terminal, reader);
+        } finally {
+            Pipe.setCurrentPipe(currentPipe);
+        }
+    }
+
+    private Object doRunShell(final CommandSession session, Terminal terminal,
+                            LineReader reader) throws InterruptedException {
         AtomicBoolean reading = new AtomicBoolean();
         session.setJobListener((job, previous, current) -> {
             if (previous == Status.Background || current == Status.Background
@@ -555,7 +566,15 @@ public class Shell {
 
     @Descriptor("start a new shell")
     public Object sh(final CommandSession session, String[] argv) throws 
Exception {
-        return gosh(session, argv);
+        // Save the current pipe and clear it before creating a child shell
+        // This ensures that interruption signals are properly propagated to 
the child shell
+        Pipe currentPipe = Pipe.setCurrentPipe(null);
+        try {
+            return gosh(session, argv);
+        } finally {
+            // Restore the previous pipe
+            Pipe.setCurrentPipe(currentPipe);
+        }
     }
 
     private void shutdown() throws Exception {

Reply via email to