SIGUSR1 - kill sigaction in C - c

In the C language create a program that creates two processes and connects them via pipe.
The first descendant redirects its' stdout into the pipe and writes (space separated) pairs of random numbers into it (function rand). Delay the output of the numbers by 1 second.
The second descendant redirects the pipe output to it's stdin, redirects it's stdout into a file called out.txt in the current directory.
The parent process waits 5 seconds and then sends SIGUSR1 to the first process (number generator). This should perform a correct termination of both processes. It waits for the sub-processes to terminate (wait function) and terminates itself.
I really need help with:
The first descendant has to treat the SIGUSR1 signal (sigaction function) and in case of receiving such signal it prints a string “TERMINATED” to it's stderr and terminates.
FILE *file;
file = fopen(NAZEV, "a+");
int pipefd[2];
pipe(pipefd);
pid_t pid1;
int retcode;
pid1=fork();
if(pid1 == 0) // child 1
{
close(roura[0]);
printf("child1...\n");
dup2(roura[1], STDOUT_FILENO);
int i = 0;
while(i < 6)
{
i++;
int a = rand();
int b = rand();
sleep(1);
printf("%d %d\n", a, b);
}
close(roura[1]);
exit(45);
}
else if (pid1 < 0)
{
printf("Fork selhal\n");
exit(2);
}
else
{
pid_t pid2;
pid2 = fork();
if (pid2 == 0) //child 2
{
close(roura[1]);
dup2(roura[0], STDIN_FILENO);
printf("child2...\n");
int i = 0;
while(i < 5)
{
i++;
int c;
int d;
scanf("%d %d", &c, &d);
printf("%d %d\n", c, d);
fprintf(file,"%d %d\n", c, d);
}
printf("child2 end\n");
exit(0);
}
else if (pid2 < 0)
{
printf("Fork error\n");
exit(2);
}else
{
sleep(5);
kill(pid1, SIGUSR1);
wait(&pid1); //wait for child 1
wait(&pid2); //wait for child 2
printf("parent end\n");
exit(0);
}
}
exit(0);
}

Adda signal handler to sigusr1 that prints to stderr and exits.
Try this, adapted to compile in cygwin:
#include <stdio.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
#endif
void sig_handler(){
fprintf(stderr,"TERMINATED");
exit(0);
}
void main(int argc, char ** argv){
FILE *file;
file = fopen("NAZEV", "a+");
int pipefd[2];
int roura[2] ;
pipe(pipefd);
pid_t pid1;
int retcode;
pid1=fork();
if(pid1 == 0) // child 1
{
close(roura[0]);
printf("child1...\n");
dup2(roura[1], STDOUT_FILENO);
if (signal(SIGUSR1, sig_handler) == SIG_ERR){
printf("\ncan't catch SIGUSR1\n");
exit(13);
}
int i = 0;
while(i < 6)
{
i++;
int a = rand();
int b = rand();
sleep(1);
printf("%d %d\n", a, b);
}
close(roura[1]);
exit(45);
}
else if (pid1 < 0)
{
printf("Fork selhal\n");
exit(2);
}
else
{
pid_t pid2;
pid2 = fork();
if (pid2 == 0) //child 2
{
close(roura[1]);
dup2(roura[0], STDIN_FILENO);
printf("child2...\n");
int i = 0;
while(i < 5)
{
i++;
int c;
int d;
scanf("%d %d", &c, &d);
printf("%d %d\n", c, d);
fprintf(file,"%d %d\n", c, d);
}
printf("child2 end\n");
exit(0);
}
else if (pid2 < 0)
{
printf("Fork error\n");
exit(2);
}else
{
sleep(5);
kill(pid1, SIGUSR1);
wait(&pid1); //wait for child 1
wait(&pid2); //wait for child 2
printf("parent end\n");
exit(0);
}
}
exit(0);
}

You need to register a signal handler using sigaction if you want to override the default action. For SIGUSR1, the default action is to terminate the process.

Related

Linux shuts down after compiling basic children process

