如何在 Mac 上自动创建“close-on-exec”套接字?

aby*_*s.7 6 c sockets macos exec fcntl

当我在 Linux 上创建套接字时,可以O_CLOEXEC在创建时指定标志:

auto fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, 0);
Run Code Online (Sandbox Code Playgroud)

所以没有办法,其他线程会在这个套接字保持打开的情况下做fork()+ exec()

但是在 Mac 上,根据手册,我不能做同样的事情:

套接字具有指定的类型,它指定了通信的语义。当前定义的类型有: SOCK_STREAM SOCK_DGRAM SOCK_RAW SOCK_SEQPACKET SOCK_RDM

该标志O_CLOEXEC只能通过调用来设置fcntl()。而且这不是原子方式 - 某些线程可能会exec()在对socket()和 的调用之间执行fcntl()

如何解决这个问题?

das*_*h-o 2

假设您的代码使用 pthreads,请考虑使用“pthread_atfork”,这使得可以为分叉指定回调。扩展了 Alk 帖子的想法,但在 fork 回调中实现了等待。

从OP来看,看起来可以控制创建套接字的代码(在Linux中它将使用SOCK_CLOEXEC),但不可能控制或修改分叉调用。


mutex_t socket_lock ;

main()
{
    ...
    // establish atfork, before starting any thread.
    mutex_t socket_lock = mutex_init(...);
    pthread_atfork(set_socket_lock, release_sock_lock, release_sock_lock) ;
    pthread_create(...) ;
    .. rest of the code ...
}
int socket_wrapper(...)
{
  set_socket_lock() ;

  int sd = socket(..);
  fcntl(sd, O_CLOEXEC);

  release_socket_lock();

  return sd;
}

void set_socket_lock(void)
{
    lock(socket_lock ) ;
}

void release_socket_lock(void)
    unlock(socket_lock ) ;    
}

Run Code Online (Sandbox Code Playgroud)

作为额外的好处,上述逻辑互斥体还将涵盖调用 fork 的情况,并且在执行 fork 时,父/子线程中的一个线程将尝试创建套接字。不确定这是否可能,因为内核可能在开始任何分叉活动之前首先挂起所有线程。

免责声明:我没有尝试运行代码,因为我无法访问 Mac 计算机。