Create multiple child processes and run execvp - c

I have a function in C which creates a child process and makes it run execvp.
int Execute(char **arg)
{
pid_t pid;
int status;
if ((pid=fork()) == 0)
{
execvp(arg[0],arg);
perror("Execvp error");
exit(1);
}
else if (pid > 0)
{
waitpid(pid, &status, 0);
}
else
{
perror("Fork error");
exit(2);
}
}
Now I want to alter the function to actually run execvp several times (for example 5), and make the parent process wait for all the children to finish. Tried wrapping it all in for loop, but execvp gets executed just once. I know that basically execvp 'replaces' the current program code, but have no idea whether the iteration does not go on.
Thank you for your help!

First, loop around the process creation collecting the child PIDs
pid_t pid[5];
int i;
for (i = 0; i < 5; i++) {
if ((pid[i]=fork()) == 0) {
execvp(arg[0],arg);
perror("Execvp error");
_exit(1);
}
if (pid[i] < 0) {
perror("Fork error");
}
}
Second, loop around the waitpid call for every valid PID.
for (i = 0; i < 5; i++) {
if (pid[i] > 0) {
int status;
waitpid(pid[i], &status, 0);
if (status > 0) {
// handle a process sent exit status error
}
} else {
// handle a proccess was not started
}
}

Related

Creating a new child process when old one is terminated in C

