I'm trying to create a program where a process forks, creating a child process, and the parent must always finish printing to the screen before the child is finished printing to the screen, no matter what. I also wish to accomplish this using signals instead of pipelining.
It is a similar problem to the question asked here: Explanation of sigsuspend needed
I understand that kill(pid,signal); is to send a signal to that pid and tell it to finish executing and terminate.
The problem is, when it executes, the child doesn't print after the suspend. Heres the code:
int main(void){
pid_t pid;
int i;
pid = fork();
if(pid==0){
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask,SIGUSR1);
printf("This is the child Process id = %d \n",getpid());
sigsuspend(&mask);
printf("The child is now complete \n");
}
else{
printf("This is the parentProcess id = %d \n",getpid());
printf("The parentProcess is complete\n");
sleep(1);
int j = kill(pid,SIGUSR1);
if (j!=0)
{
perror(NULL);
}
exit(0);
}
}
I have managed to accomplish my task (printing the parent before the child) by using a global variable int x = 0; and a signal handler method void handle1(int s){x = 1;}before the main. In the main I added signal(SIGUSR1,handle1); In the child I removed all the sigset and sigsuspend lines and instead wrote while(x==0){/*do_nothing*/} 1 line before the printf statement. So when the parent executes kill(pid,SIGUSR1) the signal handler which is inherited by the child process also gets executed and sets x=1. So the child now leaves the while loop and can print it's statement.
However I believe it would be helpful to know how to accomplish this task using sigmask_t and sigsuspend() but i cant get it to work that way.
There are 3 problems in your code:
SIGUSR1 is the signal you want to deliver to the child. You can't use sigaddset(&mask,SIGUSR1);, it does exactly the opposite of your intention.
According to POSIX standard sigsuspend() below, you should install a signal handler for SIGUSR1 to make sigsuspend() continue the following code, since the default behavior of SIGUSR1 is termination.
The sigsuspend() function shall replace the current signal mask of the calling thread with the set of signals pointed to by sigmask and then suspend the thread until delivery of a signal whose action is either to execute a signal-catching function or to terminate the process.
It would be better if you collect the child from the parent, otherwise there is a race condition.
The code below will work:
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void handler(int sig) {}
int main(void){
pid_t pid;
int i;
pid = fork();
signal(SIGUSR1, handler);
if(pid==0){
sigset_t mask;
sigemptyset(&mask);
//sigaddset(&mask,SIGUSR1);
printf("This is the child Process id = %d \n",getpid());
sigsuspend(&mask);
printf("The child is now complete \n");
}
else{
printf("This is the parentProcess id = %d \n",getpid());
printf("The parentProcess is complete\n");
sleep(1);
int j = kill(pid,SIGUSR1);
if (j!=0)
{
perror(NULL);
}
wait(NULL);
exit(0);
}
}
You have a few issues.
Your parent process should wait for the child to complete. This allows for diagnostics (such as properly waiting for the child to print), but is otherwise a bookkeeping task that is a good habit even when the waiting process will just exit:
printf("This is the parentProcess id = %d \n",getpid());
printf("The parentProcess is complete\n");
sleep(1);
int j = kill(pid,SIGUSR1);
if (j!=0)
{
perror(NULL);
exit(0);
}
waitpid(pid, NULL, 0);
exit(0);
Now, you have set SIGUSR1 in your mask to sigsuspend(), which causes the signal to be ignored. This is now more obvious once the parent is made to wait, because the parent will never exit. So, remove the line of code that sets SIGUSR1.
Finally, the default handler for SIGUSR1 will simply cause the process to exit, and so the printf will not get a chance to print. If you want it to print, you should add a signal handler for SIGUSR1. It doesn't have to do anything.
void h (int s) {}
...
sigset_t mask;
sigemptyset(&mask);
//sigaddset(&mask,SIGUSR1);
printf("This is the child Process id = %d \n",getpid());
struct sigaction sa = { .sa_handler = h };
sigaction(SIGUSR1, &sa, NULL);
sigsuspend(&mask);
printf("The child is now complete \n");
Related
I have a problem with my code,
I want all the children stop when the program start.
and after that I want just the child with the index of i to continue executing and others to be stopped .
I want to execute them in this order p0 ,p1,p2,p3,p4,p0,p1....
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#define N 5
void handler(int i)
{
if (i == SIGCONT)
{
printf("signal cont\n");
}
}
int main()
{
int pid[N];
for (int i = 0; i < N; i++)
{
if ((pid[i] = fork()) == 0)
{
/* code */
while (1)
{
printf("ici fils %d\n", i);
usleep(50000);
}
}
else
{
kill(pid[i], SIGSTOP);
// kill(pid[i], SIGSTOP);
if (i == N - 1)
{
kill(pid[i], SIGCONT);
sleep(2);
kill(pid[i], SIGSTOP);
kill(pid[0], SIGCONT);
}
else
{
kill(pid[i], SIGCONT);
sleep(2);
kill(pid[i], SIGSTOP);
kill(pid[i + 1], SIGCONT);
}
// kill(pid[i], SIGKILL);
waitpid(pid[i], NULL, 0);
}
signal(SIGCONT, &handler);
}
}
There are several issues with your code, among them:
Any processes to be stopped via SIGSTOP must not have a handler registered for that signal. Registering a handler causes the handler's behavior to replace the default behavior of stopping the process.
It's usually a bad idea to register a handler for SIGCONT. Doing so will not prevent a SIGCONT from continuing the process, which is a special characteristic of SIGCONT that can be surprising, but also the handler will fire whenever a SIGCONT is delivered, even if the process was not stopped, which is often a different kind of surprise.
You register your signal handlers only in the parent, after the first fork. The subsequently forked children will inherit those, but the first one will not. Among other things, this will prevent the first child's pause() from being unblocked by the signals the parent sends to it. You can make each child register any needed handlers for itself, or you can register them in the parent, before the first fork.
There is a race between each child's pause() and the parent's first kill() targeting that child. It is possible for the child to receive the SIGCONT before it calls pause(), in which case it will wait for the next signal. You can prevent that by blocking SIGCONT in the parent before forking, and using sigsuspend() in the child, with an appropriate mask, instead of the initial pause(). In that case, you probably want to unblock SIGCONT after returning from that initial sigsuspend().
The parent attempts to send signals to processes that it has not forked yet (kill(pid[i + 1], SIGCONT);).
It's not clear what the full behavior you are trying to achieve is, but you may want to fork all the children first, and only then start sending signals.
Update
With respect to the update to the question,
You apparently want to cycle repeatedly through the child processes, but your code runs through them only once. This is a good reason to implement what I already suggested above: fork all the children first, then, separately, do all the signalling.
In the child processes, instead of using pause(2), use raise(3) to signal the calling process to stop with SIGSTOP. There is no real need to register signal handlers.
In the parent process, after creating a child process, wait for it to stop (or terminate) by using waitpid(2) with the WUNTRACED flag set. The WIFSTOPPED(...) macro can be used to specifically determine the status of the child. The WCONTINUE flag can be used to wait for a child process to continue, and like before there is the WIFCONTINUED(...) macro.
Here is a cursory example, with no meaningful error handling. Note that concurrent sleeps, while simple, are not technically a consistent way to schedule things. The output of this program may differ slightly between executions.
#define _POSIX_C_SOURCE 200809L
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define CHILDCOUNT 5
sig_atomic_t looping = 1;
void handler(int sig) {
(void) sig;
looping = 0;
}
pid_t create_child(void) {
pid_t pid = fork();
if (!pid) {
/* child */
raise(SIGSTOP);
pid_t self = getpid();
printf("SIGCONT in %d\n", self);
while (1) {
printf("RUNNING in %d\n", self);
sleep(1);
}
/* bug net */
exit(EXIT_SUCCESS);
}
return pid;
}
void killwait(pid_t pid, int sig) {
kill(pid, sig);
int status;
waitpid(pid, &status, WUNTRACED | WCONTINUED);
if (WIFSTOPPED(status))
printf("P: C(%d) STOPPED!\n", pid);
if (WIFCONTINUED(status))
printf("P: C(%d) CONTINUED!\n", pid);
if (WIFSIGNALED(status) && SIGKILL == WTERMSIG(status))
printf("P: C(%d) SUCCESSFULLY KILLED!\n", pid);
}
int main(void) {
pid_t pids[CHILDCOUNT];
/* tentative: catch this in all processes so the parent may reap manually */
signal(SIGINT, handler);
for (size_t i = 0; i < CHILDCOUNT; i++) {
pid_t current = pids[i] = create_child();
printf("Parent now has child (%d) [#%zu].\n", current, i);
killwait(current, 0);
}
for (size_t i = 0; looping; i = (i + 1) % CHILDCOUNT) {
pid_t current = pids[i];
printf("P: C(%d) STARTING [#%zu].\n", current, i);
killwait(current, SIGCONT);
sleep(2);
killwait(current, SIGSTOP);
}
for (size_t i = 0; i < CHILDCOUNT; i++)
killwait(pids[i], SIGKILL);
}
Moving straight to the issue, how do I make Ctrl+z do what the title states?
My program implements a parent process which creates a single child process.
Both processes will display the process ID and once the child terminates a signal is sent to the parent process and the parent signal handler will display a text stating a signal has been captured.
On the child process, on top of displaying the child's process ID, it must generate a random number between 10 and 50 every time Ctrl + z is pressed. So far I can only make the child process generate 1 random number.
Below is my code:
void main() {
int pid;
int x;
int fd[2];
const int MAXLINE=4096;
char line[MAXLINE];
pid=fork();
if (pipe(fd) < 0) {
printf("Pipe error!");
}
if (pid < 0) {
printf("Fork error!");
} else if (pid == 0) { //Child process
signal(SIGTSTP, childsignal_handler);
printf("The process id is: %i\n", getpid());
sleep(1000); //Implemented to wait for a signal
} else {
printf("The process id is: %i\n", getpid()); //Parent process
pause(); //Waits for the Child process to finish
}
}
parent signal handler:
void parentsignal_handler(int signo) { //Signal Handler for the parent process
printf("The signal in the parent process has been captured\n");
}
child signal handler:
void childsignal_handler(int signo) { //Signal Handler for the child process
signal(SIGTSTP, childsignal_handler);
printf("\nThe signal in the child process has been captured\n");
randomnumbergenerator();
pause();
}
The random number generator:
void randomnumbergenerator() { //Random number generator to run everytime Ctrl+z is pressed
//signal(SIGTSTP, childsignal_handler);
int number;
int number2 = 10;
printf("Welcome to random number generator!");
printf("\nRandom number generated = %d\n", rand() % 40 + 10);
}
PS: I have read several documentations regarding various solutions such as sigsuspend, sigprocmask,pause and so on but none of them worked so far.
below are some of the documentations i have read so far:
https://www.gnu.org/software/libc/manual/html_node/Waiting-for-a-Signal.html#Waiting-for-a-Signal
https://man7.org/linux/man-pages/man2/pause.2.html
i need to implement a signal that will detect the child terminating
You don't exactly need to implement a signal; you just need to install the handler that you already have:
signal(SIGCLD, parentsignal_handler);
how do I make Ctrl+z do what the title states?
So far I can only make the child process generate 1 random number.
To prevent the parent process from being suspended (and therewith losing signal delivery), ignore the STOP signal in the parent:
signal(SIGTSTP, SIG_IGN);
And you should really pay attention to Ian Abbott's first comment and remove pause() from the signal handler; otherwise after Ctrl-Z was pressed the program will not end. At the same time change sleep(…) to while (sleep(…)) to keep a timed suspension instead of the unlimited pause().
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
void handler(int signumber)
{
return;
}
int main()
{
int i, pid;
int children_count = 5;
int arr_childprocesses[5];
int parent_pid = getpid();
for(i=0;i<children_count;i++)
{
pid = fork();
if(pid == -1)
{
perror("Err");
exit(EXIT_FAILURE);
}
if(pid == 0) break;
arr_childprocesses[i] = pid;
}
if (pid == 0) // children
{
kill(parent_pid,SIGUSR1);
printf("Child(%d) sig sent. Waiting 5s...\n",getpid());
sleep(5);
printf("Child(%d) terminated.\n",getpid());
}
else // parent
{
signal(SIGUSR1,handler);
for(i=0;i<children_count;++i)
{
waitpid(arr_childprocesses[i],NULL,0);
printf("Parent: Signal received.\n");
}
printf("Parent(%d) signals received. Waiting 3s...\n",getpid());
sleep(3);
printf("Parent(%d) terminated.\n",getpid());
}
exit(EXIT_SUCCESS);
}
I want to wait until all the children send me a signal. Then do some work with the children and with the parent too. But the program stops until all the children terminate. How should I do this?
Result:
Update 1: full code plus result included
You are probably facing a race here.
The parent receives the SIGUSR1 before its handler for this signal had been set up. As the default behaviour on receiving a SIGUSR1 is to end, the parent dies.
You want to setup the signal handler inside the parent before forking off the child.
(If from the programs design it is unacceptbale for the child to have SIGUSR1 signal handler set up, just call signal(SIGUSR1, SIG_DFL) as the 1st statement inside the child to deinstall this handler.)
To prove this theory you might like to temporarily add a sleep(1); inside the child just before the call to kill().
As a hint to fulfill your assignment:
Have a look at sigaction() as it provides a much more powerful interface to signalling then the function signal() does. Especially read about the SA_SIGINFO flag as it enables passing a siginfo_t typed variable to your signal handler. This latter variable carries info on who (identified by PID) sent the signal, which is the key to your solution.
I am trying to use signals to pass between a parent and child process, but after the first 2 statements are printed
for example in mine it shows:
CHILD 4225: Running, parent is 4224
PARENT 4224: Telling the Child Process 4225 to start
it just gets stuck running forever! I'm not sure where I am going wrong on this...
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
void p_sig_usr(int signo){
if(signo == SIGUSR1){
printf("*** Parent SIGUSR1 handler - Received 'task started' signal from child ***\n");
}
if(signo == SIGUSR2){
printf("*** Parent SIGUSR2 handler - Received 'task completed' signal from child ***\n");
}
else
printf("unexpected signal received");
return;
}
void c_sig_usr(int signo){
if(signo == SIGUSR1){
printf("*** Child SIGUSR1 handler - Received 'task start' signal from parent ***\n");
}
if(signo == SIGUSR2){
printf("*** Child SIGUSR2 handler - Received 'task complete verification' signal from parent ***\n");
}
else
printf("unexpected signal received");
return;
}
int main(void)
{
pid_t child_pid, parent_pid;
parent_pid = getpid();
struct sigaction p_sig;
sigemptyset(&p_sig.sa_mask);
p_sig.sa_flags = 0;
p_sig.sa_handler = p_sig_usr;
child_pid = fork();
if ( child_pid == -1){
perror("failed to fork a new process");
return 1;
}
if (child_pid == 0){
struct sigaction c_sig;
sigset_t c_myset;
sigemptyset(&c_sig.sa_mask);
c_sig.sa_flags = 0;
c_sig.sa_handler = c_sig_usr;
child_pid = getpid();
printf("CHILD %d: Running, parent is %d\n",child_pid, parent_pid);
sigfillset(&c_myset);
sigdelset(&c_myset, SIGUSR1);
sigsuspend(&c_myset);//suspend until get SIGUSR1
printf("CHILD: Telling parent that I'm starting task.\n");
sleep(3);
kill(parent_pid, SIGUSR1);
printf("CHILD: Performing task\n");
sigfillset(&c_myset);
sigdelset(&c_myset, SIGUSR2);
sigsuspend(&c_myset);//suspend and wait for SIGUSR2
printf("CHILD: Telling parent that work is done.\n");
kill(parent_pid, SIGUSR2);
printf("CHILD %d: Finished\n", child_pid);
}
else{
struct sigaction p_sig;
sigset_t p_myset;
sigemptyset(&p_myset);
sleep(3);//parent now sleeping to let child set up handlers
printf("PARENT %d: Telling the Child Process %d to start\n", parent_pid, child_pid);
kill(child_pid, SIGUSR1);
sigfillset(&p_myset);
sigdelset(&p_myset, SIGUSR1);
sigsuspend(&p_myset);//suspend until get SIGUSR1
sleep(3);
kill(child_pid,SIGUSR2);
printf("PARENT: Told child to notify of task completion.\n");
sigfillset(&p_myset);
sigdelset(&p_myset, SIGUSR2);//suspend until get SIGUSR2
printf("PARENT %d: Finished.", parent_pid);
}
return 0;
}
Thank you in advance for the help!
I'm just referring to the documentation for these functions—I have no experience using them.
It appears what sigfillset() is going to do is load the process signal mask into your sigset_t. This means that your sigset_t is going to contain the set of signals that are currently blocked by your process. I assume the default is nothing is blocked, so the set would be empty.
You might want to test this by printing out the contents of the set, or just looking at it in a debugger.
Now from the docs I understand what sigdelset(&p_myset, SIGUSR1) will do is remove the signal SIGUSR1 from the set you just filled. This set is by assumption already empty so it's unlikely this call does anything. Again, verify by looking at it in a debugger.
So now what sigsuspend() is going to do is replace your process signal mask with your new mask, which by assumption isn't any different than the default mask (again, check this in a debugger). Then on the child side will wait until the process receives SIGUSR1 and processes it via a signal handler. So your child will process SIGUSR1 but only because that's the default behaviour.
Your example code doesn't seem to have installed any signal handlers. I think you would have to call the sigaction() function to do that. Therefore very likely the default signal handler will run to process SIGUSR1.
According to this page, the default signal handling for SIGUSR1 is
(i) ... Abnormal termination of the process. The process is terminated with all the consequences of _exit() except that the status made available to wait() and waitpid() indicates abnormal termination by the specified signal.
So I'm guessing the child dies when the parent does kill(child_pid, SIGUSR1). This would mean the child isn't around to signal the parent back.
This is mainly guesswork on my part. What I recommend for you is learning how to use gdb or some other debugger so you can set some breakpoints and step through and learn what the program is actually doing.
You forgot to call sigaction after defining the struct sigaction on both the parent and child. Also, beware that the struct sigaction p_sig is redefined in the parent process.
So, I guess if you change your program to something like listed below, it should work.
--- foo.c 2014-06-16 16:37:10.918932118 -0300
+++ bar.c 2014-06-16 16:37:48.710228467 -0300
## -36,10 +36,6 ##
{
pid_t child_pid, parent_pid;
parent_pid = getpid();
- struct sigaction p_sig;
- sigemptyset(&p_sig.sa_mask);
- p_sig.sa_flags = 0;
- p_sig.sa_handler = p_sig_usr;
child_pid = fork();
if ( child_pid == -1){
perror("failed to fork a new process");
## -51,6 +47,7 ##
sigemptyset(&c_sig.sa_mask);
c_sig.sa_flags = 0;
c_sig.sa_handler = c_sig_usr;
+ sigaction(SIGUSR1, &c_sig, NULL);
child_pid = getpid();
printf("CHILD %d: Running, parent is %d\n",child_pid, parent_pid);
sigfillset(&c_myset);
## -69,6 +66,10 ##
}
else{
struct sigaction p_sig;
+ sigemptyset(&p_sig.sa_mask);
+ p_sig.sa_flags = 0;
+ p_sig.sa_handler = p_sig_usr;
+ sigaction(SIGUSR1, &p_sig, NULL);
sigset_t p_myset;
sigemptyset(&p_myset);
sleep(3);//parent now sleeping to let child set up handlers
What I want to do is create a parent process that lasts for 5 seconds. I also want it to send a SIGUSR1 signal every second. On this signal I want the child to do something.
The code that I put together so far is:
void alarmHandler(int sig) {
printf("\nalarm called\n");
exit(0);
}
void childHandler(int sig) {
printf("child called");
signal(SIGUSR1, childHandler);
}
int main() {
pid_t val;
if((val = fork())) { //parinte
signal(SIGALRM, alarmHandler);
printf("parent");
alarm(5);
while(1) {
kill(val, SIGUSR1);
sleep(1);
}
}else {
signal(SIGUSR1, childHandler);
printf("child");
}
return 0;
}
What I get is:
child
parent
alarm called
What I want:
child
parent
child called
child called
child called
child called
child called
alarm called
Your parent has the while loop. The child does the following:
signal(SIGUSR1, childHandler);
printf("child");
And then exits.
If it does receive SIGUSR before the exit, this will also be executed
printf("child called");
signal(SIGUSR1, childHandler);
Therefore you have a race condition as the number of child called is printed.
Just put a while (1) {} after the printf("child");
Base on the original code, add two blocks:
flush the printf: setbuf(stdout, NULL);
keep the child running: while (1) pause();
The code list as follow:
#include "stdio.h"
#include "stdlib.h"
#include <signal.h>
/* For a real-world program, printing from a signal handler is not very safe.
* A signal handler should do as little as it can, preferably only setting a flag here or there.
* And the flag should be declared `volatile`.
* Real-world example:
* I once worked on a system that used an Access database as a back end,
* and under certain circumstances a printf() call in a signal handler would write to the .mdb file instead of stdout,
* hosing the database beyond repair.
*/
void alarmHandler(int sig)
{
printf("\nparent signal alarm handler: times up\n");
exit(0);
}
void childHandler(int sig)
{
printf("\nchild signal handler\n");
// The old style should install the handler again.
signal(SIGUSR1, childHandler);
}
int main()
{
pid_t val;
signal(SIGALRM, alarmHandler);
// If not set this, we cann't the child's output.
// The stdout stream is buffered, so will only display what's in the buffer after it reaches a newline (or when it's told to).
setbuf(stdout, NULL);
if ((val = fork())) { //parinte
printf("\nparent\n");
// #Note that there is only one alarm clock per process.
// the alarm() function will return a value if another alarm has been previously set.
//
// sets a timer that generates the SIGALARM signal when times up.
// If we ignore or don’t catch this signal, the process is terminated.
alarm(5);
while(1) {
sleep(1);
kill(val, SIGUSR1);
}
printf("\nparent exit\n");
} else {
signal(SIGUSR1, childHandler);
printf("\nchild\n");
while (1)
pause(); // The pause() function suspends the process until a signal is caught.
printf("\nchild exit\n");
}
return 0;
}
And the output:
parent
child
child signal handler
child signal handler
child signal handler
child signal handler
parent signal alarm handler: times up