Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug with signal trap #5830

Closed
anykeyh opened this issue Mar 16, 2018 · 6 comments
Closed

Bug with signal trap #5830

anykeyh opened this issue Mar 16, 2018 · 6 comments

Comments

@anykeyh
Copy link

anykeyh commented Mar 16, 2018

Code to reproduce this bug (need interactive terminal):

system("echo call a subprocess")

Signal::INT.trap do
  puts "Canceled by user"
  exit
end

puts "Press CTRL+C"
gets

Expected behavior

Print "Canceled by user" and exit the program

Current behavior

Do nothing when you press Ctrl+C

Environment

Tested on MacOS with Crystal 0.24.1 / LLVM 5.0.1

Additional notes

Happens when a child process is created through backslash quote or system call.

@NIFR91
Copy link

NIFR91 commented May 3, 2018

Same problem

Crystal 0.24.2 [4f9ed8d03] (2018-03-08)

LLVM: 4.0.0
Default target: x86_64-unknown-linux-gnu

with code

at_exit{ puts "Terminated"} 
Signal::INT.trap { exit } 
puts "Infinite Loop" 
loop { } 

Expected behavior:
exit and print "Terminated" when sending interrupt signal with kill -int [pid] or Ctrl+C

Current behavior:
block in trap is never executed, and the program continues execution.


The program works with

at_exit{ puts "Terminated"} 
# Signal::INT.trap { exit } 
LibC.signal Signal::INT.value,->(s : Int32){ exit } 
puts "Infinite Loop" 
loop { } 

The program exit and print "Terminated" after kill -int [pid] or Ctrl+C

@ysbaddaden
Copy link
Contributor

@NIFR91 this is unrelated to the initial issue, and this can't work in Crystal: signals are handled through the event loop; you can't use signal handling to exit a busy loop in crystal, because the busy loop prevents the event loop to resume and handle the signal... Inserting a sleep 0 or anything IO related inside the busy loop will do the job.

Note that you need crystal master for the at_exit block to be actually run (and thus print Terminated).

ysbaddaden added a commit to ysbaddaden/crystal that referenced this issue May 4, 2018
We must always close the signal handler pipe after between a
fork/exec combination, otherwise a simple `system("")` call prevents
further signals from being handled.

fixes crystal-lang#5830
@ysbaddaden
Copy link
Contributor

Initial issue fixed in ff56d94.

@NIFR91
Copy link

NIFR91 commented May 4, 2018

@ysbaddaden , yes, you are right i didn't think it thoroughly. Maybe in my program i never yield to the event loop, ill check it.

@ysbaddaden
Copy link
Contributor

ysbaddaden commented May 5, 2018

The problem isn't related to signal handling, well, not exactly.

What happens is that Crystal expects STDIN, STDOUT and STDERR to have O_NONBLOCK but whenever those are inherited by a sub-process it may have changed (as happens here). So, the gets call is now a blocking call.

That shouldn't affect signals, but... signal handling doesn't happen on the sigaltstack, it's deferred to the event loop —for safety reasons.

Sadly, there is no easy solution to this; until the event loop gets multi-threaded, that is, or if someone rewrites the nonblocking code for STDIN, STDOUT and STDERR to not rely on O_NONBLOCK (but timers and interrupted syscalls). Oh well: #6068

@ysbaddaden
Copy link
Contributor

Duplicate of #2713.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants