The problem is that either the parent or child process is not exiting. The child process prints its message and then the program hangs. Could be stuck at system() because this doesn't happen when the system() call is removed. The unhide_string() filters out non-letters and args is defined elsewhere. The command "cmd" that's passed to get_page() is valid.
int get_page(char* cmd) {
system(cmd);
return 0;
}
int main() {
char* args_s = unhide_string(args);
if (args_s == NULL) {
printf("Please run me again :)\n");
}
if (fork() == 0) {
get_page(args_s);
printf("Guess what I did :)\n");
}
free(args_s);
return 0;
}
Fixed by having the parent wait for the child process to finish. This allowed the program to properly terminate.
Revised fork code:
if (fork() == 0) {
get_page(args_s);
printf("Guess what I did :)\n");
} else {
waitpid(-1, NULL, 0);
}
Related
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.
I have written a code which will call exec as shown below. But if I call isValid from main, both child and parent process are returning and I am getting the output twice.
I want to get the out of the exec and want to check the return value in main only once. which process I need to exit inorder to make this work properly?
int isValid(void)
{
int number, statval;
int child_pid;
child_pid = fork();
if(child_pid == -1) { printf("Could not fork! \n"); exit( 1 ); }
else if(child_pid == 0)
{
execl(...); // Child
}
else
{
// Parent
waitpid( child_pid, &statval, WUNTRACED );
if(WIFEXITED(statval))
{
if (WEXITSTATUS(statval) == 0)
return 1;
else
return 0;
}
else
printf("Child did not terminate with exit\n");
}
return 0;
}
int main(void)
{
if (isValid())
{
printf("Valid\n");
}
else
{
printf("Invalid\n");
}
}
The doubled output may occur when the execl fails. The code above does not check the execl return value. Actually the execl returns only in case of failure so there is no need to check the returned value but it is necessary to handle error anyway.
EDIT:
If the exec fails then:
Child's isValid() returns 0 at the end of the function and the main prints "Invalid"
Parent waits for the child exit and then WIFEXITED is true because child exits and WEXITSTATUS is 0 because the child exits normally. Parent's isValid returns 1 and "Valid" is printed.
#include <sys/shm.h>
int *tabPID;
int isValid(void)
{
int number, statval;
if(fork() == 0){
tabPID[1] = getpid();
execl(...); // Child
return -1;
}
// Parent
tabPID[0]=getpid();
usleep(10);//as Basile Starynkevitch suggests
waitpid(tabPID[1], &statval, WUNTRACED );
if(WIFEXITED(statval))
{
if (WEXITSTATUS(statval) == 0)
return 1;
else
return 0;
}
else
printf("Child did not terminate with exit\n");
return 0;
}
int main(void)
{
shmId = shmget(1234, 2*sizeof(int), IPC_CREAT|0666);
tabPID = shmat(shmId, NULL, 0);
if (isValid())
{
printf("Valid\n");
}
else
{
printf("Invalid\n");
}
}
You probably should do some tiny things (perhaps some usleep(3) for a few milliseconds) after the fork but before the waitpid to have some real chance to get the waitpid(2) call succeed. Otherwise, it could happen that the other process won't be scheduled to run.
BTW, you should test the return value from waitpid, .e.g. code
statval = 0;
pid_t wpid = waitpid(child_pid, &statval, WUNTRACED );
if (wpid>0) {
assert (wpid == child_pid);
if (WIFEXITED(statval)) {
if (WEXITSTATUS(statval) == 0)
return 1;
At last, regarding the title of your question, read job control wikipage, read several chapters of Advanced Linux Programming, and consider using daemon(3)
Also, just after the execl be sure to put
perror("execl");
exit(EXIT_FAILURE);
to handle the rare case of execl failure.
I am implementing a shell.
When attempting a command other than changing directories, execvp() runs, the child terminates and a new child is created. When I change directories, the child does not terminate and a new child is created. Here is a sample of my code:
for(;;) {
printf("bash: ");
parse();
...
pid_t pid = fork()
if (pid == 0)
if (!strcmp(line[0], "cd"))
if (!line[1]) (void) chdir(getenv("HOME"));
else (void) chdir(line[1]);
else execvp(line[0], line);
...
if (pid > 0) {
while (pid == wait(NULL));
printf("%d terminated.\n", pid);
}
}
cd ../; ls; runs correctly, except I have to Ctrl+D twice to end the program.
Though, if I pipe the same information (ie. mybash < chdirtest), it runs correctly once, terminates the child, runs again except in the original directly, then terminates the final child.
cd should not be invoked through a child process, the shell itself should change its current directory (that's the property of an internal command: modify the process of the shell itself).
A (primitve) shell should looks like:
for(;;) {
printf("bash: ");
parse();
// realize internal commands (here "cd")
if (!strcmp(line[0], "cd")) {
if (!line[1]) (void) chdir(getenv("HOME"));
else (void) chdir(line[1]);
continue; // jump back to read another command
}
// realize external commands
pid_t pid = fork()
if (pid == 0) {
execvp(line[0], line);
exit(EXIT_FAILURE); // wrong exec
}
// synchro on child
if (pid > 0) {
while (pid == wait(NULL));
printf("%d terminated.\n", pid);
}
}
I have a little problem with signal function.
My program in a brief:
void sigfunc(int sn)
{
if(sn == SIGINT)
printf("SIG TEXT!");
}
int main(void)
{
...
// spawn 10 children and execl my another programs
for (i = 0; i < 10; i++) {
pid = fork();
if (pid != 0) {
signal(SIGINT, sigfunc);
continue;
} else if (pid == 0) {
execl(pathtoprog[i], progname[i], NULL);
}
// wait for sig (only parent waits because programs from execl have their own while(1))
if(pid > 0)
while(1) {}
}
Problem is simple: when I press Ctrl+C I'll see SIG TEXT! but programs started by execl will crash/hang(I'm not sure, because they stop working but still exists in process monitor). How to write this sigfunc to react only for parent process and leave all children with execl alone?
I googled for answer but all the threads I found seemed to suggest using an alternative way to terminate a child process: the _Exit() function.
I wonder if using "return 0;" truly terminate the child process? I tested that in my program (I have waitpid() in the parent process to catch the termination of the child process), and it seemed to work just fine.
So can someone please confirm on this question? Does a return statement truly terminate a process like the exit function or it simply sends a signal indicating the calling process is "done" while the process is actually still running?
Thanks in advance,
Dan
Sample Code:
pid = fork()
if (pid == 0) // child process
{
// do some operation
return 0; // Does this terminate the child process?
}
else if (pid > 0) // parent process
{
waitpid(pid, &status, 0);
// do some operation
}
Using the return statement inside the main function will immediately terminate the process and return the value specified. The process is terminated completely.
int main (int argc, char **argv) {
return 2;
return 1;
}
This program never reaches the second return statement, and the value 2 is returned to the caller.
EDIT - Example from when the fork happens inside another function
However if the return statement is not inside the main function, the child process will not terminate until it has reached down into main() again. The code below will output:
Child process will now return 2
Child process returns to parent process: 2
Parent process will now return 1
Code (tested on Linux):
pid_t pid;
int fork_function() {
pid = fork();
if (pid == 0) {
return 2;
}
else {
int status;
waitpid (pid, &status, 0);
printf ("Child process returns to parent process: %i\n", WEXITSTATUS(status));
}
return 1;
}
int main (int argc, char **argv) {
int result = fork_function();
if (pid == 0) {
printf ("Child process will now return %i\n", result);
}
else {
printf ("Parent process will now return %i\n", result);
}
return result;
}