Search code examples
c++forkparent-child

how to catch a child process as soon as it ends?


i wrote a copy function that uses fork in order to make the function run in the back ground , the child process should copy the file , and the parent process doesn't wait for the child until it finishes , my problem is that i want to print " copying was complete " massage when the child finishes copying the file , but i don't know how to catch the child process as soon as it ends ant help ?

void copyFunction::execute() {

    char *buff = new char[1024]();
    int fdRead = open(args[1], O_RDONLY);
    if (fdRead == -1) {
        perror(" error: open failed");
        return;
    }

    int fdWrite = open(args[2], O_WRONLY | O_TRUNC);
    if (fdWrite ==-1) {                // if we couldn't open the file then create a new one (not sure if we supposed to this ?)
        fdWrite = open(args[2], O_WRONLY | O_CREAT, 0666);
        if (fdWrite == -1) {
            perror(" error: open failed");
            return;
        }
    }

    PID = fork();
    if (PID == 0) {
        setpgrp();

        int count = read(fdRead, buff, 1);  /// read from the file fd1 into fd2
        while (count != -1) {
            if (!count) {
                break;
            }
            if (write(fdWrite, buff, 1) == -1) {
                perror(" error: write failed");
                return;  // not sure if we should return
            }
            count = read(fdRead, buff, 1);
            if (count == -1) {
                perror(" error: read failed");
                exit(1) ;
            }
        }
        exit(1) ;
    }  if (PID > 0) { 
            SmallShell::getInstance().Jobs_List.addJob(SmallShell::getInstance().currentCommand, false);
            return;

    } else {
        perror(" error: fork failed");
    }
}

where to call ?

 cout << "copying was complete" << endl;

Solution

  • This is a fairly broad topic and this can be done in a variety of ways. When a process terminates its parent process receives a SIGCHLD signal. You can set up a signal handler for that using sigaction() (older C/C++ code also use the older signal() function for this).

    The main problem with that approach is that the entire C/C++ library is completely off-hands from any code that runs in a signal handler. None of it is signal safe. Can't touch it. Can't use it. You can't do anything in your signal except to make direct operating system calls. Well, you can't do anything else without a lot of pain and tears.

    But for most simple use cases this might be sufficient.

    But if you do need more breathing room, you have to do more work. On Linux you can use a signal file descriptor that, pretty much, turns the signal into a file that can be read in an orderly, organized fashion. On BSD you can use kqueue notifications to do the same thing. A rather crude simulation of this approach is to create a plain, garden variety pipe(). You create it in advance, and use a plain signal handler that writes a byte to the pipe (which it can do, directly, using the write() system call). In both cases -- the full-fledged signal handler, or a pale imitation of it using an interla pipe -- your main application can use poll() to know when the signal is received, meaning that your child process has terminated. Or maybe your main application can use an execution thread that's dedicated for that purpose.

    And you can finally celebrate. That's a lot of work, isn't it?