Linux 文件描述符标记之 FD_CLOEXEC

重读 The method to epoll’s madness 之前转载的这篇博客,里边提到的文件描述标记文件描述状态

 

当前的Linux 支持的文件描述符标记只有 FD_CLOEXEC,可通过 fcntl 指定宏 F_SETFD 和 F_GETFD 来设置和读取文件描述符标记,参看 GUN 文件描述符标记文档

系统调用 open 可以指定 O_CLOEXEC 来置位文件描述符的 FD_CLOEXEC 标记。包括创建 socket 的第二个参数现在可

int socket(int socket_family, int socket_type, int protocol)

提供 SOCK_CLOEXEC 宏来最终设置 FD_CLOEXEC 标记,这样可以节省一次另外调用 fcntl 来设置的系统条用开销。

以及也提供类似功能的 accept4 和 epoll_create1

int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)

int epoll_create1(int flags)

在创建文件描述符就设置 FD_CLOEXEC标记要解决的问题是:在多线程程序当中,使用 fcntl 来设置 FD_CLOEXEC 可能会有竞态条件。父进程的一个线程进行fork,另外一个线程在调用 fcntl 设置该标记,这样文件描述符可能最终会泄露到子进程当中。英文解释参看 open 的帮助文档中的 O_CLOEXEC 条目

 O_CLOEXEC (since Linux 2.6.23)
              Enable the close-on-exec flag for the new file descriptor.
              Specifying this flag permits a program to avoid additional
              fcntl(2) F_SETFD operations to set the FD_CLOEXEC flag.

              Note that the use of this flag is essential in some
              multithreaded programs, because using a separate fcntl(2)
              F_SETFD operation to set the FD_CLOEXEC flag does not suffice
              to avoid race conditions where one thread opens a file
              descriptor and attempts to set its close-on-exec flag using
              fcntl(2) at the same time as another thread does a fork(2)
              plus execve(2).  Depending on the order of execution, the race
              may lead to the file descriptor returned by open() being
              unintentionally leaked to the program executed by the child
              process created by fork(2).  (This kind of race is in
              principle possible for any system call that creates a file
              descriptor whose close-on-exec flag should be set, and various
              other Linux system calls provide an equivalent of the
              O_CLOEXEC flag to deal with this problem.)

Linux 上,所有的创建文件描述符的地方,基本都带有一个 flags 参数,可以用于传入 CLOEXEC 标志。包括 signalfd(SFD_CLOEXEC),eventfd(EFD_CLOEXEC),timerfd_create(TFD_CLOEXEC)。

timerfd 等

Guess you like

Origin blog.csdn.net/zhouguoqionghai/article/details/102881085