In this simple C code, I am trying to create 10 children. Then do some work (such as printing the time) in them individually. Then I try to kill all of them in parent process. You will easily understand the code below. The problem is that, whenever I run this, first it gives the various outputs from children then Linux shuts down. Then I start from passing user password and everything is closed. Why this happens?
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdlib.h>
#include <time.h>
int main() {
pid_t pids[10];
int i;
int n= 10;
for (i= 0; i<n; ++i) {
if ((pids[i] = fork()) <0) {
perror("fork");
abort();
}
else if (pids[i] == 0) {
struct timeval tv;
time_t t;
struct tm*info;
char buffer[64];
gettimeofday(&tv,NULL);
t = tv.tv_sec;
info = localtime(&t);
sleep(1);
printf("CHILD PID: %d and the time is %s\n",getpid(),asctime(info));
}
}
int status;
pid_t pid;
sleep(5);
while (n >0) {
pid = wait(&status);
kill((long)pid, SIGTERM);
printf("CHILD %d killed.",pid);
--n;
}
}
In process created by fork() all variables have the same value as before fork. After fork in this your code
for (i= 0; i<n; ++i) {
if ((pids[i] = fork()) <0) {
perror("fork");
abort();
}
else if (pids[i] == 0) {
...
}
}
i in child process is the same as it was in parent before fork, so for loop continue to execute and spawn a lot of grand children processes.
After loop is executed all spawned processes call wait(). Processes which are spawned on last iteration (with i==9) have no children, so wait() indicates error by returning -1 (and errno==ECHILD). Then you call kill() with pid==-1, which is:
If pid equals -1, then sig is sent to every process for which the calling process has permission to send signals, except for process 1 (init)
If you want child processes to terminate by themself then you should exit explicitly, e.g. with _exit() function. In this case you don't need to send TERM signal:
int main(void)
{
pid_t pids[10];
int i;
int n = 10;
for (i = 0; i<n; ++i)
{
if ((pids[i] = fork()) < 0)
{
perror("fork");
abort();
// abort() never return, "else" is not needed
}
if (pids[i] == 0)
{
struct timeval tv;
time_t t;
struct tm*info;
gettimeofday(&tv,NULL);
t = tv.tv_sec;
info = localtime(&t);
sleep(1);
printf("CHILD PID: %d and the time is %s\n",getpid(),asctime(info));
_exit(0); // terminate process explicitly
}
}
int status;
pid_t pid;
sleep(5);
while (n > 0)
{
pid = wait(&status);
// No kill needed for already exited process
// kill((long)pid, SIGTERM);
if (pid == -1)
{
perror("wait");
abort();
} else {
printf("CHILD %d killed.\n", pid);
}
--n;
}
}
If you want to terminate child processes from parent process then children should wait until terminated, but you should send signal before waiting for child process termination:
int main(void)
{
pid_t pids[10];
int i;
int n = 10;
for (i = 0; i<n; ++i)
{
if ((pids[i] = fork()) < 0)
{
perror("fork");
abort();
// abort() never return, "else" is not needed
}
if (pids[i] == 0)
{
struct timeval tv;
time_t t;
struct tm*info;
gettimeofday(&tv,NULL);
t = tv.tv_sec;
info = localtime(&t);
sleep(1);
printf("CHILD PID: %d and the time is %s\n",getpid(),asctime(info));
// wait until terminated
for (;;)
pause();
}
}
int status;
pid_t pid;
sleep(5);
for (i = 0; i<n; ++i) {
if (kill(pids[i], SIGTERM) == -1) {
perror("kill");
}
}
while (n--)
{
pid = wait(&status);
if (pid == -1)
{
perror("wait");
abort();
} else {
printf("CHILD %d killed.\n", pid);
}
}
}

Passing data from one pipe to another

