Reputation: 27
I created multiple child processes by fork() and had them run executable file by execl().
I want to check if there is any execl() that is failed (ex: try to execute non-exist file). By, try to execl() all the programs and if one of them is failed then return 1 before start communicates with any programs.
here is reference code, (assume all the setups are correct)
#DEFINE NUMBEROFCHILD 4
char** exeFile = {"./p1", "./p2", "./p3", "nonexist"); //"nonexist" is a non-exist program
int main(int argc, char** argv){
pid_t childPID [numberOfChild];
for (int i = 0; i<numberOfChild; i++) {
//setting up pipes
pid_t childPID[i] = fork();
if(childPID[i] < 0) {
//close all pipes and quit
}else if (childPID[i] == 0) {
//redirect pipe
execl(exeFile[i],"args",(char*)0;
return 1;
//I'm expecting this to return when it try to execute "nonexist"
//but it didn't and keep running successed execl()
}else {
//close un-use pipes
}
}
while(true) {
for (int i = 0; i<numberOfChild; i++) {
//communicate with childs through pipe
}
}
for (int i = 0; i<numberOfChild; i++) {
//close reminded pipes
if (waitpid(childPID[i], NULL, 0) == -1){
return 1;
}
}
return 0;
}
This program still sent message to "nonexist" (but didn't receive anything back from it as expect).
Are there anyways to achieve my goal? Thank you!
Upvotes: 1
Views: 3043
Reputation: 7923
The only robust (yet quite exotic, an maybe not very portable) way to achieve your goal is to use ptrace
. The parent sets PTRACE_TRACEEXEC
option, forks all children, and wait()
in the loop. The child does
} else if () {
ptrace(PTRACE_TRACEME, ...);
execl(...);
}
The parent shall keep looping wait
until all children report either PTRACE_EVENT_EXEC
or an exit. In first case, the exec
was successful, and the child is stopped. When you know that every child reported, and you are satisfied with their state, do ptrace(PTRACE_DETACH, ...)
on all of them and proceed as desired.
Upvotes: 0
Reputation: 30718
You can arrange give the child one end of a pipe()
, set to close-on-exec.
After the execl()
fails (i.e. if the call returns), the child will write()
to the pipe. If the parent receives anything on its end of the pipe (checking with poll()
or similar), then it knows the child has failed.
If the message from the child contains an identifier of the child, then the pipe can be shared across all the children. Try to keep the write()
small enough to be atomic, though!
Upvotes: 3