why my handler does not give me the exit status in C? - c

currently I have the code like that:
void handler(int sig) {
int stat;
wait(&stat);
if (WIFEXITED(stat))
printf("%d", WEXITSTATUS(stat));
}
int main() {
int i;
pid_t pids[5];
signal(SIGCHLD, handler);
for (i=0; i<5; i++)
if ((pids[i] = fork()) == 0) {
printf("1");
while (1) ; /* inf loop */
}
for (i=0; i<5; i++)
kill(pids[i], SIGKILL);
sleep(1);
return 2;
}
All necessary head files were included such as <signal.h> and <stdlib.h>
I assume that I would at least get the exit status when running, but there is no output. Why is that?

But the child processes don't exit, they are killed. They are terminated by a signal. Use WIFSIGNALED to check if the process was killed by a signal, and WTERMSIG to get the signal number.
For a process to "exit" it has to either return from the main function, or call exit.

Related

fork() in C. I need explanation on this code

So, i have this piece of C code
I can't grasp what the second 'for' segment is about. When does it get terminated abnormally?
Can someone enlighten me on that?
#include<unistd.h>
#include<stdio.h>
#include <sys/wait.h>
#define N 30
int main() {
pid_t pid[N];
int i;
int child_status;
for (i = 0; i < N; i++) {
pid[i] = fork();
if (pid[i] == 0) {
sleep(60 - 2 * i);
exit(100 + i);
}
}
for (i = 0; i < N; i++) {
pid_t wpid = waitpid(pid[i], & child_status, 0);
if (WIFEXITED(child_status)) {
printf("Child%d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status));
} else {
printf("Child%d terminated abnormally\n", wpid);
}
}
return (0);
}
When child is terminate ,to be able to find with which value the child was terminated (either with exit or with return) i have to pash the second parametre in waitpid() with pointer to an integer.So in that integer on return from the call it will include 2 types of information
a) if child was terminated well with return or exit or stoped unexpectedly
b)the second type will be having the termination value.
If i want to know the information from (a) i need to use the macro WIFEXITED(), if this give me true the (b) emerged from macro WEXITSTATUS().This is a simple example
#include <stdio.h>
#include <stdlib.h> /* For exit() */
#include <unistd.h> /* For fork(), getpid() */
#include <sys/wait.h> /* For waitpid() */
void delay() { /* Just delay */
int i, sum=0;
for (i = 0; i < 10000000; i++)
sum += i;
printf("child (%d) exits...\n", getpid());
exit(5); /* Child exits with 5 */
}
int main() {
int pid, status;
pid = fork();
if (pid == 0) /* child */
delay();
printf("parent (%d) waits for child (%d)...\n", getpid(), pid);
waitpid(pid, &status, 0);
if (WIFEXITED(status)) /* Terminated OK? */
printf("child exited normally with value %d\n", WEXITSTATUS(status));
else
printf("child was terminated abnormaly.\n");
return 0;
}
SOS The macro WEXITSTATUS() return only the 8 least important bits of the value when the child is terminate.So if the child wants to "say" something to his parent through exit/waitpid it must be a number up to 255.

Can this program exit normally?

