Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to handle signal on windows with haskell?

Is there something like System.Posix on windows?

I want the code below to run on windows, should I change it?

import IO
import Control.Exception hiding (catch)
import Control.Concurrent
import Network
import System.Posix   ---cannot be run on windows.

main = withSocketsDo (installHandler sigPIPE Ignore Nothing >> main')
    --so the signal handler cannot be used

main' = listenOn (PortNumber 9900) >>= acceptConnections

acceptConnections sock = do
        putStrLn "trying to accept" -- debug msg
        conn@(h,host,port) <- accept sock
        print conn -- debug msg
        forkIO $ catch (talk conn `finally` hClose h) (\e -> print e)
        acceptConnections sock

talk conn@(h,_,_) = hGetLine h >>= hPutStrLn h >> hFlush h >> talk conn

for example ,if I want the program to quit when ctrl+c,I must add a handler for SIGINT ,so in c++,write some code like this:

void callback(int sig) 
{ 
   // printf("catch\n"); 
} 
... 
signal(SIGINT,callback); 

But I don't know how to do this in haskell,use FFI?

like image 233
vzex Avatar asked Apr 26 '12 12:04

vzex


4 Answers

Late to the party, but I wrote a library which can help. It allow signal handling on both Windows and Linux. It is avaliable on hackage: https://hackage.haskell.org/package/signal

like image 164
remdezx Avatar answered Sep 30 '22 20:09

remdezx


import Foreign
import Foreign.C.Types

type Handler = CInt->IO ()
foreign import ccall "wrapper"
  genHandler:: (Handler) -> IO (FunPtr Handler)

foreign import ccall safe "signal.h signal"
        install:: CInt->FunPtr Handler->IO CInt
main=do
        s<-genHandler (\x->putStrLn $ "catch "++(show x))
        res<- install 2 s
        putStrLn $ show res
        s<-getLine

the code above is what i wanna do,just import the signal function,with a haskell callback.

like image 31
vzex Avatar answered Sep 30 '22 21:09

vzex


I am not a Windows expert, so I don't know what you will need to do to ignore whatever event you're ignoring here. You'll probably want to poke around in the Win32 documentation for whichever version you have installed. However, I do know a bit about the build system and how to get one of two versions of a function to build. So the strategy will look like this:

  1. Make two directories, unix-src and Win32-src (or some similar names).
  2. In each directory, put a module OSCompat (or some similar name) containing something like this:

    -- unix-src/OSCompat.hs
    module OSCompat where
    import System.Posix
    ignorePipe = installHandler sigPIPE Ignore Nothing
    
    -- Win32-src/OSCompat.hs
    module OSCompat where
    import System.Win32
    ignorePipe = -- ???
    
  3. In your project.cabal file, put something like the following in your executable block:

    if os(windows)
        build-depends: Win32
        hs-source-dirs: Win32-src
    else
        build-depends: unix
        hs-source-dirs: unix-src
    
  4. Change your top-level module to look like this:

    import OSCompat
    main = withSocketsDo (ignorePipe >> main')
    
like image 35
Daniel Wagner Avatar answered Sep 30 '22 20:09

Daniel Wagner


I don't think that you can do something like that on Windows. Windows is not Posix-compatible, so it does not support signals in full extent, e.g. it does not support sending signals to other processes. Also the number of signals available is pretty limited.

If I understood correctly you are ignoring SIGPIPE to protect your program from exiting if its output was piped to another process and then that process terminates, right? Sorry, I don't know how to do this in Windows (and in fact you don't often see programs communicating through simple pipe on Windows). If your signal handling is connected with sockets, this may help.

like image 22
Vladimir Matveev Avatar answered Sep 30 '22 20:09

Vladimir Matveev