Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
382 views
in Technique[技术] by (71.8m points)

c - fd leak, custom Shell

I'm working on a custom shell that can handle multiple pipes. But every time I execute a new pipeline and check the process with ls -l /proc/pid/fd I get something like in the picture below and the list keeps expanding with every new pipeline executed:

screenshot of terminal

Question: Is this considered as a fd leak? And how do I fix it?

Here's a code snippet for my pipeline execution:

enum PIPES {READ, WRITE};

void execute_pipeline(char*** pipeline)
{
    int fd[2];
    int fd_backup = 0;
    pid_t child_pid;

    while (*pipeline != '')
    {
        pipe(fd);
        child_pid = fork();

        if(child_pid == -1)
        {
            perror("fork");
            exit(1);
        }
        else if(child_pid == 0)
        {
            dup2(fd_backup, 0);// (old, new)
            close(fd[READ]);

            if(*(pipeline + 1) != '')
            {
                dup2(fd[WRITE], 1);
            }
            execvp((*pipeline)[0], *pipeline);
            exit(1);
        }
        else// Parent process
        {
            wait(NULL);
            close(fd[WRITE]);
            fd_backup = fd[READ];
            pipeline++;
        }
    }
}

EDIT

An example how to call execute_pipeline:

char *ls[] = {"ls", "-l", NULL};
char *sort[] = {"sort", "-r", NULL};
char *head[] = {"head", "-n", "3", NULL};
char **pipeline[] = {ls, sort, head, NULL};

execute_pipeline(pipeline);
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Let's be accurate regarding the file descriptors and bear in mind that during fork and execvp file descriptors are inherited by child processes unless marked as w/ CLOEXEC flag. Check the man pages:

fork(2): The child inherits copies of the parent's set of open file descriptors. Each file descriptor in the child refers to the same open file description (see open(2)) as the corresponding file descriptor in the parent.

open(2): By default, the new file descriptor is set to remain open across an execve(2) (i.e., the FD_CLOEXEC file descriptor flag described in fcntl(2) is initially disabled); the O_CLOEXEC flag, described below, can be used to change this default. The file offset is set to the beginning of the file (see lseek(2)).

But this behaviour, I supposed, exactly what you were relying on by calling fork after pipe...

No other words, lets' draw this:

             stdin, stdout                                                                   
                   /                                                                        
                  /                                                                         
                 /                                                                          
                /                                                                           
               / R; W;                                                                      
              /                                                                             
       Child -            - Parent                                                           
 stdin/out, R(del),W       stdin/out, R(fd_backup), W(del)                                   
                                  /                                                         
                                 /                                                          
                                /                                                           
                               /                                                            
                              / R1; W1;                                                     
                             /                                                              
                      Child -            - Parent                                            
               stdin/out, R(fd_backup),   stdin, stdout                                      
                            R1(del), W1   R(fd_backup - old);                                
                                          R1(fd_backup - new); W1(del)                       
                                                    /                                       
                                                   /                                        
                                                  /                                         
                                                 /R2; W2;                                   
                                                /                                           
                                               /                                            
                                        Child -             - Parent                         
                                 stdin, stdout,             stdin, stdout                    
                                R(fd_backup - old),         R (fd_backup - old),             
                                R1(fd_backup - new),        R1 (fd_backup - new),            
                                R2(del),W2                  R2 (fd_backup - newest!),                                                                                            

I hope the picture is self explanatory.

Child processes will die anyway and all their fds will be closed (so no issue with them). But the parent process is left with 3 opened fds and they keep growing with each pipe executed.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...