int ccount=0;
void child_handler(int sig){
int child_status;
pid_t pid = wait(&child_status);
ccount--;
}
void fork() {
pid_t pid[N];
int i, child_status;
ccount=N;
signal(SIGCHLD, child_handler);
for (i=0; i<N ; i++) {
if ((pid[i]=fork())==0) {
sleep(1); exit(0);
}
while (ccount>0) pause();
}
In this function, suppose that any one parent process receive the last SIGCHLD signal, Nth signal, between while and paust(). Then it cannot exit() because it cannot escape from while loop.
Then can I say that this program exits unnormally?

how to send a sigterm signal

In my following program i have two processes( the father and the child) both do the same thing but we want to figure out how will finish his task first. There is a randomized number of seconds both will sleep causing the challenge of who finishes first more random. Both are sending signals to the other process, when five signals have been recieved the process will then send a SIGTERM to the other process signaling that it has finished first. that other process will print that the opponent process has won. My problem is with sending that sigterm signal to the other process, ive tried kill function, singal function and dont know where is my mistake and what to try next. So any help would e=be appreciated below is my code:
//--------including--------------
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
//-------global----------------
int sig1_counter=0;
int sig2_counter=0;
//-------prototypes--------------
void catch_sigusr1(int sig_num) ;
void catch_sigusr2(int sig_num) ;
void do_son() ;
void do_dad() ;
//--------main------------------
int main (){
pid_t pid;
srand((unsigned)time(NULL));
signal(SIGUSR1, catch_sigusr1) ;
signal(SIGUSR2, catch_sigusr2) ;
pid = fork() ;
switch(pid) {
case -1 : perror("fork() failed") ;
exit(EXIT_FAILURE) ;
case 0 : do_son() ;
exit(EXIT_SUCCESS) ;
default: do_dad() ;
exit(EXIT_SUCCESS) ;
}
return EXIT_SUCCESS;
}
//-------functions-------------------
void do_son() {
int i ;
for (i=0;i<10;i++)
{
int sleep_time=rand()%4;
sleep(sleep_time);
int num=rand()%2;
if (num==0)
kill(getpid(), SIGUSR1) ;
else
kill(getpid(), SIGUSR2);
}
}
//---------------------------------
void do_dad() {
int i ;
for (i=0;i<10;i++)
{
int sleep_time=rand()%4;
sleep(sleep_time);
int num=rand()%2;
if (num==0)
kill(getpid(), SIGUSR1) ;
else
kill(getpid(), SIGUSR2);
}
}
//---------------------------------
void catch_sigusr1(int sig_num) {
signal(SIGUSR1, catch_sigusr1);
printf(" process %d got signal SIGUSR1\n", getpid()) ;
if (sig_num==SIGTERM)
{
printf("process %d win\n", getpid());
exit(EXIT_SUCCESS);
}
sig1_counter++;
if (sig1_counter==5)
{
printf(" process %d surrender\n", getpid()) ;
kill(getpid(),SIGTERM); // here we have a mistake
//signal(SIGTERM,catch_sigusr2); // !!!!!!!!!!!
exit(EXIT_SUCCESS);
}
}
//---------------------------------
void catch_sigusr2(int sig_num) {
signal(SIGUSR2, catch_sigusr2) ;
printf(" process %d got signal SIGUSR2\n", getpid()) ;
if (sig_num==SIGTERM)
{
printf("process %d win\n", getpid());
exit(EXIT_SUCCESS);
}
sig2_counter++;
if (sig2_counter==5)
{
printf(" process %d surrender\n", getpid()) ;
kill(getpid(),SIGTERM);
//signal (SIGTERM,catch_sigusr1);
exit(EXIT_SUCCESS);
}
}
Both your do_son() and do_dad() functions send signals to getpid(), which means they are signalling only themselves rather than each other.
In order to signal each other, you need:
do_dad() to send the signal to pid, the return value from fork() being the child PID; and
do_son() to send the signal to getppid(), the parent PID, noting the use of non-sexist terms in the system call :-)
In other words, something like this in your main function:
switch (pid = fork()) {
case -1:
perror("fork() failed");
break;
case 0:
do_both(getppid());
break;
default:
do_both(pid);
break;
}
The reason there's no distinct parent and child function any more is that the only difference is which PID gets signalled. Because you're passing that in as a parameter, you can combine the two functions:
void do_both(pid_t other) {
for (int i = 0; i < 10; i++) {
int sleep_time = rand() % 4;
sleep(sleep_time);
if ((rand() % 2) == 0)
kill(getpid(), SIGUSR1);
else
kill(getpid(), SIGUSR2);
}
}

sigwait() repeatedly unblocked by SIGUSR1

