C signals do not work correctly - c

I'm facing an error with the folllowing code.
It only executes the handler related to the odd numbers (in case the parent produces a odd random number included between 1 and 10), while the one for the even is always "mute".
Could someone help me out?
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <signal.h>
#include <math.h>
pid_t pid1,pid2;
int r, ric1, ric2;
int fd[4]; //per 2 processi figli
void handler_one(){
read(fd[0], &ric1, sizeof(int));
printf("Im the first child process...the even received numebr is...%d\n", ric1);
sleep(1);
}
void handler_two(){
read(fd[2], &ric2, sizeof(int));
printf("I'm the second child process...the odd receiver number is...%d\n", ric2);
sleep(1);
}
void main(){
pipe(fd);
pipe(fd+2);
pid1=fork();
if(pid1)
pid2=fork();
while(1){
if(pid1<0 || pid2<0){
perror("AN ERROR OCCURRED!!!!!!!\n");
exit(1);
}
else if(!pid1 && pid2){ //child #1
signal(SIGUSR1, handler_one);
}
else if(pid1 && !pid2){ //child #2
signal(SIGUSR2, handler_two);
}
else{ //padre
printf("I'm the parent and I'm gonna send a random number\n");
r=rand()%10+1;
if(r%2==0){
write(fd[1], &r, sizeof(int));
kill(pid1, SIGUSR1);
}
else{
write(fd[3], &r, sizeof(int));
kill(pid2, SIGUSR2);
}
sleep(1);
}
}
}

Your condition for setting up the child 1 signal handler is incorrect. Instead of
else if(!pid1 && pid2){ //child #1
it should be
else if(!pid1 && !pid2){ //child #1
Not sure if you are guaranteed pid1 and pid2 are initialized to zero, you may want to do that explicitly.

Related

How to use pipes and signals correctly at the same time?

I have 2 children, and I want to send signals from children to parent, and an answer (random number, why? why not...) named pipe from the parent to each child.
I have this code:
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#define WRITE(Str) (void)write(1,Str,strlen(Str))
void handler(int signumber)
{
WRITE("Signal arrived\n");
}
int main(){
/*random number */
srand(time(NULL)); //random number
int r = rand() % 2; //random number between 0 and 1
char original1[]="rdnr: ";
original1[6]=r+'0';
r = rand() % 2;
char original2[]="rdnr: ";
original2[6]=r+'0';
/*pipe, named pipe*/
int pid,fd,fd2;
printf("Fifo start!\n");
int fid=mkfifo("fifo.ftc", S_IRUSR|S_IWUSR ); // creating named pipe file
int fid2=mkfifo("fifo2.ftc", S_IRUSR|S_IWUSR );
if (fid==-1) //error handling
{
printf("Error at fid number: %i",errno);
exit(EXIT_FAILURE);
}
if (fid2==-1) //error handling
{
printf("Error at fid2 number: %i",errno);
exit(EXIT_FAILURE);
}
printf("Pipe system OK!\n");
/*signal*/
sigset_t sigset;
sigemptyset(&sigset); //empty signal set
sigaddset(&sigset,SIGTERM); //SIGTERM is in set
//sigfillset(&sigset); //each signal is in the set
sigprocmask(SIG_BLOCK,&sigset,NULL); //signals in sigset will be blocked
signal(SIGTERM,handler); //signal and handler is connetcted
signal(SIGUSR1,handler);
pid_t child2;
pid_t child=fork();
if (child>0)
{
child2 = fork();
if(child2>0){
printf("Parent, wainting for signal...\n");
sigsuspend(&sigset);
sigprocmask(SIG_UNBLOCK,&sigset,NULL);
int status;
wait(&status);
printf("Parent got 2 signal!\n");
printf("Parent will send 2 random number: %s and %s\n", original1, original2);
fd=open("fifo.ftc",O_WRONLY);
write(fd,original1,12);
close(fd);
fd2=open("fifo2.ftc",O_WRONLY);
write(fd2,original2,12);
close(fd2);
printf("Parent has sent the numbers!\n");
}
else{
printf("I'm child2.\n");
printf("child2 signalnr: %i (it is not blocked)\n", SIGUSR1);
kill(getppid(),SIGUSR1);
/*get pipe*/
sleep(5);
char s[1024]="nothn";
printf("got on pipe, in child2: %d!\n",fid);
fd=open("fifo.ftc",O_RDONLY);
read(fd,s,sizeof(s));
printf("got this on pipe, by child2: %s \n",s);
close(fd);
// remove fifo.ftc
unlink("fifo.ftc");
}
}
else
{
printf("I'm child1.\n");
printf("child1 signal nr: %i (it is blocked)\n",SIGTERM);
sleep(3);
kill(getppid(),SIGTERM);
//sleep(5);
/*get pipe*/
char s[1024]="nothn";
printf("Got this on pipe, by child1: %d!\n",fid2);
fd2=open("fifo2.ftc",O_RDONLY);
read(fd2,s,sizeof(s));
printf("got this inpipe fd2: %s by child2 \n",s);
close(fd2);
// remove fifo2.ftc
unlink("fifo2.ftc");
}
return 0;
}
And the pipes, and the signals work correctly if I use them separately, but together, here, not.
I got only this:
Fifo start!
Error at fid number: 17
by error handlers.
How can I use correctly the pipes and the signals at the same time?
UPDATE:
I've rethinked the parent as was mentioned in the comment section, now the output, what I can see is:
Fifo start!
Pipe system OK!
Parent, wainting for signal...
I'm child2.
I'm child1.
child1 signal nr: 15 (it is blocked)
child2 signalnr: 10 (it is not blocked)
Handled signal nr: 10
Got this on pipe, by child1: 0!
Handled signal nr: 15
got on pipe, in child2: 0!
So, the problem as I see is, the child process can't wait for the pipes, how can I solve this?
UPDATE2:
If I delete
int status;
wait(&status);
from the parent then works fine, just nothing is the to ensure the second signal arrives before the pipe things.
One repeating error in your code:
char original1[]="rdnr: ";
original1[6]=r+'0';
sizeof original1 is 7, the character at index 6 is the zero terminator of the string. By overwriting the zero terminator with r+'0' you destroy the string property of the array, so that you can no longer use strlen on it.
Fix:
char original1[] = "rdnr: 0";
original1[sizeof original1 - 2] += r;

Fork and exec several children in linux

I want to fork and exec several processes from another.
My parent code is
/*Daddy.c*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(void)
{
int status;
char *nChild;
for (int i=0; i<3;i++){
int pid = fork();
if (pid == 0)
{
sprintf(nChild, "%d", i);
printf("%d\n", i);
char *const arguments[]={nChild, NULL};
fflush(NULL);
execv("child",arguments);
printf("\nNo , you can't print!\n");
}else if (pid == -1){
printf("%d\n", getpid());
exit(0);
}
}
wait(&status);
printf("Dad %d went out!\n", getpid());
exit(0);
}
and my child process is
/*child.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int args, char **argv){
if( args !=2){
printf("Child going away!\n");
exit(1);
}
printf("Child %s: %d going away stylishly!\n", argv[1], getpid());
exit(0);
}
When I don´t create three forks, but one, I know how to create the child, do some work and exit from child and parent. But, in this case, with several children it seems like the child never executes.
Because of the line wait(&status) I did hope that when the first child exits, the parent also exits but, any child prints any message.
Some relevant previous questions didn´t help.
You need to make parent wait for all child processes to finish. If not, assume that 1 child waited for is done and then parent exits. What about the other 2 children? They become orphan since their parent doesn't wait for them.
pid_t wpid;
int status = 0;
.
.
while ((wpid = wait(&status)) > 0); // the parent waits for all the child processes
This code did the job
/* daddy.c */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
int main(void)
{
int status=0;
char nChild[16];
pid_t wpid;
for (int i=0; i<3;i++){
sprintf(nChild, "%d", i);
int pid = fork();
if (pid == 0)
{
printf("%s\n", nChild);
char *const arguments[]={"child", nChild, NULL};
fflush(NULL);
execv("child",arguments);
printf("\nNo , you can't print!\n");
}else if (pid == -1){
printf("%d\n", getpid());
exit(0);
}
}
while ((wpid=wait(&status)) >0);
printf("Dad %d went out!\n", getpid());
exit(0);
}
As #OnzOg said in the comments of the question, allocation of nChild was the main problem. Also execv need pass child name twice, one as argument.
And finally, to improve the code, parent process needs to wait all processes to finish.

how can I send a signal between a child and a parent processes in linux

I have two cods the first one is for the parent which sends a signal (SIGUSER1) to the child and when the child receive it he should print that he received it.
Parent code
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
void sighand(int);
int main()
{
int cpid, ppid;
ppid = getpid();
printf("My process ID is %d\n", ppid);
FILE *fp1;
fp1 = fopen("cpid.txt", "w+");
cpid = fork();
if ( cpid == 0 ) {
printf("I am the child => PID = %d\n", getpid());
}
else
printf("I am the parent => PID = %d, child ID = %d\n", getpid(), cpid);
fprintf(fp1, "%d\n", cpid);
// kill(cpid, SIGUSR1);//id, signal, send
sigset(SIGUSR2, sighand);
return 0;
}
void sighand(int the_sig){
if (the_sig == SIGUSR2){
printf("sigusr2 received");
exit(1);
}
}
Child code
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
void sighand1(int);
int main()
{
FILE *fp1;
int pid;
fp1 = fopen("cpid.txt", "r");
fscanf(fp1, "%d,", &pid);
sigset(SIGUSR1,sighand1);
while(1) {
printf("Waiting..");
sigpause(SIGUSR1);
}
return 0;
}
void sighand1(int the_sig)
{
if (the_sig == SIGUSR1){
printf("sigusr1 received");
exit(1);
}
}
When I start the code it prints that the process (child) was created then when I send a signal it wont do any thing the child stuck in a loop or the wait and the parent wont do anything can any one tell me where did i go wrong in my code or logic.
Your code has several problems:
You try to pass some pid through a file, but you can use the getppid() function (get parent id)
You have some child code, but it is not called
no signal is launched
So your code can be corrected this way:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
void parent_handler(int the_sig)
{
if (the_sig == SIGUSR2){
printf("sigusr2 received in parent\n");
}
}
void child_handler(int the_sig)
{
if (the_sig == SIGUSR1){
printf("sigusr1 received in child\n");
kill(getppid(), SIGUSR2);
exit(1);
}
}
int child_function()
{
/* prepare to receive signal */
sigset(SIGUSR1,child_handler);
while(1) {
printf("Waiting..");
fflush(stdout);
/* wait for signal */
sigpause(SIGUSR1);
}
return 0;
}
int main()
{
int cpid, ppid;
ppid = getpid();
printf("My process ID is %d\n", ppid);
cpid = fork();
if ( cpid == 0 ) {
printf("I am the child => PID = %d\n", getpid());
child_function();
return 0;
}
else
printf("I am the parent => PID = %d, child ID = %d\n", getpid(), cpid);
/* child will never reach this point */
sleep(1);
/* prepare parent to received signal */
sigset(SIGUSR2, parent_handler);
/* send signal to child */
kill(cpid, SIGUSR1);
sleep(1);
return 0;
}

To share an unsigned int between parent and child after fork()?

I'm trying to write a small program that generates a child process with fork() that will have to increase a variable shared with the parent, how do I share an unsigned int variable?
code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
static unsigned int elapsed;
int count(){
while(1){
sleep(1);
elapsed++;
}
exit(EXIT_SUCCESS);
}
void hadler(int sig){
if( sig == SIGUSR1){
printf("elapsed: %u\n", elapsed);
}
}
int main(){
pid_t pid = getpid();
printf("This is my pid: %d\n", pid);
pid = fork();
if(pid == 0)
count();
while(1){
signal(SIGUSR1, hadler);
}
}
You can see there is a child than exec count() (increase a variable "elapsed" every second). The parent is waiting for SIGUSR1, when receive the signal he print the "elapsed".
Naively I tried to use a static global variable but it doesn't work for obvious reasons.

Calling every child process at once to kill?

I have to write an program which will generate a random amount of processes, and then will kill them one after one, after they all were created.
My problem is that I can't stop the child processes after being created.
Also, I try to call the termination-output to stdout from a child process, but don't really know how to solve it (because pid = 0 is for every child process).
#define _POSIX_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{
//int status;
srand(time(NULL));
int amount = (rand())%9+1;
pid_t fatherid = getpid();
printf("Hello I am a parent process, my PID is %d and I will now create %d children.\n",fatherid,amount);
pid_t pid = 1;
pid_t pidarr[amount];
for(int i = 0;i<amount;i++){
if(pid != 0){
pid = fork();
pidarr[i] = pid;
if(pid ==0){
printf("Hello I am a child process, my PID is %d and my parent has the PID %d.\n",getpid(),fatherid);
}
sleep(1);
}
}
if(pid != 0){
wait(NULL);
}
for(int i = (amount-1);i >= 0;i--){
if(pidarr[(i-1)] != 0){
printf("Hello I am a child process %d, I will terminate now.\n",getpid());
}
sleep(rand()%4);
if(pid != 0){
kill(pidarr[i],SIGKILL);
printf("Child Process %d was terminated.\n",pidarr[i]);
}
}
if(pid != 0){
printf("All child processes were terminated. I will terminate myself now.\n");
}
return EXIT_SUCCESS;
}
the following code shows how to handle fork and child processes.
the code compiles cleanly, is tested and works
#define _POSIX_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
int main( void )
{
//int status;
srand(time(NULL));
int amount = (rand())%9+1;
pid_t fatherid = getpid();
printf("Hello I am a parent process, my PID is %d and I will now create %d children.\n",fatherid,amount);
pid_t pid;
pid_t pidarr[amount];
for(int i = 0;i<amount;i++)
{
pid = fork();
if( -1 == pid )
{ //then, fork() error
perror( "fork() failed" );
exit(1);
}
// implied else, fork() successful
//pidarr[i] = pid;
if(!pid )
{ // then child process
printf("Hello I am a child process, my PID is %d and my parent has the PID %d.\n",getpid(),fatherid);
exit(0); // exit child process
}
// implied else, parent process
pidarr[i] = pid;
sleep(1);
} // end for
for(int i = (amount-1); i >= 0; i--)
{
kill(pidarr[i],SIGKILL);
printf("Child Process %d was terminated.\n",pidarr[i]);
}
printf("All child processes were terminated. I will terminate myself now.\n");
return(0);
} // end function: main
I am not sure about other parts of your logic (e.g. the if clause inside the fork loop), but
if(pid != 0){
wait(NULL);
}
looks suspiciously as of the parent process waits for a child to exit so that it doesn't get to the code which would kill the children at all (unless they exit on their own, but then the killing seems pointless).
Some issues in your code:
1) As #Peter Schneider points out,
parent process waits for a child to exit so that it doesn't get to the code which would kill the children
So first of all, you have to get rid of:
if(pid != 0){
wait(NULL);
}
2) The for loop that kills the children has to be executed only by the parent process, so the if clause embraces the for:
if(pid != 0){
for(int i = (amount-1);i >= 0;i--){
kill(pidarr[i],SIGKILL);
printf("Child Process %d was terminated.\n",pidarr[i]);
}
}
3) The child processes have to wait doing something until parent kills them, so append the following else clause to the above if:
else{
while(1){
printf("I am a child process %d. Will sleep for 2 senconds\n",getpid());
sleep(2);
}
}
4) the following code makes no sense, because when children are killed they simply stop working.
if(pidarr[(i-1)] != 0){
printf("Hello I am a child process %d, I will terminate now.\n",getpid());
}
If you want children to do something when the signal from kill() gets to them, you will have to use signals.

Resources