How bring back child process to background - c

I asked quesiton, before this. And Thanks to help from others, I made sample code that runs bc command continuously until I enter '1'.
In this code, I use tcsetpgrp() to give child the control of terminal.
When I run the code, bc command works well. However, when I enter 'quit', child process receives SIGSTP and code is ended. (What I want is continuing while loop!!)
int main()
{
while(1){
int n;
scanf("%d", &n);
execute();
if (n == 1)
break;
}
}
void execute()
{
char *args[] = {"bc", 0};
pid_t pid = fork();
if (pid == 0){
execvp("bc", args);
}
if (pid > 0){
setpgid(pid, pid);
tcsetpgrp(STDIN_FILENO, getpgid(pid);
wait(0);
}
}
I think that I should change child to background and parent to foreground after execvp. However, after execvp function, child process terminates, so it seems possible to do that.
So, I also added
signal(SIGSTP, handler);
where handler function is
void handler(int sig){
tcsetpgrp(STDIN_FILENO, getpgid(getppid()));
exit(0);
}
However, handler function does not executed when I enter 'quit' while bc command is executed.
So, now, I don't know how to solve it. I really want to handle this problem. Please help me..

Related

C linux tcsetpgrp stops parent process even after calling to ignore it

Ok so I wrote this tiny program in order to test how tcsetpgrp behaves and in general handling signals, now I've seen a few posts here asking about tcsetpgrp but for some reason the solutions in those posts are not working for me.
int main() {
signal(SIGINT,sig_handler);
static char line[4096];
int line_num = 0;
pid_t id = fork();
if(id == 0 )
{
while (fgets(line, 4096, stdin)) {
printf("\nyou wrote something");
}
}
else
{
int pgid_child = id;
printf("child group : %d", pgid_child);
signal(SIGTTOU, SIG_IGN);
tcsetpgrp(0, pgid_child);
wait(NULL);
}
return 1;
}
what I expect to happen:
the terminal will ask for input as long as the user continues to write into it, but if the user presses ctrl+c then the program will end.
what actually happens:
as soon as the child process is set to foreground group the SIGTTOU is called to all other processes and the parent process also stops, even though I've asked to ignore that signal.
does anyone know why is this happening?

Fork() with multiple children and with waiting for all of them to finish

I want to create a program in C, where I use fork() to create multiple children, then wait for all of them to finish and do parent code (only once).
I tried using for loop and two forks but I there is a problem: either parent code isn't running at the end or children are not running parallel.
//Number of processes I want to create
int processes = 6;
pid_t *main_fork = fork();
if(main_fork ==0){
for(int i=0;i<processes;i++){
pid_t *child_fork = fork();
if(child_fork ==0){
// child code
exit(0);
}
else if(child_fork >0){
//And here is the problem, with the wait: children don't
//run parallel and if I delete it, the main parent code doesn't run
wait(NULL);
}else{
// Child fork failed
printf("fork() failed!\n");
return 1;
}
}
}else if(main_fork >0){
wait(NULL);
//Main parent code - here I want to do something only once after all
//children are done
}else{
// Main fork failed
printf("fork() failed!\n");
return 1;
}
If somebody could could fix my code, or write a better solution to this problem I would be so grateful!
If you want all the children to run in parallel, you have to do the wait after all the children has been started. Otherwise you start a child, wait for it to finish, start a new one, wait for that to finish, start a third one, wait for the third one to finish, and so on...
So what you typically want to do is to start all the children and put all the pid_t in an array, and when you are finished you may call wait() for each pid_t
This is the simple, and good enough solution for your case.
Here is a sample code that you can fit to your problem:
pid_t children[processes];
for(int i=0; i<processes; i++)
{
pid_t child = fork();
if(child == 0)
{
// child code
....
// We call _exit() rather than exit() since we don't want to clean up
// data structures inherited from parent
_exit(0);
}
else if (child == -1)
{
// Child fork failed
fprintf(stderr, "myprog: fork failed, %s", strerror(errno));
// Do real cleanup on failure is to complicated for this example, so we
// just exit
exit(EXIT_FAILURE);
}
children[i] = child;
}
// Do something if you want to do something before you expect the children to exit
....
for(int i=0; i<processes; i++)
{
pid_t child = children[i];
int status;
waitpid(child, &status, );
// Do something with status
}
Naturally this is not a complete example that fits any situation. Sometimes you have to tell the children when they should exit. Other times the children are not started/stopped in one go, and you have to play with asynchronous events, and so on...

Shell prompt returns before the child process complets via putty

Please review the following code example:
int main() {
pid_t childpid;
char buf[100] = {0};
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0) {
sprintf(buf,"child process id: %d\n",getpid());
write(1,buf,strlen(buf));
}
else {
sprintf(buf,"parent process id: %d\n",getpid());
write(1,buf,strlen(buf));
// fix here
wait(&childpid);
}
return 0;
}
When run directly on terminal on Linux machine, the output as expected:
[user#192 ~]$ ./test
parent process id: 28788
child process id: 28789
On another hand running the same via Putty brings:
parent process id: 28978
[user#192 ~]$ child process id: 28979
Thanks everybody for the suggestions. Adding a wait call brings prompt after child finishes.
I hope that it is a good idea to consider in a same question another case where the output differs as well, but independently of the wait() call.
This is dup() call implementation:
int main() {
pid_t childpid;
char string[] = "c\nb\na";
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0) {
close(0); // close STDIN
close(fd[1]); // close write end of a pipe
dup(*fd); // duplicate read end of the pipe to STDIN
execlp("sort","sort",NULL); // run sort(1) command
}
else {
close(*fd); // close read end of a pipe
write(fd[1],string,strlen(string));
}
return 0;
}
And again to different outputs, running program directly from the terminal,
gives:
[user#192 pipe]$ ./dup
a
b
c
[user#192 pipe]$
and via putty connection:
root#debian-512mb-ams2-01:~/C/inner/pipe# a
b
c
In the second example prompt never come back :(
What it can be?)
You need to wait() for the child process:
if(childpid == 0) {
sprintf(buf,"child process id: %d\n",getpid());
write(1,buf,sizeof(buf));
}
else {
sprintf(buf,"parent process id: %d\n",getpid());
write(1,buf,sizeof(buf));
wait(childpid); // <---
}
return 0;
All the child processes created inside a main process dies prematurely when the main process exit or dies. Hence before exit from the main process we need to have tell the operating system that please complete all the child processes before exit from the main process. For that you have to add wait() system call with a int value or NULL . For testing purpose you can use a sleep() statement as well.
write(1,buf,sizeof(buf));
wait(NULL); // just for testing sleep(5); sleep for 5 second to complete the child process
I think it may be related to latency in finishing processes (they are running independently).
Putty just show you prompt after core process is finished but it is not deterministic in your case.

C - meaning of wait(NULL) when executing fork() in parallel

In the code below, do the forks actually run in parallel or one after another?
What is the meaning of wait(NULL) ?
(The program creates an n number of child processes, n is supplied via command line)
int main ( int argc, char *argv[] ) {
int i, pid;
for(i = 0; i < atoi(argv[1]); i++) {
pid = fork();
if(pid < 0) {
printf("Error occured");
exit(1);
} else if (pid == 0) {
printf("Child (%d): %d\n", i + 1, getpid());
exit(0);
} else {
wait(NULL);
}
}
}
They do run in parallel, up until the point that one of them waits.
wait(NULL) or more accurately wait(0) means wait until a state change in the child process. To find out about Unix / Linux C api calls, type man <function Name> on the command line. You'll need to get used to reading those pages, so better start now.
In your case
man wait
would have given you what you needed.
Since you've only fork(...)ed once, you have only one child. The parent waits until it changes state, and since the child's state during the fork is the same as the parent's state prior to the fork (that of running), the likely outcome is that the parent waits until the child dies. Then the parent will continue executing, but since it doesn't have much to do after the wait(...) call, it will quickly exit too.

Forking Multiple Times

So this is a snippet of my code:
pid_t children[MAX_PIPES];
for (i = 0; i < numPipes; i++)
{
pid_t child_pid = fork();
children[i] = child_pid;
switch(child_pid)
{
case 0:
// Some code thats executed in the child that executes execv()
break;
case -1: // Unable to create child
perror("fork");
break;
}
}
// Wait for children
for (j = 0; j < numPipes && children[j] != 0; j++)
{
if (background)
waitpid(children[j], &status, WNOHANG);
else
waitpid(children[j], &status, 0);
}
Currently it works fine when I only call execv() once, but I am trying to execute multiple commands using execv() one after the other inside the already forked child process.
How do I go about adding that functionality? I have tried to add another fork() inside a loop inside the child but it wasnt successful.
Any ideas would be greatly appreciated. Thanks
execv, like the other exec() commands, doesn't return except on failure. The context for the new program is loaded in place of the current program.
Your problems is that execv replaces the entire child process with the command being called, so you can't put more than one execv command into the child process.
If you want to have multiple commands, you have to fork(), execv() each one. You're could use system(), but it doesn't process parameters in the same manner as execv() (it launches a shell).
If you want to run multiple commands, then you should do a second fork() ... execv() using a wrapper akin to:
int
subv(char *path, char * const argv[])
{
int ret;
pid_t a_pid = fork();
if (a_pid == -1) return -1;
if (a_pid != 0) { wait(&ret); return ret; }
return execv(path, argv);
}
The you replace all the execv calls with subv() and deal with the return code appropriately.

Resources