1

So my objective is to spawn n child processes and let them run concurrently(each one exec's a different program).

The tricky thing is that, for each one of them, I have to assure that they don't exceed a predetermined amount of time executing.(not globally, but relative to it's start time).

I only have a working code that spawns the processes, execs each one and then waits for all of them to finish.(based on this answer).

I've tried to use SIGALRM but I can not figure out how to set one alarm per fork so it does timeout each process relative to its start time and not based on the parent's starting time.

Regarding time measuring I'm not sure how could I get the execution time of each fork.

In a regular situation I would just get the delta of start and finishing time inside the child code, but in this case and if I'm not mistaken all of them execute something so I lose any reference of the following code.

for (int j = 0; j < prog_count; j++) {
            pid_t monitor_pid = fork();
            if(monitor_pid==0){
                execvp(programs[j]->executable, programs[j]->exec_args);
            }

    }
while ((wpid = wait(&status)) > 0);

I've seen a lot of examples that spawn one child and control it's execution time with a sleeping timer process that runs in parallel, but i can't figure out how to extend that solution to my situation.

Fgbruna
  • 127
  • 7
  • regarding: `execvp(programs[j]->executable, programs[j]->exec_args);` The `exec*()` functions can fail. So this statement should be followed by: `perror( "exec*() failed" ); exit( EXIT_FAILURE );` – user3629249 Aug 26 '19 at 23:34
  • You could use the `setitimer()` function rather than `alarm()` – user3629249 Aug 26 '19 at 23:36

1 Answers1

1

From man alarm

Application Usage

[...] A new process image created by one of the exec functions inherits the time left to an alarm signal in the old process' image.

So you can try to write something like:

#define LIMIT_TIME_SEC 10

for (int j = 0; j < prog_count; j++) {
    pid_t monitor_pid = fork();
    if(monitor_pid==0){
        alarm(LIMIT_TIME_SEC);
        execvp(programs[j]->executable, programs[j]->exec_args);
    }

}
while ((wpid = wait(&status)) > 0);

In this code, the alarm function is called after the fork so it affects only the child process. When time indicated to alarm is reached, the SIGALARM is send to the process launched by exec function which will terminates it if it doesn't handle the signal.


If each sub-program has a different timeout, you can replace LIMIT_TIME_SEC by some array indexed like programs array.


If you want to know how much time took child processes to execute, you can built something like that:

  • record the child pid in program struct add the necessary member (pid_t pid;)
  • record the time at which the child has been launched, from parent, add member (time_t launch_time;)

for (int j = 0; j < prog_count; j++) {
    pid_t monitor_pid = fork();
    
    if (monitor_pid==0)
    {
        /** in child **/
        /* set a limit time of execution */
        alarm(LIMIT_TIME_SEC);
        /* execute the program */
        execvp(programs[j]->executable, programs[j]->exec_args);
    }
    else
    {
        /** in parent **/
        /* record the starting time */
        programs[j]->launch_time = time(NULL);
        
        /* record the pid */
        programs[j]->pid = monitor_pid;
    }

}
while ((wpid = wait(&status)) > 0)
{
    /* a child terminates, let's find it */
    for (int j = 0; j < prog_count; ++tj)
    {
        if (programs[j]->pid == wpid)
        {
            /* print process information */
            printf("program %s terminated in %df seconds\n",
                    programs[j]->executable,
                    difftime(time(NULL) - programs[j]->launch_time));

            /* process found, not necessary to go further */
            break;
        }
    }
}
Community
  • 1
  • 1
Mathieu
  • 8,840
  • 7
  • 32
  • 45
  • Thanks for the reply, it is definitely working as intended.I guess i got caught up reading answers to specific problems here in stackoverflow and just skimmed the alarm man page.Now i just have the time measuring thing left, but i'm still a little confused on where should i put that logic.I could start a timer right after alarm, but where would i calculate the elapsed time? – Fgbruna Aug 26 '19 at 17:59
  • have the parent code always save the PID of the child process. Then when the parent thinks the child has run for long enough, call `kill( childpid, -9 )` to kill the specific child process – user3629249 Aug 26 '19 at 23:41