I am new to pipes but how do I redirect the output from child_1 to the input for child_2?
I am trying to pass the value from the parent to child_1, adds 1 to the value, print the value, then use that output and pass it into child_2, add 1 again, and finally print the value.
The code below has the right output value for child_1, but not for child_2, how do I redirect the output from child_1 to the input for child_2?
Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char * argv[]) {
int fd[2];
int PID;
pipe(fd); //fd1[0] = read | fd1[1] = write
PID = fork(); // spawn child_1
if (PID < 0){ // failed to fork
perror("Unable to fork child");
exit(1);
}
if (PID > 0) { // parent
int value = 100;
// since parent is only writing, close the reading end of pipe
close(fd[0]);
// write the data to the write end of the pipe
write(fd[1], &value, sizeof(int));
// then close the writing end of the pipe (parent)
close(fd[1]);
/**********************************************************/
} else { // child 1
int val = 0;
// read from the parent pipe
read(fd[0], &val, sizeof(int));
val += 1;
// is this how to redirect from one pipe to another?
dup2(fd[0], fd[1]);
// this prints the right value for val (val [101] = value [100] + 1)
printf("Child [%d] read value %d\n", getpid(), val);
// close the reading end of the pipe for child_1
close(fd[0]);
int PID2 = fork(); // make child 2
if(PID2 == 0) { // child 2
int val2 = 0;
close(0); // close stdin since we are trying to take the value from child_1
// read input from child_1 pipe (NOT WORKING?)
read(fd[0], &val2, sizeof(int));
val2 += 1;
printf("Child [%d] out %d\n", getpid(), val2);
close(fd[0]);
}
}
return EXIT_SUCCESS;
}
The way you have things set up, there's no need to use dup2() or any other I/O redirection.
Add #include <unistd.h> to the list of include files (and remove #include <string.h> — it seems to be unused)
Delete: dup2(fd[0], fd[1]);
Delete: close(fd[0]);
Delete: close(0);
Before the second fork(), add write(fd[1], &val, sizeof(val));
When you have close(fd[0]) in the first child, you effectively close fd[0] for the second child too.
You should check the status of the read and write operations before using the results.
Those changes lead to:
/* SO 7383-1815 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int fd[2];
int PID;
pipe(fd);
PID = fork();
if (PID < 0)
{
perror("Unable to fork child");
exit(EXIT_FAILURE);
}
if (PID > 0)
{
int value = 100;
close(fd[0]);
write(fd[1], &value, sizeof(int));
close(fd[1]);
}
else
{
int val = 0;
if (read(fd[0], &val, sizeof(val)) != sizeof(val))
{
perror("read() failed in child 1");
exit(EXIT_FAILURE);
}
val += 1;
printf("Child [%d] read value %d\n", getpid(), val);
if (write(fd[1], &val, sizeof(val)) != sizeof(val))
{
perror("write() failed in child 1");
exit(EXIT_FAILURE);
}
int PID2 = fork();
if (PID2 == 0)
{
int val2 = 0;
if (read(fd[0], &val2, sizeof(val2)) != sizeof(val2))
{
perror("read() failed in child 2");
exit(EXIT_FAILURE);
}
val2 += 1;
printf("Child [%d] out %d\n", getpid(), val2);
close(fd[0]);
close(fd[1]);
}
}
return EXIT_SUCCESS;
}
When compiled (cleanly with options set fussy), it produces output such as:
Child [34520] read value 101
Child [34521] out 102
I believe this is what was wanted.

Child process not waking up after a sigsuspend (C)

I have to create a program that generates 2 childs and each of them has to generate a random number. After that the child who generated the lowest number has to send a SIGUSR1 to the other child. In my case i wanna send a SIGCONT to child 1 to wake him up so that he can send SIGUSR1 to the other process but child 1 doesn't wake up.. any help? Thanks in advance.
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
#define N 2
int getRand(int upper)
{
srand(time(0));
int random;
random = rand() % upper;
return random;
}
void sighandler(int signo)
{
if (signo == SIGUSR1)
{
printf("Received SIGUSR1, my PID is %d\n\n", getpid());
exit(0);
}
if (signo == SIGUSR2)
{
printf("Received SIGUSR2.. I woke up! (My PID is %d)\n\n", getpid());
}
}
int main (int argc, char **argv)
{
int i, r, m, b;
int status = 0;
int tabcpid[N], ppid, wpid;
int fd[2], fdbool[2]; //fd [0 = read] [1 = write]
sigset_t set, zeromask;
struct sigaction action;
//Gestione segnali
sigemptyset(&zeromask);
sigemptyset(&action.sa_mask);
action.sa_handler = sighandler;
action.sa_flags = 0;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigprocmask(SIG_BLOCK, &set, NULL);
if (sigaction(SIGUSR1, &action, NULL) == -1)
{
perror("Error while doing sigaction.\n\n");
}
if (pipe(fd) == -1)
{
printf("Error opening pipe fd!\n\n");
exit(1);
}
if (pipe(fdbool) == -1)
{
printf("Error opening pipe fdbool!\n\n");
exit(1);
}
printf("\nPipes opened successfully. Forking ...\n\n");
sleep(2);
for (i = 0; i < N; i++)
{
if ((tabcpid[i] = fork()) == 0) //Child code
{
int n = atoi(argv[1]);
m = getRand(n);
b = 20;
ppid = getppid();
printf("I'm the son process #%d with PID: %d\n", i + 1, getpid());
printf("Random number in interval 0 - %d: %d\n\n", n, m);
sleep(2);
if (i == 0)
{
close(fd[0]);
write(fd[1], &m, sizeof(int));
close(fd[1]);
printf("Suspending..\n\n");
sigsuspend(&zeromask);
printf("So' ripartitoo\n\n");
/*
close(fdbool[1]);
read(fdbool[0], &b, sizeof(int));
close(fdbool[0]);
printf("--- b value: %d\n\n", b);
if (b == 0)
{
printf("I'm the process %d and I got the lowest number, SIGUSR1 sent to my brother.\n\n", getpid());
kill(tabcpid[1], SIGUSR1);
}
sleep(2);
*/
}
else
{
close(fd[1]);
read(fd[0], &r, sizeof(int));
close(fd[0]);
int lower = (r < m) ? r : m;
int igotlower = (m < r) ? 1 : 0;
printf("--- igotlower value: %d\n\n", igotlower);
close(fdbool[0]);
write(fdbool[1], &igotlower, sizeof(int));
close(fdbool[1]);
//printf("Got %d from other child process, while i got %d.\nThe smallest number is %d.\nMy PID is %d and the other process' PID is %d.\n\n", r, m, lower, getpid(), tabcpid[0]);
//sleep(2);
if (igotlower == 1)
{
printf("I'm the process %d and I got the lowest number, SIGUSR1 sent to my brother..\n\n", getpid());
kill(tabcpid[0], SIGUSR1);
sigsuspend(&zeromask);
}
else
{
printf("I'm sending SIGCONT to %d\n\n", tabcpid[0]);
kill(tabcpid[0], SIGCONT);
sigsuspend(&zeromask);
}
}
sleep(2);
}
sleep(2);
}
wait(&status);
close(fdbool[1]);
read(fdbool[0], &b, sizeof(int));
close(fdbool[0]);
kill(tabcpid[b], SIGUSR1);
wait(&status);
printf("It's me the father... it's all over, we're done!\n\n");
sleep(2);
return 0;
}

