I am new in C. I am trying to make a shell - like program. I am currently making a signal handler, which means, when the process is running and somebody pressed ctrl + Z the process should pause and go to background while shell has to continue. The problem here is: parent process is making wait(NULL), but child is not ending the program so basically parent waits the child which is not ending the program yet. How to make it so that parent continues to work foreground. (you can see my code How to redirect signal to child process from parent process? here)
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
pid_t pid;
void send_signal(int signum){
kill(pid, signum);
}
void init_signals(){
signal(SIGINT, send_signal);
signal(SIGTSTP, send_signal);
}
int main(){
init_signals();
pid = fork();
if(pid > 0){
//Parent Process
printf("PARENT: %d\n", getpid());
waitpid(pid, NULL, WUNTRACED);
printf("Parent out of wait, i think this is what you are expecting\n");
} else {
struct sigaction act = {{0}};
act.sa_handler = send_signal;
act.sa_flags = SA_RESETHAND;
sigaction(SIGTSTP, &act, NULL);
sigaction(SIGINT, &act, NULL);
perror("sigaction ");
printf("CHILD: %d\n", getpid());
// Child Process
while(1){
usleep(300000);
}
}
return 0;
}
I think above code can serve your purpose. Let me explain it.
In your code [How to redirect signal to child process from parent process? you have handled signal and from hander context sending same signal.When you pressed Ctrl + c or Ctrl + z both parent and child receives signal. Now as per the handler code
void send_signal(int signum) {
kill(pid, signum);
}
when handler will execute in parent's context pid will be equal to child's pid so it will send signal to child but when handler runs in child context pid value will be 0, so it sends signal to whole process group i.e. parent as well as child. this make you code to run handler recursively for infinite times. Due to this you are not getting desired result.
I have modified two things to get desired result.
child context
In child context restore the signal action to the default upon entry to the signal handler so that when child receives signal for second time signal default action can be performed.
parent context
use waitpid() instead of wait().
pid_t waitpid(pid_t pid, int *status, int options);
The waitpid() system call suspends execution of the calling process until a child specified by pid argument has changed state. By default, waitpid() waits only for terminated children, but this behavior is modifiable via the options argument.
`WUNTRACED` also return if a child has stopped
Due to WUNTRACED parent process will return when child will be stopped or terminated.
I hope it will serve you purpose ask me if it don't.
Related
I want to write a program in which the parent creates exactly 1 child process. The child process should print its pid to the standard output and then finish. The parent process should waits until it is sure that the child has terminated. The parent terminates after it has waited for the child process.
Thats what I got so far:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int child;
child = fork();
if (child == 0)
{
printf("Child process has PID: %d. \n", getpid());
exit(0);
}
// how can the parent process find out it the child process was terminated successful?
printf("Child process terminated successfully\n");
return EXIT_SUCCESS;
}
How can the parent-process find out if the child process was terminated? I can't use wait() or waitpid() in this programm.
Thanks for your help!
When a child process terminates a SIGCHLD signal will be sent to the parent, by default the parent will ignore the SIGCHLD, however you can register a signal handler that will catch it.
You need to be careful what you do in the signal handler - quite a few standard function aren't safe to use.
The SIGCHLD approach turns up in code when the parent has it's own work to do and can't just wait for the child. If the parent just spawns children and then waits for them to finish the wait() and waitpid() are the best solution.
Finally if you don't call wait() or waitpid() you risk creating a zombie process, the child process expects it's parent to receive it's exit status through a call to one of these functions.
As I said in remark use the signal SIGCHLD, for instance :
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
void handler(int sig)
{
pid_t chpid = wait(NULL);
/* WARNING : to show the call of the handler, do not do that
in a 'real' code, we are in a handler of a signal */
printf("Child pid %d ended (signal %s)\n", chpid, sig);
/* does 'something' to allow the parent to know chpid
terminated in a way compatible with parent requirement */
}
int main(void)
{
signal(SIGCHLD, handler);
if (!fork())
{
printf("Child pid is %d\n", getpid());
sleep(1);
return 0;
}
printf("Parent pid is %d\n", getpid());
getchar();
return 0;
}
Note when the signal arrive you have to call wait(NULL) but because by definition the child terminated the function returns immediately
Compilation and execution :
pi#raspberrypi:/tmp $ gcc -pedantic -Wall -Wextra s.c
pi#raspberrypi:/tmp $ ./a.out
Parent pid is 21743
Child pid is 21744
Child pid 21744 ended (signal 17)
<enter>
pi#raspberrypi:/tmp $
Of course the signal 17 is SIGCHLD because it is the only one the program catches
I need to fork two child-processes. One can receive the signal 3, print hello and send the signal 4 to the the other child process; The other can receive the signal 4, print world and send the signal 3 to the first child process.
To start, the father process will send the signal 3 to the first child process after sleeping for 3 seconds.
Then 3 seconds later, the father process will send SIGKILL to kill both of them.
I don't know how to send signals to a specific child process (I knew that we had a function kill to send signals but I don't know to use it here).
Here is my code:
#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
void func(int n)
{
printf("ping\n");
// how to send signal 4 to the second process?
}
void func2(int n)
{
printf("pong\n");
// how to send signal 3 to the first process?
}
int main()
{
pid_t pid;
int i;
for(i = 0; i < 2; i++)
{
pid = fork();
if(pid == 0)
{
if(i == 0)
{
signal(3, func);
}
else
{
signal(4, func2);
}
while(1);
}
else
{
if(i == 1)
{
sleep(3);
// how to send signal 3 to the first child process?
sleep(3);
// how to kill the two children?
}
}
}
return 0;
}
you could use the popen() function to open a process by forking and opening a pipe to that process (instead of using fork() directly)
The parent knows the PID of each process so can then easily pass the pid of the second child to the first child.
The first child can use the pid and the kill()` function to pass a signal to the second child.
SO, use popen() to start the first child. use fork() to start the second child, then pass the pid from the second child to the first via the stream created with popen().
the handling of the pid value returned from the call to fork() is not being handled correctly.
The posted code is making the assumption that the call to fork() was successful... This is not a safe/valid assumption
The code also needs to check for the pid being -1 and appropriately handling that error.
when a child process completes, it should NOT sit in a while() loop but rather exit, using the exit() function.
The parent, should not just exit, as that leaves the two child processes as zombies. (zombies are very difficult to get rid of short of a system reboot.)
Rather, the parent should call wait() or even better waitpid() (and remember the child processes need to actually exit, NOT sit in a while() loop.
1) the func() and func2() should check the parameter to assure that it was the correct signal that was being processed.
2) the man page for signal() indicates that it should not be used. The man page suggest using: sigaction(),
When you fork you get the new pid. Per the kill manpage you call kill(pid_t pid, int sig); using the pid
Is there any way to prevent creation of zombie processes while I am using fork() and exec() to run an application in background? The parent should not wait() for the child to complete. Also I cannot use sigaction() and sigaction.sa_handler because it affects all child processes which I don't want. I want something that will reap that particular child only, or that will prevent from spawning any zombie. Please help.
If you want to create a "detached" process that you don't have to wait for, the best way is to fork twice so that it's a "grandchild" process. Immediately waitpid on the direct child process, which should call _exit immediately after forking again (so this waitpid does not block forward progress in the parent). The grandchild process will be orphaned so it gets inherited by the init process and you never have to deal with it again.
Alternatively you can install a signal handler for SIGCHLD with SA_NOCLDWAIT. However this is a really bad idea in general since its effects are global. It will badly break any library code you use that needs to be able to wait for child processes, including standard library functions like popen, possibly wordexp, possibly grantpt, etc.
To prevent of zombie processes you need to tell the parent to wait for the child, until the child's terminates the process.
You need to use the waitpid() function that is included in the library 'sys/wait.h'
Down here you have an example code that you can use the waitpid() function.
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
int main()
{
pid_t child_pid;
int status;
int local = 0;
/* now create new process */
child_pid = fork();
if (child_pid >= 0) /* fork succeeded */
{
if (child_pid == 0) /* fork() returns 0 for the child process */
{
printf("child process!\n");
// Increment the local and global variables
printf("child PID = %d, parent pid = %d\n", getpid(), getppid());
}
else /* parent process */
{
printf("parent process!\n");
printf("parent PID = %d, child pid = %d\n", getpid(), child_pid);
wait(&status); /* wait for child to exit, and store child's exit status */
}
//code ..
#R: In fairness, there ARE usercases where one might fork a job, and where there is absolutely no need to react on the result of the spawned child.
Any call of a wait() function may eventually block the parent if there is no answer, may it? This might crash an airplane...
You can register a signal handler mechanism to prevent the child process to get zombie,
this
Link will be helpful to resolution of your problem.
I have a main that runs program from the command line arguments. The command line program is forked and run in the child process. When SIGINT is sent, I want to catch it and ask the user to confirm that he/she want to quit. If yes, both parent and child end, else child keeps running.
My problem is that I can't get the child to start running back up, when user says no.
I have tried SIGSTOP & SIGCONT but these actually just cause the processes to stop.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
extern char **environ;
void sigint_handler(int sig);
void sigint_chldhandler(int sig);
int main( int argc, char** argv)
{
int pid;
signal(SIGINT,sigint_handler);
if((pid=fork())==0)
{
printf("%d\n",pid);
execve(argv[1],argv,environ);
}
int status;
waitpid(pid,&status,0);
}
void sigint_handler(int sig)
{
printf("Do you want to quit?Yes/No:\n");
char buf[4];
fgets(buf, sizeof(char)*4, stdin);
printf("child pid:%d\n",getpid());
printf("parent pid:%d\n",getppid());
if(strcmp(buf,"Yes")==0)
{
kill(-getpid(),SIGKILL);
printf("Exiting!\n");
exit(0);
}
}
Unless you rig the child's signal handling, it will be terminated by the interrupt when the signal is sent, regardless of what happens in the parent. Therefore, you will need to be rather more sophisticated. I think you will need something along the lines of:
Parent process sets its SIGINT signal handler.
Parent forks.
Child process sets its SIGINT handling to SIG_IGN.
Child executes specified command.
Parent waits for SIGINT to arrive, probably while running waitpid().
When it arrives, it sends SIGSTOP to the child.
It asks the question and gets the response.
If the response is to continue, then it sends SIGCONT to the child and returns to its waiting mode.
If the response is to stop, then it sends first SIGCONT and then SIGTERM (or another signal other than SIGINT) to the child to kill it. (Using SIGKILL is not sensible; the child should be given a chance to exit in response to SIGTERM or SIGHUP. If the child doesn't take the death threat seriously, then you can send it SIGKILL.)
When the parent has established that the child has exited, it can exit in its own turn.
Note that if the child process is running something like vim, which alters the terminal settings dramatically, then sending it SIGKILL will leave the terminal in a cockeyed state. It is fiddly setting it back to a sane state; it is better to give the program a chance to reset the terminal settings in its own right.
SIGINT comes to parent process and to child process (to process group).
Parent process calls your handler.
Child processes this signal by default.
You can use this, for example:
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
int main()
{
pid_t pid;
char c;
switch(pid = fork())
{
case -1:
printf("!!!");
return -1;
break;
case 0:
printf("child started\n");
while(1) { };
break;
default:
while(1)
{
c = getchar();
if(c == 'q')
{
//your conditions
kill(pid, SIGKILL);
return 0;
}
}
break;
}
return 0;
}
My target is to intercommunicate main process and its "fork" children.
Communication is done by signal delivery.
My problem appears when first child gets stuck waiting when waiting for SIGUSR1 signal.
I have no real idea why it gets stuck on that point. Evenmore if I sent signals by console, that child process seems not paying attention.
Could anybody help me?
Here comes the code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
int N = 5;
int _pipe[2];
pid_t children[5];
void main(){
pid_t parent_pid;
pid_t pid;
int i = 0;
sigset_t set;
sigfillset(&set);
parent_pid = getpid();
fprintf(stderr,"I am main process, here comes my pid %u\n",getpid());
if (0>pipe(_pipe)) fprintf(stderr,"Error when creating pipe");
//Start creating child processes
while (i < N){
pid = fork();
if (pid == 0){
close(_pipe[1]);
break;
}
else{
fprintf(stderr,"Created child with pid %u\n",pid);
children[i] = pid;
write(_pipe[1],&pid,sizeof(pid_t));
}
i = i+1;
}
i = 0;
// What main process does
if (pid>0){
close(_pipe[0]);
close(_pipe[1]);
sigdelset(&set,SIGUSR2);
sigdelset(&set,SIGTERM);
sigdelset(&set,SIGKILL);
// Main process sends signal to each child
while(i < N){
kill(children[i],SIGUSR1);
fprintf(stderr,"Sent SIGUSR1 to child %u\n",children[i]);
// .. Now just wait for SIGUSR2 arrival
sigsuspend(&set);
i = i+1;
}
}
// What children do
else{
// Wait for main process SIGUSR1 delivery
sigdelset(&set,SIGUSR1);
sigsuspend(&set);
fprintf(stderr, "SIGUSR1 arrived child %u from its father",getpid());
// Once SIGUSR1 has arrived, pipe is read N times
while((i < N) && (read(_pipe[0],&pid,sizeof(pid_t))>0)){
children[i] = pid;
i = i+1;
}
close(_pipe[0]);
// After reading pipe, a reply is sent to parent process
kill(parent_pid,SIGUSR2);
}
}
The problem most likely has to-do with the fact that the parent is sending the signals to the child processes immediately after it has forked them, and the child processes aren't blocking the signal. Thus by the time you call sigsuspend() in the child process, the signal has already been delivered to the child, and now it just sits there waiting for a signal that's never coming. You can quickly test this theory by placing a call to sleep() in the main process for a second or two before it starts sending signals. Keep in mind that as your code is structured right now, sigsuspend() won't work right without signal handlers for the signals you're waiting on ... so I suggest the following when working with signals like this:
In the parent process, block all the signals that you're planning on using for communication between the parent and child processes. You'll need to call sigprocmask() for this.
Have the parent fork the child processes
In the child processes simply call sigwait() using a signal set containing the blocked signals being used for communication ... you don't need sigsuspend() for what you're doing here.
After the parent process has sent the signals to the children, it too can call sigwait() to wait for the child process replies.
Here is an example of your code that does work: http://ideone.com/TRcqga