title: Haskell: getProcessStatus blocking SIGINT
body: <p>I'm trying to write a simple shell in Haskell, but I cant get the signal handling to work. If no command is running, sending <code>SIGINT</code> to the shell process triggers the signal handler. But when a blocking call to <code>getProcessStatus</code> is made, the signal is ignored. Sending a signal immediately to the child process of course kills the child and makes the blocking call return. </p>
  
  <p>Replacing the blocking call with <code>Control.Concurrent.threadDelay</code> does not prevent the signal, i.e., everything works as intended. Replacing the blocking flag to <code>getProcessStatus</code> with <code>False</code> makes the function return before the child process has finished.</p>
  
  <p>Reference to process package: <a href="https://hackage.haskell.org/package/unix-2.7.1.0/docs/System-Posix-Process.html#v:getProcessStatus" rel="nofollow">https://hackage.haskell.org/package/unix-2.7.1.0/docs/System-Posix-Process.html#v:getProcessStatus</a></p>
  
  <p>The relevant code is below, see the (only) commented line.</p>
  
  <pre><code>main :: IO ()
  main = do
      pidRef &lt;- (newIORef [] :: IO (IORef [ProcessID]))
      setSigHant pidRef
      doPrompt pidRef
  
  printPrompt :: IO ()
  printPrompt = fdWrite stdError "λ➔ " &gt;&gt; return ()
  
  doPrompt :: IORef [ProcessID] -&gt; IO ()
  doPrompt pidRef = do
      printPrompt
      tryLine &lt;- try getLine :: IO (Either SomeException String)
      case tryLine of 
          Left _ -&gt; do
              putStrLn ""
              exitSuccess
          Right line -&gt; do
              tryCl &lt;- try (parse line) :: IO (Either SomeException [Command])
              case tryCl of 
                  Left e -&gt; fdWrite stdError (show e ++ "\n") &gt;&gt; return ()
                  Right cl -&gt; 
                      if length cl &gt; 0 &amp;&amp; (cmd . head) cl == "cd" then
                          cd (head cl)
                      else do
                          execCommands pidRef cl (stdInput, stdOutput)
                          pids &lt;- readIORef pidRef
  
                          -- This call to getProcessStatus blocks the signals
                          _ &lt;- sequence $ map (getProcessStatus True False) pids
                          _ &lt;- writeIORef pidRef []
                          return ()
              doPrompt pidRef
  
  setSigHant :: (IORef [ProcessID]) -&gt; IO ()
  setSigHant pidRef = do
      let handler = Catch (sigIntHandler pidRef)
      installHandler sigINT handler Nothing
      return ()
  
  
  sigIntHandler :: (IORef [ProcessID]) -&gt; IO ()
  sigIntHandler pidRef = do
      pids &lt;- readIORef pidRef
      sequence_ $ map (signalProcess sigINT) pids
      fdWrite stdError "\n"
      printPrompt
  </code></pre>