Skip to content

Instantly share code, notes, and snippets.

@zdennis
Last active August 29, 2015 14:16
Show Gist options
  • Save zdennis/3a0b685047ac086725b0 to your computer and use it in GitHub Desktop.
Save zdennis/3a0b685047ac086725b0 to your computer and use it in GitHub Desktop.
Annoying REPL SIGSTOP Issue
  • Make sure you are running the bash shell.
  • Run repl.rb which will echo what you print unless you enter "irb".
  • Type "irb" to launch a new irb process.
  • Hit Ctrl-Z to send SIGTSTP to stop the irb process.
  • You'll be brought back to the main repl.
  • Type "foo", hit enter. You'll be echoed "oo".
  • Type "foo" again, hit enter. You'll see "foo".
  • Now hit Ctrl-C to interrupt the process, it will die and the missing "f" will show up.

This seems to not be a problem with irb, but any child process that calls "gets". If you launch "irb" from bash though and do the same steps, bash doesn't exhibit this issue, just a ruby REPL.

Also, if you run tcshas the parent shell and do the above, the issue doesn't happen. What's going on?

2015-03-07 10:00pm Update

This problem happens every time when running Bash (3.x or 4.x) under OSX if bash is the parent shell that the process starts in. The issue doesn't seem to exist when running under Linux (at least not on the one Linux box I tested it with).

If bash is not the parent, but say tcsh is, then the problem no longer exists. However, is bash is in hte parent tree then it still fails. E.g. don't start tcsh from within bash to test.

A possibly related issue is exhibited if you run the "dash" shell from within bash, and then run "irb" inside of dash. Once irb is up hit Ctrl-Z to suspend. The dash shell will be frozen. However, if you load dash (not from within bash) then load "irb" and Ctrl-Z, there is no issue.

Signal.trap("SIGTSTP", "IGNORE")
pids = []
stty_save = `stty -g`
loop do
print "#{$0}> "
input = STDIN.gets.chomp
if input == "exit"
exit
else
command = nil
if input == "irb"
command = "irb"
elsif input == "fg" && pid.last
Process.kill "SIGCONT", pids.last
else
puts input
next
end
if command
pid = fork do
Signal.trap("SIGTSTP", "DEFAULT")
exec command
end
pids << pid
end
pid, status = Process.waitpid2 pids.last, Process::WUNTRACED if pids.last
if status.stopsig == Signal.list["TSTP"]
system "stty", stty_save
puts "Stopped"
else
pids.pop
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment