面白い質問です!
外国の呼び出しのブロックを中断することはできないので、Linuxでスレッドを中断できることに少し驚いています。また、forkOS
助けにはなりません-それは単に外部コードにスレッドローカルストレージを割り当てさせるだけですが、ブロッキング動作とは何の関係もありません。ただし、acceptは非ブロッキングに設定できることを思い出してください。
保留中の接続がキューに存在せず、ソケットが非ブロックとしてマークされていない場合、accept()は接続が存在するまで呼び出し元をブロックします。ソケットが非ブロッキングとしてマークされ、保留中の接続がキューに存在しない場合、accept()はエラーEAGAINまたはEWOULDBLOCKで失敗します。
これは、Posixシステムのネットワークライブラリで行われていることです。これにより、accept
を中断できます。
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.
さて、Windowsでacceptを-threadedランタイムで使用すると、accept_safe(他のスレッドが進行できるようになります)が使用されますが、ソケットは非ブロッキングモードになりません。
accept sock@(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
2005年以降、network
パッケージのバージョンは、-threadedを使用するWindowsで、としてマークされたaccept呼び出しを明示的に使用し、safe
他のスレッドの進行を許可しますが、ソケット自体を非ブロックモードに設定しません(呼び出しスレッドがブロックします)。
それを回避するために、2つのオプションがあります。
- Windowsでノンブロッキングaccept呼び出しを行う方法を理解し、ネットワークライブラリにパッチを適用します。たとえば、snapやyesodがここで何をするかを見て、すでに解決されているかどうかを確認します。
- ある種の監視スレッドを使用してepollを偽造し、ブロックされた子スレッドの進行状況を監視します。