I am writing a program that takes a list of UNIX commands from a file and executes them sequentially. To keep everything in order, I must have each command initialized and kept waiting for SIGUSR1 via sigwait(). When every command is initialized, then every command can execute.
Usage: > program.c input.txt
However, it appears that SIGUSR1 is repeatedly called, completely surpassing sigwait(). What is going on here? I've tried so many different things, but it's recently modeled after this answer. To rephrase, I want the signal to be raised for commands immediately after initialization. I want the signal to be unblocked when all commands are completely initialized
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
void on_sigusr1(int sig)
{
// Note: Normally, it's not safe to call almost all library functions in a
// signal handler, since the signal may have been received in a middle of a
// call to that function.
printf("SIGUSR1 received!\n");
}
int main(int arc, char* argv[])
{
FILE *file;
file = fopen(argv[1] ,"r");
int BUF_SIZE = 100;
char *token;
char buffer[BUF_SIZE];
char programs[BUF_SIZE];
char *commands[BUF_SIZE];
int i = 0;
int counter = 1;
while (fgets(buffer, sizeof buffer, file ) != NULL)
{
strcpy(programs, buffer);
int length = strlen(buffer)-1;
if (buffer[length] == '\n')
{
buffer[length] = '\0';
}
i = 0;
token = strtok(buffer," ");
while(token != NULL)
{
commands[i++] = token;
token = strtok(NULL, " ");
}
commands[i] = 0;
pid_t pids[counter];
// Set a signal handler for SIGUSR1
signal(SIGUSR1, &on_sigusr1);
// At program startup, SIGUSR1 is neither blocked nor pending, so raising it
// will call the signal handler
raise(SIGUSR1);
// Now let's block SIGUSR1
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
sigprocmask(SIG_BLOCK, &sigset, NULL);
// SIGUSR1 is now blocked, raising it will not call the signal handler
printf("About to raise SIGUSR1\n");
raise(SIGUSR1);
printf("After raising SIGUSR1\n");
for(i = 0; i < counter; ++i)
{
pids[i] = fork();
if(pids[i] > 0)
{
printf("Child process %d ready to execute command %s", getpid(), programs);
// SIGUSR1 is now blocked and pending -- this call to sigwait will return
// immediately
int sig;
int result = sigwait(&sigset, &sig);
if(result == 0) {
printf("Child process %d executing command %s", getpid(), programs);
execvp(commands[0], commands);
}
}
}
// All programs have been launched
for(i = 0; i < counter; ++i)
{
wait(&pids[i]);
}
// All programs are waiting to execute
for (i = 0; i < counter; ++i)
{
// SIGUSR1 is now no longer pending (but still blocked). Raise it again and
// unblock it
raise(SIGUSR1);
printf("About to unblock SIGUSR1\n");
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
printf("Unblocked SIGUSR1\n");
}
}
exit(0);
fclose(file);
return 0;
}
UPDATE: Tried changing signal() to sigaction(). No change.
You should consider calling sigwait after checking to see if that pid is a child process.
So maybe put
int sig;
and
int result = sigwait(&sigset, &sig);
within an if statement that checks if the pid is == 0 which would indicate that it is a child. Otherwise you would be sigwaiting a parent process.
If the pid is greater than 0 it's a parent process id and if it's less than zero its an error.
Then for each process in your array of pids you would call kill(pid_array[i], SIGUSR1) to unblock it.

Parent and child proc sync using signals

I have some troubles:
it is not clear for me how to synchronise parent and child processes using signals, and this code doesn't work.
I thought that it should work like that: parent sends signal to child, child's pause() is end, child sends signal to parent, parent's pause() is end .. etc
why it is not so?
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
void handler_cp() {
}
void handler_pc() {
}
void child_proc() {
int i = 0;
for (; i < 50; ++i) {
pause();
kill(getppid(), SIGUSR2);
}
void parent_proc(pid_t ch) {
int j = 0;
for (; j < 50; ++j) {
kill(ch, SIGUSR1);
pause();
}
}
int main(int argc, char* argv[]) {
signal(SIGUSR1, handler_cp);
signal(SIGUSR2, handler_pc);
pid_t ch = fork();
if (ch == 0)
child_proc();
else
parent_proc(ch);
return 0;
}
The signal may arrive before pause is called, in which case it will deadlock. Using signals for synchronization is, in general, a very bad idea.
In the child_proc method, reverse the lines as :
kill(getppid(),SIGUSR2);
pause();
This will wake the parent before the child goes to sleep.

Resources