close on exec

作用

O_CLOEXEC和FD_CLOEXEC作用:打开的文件描述符在执行exec调用新程序前自动被关闭

  • O_CLOEXEC模式下open和标志设置为原子操作,2.6.23后才支持。
  • FD_CLOEXEC需单独调用fcntl 设置FD_CLOEXEC,此时open和fcntl两个操作不是原子操作。
  • 两种方式下的fd在通过fork调用产生的子进程中均不被关闭。
  • 调用dup族类函数得到的新文件描述符将清除O_CLOEXEC模式。
example

int fd = open(file_name, O_RDWR|O_CLOEXEC, S_IRUSR);

or

int fd = open(file_name, O_RDWR, S_IRUSR);
int val = fcntl(fd, F_GETFD);
if (val > 0) {
    fcntl(fd, F_SETFD, val | FD_CLOEXEC);
内核实现

这里主要简单介绍一下内核是如何利用这个标志,在exec的哪个位置关闭文件,内核调用路径如下
单内核在加载一个可执行文件时,调用路径如下
load_elf_binary
setup_new_exec(bprm)
do_close_on_exec(struct files_struct *files)

void do_close_on_exec(struct files_struct *files)
{
        unsigned i;
        struct fdtable *fdt;

        /* exec unshares first */
        spin_lock(&files->file_lock);
        for (i = 0; ; i++) {
                unsigned long set;
                unsigned fd = i * BITS_PER_LONG;
                fdt = files_fdtable(files);
                if (fd >= fdt->max_fds)
                        break;
                set = fdt->close_on_exec[i];
                if (!set)
                        continue;
                fdt->close_on_exec[i] = 0;
                for ( ; set ; fd++, set >>= 1) {
                        struct file *file;
                        if (!(set & 1))
                                continue;
                        file = fdt->fd[fd];
                        if (!file)
                                continue;
                        rcu_assign_pointer(fdt->fd[fd], NULL);
                        __put_unused_fd(files, fd);
                        spin_unlock(&files->file_lock);
                        filp_close(file, files);
                        cond_resched();
                        spin_lock(&files->file_lock);
                }

        }
        spin_unlock(&files->file_lock);
}
reference

  • O_CLOEXEC模式和FD_CLOEXEC选项

你可能感兴趣的:(close on exec)