Mohamed Ramzy
Mohamed Ramzy

Reputation: 13

How to stop a child process if not completed after a timeout

I have a program that starts a child (r.out), and that child has a time limit.

I want to know how to stop running r.out after passing the time limit.

I am running the code on Linux.

This is what I have so far:

#include <unistd.h>
#include <signal.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>

#define TIME_LIMIT 1             //determine time limit

void my_function();         //supposed to include the submitted code
void alarm_handler(int);



int main()
{
    if (sigaction(SIGALRM, NULL, NULL) == -1)
        err(1, NULL);

    signal(SIGALRM, alarm_handler);    // assigning an alarm handler for SIGALRM

    alarm(TIME_LIMIT);  // install an alarm to be fired after TIME_LIMIT

    system("./r.out"); //Running the file

    alarm(0);
    return 0;
}


void alarm_handler(int sig)
{
    printf("%s" , "Time limit exceeded");
    //Here i want a code to stop the r.out file
}

Upvotes: 1

Views: 5589

Answers (1)

dbush
dbush

Reputation: 223947

In order to kill the child, you need to know its pid. You can get it if you start the program with fork and exec instead of system.

In addition to a signal handler for SIGALRM, set up one for SIGCHLD (received when a child process finishes) as well. After calling alarm to set the timer, call pause. This function will return when you get either of the two signals.

In the signal handlers you should only set a global flag. Calling printf from within a signal handler can lead to undefined behavior.

After pause returns, check each of the two flags. If the timeout flag is set, you can terminate the child with kill.

In either case, call wait to reap the child process's pid.

#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

#define TIME_LIMIT 1             //determine time limit

void alarm_handler(int);
void child_handler(int);

int timeout = 0;
int child_done = 0;

int main()
{
    pid_t pid = fork();
    if (pid == -1) {
        perror("fork failed");
        exit(1);
    } else if (pid == 0) {
        // child process
        execl("./r.out","r.out", NULL);
        perror("exec failed");
        _exit(1);
    }

    // set up the signal handlers after forking so the child doesn't inherit them

    signal(SIGALRM, alarm_handler);
    signal(SIGCHLD, child_handler);

    alarm(TIME_LIMIT);  // install an alarm to be fired after TIME_LIMIT
    pause();

    if (timeout) {
        printf("alarm triggered\n");
        int result = waitpid(pid, NULL, WNOHANG);
        if (result == 0) {
            // child still running, so kill it
            printf("killing child\n");
            kill(pid, 9);
            wait(NULL);
        } else {
            printf("alarm triggered, but child finished normally\n");
        }
    } else if (child_done) {
        printf("child finished normally\n");
        wait(NULL);
    }

    return 0;
}


void child_handler(int sig)
{
    child_done = 1;
}

void alarm_handler(int sig)
{
    timeout = 1;
}

Upvotes: 1

Related Questions