`getErrno`和线程

gsp*_*spr 8 multithreading haskell errno ghc

getErrno读取文档:

在当前线程中获取errno的当前值.

我不清楚这是否意味着当前的OS线程.特别是,errno每当Haskell线程从一个OS线程迁移到另一个OS线程时,(线程)运行时是否会获取并存储?

这个问题似乎有关系,但我不清楚是否有关于操作系统或Haskell线程的内容.

jek*_*kor 7

对于最近版本的GHC,运行时保存errno在线程存储对象(TSO)中,并在将运行时线程迁移到另一个OS线程时负责管理它.这意味着errno在unbound(forkIO)和bound(forkOS)线程中依赖它应该是安全的.这是Linux的测试:

err.hs

import Control.Concurrent
import Control.Exception
import Foreign.C

foreign import ccall safe get_ostid :: IO CUInt
foreign import ccall safe sleep :: CUInt -> IO CUInt
foreign import ccall unsafe get_errno :: IO CInt
foreign import ccall unsafe set_errno :: CInt -> IO ()

forkIO' f = do
  done <- newEmptyMVar
  forkIO (f `finally` putMVar done ())
  return (takeMVar done)

prefix = do
  id <- get_ostid
  return $ show id ++ ": "

main = do
  wait <- forkIO' $ do -- spawn a lightweight thread
    errno <- get_errno
    (putStr =<< prefix) >> putStrLn ("outer errno is " ++ show errno)
    (putStr =<< prefix) >> putStrLn "Setting outer errno to 3"
    set_errno 3
    wait' <- forkIO' $ do -- spawn another lightweight thread
      errno <- get_errno
      (putStr =<< prefix) >> putStrLn ("inner errno is " ++ show errno)
      (putStr =<< prefix) >> putStrLn "Setting inner errno to 2"
      set_errno 2
      sleep 2 -- force this lightweight thread to tie up the OS thread
      errno <- get_errno
      (putStr =<< prefix) >> putStrLn ("inner errno is " ++ show errno)
    threadDelay 1000000 -- wait a second
    -- By now, we should be in another OS thread.
    errno <- get_errno
    (putStr =<< prefix) >> putStrLn ("outer errno is " ++ show errno)
    wait'
  wait
Run Code Online (Sandbox Code Playgroud)

err.c

#include <errno.h>
#include <sys/syscall.h>
#include <unistd.h>

int get_errno(void) { return errno; }
void set_errno(int e) { errno = e; }

unsigned get_ostid(void) {
  return syscall(SYS_gettid);
}
Run Code Online (Sandbox Code Playgroud)

编译:

ghc -o err -threaded err.hs err.c
Run Code Online (Sandbox Code Playgroud)

结果应该类似于:

12282: outer errno is 0
12282: Setting outer errno to 3
12282: inner errno is 0
12282: Setting inner errno to 2
12283: outer errno is 3
12282: inner errno is 2
Run Code Online (Sandbox Code Playgroud)

OS线程ID打印在每行的开头.请注意,errnoof 3迁移到第二个OS线程(12283).