I'm having trouble looping through my shell and terminating a background process. I can't figure out the proper usage of waitpid after looking at a few questions like this for hours, so I'll describe my problem.
I need to run a sleep command for a few seconds, save that pid, run an ls command and keep my shell running while the sleep runs in the background. The next foreground process that executes, (ls) afterwards will clean up the background process after executing. So I wrote something like this
while(1) {
//Prompt user input
//Get input from user
//Parse & tokenize
//Determine if this process is to run in the background
if((strcmp(symbols[0], "&") == 0) || (strcmp(symbols[0], "&\n") == 0)) {
backgroundFlag = true;
} else {
backgroundFlag = false;
foregroundFlag = true;
}
pid_t childPid = fork();
if(backgroundFlag == true && childPid != 0) {
backgroundPid = childPid;
}
//Determine the process
if(childPid == 0) {
//Run in the background
if(backgroundFlag == true) {
printf(">>>IN CHILD(background): backgroundPid = %d\n", getpid());
backgroundPid = getpid();
} else {
foregroundFlag = true;
//debug
printf("\n>>>IN CHILD: pid = %d\n", getpid());
}
//Save this for child pid
childPid = getpid();
//Execute the command
execvp(command1[0], args1-1);
} else {
printf("\n>>>In Parent: pid = %d\n", getpid());
//this is the parent
if(backgroundFlag == false && backgroundPid == 0) {
wait(NULL);
foregroundFlag = false;
printf("\n...Child reaped: pid = %d\n", childPid);
} else if (backgroundFlag == true && backgroundPid > 0) {
pid_t return_pid = waitpid(backgroundPid, 0, WNOHANG);
if(return_pid == backgroundPid) {
printf("\n...background child reaped: pid = %d\n", backgroundPid);
backgroundPid = 0;
}
}
}
}
but the shell just runs the process, hangs and never gives me a reaped message. In that case when I hit enter, it will restart the parent to the top of the loop, but never reap the background process. What exactly am I doing wrong? I tried looping with backgroundPid and -1, WNOHANG, and a few other flags, but I just keep getting the same thing - either it will run and hang never prompting again for input until hitting ENTER, or it will run first and not allow any other foreground processes to go.
Either way it never reaps the background.
This is what i get as result of doing sleep(3) & (it's a custom sleep that echoes), then ls before completion, then ls again
progShell> ./customecho testing &
COMMAND #1: ./customecho
...The above command will be executed in background
>>>In Parent: pid = 7774
Freeing input...
backgroundPid - 7793
looping...
>>>IN CHILD(background): backgroundPid = 7793
progShell> ls
COMMAND #1: ls
>>>In Parent: pid = 7774
Freeing input...
backgroundPid - 7793
looping...
progShell>
>>>IN CHILD: pid = 7794
Makefile progShell progShell.c customecho.c customecho
customecho PID=7793: testing
Then only after hitting ENTER do i get this...
no termination...
Freeing input...
backgroundPid - 7793
looping...
Edit: played around for a while, and managed to fix a bit of the code -
while(1) {
//Determine if this process is to run in the background
if((strcmp(symbols[0], "&") == 0) || (strcmp(symbols[0], "&\n") == 0)) {
backgroundFlag = true;
backgroundFinishedFlag = false;
} else {
backgroundFlag = false;
foregroundFlag = true;
}
printf("Background finished: %d\n", backgroundFinishedFlag);
printf("Background flag: %d\n", backgroundFlag);
//Create a new process
pid_t childPid = fork();
//Determine if this process is to run in the background, and assign appropriately per process.
if(backgroundFlag == true && childPid == 0) {
backgroundPid = getpid();
printf("Background process (PID=%d)\n", backgroundPid);
} else if(backgroundFlag == true) {
backgroundPid = childPid;
}
//Determine the process we are in - this is child
if(childPid == 0) {
//debug
//Run in the background
if(backgroundFlag == true) {
printf(">>>IN CHILD(background): backgroundPid = %d\n", getpid());
} else {
//Run in the foreground
printf("\n>>>IN CHILD: pid = %d\n", getpid());
}
//Save this for child pid
childPid = getpid();
//Execute the command
execvp(command1[0], args1-1);
} else {
//this is the parent
//debug
printf("\n>>>In Parent: pid = %d\n", getpid());
printf("\t this parent's child is - %d and background id is %d\n", childPid, backgroundPid);
//There is a foreground process - execute it first.
if(foregroundFlag) {
waitpid(childPid, NULL, 0);
foregroundFlag = false;
printf("\n...Child reaped: pid = %d\n", childPid);
}
//Determine if there is a background process to be reaped
if(backgroundFinishedFlag == false && backgroundPid > 0 && (waitpid(backgroundPid, NULL, WNOHANG) > 0)) {
printf("\nTerminating background process now!\n");
backgroundFinishedFlag = true;
backgroundPid = 0;
}
}
}
It terminates child in background upon completion of next foreground process...
Just one problem is, when the background process is finished, I would like it to prompt for input again - is there any signal catch I can use to do this? Ex... after the sleep prints, it overwrites the "shellProg> " prompt looking like input and leaves a blank space to use for input.
shellProg> sne PID=9886: testing
(i hit enter or any input here otherwise no prompt)
Freeing input...
backgroundPid - 9886
looping...
shellProg>
Related
I MUST use fork() and execlp() to create and annotate the given process hierarchy:
I cannot wrap my head around when each process should be forked in order to reflect this hierarchy, add to that the non-negotiable use of execlp() which replaces the current process image.
Here is what I managed to come up with (please excuse the very non-DRY code, I'm new to these concepts):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#define oops(m) {perror(m); exit(EXIT_FAILURE);}
int main() {
pid_t pid1_1, pid1_2, pid1_1_1, pid1_1_2, pid1_2_1, pid1_2_2;
pid1_1 = fork();
if (pid1_1 < 0) {
oops("Fork Failed!");
}
// child 1.1
if (pid1_1 == 0) {
printf("I am the child %d\n", getpid());
if (execlp("./iam", "iam", "1.1", NULL) < 0)
oops("Execlp Failed!");
} else {
// grandchild 1.1.1
pid1_1_1 = fork();
if (pid1_1_1 < 0) {
oops("Fork Failed!");
}
if (pid1_1_1 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.1.1", NULL) < 0)
oops("Execlp Failed!");
}
//grandchild 1.1.2
pid1_1_2 = fork();
if (pid1_1_2 < 0) {
oops("Fork Failed!");
}
if (pid1_1_2 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.1.2", NULL) < 0)
oops("Execlp Failed!");
}
}
pid1_2 = fork();
if (pid1_2 < 0) {
oops("Fork Failed!");
}
// child 1.2
if (pid1_2 == 0) {
printf("I am the child %d\n", getpid());
if (execlp("./iam", "iam", "1.2", NULL) < 0)
oops("Execlp Failed!");
} else {
// grandchild 1.2.1
pid1_2_1 = fork();
if (pid1_2_1 < 0) {
oops("Fork Failed!");
}
if (pid1_2_1 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.2.1", NULL) < 0)
oops("Execlp Failed!");
}
// grandchild 1.2.2
pid1_2_2 = fork();
if (pid1_2_2 < 0) {
oops("Fork Failed!");
}
if (pid1_2_2 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.2.2", NULL) < 0)
oops("Execlp Failed!");
}
}
// pid > 0 ==> must be parent
printf("I am the parent %d\n", getpid());
/* parent will wait for the child to complete */
if (waitpid(-1, NULL, 0) < 0)
printf("-1 from wait() with errno = %d\n", errno);
printf("Child terminated; parent exiting\n");
exit(EXIT_SUCCESS);
}
My output shows that this hierarchy is not set up correctly. For example, manually stepping through with gdb and finishing the PID for 1.2 terminates the entire process tree (when 1.1 sub-tree should be left in tact).
Any suggestions for where I'm going wrong with logically replicating this process hierarchy would be really appreciated. Thanks!
Any suggestions for where I'm going wrong with logically replicating this process hierarchy would be really appreciated.
Check this part of code at start of your program:
pid1_1 = fork();
this will fork a child process. After this you are doing:
if (pid1_1 == 0) {
printf("I am the child %d\n", getpid());
if (execlp("./iam", "iam", "1.1", NULL) < 0)
......
That means, now the child process image will be replaced by another process image.
As per picture you have shown, a process is supposed to fork 2 child process before calling execlp(), if it is a parent process in the given process tree. Similar kind of problems are there in below part of your code.
I cannot wrap my head around when each process should be forked in order to reflect this hierarchy, .....
Look at the process tree closely and you will find it as a perfect binary tree where every internal node has 2 child and all leaf nodes are at same level.
That said, every process should create 2 child process and then call execlp() and as soon as you reach to the given height (which is 2 in your case), no child process should fork further.
I will show you how to create the process hierarchy and you can add the execlp() call to replace the current process image with some other process image.
add to that the non-negotiable use of execlp() which replaces the current process image.
I believe, here, the current process means the process which is forking of child processes and this includes the top most process (equivalent to root in tree) as well.
To create the hierarchy of process as perfect binary tree, you can do:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main (int argc, char *argv[]) {
int height;
if (argc != 2) {
printf ("Invalid number of arguments, exiting..\n");
exit (0);
}
height = atoi (argv[1]);
if (height < 0) {
printf ("Invalid input.\n"); // error handling can be better
exit (0);
}
printf ("Parent process, my pid = %d, height = %d\n", getpid(), height);
for (int i = 0; i < height; ++i) {
printf ("\nMy pid : %d, current height of tree : %d, forking..\n", getpid(), i);
pid_t pid = fork();
if (pid == -1) {
printf ("Fork failed\n");
} else if (pid == 0) {
printf ("My pid = %d, [my parent : %d], I am child 1..\n", getpid(), getppid());
// this sleep is for sequenced output, otherwise it's not needed
// sleeping for 1 second
sleep (1);
continue;
}
pid = fork();
if (pid == -1) {
printf ("Fork failed\n");
} else if (pid == 0) {
printf ("My pid = %d, [my parent : %d], I am child 2..\n", getpid(), getppid());
// this sleep is for sequenced output, otherwise it's not needed
// sleeping for 1 second
sleep (1);
continue;
}
// break the loop as the current process is done with forking 2 child process
break;
}
// ADD execlp call here
// This part of code is to just show you the hierarchy.
// If you add execlp call above then part is not needed.
while (wait(NULL) > 0);
printf ("pid %d : I am EXITING\n", getpid());
// added sleep for sequenced output, otherwise it's not needed
sleep (1);
return 0;
}
Usage: ./a.out <height_of_process_tree>
Output:
# ./a.out 0
Parent process, my pid = 50807, height = 0
pid 50807 : I am EXITING
# ./a.out 1
Parent process, my pid = 50808, height = 1
My pid : 50808, current height of tree : 0, forking..
My pid = 50809, [my parent : 50808], I am child 1..
My pid = 50810, [my parent : 50808], I am child 2..
pid 50810 : I am EXITING
pid 50809 : I am EXITING
pid 50808 : I am EXITING
# ./a.out 2
Parent process, my pid = 50811, height = 2
My pid : 50811, current height of tree : 0, forking..
My pid = 50812, [my parent : 50811], I am child 1..
My pid = 50813, [my parent : 50811], I am child 2..
My pid : 50812, current height of tree : 1, forking..
My pid : 50813, current height of tree : 1, forking..
My pid = 50814, [my parent : 50812], I am child 1..
My pid = 50815, [my parent : 50813], I am child 1..
My pid = 50816, [my parent : 50812], I am child 2..
My pid = 50817, [my parent : 50813], I am child 2..
pid 50814 : I am EXITING
pid 50815 : I am EXITING
pid 50816 : I am EXITING
pid 50817 : I am EXITING
pid 50812 : I am EXITING
pid 50813 : I am EXITING
pid 50811 : I am EXITING
Im currently working on a class work in the Introduction to Operative Systems course, and we are asked to build a simple command interpreter in C.
For this interpreter, if we put '&' before a comand we execute it in the background and if we put ';' we execute it as usual (in the foreground). We are using fork and process management functions, so when we are in the parent process, if we typed ';' we simply wait until the child process (executing the comand, for example pwd), and if we put '&' we just dont wait and we break from the switch-case on where we are.
this is the code:
err = get_arguments(buf, n, arg, MAXARG); //if we type & sleep 5 we get the sleep 5 in the arg
id = fork();
switch (id){
case -1:
errore("fork");
break;
case 0: /* child process */
/* execute the command using execvp */
pid = getpid();
pid_parent = getppid();
if(buf[0] == '&') {
printf("-U------- Child: just created (PID %d - Parent PID: %d): now executing'%s ...' in the background...\n",
pid, pid_parent, arg[0]);
} else if(buf[0] == ';') {
printf("-U------- Umea naiz: sortu berria (PID %d - Parent PID: %d): orain '%s ...' exekutatzera aurreko planoan...\n",
pid, pid_parent, arg[0]);
}
execvp(arg[0], arg);
printf("-U------- Child (PID %d): i'm here only if an error has ocurred\n",
pid);
errore("exec");
break;
default: /* parent */
pid_child = id;
pid = getpid();
printf("-G------- Parent (PID %d): child process '%s ...' (PID %d) started \n",
pid, arg[0], pid_child);
if(buf[0] == '&') { // if we want to execute in the background
break; //break and don't wait for the child to stop
} else if(buf[0] == ';') { // if it's in the foreground
/* wait until child finishes */
pid_finished = wait(&status);
if ( pid_finished != pid_child) {
errore("wait");
} else {
if (WIFEXITED(status)){ // get the return code
child_return_code = WEXITSTATUS(status);
printf("-G------- Parent (PID %d): a child process (PID %d) has finished with the %d return code\n",
pid, pid_finished, child_return_code);
}
};
}
break;
}
}
for (n = 0; n < BUFSIZE; n++) buf[n] = '\0';
write(1, "prompt$ ", 9); //write the prompt again
When I write ; pwd for example, it obviously works great. How ever, i want the parent process to know when a child process that has been executed in the background, has finished. And when if happens, print it's id and the return code.
I don't know how to do this, because when execvp is used, the code that comes after it only gets executed when an error happens. So how can I know when this child process has finished in the background?
My code was in spanish so maybe something is spelled wrong, I tried my best.
Thank you so much!
I am implementing a simple shell in C. The runCommand works fine for all the other processes but when I run a program using & (Background process). The command-line prompt gets stuck and does not prompt again until I press enter again or some other input from the keyboard.
I am not sure what exactly is causing this issue. I have implemented flush to clear the stdout but still the same error.
Main Driver Function. Runs in a loop to keep prompting the user after each command execution.
/* Simple Shell implementation. Prompts until exit received from user or any other errors */
int eggShell()
{
char *lineRead;
char **command;
char *commandsPathFull = getenv("PATH"); //Get the $PATH in the environment
while (1)
{
fflush(stdout);
signal(SIGCHLD, sigchld_handler);
lineRead = readline("esh> ");
command = parseCommand(lineRead, " ");
int backgroundTask = 0;
if (command[0] != NULL)
{
if (strcmp(command[0], "exit") == 0)
{
free(command);
free(lineRead);
return 1;
}
if (command[1] != NULL)
{
for (size_t i = 1; command[i] != (char *)NULL; i++)
{
if (strcmp(command[i], "&") == 0)
{
backgroundTask = 1;
}
}
}
if ((validCommand(command[0], commandsPathFull)) == 1)
{
printf("Running Command\n");
runCommand(command, backgroundTask);
free(command);
free(lineRead);
}
}
fflush(stdout);
}
free(lineRead);
free(command);
return 1;
}
The Runcommand forks a new process for each command. If the command is not background command parent does not wait for the child to finish.
/* Receives a command and runs it using fork
returns 1 on successfull execution.*/
int runCommand(char **command, int bckTask)
{
pid_t pid, wpid;
int status;
pid = fork();
// Child process
if (pid == 0)
{
//Execute the command
if (execvp(command[0], command) == -1)
{
perror("esh Exec:");
}
exit(EXIT_FAILURE);
}
// Error forking
else if (pid < 0)
{
perror("esh fork error:");
}
// Parent process
else
{
// wait until either the processes are exited or killed
// If not a background task
if (bckTask != 1)
{
// {
do
{
wpid = waitpid(pid, &status, WUNTRACED);
if (wpid == -1)
{
perror("Esh Wait PID:");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
//printf("Foreground Task\n");
//waitpid(pid, &status, 0);
}
else if (bckTask == 1)
{
printf("Command %s | Background PID: %d\n", command[0], pid);
return 1;
// do
// {
// wpid = waitpid(-1, &status, WNOHANG);
// printf("Background pid: %d\n", pid);
// if (wpid > 0)
// {
// printf("Completed Background pid: %d\n", wpid);
// }
// } while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
}
return 1;
}
Current Output:
esh> ls
Running Command
esh esh.c Makefile README.md
esh> echo "Hello World"
Running Command
"Hello World"
esh> echo "Hello 2" &
Running Command
Command echo | Background PID: 16618
esh> "Hello 2" &
(At this point the cursor is stuck. I need to press enter again to get the prompt)
esh>
I am trying to fork my C application, running on an embedded linux environment, and get its return value for failure/success analysis.
I looked at similar questions (e.g. this, this, this, this and some other Q/A..) but still can't get it to work.
code:
static int fork_test(const char *src, const char *dst)
{
int childExitStatus;
pid_t pid;
int status;
DEBUG_PRINT("forking");
pid = fork();
if (pid == 0) { // child
sleep(2);
DEBUG_PRINT("child - exiting");
exit(1);
}
else if (pid < 0) {
return -1;
}
else { // parent
int i;
for (i = 0 ; i < 10 ; i++)
{
pid_t ws = waitpid(pid, &childExitStatus, WNOHANG);
if (-1 == ws)
{
DEBUG_PRINT("parent - failed wait. errno = %d", errno);
return -1;
}
if (0 == ws)
{
DEBUG_PRINT("parent - child is still running");
sleep(1);
continue;
}
}
if (10 == i)
return -1;
DEBUG_PRINT("parent - done waiting");
if (WIFEXITED(childExitStatus)) /* exit code in childExitStatus */
{
DEBUG_PRINT("parent - got status %d", childExitStatus);
status = WEXITSTATUS(childExitStatus); /* zero is normal exit */
if (0 != status)
{
DEBUG_PRINT("parent - picked up bad exit status");
return status;
}
return 0;
}
else
{
DEBUG_PRINT("parent - bad exit route");
return -1;
}
}
}
This provided this output:
forking
parent - child is still running
parent - child is still running
parent - child is still running
child - exiting
parent - failed wait. errno = 10
note that errno=10 means ECHILD.
so i tried to add:
...
DEBUG_PRINT("forking");
signal(SIGCHLD,SIG_DFL);
pid = fork();
...
(or with SIG_IGN) with no difference.
I can successfully add a signal handler for SIGCHLD, and might be able to wait for signal, instead of the child process, with sigwait() or the likes, but it seems like a bad solution..
Any idea what I'm missing here?
$ uname -mrso
Linux 3.18.20 armv7l GNU/Linux
Your code nicely tests for "errors". Good.
But the code unfortunately misses to catch the case you are after, the one where waitpid() actually returns the child's PID.
You could achieve this like so:
for (i = 0 ; i < 10 ; i++)
{
pid_t ws = waitpid(pid, &childExitStatus, WNOHANG);
if (-1 == ws)
{
DEBUG_PRINT("parent - failed wait. errno = %d", errno);
return -1;
}
else if (0 == ws)
{
DEBUG_PRINT("parent - child is still running");
sleep(1);
continue;
}
DEBUG_PRINT("parent - successfully waited for child with PID %d", (int) ws);
break;
}
Some days ago, I asked here how to start a program using C without using fork(). This solution is working fine.....except that I can't kill this child process!
My program (in this case, 'rbfeeder') has some threads....and when I send kill signal, only threads are killed (I think). What am I doing wrong?
This is the code used to 'start' rbfeeder:
/*
* Start dump1090, if not running
*/
void startDump(void) {
if (p_dump != 0) {
log_level(8, "Looks like dump is already running.\n");
return;
}
pid_t ret = run_cmd("/home/jmaurin/dev/client/rbfeeder");
if (ret != 0) {
log_level(8, "Ok, started! Pid is: %i\n", ret);
p_dump = ret;
sendStats();
} else {
log_level(8, "Error starting dump1090\n");
p_dump = 0;
sendStats();
}
return;
}
And this is the code to 'stop':
void stopDump(void) {
if (checkDumpRunning()) {
log_level(3, "Dump is running, let's try to kill.\n");
if (kill(p_dump, SIGKILL) == 0) {
log_level(3,"Succesfull kill dump!\n");
sendStats();
return;
} else {
log_level(3,"Error killing dump.\n");
return;
}
} else {
log_level(3, "Dump is not running.\n");
}
return;
}
and run_cmd function:
pid_t run_cmd(char *cmd) {
pid_t pid, ret;
char *argv[] = {"sh", "-c", cmd, NULL};
int status, s;
posix_spawn_file_actions_t file_actions;
posix_spawn_file_actions_t *file_actionsp;
s = posix_spawn_file_actions_init(&file_actions);
if (s != 0)
return 0;
//STDERR_FILENO
s = posix_spawn_file_actions_addclose(&file_actions,STDERR_FILENO);
if (s != 0)
return 0;
file_actionsp = &file_actions;
//printf("Run command: %s\n", cmd);
status = posix_spawn(&pid, "/bin/sh", file_actionsp, NULL, argv, environ);
if (status == 0) {
log_level(8, "Child pid: %i\n", pid);
ret = pid;
/*
if (waitpid(pid, &status, 0) != -1) {
printf("Child exited with status %i\n", status);
} else {
perror("waitpid");
}
*/
} else {
// printf("posix_spawn: %s\n", strerror(status));
ret = 0;
}
return ret;
//printf("End of run\n");
}
p_dump is a global variable to hold PID.
This image is when my 'client' receive the command (over ethernet) to start external program:
Then, an HTOP on the same machine....see that PID are the same, which means that my variable is correct:
Then, I've sent an 'stop' command and my client executed 'stopDump', but one process still running (the other threads from same program are 'killed'):
The external program doesn't 'spawn/fork' itself, but it does have threads.
Your kill is completing successfully, because the process is becoming a zombie, (The Z in the status column in HTOP). A zombie is a process that still has metadata in the kernel, but is not actually running. To get rid of the zombie, the parent has to wait on the process. As your process is the parent, adding a call to waitpid(p_dump) after the kill succeeds should handle this.
The answer by user1937198 worked fine, but I found another way that doesn't need to call any function, like 'waitpid'.
struct sigaction sigchld_action = {
.sa_handler = SIG_DFL,
.sa_flags = SA_NOCLDWAIT
};
sigaction(SIGCHLD, &sigchld_action, NULL);
At least in my case, it's preventing zombie proccess after kill. It's works fine.