forkfile-descriptorcontention

Same file descriptor after fork()


I'm trying to understand what means duplicating a file descriptor after calling fork() and its possible effects on contention.

In "The Linux Programming Interface" 24.2.1 (p517):

When a fork() is performed, the child receives duplicates of all of the parent's file descriptors. These duplicates are made in the manner of dup(), which means that corresponding descriptors in the parent and the child refer to the same open file description.

When I run this same code:

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/wait.h>

int main(void) {
    char* fl = "/tmp/test_fd";
    int fd;
    fd = open(fl, O_CREAT|O_TRUNC|O_WRONLY, 0666);
    if(!fork()) {
        printf("cfd=%d\n", fd);
        _exit(0);
    } else {
        int status;
        printf("ffd=%d\n", fd);
        wait(&status);
        close(fd);
        unlink(fl);
    }
}

I get the same file descriptor (number?) for both processes: ffd=3 and cfd=3. But when run this code using dup():

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

int main(void) {
    char* fl = "/tmp/test_fd";
    int cfd, ffd;
    ffd = open(fl, O_CREAT|O_TRUNC|O_WRONLY, 0666);
    cfd = dup(ffd);
    printf("ffd=%d\n", ffd);
    printf("cfd=%d\n", cfd);
    close(ffd);
    unlink(fl);
}

I get different file descriptors: ffd=3 and cfd=4.

Then, I have the following questions:

  1. What means fork() creates a copy of the parent's file descriptors?
  2. Is there contention when two processes (father and child) perform an operation like fstat() concurrently on the same file descriptor?
  3. And what about two processes performing fstat() concurrently with two different file descriptors pointing to the same file?

Solution

  • When you see the phrase "duplicate a file descriptor", you need to understand it as "create a new file descriptor which points to the same thing the other one is pointing to".

    So when you duplicate fd 3, you get fd 4. The aren't the same number, but they identify the same object.

    In the case of fork, you must remember that the meaning of a file descriptor is contained within a process. Lots of processes have a valid fd 3, but they're not all referring to the same object. With fork, you have a duplicate of fd 3 that is also fd 3, but in a different process so those 3's aren't inherently identical; they're identical because fork made a copy.

    You can close the fd and open a different file in the child process, and you'll still have two processes in which fd 3 is valid, but they aren't copies of the same thing anymore. Or you could have the child dup the fd 3 to get fd 4, then close fd 3, and then you'd have fd 3 in the parent and fd 4 in the child referring to the same object.

    The same number in a different process doesn't mean anything.

    Also note that the object referred to by a file descriptor isn't a file. There's something in between a file descriptor and a file, and it's called an open file description. Both fork and dup cause an open open file description to be shared. The main consequence of the sharing is that when the current file position (set by lseek or advanced by read and write) changes, all of the related file descriptors are affected, and when flags (like O_NONBLOCK) are changed, all the related file descriptors are affected.

    In contrast if you open the same file twice, you get two file descriptors that refer to the same file, but through different open file descriptions, so they have independent flags and seek position.

    fstat being a readonly operation, I don't see what kind of "contention" you're imagining for it.