C fork and pipe printing pid in order

So I need this program which needs to create argv[1] child using fork() and print what children number are they and what PID do they have in order of its creation.
I have to do that using pipes blocking properties.
Example output:
I am child 1 and my PID is 25853.
I am child 2 and my PID is 25854.
I am child 3 and my PID is 25855.
This is what I have tried so far, but it doesn't respect the order of children creation.
int main(int argc, char* argv[])
{
char buffer[80];
int p[2], i;
int pid = getpid();
for (i = 0; i < atoi(argv[1]); i++) {
pipe(p);
if (fork() == 0) {
read(p[0], &pid, sizeof(pid)); // It should block here until there's
// something in the pipe to read
sprintf(buffer, "I am child %d and my PID is %d\n", i + 1, getpid());
write(1, &buffer, strlen(buffer));
close(p[0]);
close(p[1]);
exit(0);
}
else { // parent
close(p[0]);
write(p[1], &pid, sizeof(pid));
close(p[1]); // The child is able to read the EOF now.
}
}
while ((waitpid(-1, NULL, 0)) > 0)
;
close(p[0]);
close(p[1]);
sprintf(buffer, "I've finished\n");
write(1, &buffer, strlen(buffer));
}
I feel like I am close but I am not using the pipes block poperties correctly.
I need some advice, thanks.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
if (argc != 2) {
return 1;
}
int const n = atoi(argv[1]);
for (int i = 0; i < n; i++) {
int p[2];
if (pipe(p) != 0)
return 1;
int pid = fork();
if (pid == 0) {
close(p[1]);
if (read(p[0], &pid, sizeof pid) != sizeof pid)
return 1;
close(p[0]);
fprintf(stdout, "I am child %d and my PID is %d\n", i + 1, pid);
return 0;
}
else if (pid > 0) {
close(p[0]);
if (write(p[1], &pid, sizeof pid) != sizeof pid)
return 1;
close(p[1]);
if (waitpid(pid, NULL, 0) == -1)
return 1;
}
else {
return 1;
}
}
fprintf(stdout, "I've finished\n");
}

Why my fork() does not output anything?

As code , why I don't get any outputs , can anybody tell me the issue? like that I have two fork() and each will run in a child process and my parent process will not be exit, seems right, but still don't get anything output.
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
/***********************************/
printf("--beginning of program\n");
int counter = 0;
pid_t pid1 = 0;
pid_t pid2 = 0;
while(1){
if(pid1 == 0)
pid1 = fork1();
if(pid2 == 0)
pid2 = fork2();
}
printf("--end of program--\n");
return 0;
}
/* Two fork() */
pid_t fork1(){
pid_t pid = fork();
if(pid ==0 )
{
while(1){
sleep(1);
fprintf(stdout," fork1 ");
}
}
return pid;
}
pid_t fork2(){
pid_t pid = fork();
if(pid ==0 )
{
while(1){
sleep(1);
fprintf(stdout," fork1 ");
}
}
return pid;
}
stdout is buffered, it will normally only be flushed on a newline or if you explicitly flush it.
You can get your code to output the lines from the children processes by adding a newline in your statements:
fprintf(stdout, "fork1\n");
Or by explicitly flushing the buffer after the fprintf:
fflush(stdout);

Resources