Search code examples
crystal-lang

Correct way to catch SIGINT and cleanup?


Writing a cli tool that on startup turns on the OS X web proxy and on shutdown I'd like to turn it off again. What's the correct way to catch SIGINT and perform app cleanup? Tried the following and it traces the message but does not run the system command or exit:

Signal::INT.trap do
  puts "trap"
  fork do
    system "networksetup -setwebproxystate Wi-Fi off"
  end
  exit
end

This code does exit but gives an 'Invalid memory access' error

at_exit do
  fork do
    system "networksetup -setwebproxystate Wi-Fi off"
  end
end

LibC.signal Signal::INT.value, ->(s : Int32) { exit }
Invalid memory access (signal 10) at address 0x10d3a8e00
[0x10d029b4b] *CallStack::print_backtrace:Int32 +107
[0x10d0100d5] __crystal_sigfault_handler +181
[0x7fff6c5b3b3d] _sigtramp +29

UPDATE

Here's the complete 'app' using Signal::INT.trap, for me running that will correctly turn on and off the OS X proxy settings but the loop will continue to run after the interrupt signal.

fork do
  system "networksetup -setwebproxy Wi-Fi  127.0.0.1 4242"
end

Signal::INT.trap do
  puts "trap"
  fork do
    system "networksetup -setwebproxystate Wi-Fi off"
  end
  exit
end

loop do
  sleep 1
  puts "foo"
end

Solution

  • You can use a Fibers?

    spawn do
      system "networksetup -setwebproxy Wi-Fi  127.0.0.1 4242"
    end
    
    sleep 0.1
    
    Signal::INT.trap do
      puts "trap"
      spawn do
        system "networksetup -setwebproxystate Wi-Fi off"
      end
      sleep 0.1
      exit
    end
    
    loop do
      sleep 1
      puts "foo"
    end