¡Pregunta interesante!
No puede interrumpir el bloqueo de llamadas externas, por lo que estoy algo sorprendido de que pueda interrumpir el hilo en Linux. Además, forkOS
no ayuda; eso solo permite que el código externo asigne almacenamiento local de subprocesos, pero no tiene nada que ver con el comportamiento de bloqueo. Pero recordemos que acepta se puede configurar para no bloqueante:
Si no hay conexiones pendientes están presentes en la cola, y el zócalo esté no marcados como sin bloqueo, aceptar() bloquea la persona que llama hasta que la conexión está presente . Si el socket está marcado como no bloqueante y no hay conexiones pendientes en la cola, accept() falla con el error EAGAIN o EWOULDBLOCK.
que es lo que se hace in the Network library for Posix systems. Esto permite entonces la accept
a ser interrumpido.
Una nota interesante acerca de Windows:
-- On Windows, our sockets are not put in non-blocking mode (non-blocking
-- is not supported for regular file descriptors on Windows, and it would
-- be a pain to support it only for sockets). So there are two cases:
--
-- - the threaded RTS uses safe calls for socket operations to get
-- non-blocking I/O, just like the rest of the I/O library
--
-- - with the non-threaded RTS, only some operations on sockets will be
-- non-blocking. Reads and writes go through the normal async I/O
-- system. accept() uses asyncDoProc so is non-blocking. A handful
-- of others (recvFrom, sendFd, recvFd) will block all threads - if this
-- is a problem, -threaded is the workaround.
Ahora, aceptar en Windows, con el tiempo de ejecución -enhebrado, utiliza accept_safe (que permite a otros hilos para avanzar) - pero no pone el socket en no-bloqueo:
accept [email protected](MkSocket s family stype protocol status) = do
currentStatus <- readMVar status
okay <- sIsAcceptable sock
if not okay
then
ioError (userError ("accept: can't perform accept on socket (" ++ (show (family,stype,protocol)) ++") in status " ++
show currentStatus))
else do
let sz = sizeOfSockAddrByFamily family
allocaBytes sz $ \ sockaddr -> do
#if defined(mingw32_HOST_OS) && defined(__GLASGOW_HASKELL__)
new_sock <-
if threaded
then with (fromIntegral sz) $ \ ptr_len ->
throwErrnoIfMinus1Retry "Network.Socket.accept" $
c_accept_safe s sockaddr ptr_len
else do
paramData <- c_newAcceptParams s (fromIntegral sz) sockaddr
rc <- asyncDoProc c_acceptDoProc paramData
new_sock <- c_acceptNewSock paramData
c_free paramData
when (rc /= 0)
(ioError (errnoToIOError "Network.Socket.accept" (Errno (fromIntegral rc)) Nothing Nothing))
return new_sock
Desde 2005, las versiones del paquete de network
, en Windows con -enhebrado utilizar explícitamente aceptar una llamada marcada como safe
, permitiendo que otros hilos para hacer progresos, pero no se establece el propio zócalo en modo sin bloqueo (por lo que el hilo llamante bloquea).
Para evitar que veo dos opciones:
- encontrar la manera de hacer una llamada sin bloqueo aceptar en Windows, y el parche de la biblioteca de red - mirar lo que, por ejemplo, chasquido o yesod hazlo aquí, para ver si ya lo resolvieron.
- utiliza algún tipo de hilo de supervisión para simular epoll, supervisando los hilos secundarios bloqueados para el progreso.
Relacionado: http://stackoverflow.com/questions/6185189/howto-kill-a-thread-in-haskell –