如何在Mac上原子地创建“close-on-exec”套接字?

9

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

auto fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, 0);

因此,没有其他线程可以使用fork()+exec()方式保持此套接字处于打开状态。
但是在Mac上,根据手册,我无法做同样的技巧:
套接字具有指定的类型,该类型指定通信的语义。当前已定义的类型为:
SOCK_STREAM SOCK_DGRAM SOCK_RAW SOCK_SEQPACKET SOCK_RDM
标志O_CLOEXEC只能通过调用fcntl()来设置。而这不是原子方式 - 一些线程可能会在调用socket()fcntl()之间执行exec()
如何解决这个问题?
1个回答

2
假设你的代码使用pthread,考虑使用“pthread_atfork”,它可以指定分叉时的回调。从Alk的帖子中延伸思路,在分叉回调中实现等待。从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 ) ;    
}


作为额外的奖励,上述逻辑互斥锁也将涵盖调用fork时的情况,并且在执行fork时,父/子线程中的一个线程将尝试创建套接字。不确定是否可能发生这种情况,因为内核可能会在启动任何fork活动之前先挂起所有线程。
免责声明:我没有尝试运行代码,因为我没有访问Mac机器的权限。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接