I've included code that creates a series of child processes to divide the work for a task. There's a random chance for it to terminate (handled by the word_count function from which it calls abort()) and on this event, it should create a new child process to replace it. However, the program is being blocked on the read. I know this code is messy, but I want understand the problem before cleaning it up.
int pipes[nChildProc][2]; //pipe fd[0] is read end, fd[1] is write end
long child_f_size = fsize / nChildProc;
pid_t pids[nChildProc];
//start dividing the work among child processes
for(int i = 0; i < nChildProc; ++i) {
//srand(time(NULL));
//int crash = ((rand() / RAND_MAX + 1.0) < crashRate) ? 1 : 0;
if(pipe(pipes[i]) != 0) {
printf("Failed to create pipe.\n");
exit(1);
}
pid_t pid = fork();
FILE *child_fp;
pids[i] = pid;
if(pid < 0) {
printf("Failed to create child process.\n");
exit(1);
}
else if(pid == 0) { //child process
count_t temp_count = readFromFile(child_fp, fsize, child_f_size, char* name, int i, int nChildProc);
//IPC with the main process
if(write(pipes[i][1], &temp_count, sizeof(temp_count)) == -1)
printf("failed to write to pipe.\n");
close(pipes[i][1]);
close(pipes[i][0]);
exit(0); //deallocate process' memory space
}
}
//wait for a children to finish
int ret, status, i = 0;
while(wait(NULL) != -1) { // while there are children to wait on
ret = waitpid(pids[i], &status, WUNTRACED);
if(ret == -1) {
continue;
}
if(ret != 0) {// didn't exit normally
if(pipe(pipes[i]) != 0) {
printf("Failed to create pipe.\n");
exit(1);
}
pid_t pid = fork();
FILE *child_fp;
pids[i] = pid;
if(pid < 0) {
printf("Failed to create child process.\n");
exit(1);
}
else if(pid == 0) { //child process
count_t temp_count = readFromFile(child_fp, fsize, child_f_size, char* name, int i, int nChildProc);
//IPC with the main process
if(write(pipes[i][1], &temp_count, sizeof(temp_count)) == -1)
printf("failed to write to pipe.\n");
close(pipes[i][1]);
close(pipes[i][0]);
exit(0); //deallocate process' memory space
}
}
i = (i + 1) % nChildProc;//loop back to detect more processes that were terminated
}
long bytes;
count_t temp;
temp.linecount = 0;
temp.wordcount = 0;
temp.charcount = 0;
//add up all the values from children to count
printf("time to read.\n");
for(unsigned int j = 0; j < nChildProc; ++j) {
if((bytes = read(pipes[j][0], &temp, sizeof(temp))) < 0) {//blocked here
printf("Failed to read from pipe {%d}.\n", j);
exit(1);
}
if(bytes != 0) {
count.linecount += temp.linecount;
count.wordcount += temp.wordcount;
count.charcount += temp.charcount;
}
close(pipes[j][1]);
close(pipes[j][0]);
}
A couple of issues jump out:
if(ret != 0) {// didn't exit normally you've confused ret (which is the pid) for status (which is the exit code of the child)
You can't call wait on a process twice, since calling wait allows the system to release the resources associated with the process. You have several options on how to rewrite this code:
while(wait(NULL) != -1) { // while there are children to wait on
ret = waitpid(pids[i], &status, WUNTRACED);
One easy way is to use wait then lookup in the array which index it belongs to.
while((pid = wait(&status)) {
if (pid == -1) { // no children to wait on
break;
}
for(int i = 0; i < nChildProc; ++i) {
if (pid == pids[i]) break;
}
if (i >= nChildProc) {
unexpected_pid_do_something_smart();
}
// Leave the rest of the loop the same
Note: I didn't compile or test the above code.

waitpid hangs even though child process is dead

i have the following function:
int run_func(command history[MAX_INPUT_SIZE], char** args, int capacity) {
int need_to_wait = 1;
int i = 0;
char* arg = args[0];
int status;
while (arg != NULL) {
if (strcmp(arg, "&") == 0) {
need_to_wait = 0;
break;
}
arg = args[i++];
}
pid_t wait_pid;
pid_t pid = fork();
int res;
if (pid == 0) {
res = execvp(args[0], args);
if (res == -1) {
printf("exec failed\n");
fflush(stdout);
return 0;
}
} else if (pid < 0) {
printf("fork failed\n");
fflush(stdout);
return 0;
} else {
if (need_to_wait){
do {
wait_pid = waitpid(pid, &status, 0);
} while(!WIFEXITED(status) && !WIFSIGNALED(status));
}
history[capacity - 1].pid = pid;
}
return 1;
}
the issue I have is that the bottom while loop, hangs and doesn't stop whenever I get an invalid command such as 'hello' from the user from the terminal until I press enter again.
this function is being called from another function that receives input from the user.
Copying comment into an answer.
Side issues:
Error messages should be printed to stderr, not stdout.
There's no need to save or test the return value from execvp() — if it returns, it failed; if it succeeds, it does not return.
Main observation:
You should almost certainly have an exit() or _exit() instead of return 0; in the error handling code after execvp(). When the command fails (hello?), then you end up with two processes running — one from the failed execvp() and one is the parent process. This is apt to confuse everything as you have two processes trying to read the terminal at the same time.

Create background process in C using sigset()

I am making my own shell in C. This is my basic code for running a process:
pid_t childpid;
int status;
int ret = 0;
if (strcmp(line[0], "exit") == 0) {
return;
}
childpid = fork();
if (childpid >= 0) {
if (childpid == 0) {
ret = execvp(line[0], &line[0]);
if (ret == -1) {
printf("ERROR\n");
exit(0);
}
exit(ret);
} else {
waitpid(childpid, &status, 0);
ret = WEXITSTATUS(status);
}
} else {
perror("fork");
exit(-1);
}
Where line is a "string array" holding the commands to run.
Now say I want to run a background process - I have to use sigset. A parent doesn't wait for a backgrounded child process, right? How do I handle this without the child becoming a background process?

unexpected termination of program running in a loop

This is a cleaned code that I'm using in order to execute shell commands.
Though isExit is always 0 and loop should run as long as it is !isExit, my program terminates after one loop with the command ls as argument to execute.
Does anyone have any idea?
The output is OK (ls) but then program terminates.
The code is written in C, on Eclipse.
Running on Ubuntu 12 which is running on VM over Windows 7.
int main() {
int numberOfCommands, numOfWords, i, isExit = 0, isBackGround = 0, isSucces;
char input[256];
char *cmdAndArgs[256];
char *commands[256];
do{
// gets and parses user command...
ExecuteCmd(cmdAndArgs);
} while (!isExit);
return EXIT_SUCCESS;
}
void ExecuteCmd(char *cmdAndArgs[]){
pid_t pid;
pid = fork();
if (pid != 0) {
execvp(cmdAndArgs[0], cmdAndArgs);
exit(0);
} else {
waitpid(pid, &status, 0);
}
}
You're running the execvp in the parent process, not in the child. the logic:
pid_t pid;
pid = fork();
if (pid != 0) {
execvp(cmdAndArgs[0], cmdAndArgs);
exit(0);
} else {
waitpid(pid, &status, 0);
}
should be reversed to:
pid_t pid;
pid = fork();
if (pid == 0) { /* Child */
execvp(cmdAndArgs[0], cmdAndArgs);
exit(0);
} else if (pid == -1) {
perror("fork");
} else {
waitpid(pid, &status, 0);
}
the return codes from fork() are: -1 == fork failed (use errno to determine the reason). 0 == I am the child. > 0 == I am the parent. See the reference for fork under the RETURN VALUE section.
Is it possible that you have a buffer overflow in // gets and parses user command...? If you write past the allocated space, you can end up overwriting the value of isExit

Concurrent processes in C

How can I have 3 processes running in parallel? Is this solution below correct?
In my solution I put some code to see the time elapsed and I think this is tunning in sequential mode. I need to put pid1, pid2 and pid3 running at the same time.
pid = fork();
if(pid == 0) {
//code...
exit(EXIT_SUCCESS);
} else if(pid > 0) {
pid1 = fork();
if(pid1 == 0) {
//pid1 code...
exit(EXIT_SUCCESS);
} else if(pid1 > 0) {
waitpid(pid1, &status, 0);
} else {
printf("Fork error %d.\n", errno);
}
pid2 = fork();
if(pid2 == 0) {
//pid2 code...
exit(EXIT_SUCCESS);
} else if(pid2 > 0) {
waitpid(pid2, &status, 0);
} else {
printf("Fork error %d.\n", errno);
}
pid3 = fork();
if(pid3 == 0) {
//pid3 code...
exit(EXIT_SUCCESS);
} else if(pid3 > 0) {
waitpid(pid3, &status, 0);
} else {
printf("Fork error %d.\n", errno);
}
waitpid(pid, &status, 0);
}
You keep waiting for one child to complete before you launch the next. Try something like:
for (int i = 0; i < 3; ++i)
{
pid = fork();
if (pid < 0)
error
if (pid == 0)
{
child does thing
exit
}
}
for (int i = 0; i < 3; ++i)
{
wait(&status);
}
EDIT
So just change your code to something like this and wait at the end.
if (pid2 == 0)
{
//pid2 code...
exit(EXIT_SUCCESS);
}
else
if (pid2 < 0)
{
printf("Fork error %d.\n", errno);
}
//....same outline for 3, etc.
Check out my wrap program, specifically the code for wrapc. It forks itself twice, execs one child into wrap, reads, writes to wrap, then reads back in the other child.
Your question is somewhat vague -- are you seeing 3 processes running in parallel or not?
the way your code is written you are exiting the child processes straight away.

Resources