Home > Back-end >  Pausing and resuming a shell process from C
Pausing and resuming a shell process from C

Time:10-09

From C , I wish to submit a process, pause, resume it and stop it. For this, I am first using the following function to run a shell process in the background and save the associate PID. I found the function at this post (and only removed the standard input and output).

int system2(const char * command)
{
    int p_stdin[2];
    int p_stdout[2];
    int pid;

    if (pipe(p_stdin) == -1)
        return -1;

    if (pipe(p_stdout) == -1) {
        close(p_stdin[0]);
        close(p_stdin[1]);
        return -1;
    }

    pid = fork();

    if (pid < 0) {
        close(p_stdin[0]);
        close(p_stdin[1]);
        close(p_stdout[0]);
        close(p_stdout[1]);
        return pid;
    } else if (pid == 0) {
        close(p_stdin[1]);
        dup2(p_stdin[0], 0);
        close(p_stdout[0]);
        dup2(p_stdout[1], 1);
        dup2(::open("/dev/null", O_RDONLY), 2);
        /// Close all other descriptors for the safety sake.
        for (int i = 3; i < 4096;   i)
            ::close(i);

        setsid();
        execl("/bin/sh", "sh", "-c", command, NULL);
        _exit(1);
    }

    close(p_stdin[0]);
    close(p_stdout[1]);

    
    return pid;
}

Then, I am using the kill function, to pause, resume and stop the process but it does not work as I expected. Here is an example:

int main()
{
    // The process prints on file allowing me to figure out whether the process is paused / stopped, or is running
    const char * command = "for i in {1..1000}; do echo $i >> /Users/remi/test/data.txt; sleep 1s;done";

    // Run the command and record pid
    auto pid = system2(command);
    std::cout << "pid = " << pid << "\n";  
    // with this pid, I could ensure that `ps -p <pid>` returns the correct command

    std::cout << "process should be running!\n"; // It is!

    // wait
    std::this_thread::sleep_for(std::chrono::seconds(10));

    // pause
    kill(pid, SIGTSTP);
    std::cout << "process should be paused!\n"; // But it is not!

    // wait
    std::this_thread::sleep_for(std::chrono::seconds(10));

    // resume process
    kill(pid, SIGCONT);
    std::cout << "process should be running!\n"; // Sure, it is as it has never been stopped

    // wait 
    std::this_thread::sleep_for(std::chrono::seconds(10));

    // Kill process
    kill(pid, SIGSTOP);
    std::cout << "process should be stopped!\n"; // That worked!

    // wait 
    std::this_thread::sleep_for(std::chrono::seconds(10));
}

Can you please help me figure out how to fix this code to ensure the process stops and resume as I was expected.

FYI, I am on a macOS and wish the solution work on any POSIX system.

CodePudding user response:

Note that both SIGTSTP and SIGSTOP signals are actually pausing the process. The first can be ignored by the process but the latter can’t be. If you wish to pause the process no matter what use SIGSTOP.

To kill the process, use SIGTERM or SIGKILL.

  • Related