kill() usage confusion in C - c

I have read the manual of kill, and I know that it is a system call for sending a signal. I write a simple multi process code, each child process will do the handler function if it catch a specified signal, which is SIGUSR1 in my code.
In my code, I have made 3 processes, each process will print out "yo" if they catch SIGUSR1 signal, but the output only print out one time or two time..? That really confuse me, thanks for your help!
Here is my code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <time.h>
#include <signal.h>
#include <sys/time.h>
#include <string.h>
#define N 3
int pid_id[N];
void handler (int signum)
{
printf("yo\n");
}
void child(int process_index)
{
struct sigaction sa;
/* Register */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sigaction(SIGUSR1, &sa, NULL);
printf("I am %d.\n", getpid());
pid_id[process_index] = getpid();
sleep(5);
exit(0);
}
int main()
{
int i, status;
pid_t pid[N];
pid_t pid_wait;
for (i=0;i<N;i++)
{
pid[i] = fork();
if (pid[i]==0)
{
child(i);
}
}
for (i=0;i<N;i++)
kill(pid_id[i], SIGUSR1);
for (i=0;i<N;i++)
{
do
{
pid_wait = waitpid(pid[i], &status, WNOHANG);
}while(pid_wait != pid[i]);
}
printf("all done\n");
return 0;
}

Remember that you're dealing with multiple processes now. Just because in the code it looks like you ran child before kill doesn't mean that it happened in that order. The order of execution is entirely dependent on how the OS schedules CPU time for these processes.
What's happening is that some of the child processes are killed before they can install their signal handler. This is an example of a race condition, much like the sort you get when starting new threads.
This can be solved by synchronising the parent with its children, so that it doesn't continue until all children have notified back that they have completed their necessary initialisation steps.

Related

How to join a thread which have fork in it?

Following is the case.
{
...
pthread_create(thread_id, NULL, thread_fun, NULL);
pthread_join(thread_id, NULL);
...
}
void * thread_fun(void * arg)
{
if(fork())
{
printf("In Parent\n");
pthread_exit(NULL);
}
else
{
printf("In Child\n");
pthread_exit(NULL);
}
}
How to use pthread_join() in such a way that I can wait for both child and parent process in thread?
Put all threads into endless loops and then inspect the whole program state with ps, top, htop or similar tools. You will find that the child process only has a single thread, while the parent process has (at least) two.
Now, concerning your question how to use pthread_join() to wait for the child process, you simply can't, because you can only use it to wait for threads in the same process. You could wait for the child process to terminate (waitpid()).
If the above doesn't answer your question (it's a bit unclear because you want to "wait for both child and parent process", which is where I wonder from which process' context) take a step back instead and describe on a higher level what you're trying to achieve instead. In other words, this could be a so-called "XY Problem". Do a bit of research on that term, it's a good thing to learn and understand in any case.
There's basically two ways you can do it. You can either have the child thread wait for the child process before it exits, or you can pass the PID of the child process to the parent thread so it can wait for it. Here's the first approach:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
void *thread_fun(void *arg);
int main(void) {
pthread_t thread;
pthread_create(&thread, NULL, thread_fun, NULL);
pthread_join(thread, NULL);
return 0;
}
void *thread_fun(void *arg) {
pid_t pid = fork();
if(pid) {
printf("In Parent\n");
waitpid(pid, NULL, 0);
pthread_exit(NULL);
} else {
printf("In Child\n");
exit(0);
}
}
And here's the second:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
struct locked_pid {
sem_t sem;
pid_t pid;
};
void *thread_fun(void *arg);
int main(void) {
pthread_t thread;
struct locked_pid s;
sem_init(&s.sem, 0, 0);
pthread_create(&thread, NULL, thread_fun, &s);
sem_wait(&s.sem);
waitpid(s.pid, NULL, 0);
pthread_join(thread, NULL);
sem_destroy(&s.sem);
return 0;
}
void *thread_fun(void *arg) {
pid_t pid = fork();
if(pid) {
struct locked_pid *s = arg;
s->pid = pid;
sem_post(&s->sem);
printf("In Parent\n");
pthread_exit(NULL);
} else {
printf("In Child\n");
exit(0);
}
}
Note that the first is much simpler than the second. This is because in the second, you need a semaphore so that the parent process knows when the child PID gets written.
By the way, there's two things you should know about this code before you use it in anything important:
It doesn't have any error-checking, even though most of the functions it uses can fail.
POSIX says "If a multi-threaded process calls fork() ... the child process may only execute async-signal-safe operations until such time as one of the exec functions is called." This means that you shouldn't be doing printf("In Child\n");.

Process dies after SIGINT signal

I don't understand what is happening here, I have a parent process which handles the SIGINT signal and then makes a child. What I expect when I press Ctrl+C is that both processes will print "SIGINT received" and then continue but it turns out that the parent process dies after receiving SIGINT but the child is still there. I can't understand that.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/signal.h>
#include <string.h>
void handler (int sig) {
printf("SIGINT received\n");
}
void child() {
while (1) {
printf("I'm the child\n");
sleep(1);
}
exit(0);
}
int main(int argc, char *argv[]) {
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = &handler;
// Link SIGINT with the handler
sigaction(SIGINT, &act, NULL);
// Create child
if (fork() == 0) child();
wait(NULL);
return 0;
}
An example of execution:
$ ./test_signals
I'm the child
^CSIGINT received
I'm the child
SIGINT received
$ I'm the child
I'm the child
So both processes handle SIGINT but the parent dies while the child continues...
The parent process is blocked in the main function and upon receiving the signal, handles it and returns from the call to wait with an error.
The child is just looping in the while handling SIGINT. When handled code returns where it was (probably blocked in sleep) and it continues to loop.
That code may illustrates what happens:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/signal.h>
#include <string.h>
#include <sys/errno.h>
void handler (int sig) {
printf("SIGINT received %d\n",getpid());
}
void child() {
while (1) {
printf("I'm the child\n");
sleep(1);
}
exit(0);
}
int main(int argc, char *argv[]) {
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = &handler;
// Link SIGINT with the handler
sigaction(SIGINT, &act, NULL);
// Create child
if (fork() == 0) child();
int r = wait(NULL);
if (r==-1 && errno==EINTR) printf("signal probably received in parent\n");
return 0;
}
Be aware that calling printf in a signal handler is forbidden.

signal handler showing confusion in C

I am trying to use signal to sync N processes then print out something.
Each child process register a handler which print "yo" and "hihi" when catching SIGUSR1.
I use kill(0, SIGUSR1) to trigger every process. Since the default action for catching SIGUSR1 is being killed, I set a do-nothing handler for the main process so that it will wait all child died.
The fork and send signal program will repeat for k times, I expect it will show out N*k times "yo" and "hihi". However, it doesn't show enough "yo" and "hihi" as I expect. The number of "yo" is different every execution.
Here is my code, and thanks for your help!
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <time.h>
#include <signal.h>
#include <sys/time.h>
#include <string.h>
#define N 3
int pid_id[N];
void handler2 (int signum)
{
printf("hihi\n");
}
void handler (int signum)
{
signal(SIGUSR2, handler2);
printf("yo\n");
raise(SIGUSR2);
}
void handler_do_nothing (int signum)
{
;
}
void child(int process_index)
{
struct sigaction sa;
/* Register */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sigaction(SIGUSR1, &sa, NULL);
printf("I am %d.\n", getpid());
pid_id[process_index] = getpid();
sleep(1);
exit(0);
}
int main()
{
int i, k, status;
pid_t pid[N];
pid_t pid_wait;
struct sigaction sa_main;
/* Register */ /* Main process will terminate if catch SIGUSR1 by default setting*/
memset(&sa_main, 0, sizeof(sa_main));
sa_main.sa_handler = handler_do_nothing;
sigaction(SIGUSR1, &sa_main, NULL);
/* Race k times */
for (k=0;k<3;k++)
{
for (i=0;i<N;i++)
{
pid[i] = fork();
if (pid[i]==0)
{
child(i);
}
}
// sleep();
kill(0, SIGUSR1);
for (i=0;i<N;i++)
{
do
{
pid_wait = waitpid(pid[i], &status, WNOHANG);
printf("I am waiting..\n");
sleep(1);
}while(pid_wait != pid[i]);
}
}
printf("all done\n");
return 0;
}
Your child processes are being signalled before they have had time (i.e. execution resource scheduled) to install the new signal handler.
This means that when the main program sends SIGUSR1, some subset of the child processes will still have handler_do_nothing installed.
If you want to wait until the child processes have all finished setting up, you will need to add some interprocess communication mechanism - e.g. the children could signal the parent process when they are ready.

Sending and handling a signal on a cloned thread

UPDATE: This appears to be a timing issue. Adding a call to sleep before the call to kill makes everything work as expected.
I have been playing with clone(2) and trying to get a handle on how it works. I am currently having trouble sending signals to a cloned process. I have the following code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
volatile int keep_going = 1;
typedef void (*sighandler_t)(int);
void handler(int sig) {
printf("Signal Received\n");
keep_going = 0;
}
int thread_main(void* arg) {
struct sigaction usr_action;
sigset_t block_mask;
sigfillset(&block_mask);
usr_action.sa_handler = &handler;
usr_action.sa_mask = block_mask;
usr_action.sa_flags = 0;
sigaction(SIGUSR1, &usr_action, NULL);
printf("Hello from cloned thread\n");
while(keep_going);
}
int main(int argc, char **argv) {
void* stack = malloc(4096);
int flags = SIGCHLD;
int child_tid = clone(&thread_main, stack + 4096, flags, NULL);
if (child_tid < 0) {
perror("clone");
exit(EXIT_FAILURE);
}
printf("My pid: %d, child_tid: %d\n", (int) getpid(), (int) child_tid);
int kill_ret = kill(child_tid, SIGUSR1);
if (kill_ret < 0) {
perror("kill");
exit(EXIT_FAILURE);
}
int status = 0;
pid_t returned_pid = waitpid(child_tid, &status, 0);
if (returned_pid < 0) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
exit(EXIT_SUCCESS);
}
Which yields the following output:
My pid: 14101, child_tid: 14102
killed by signal 10
The child was obviously killed as a result of the signal, why did the signal handler not get called?
To avoid the race condition, catch the signal on the parent, before the clone() call. The child inherits a copy of the parent's signal handlers. You can reset it later on the parent to SIG_DFL if you want. (Also, getpid() is async-signal-safe, if you want to emulate SIG_DFL behaviour on the parent).
The child is not receiving the signal because before the child has reached to the call to sigaction the parent is sending the signal and thats why it is getting killed. You should avoid setting the signal handler this way. Still if you want to do this way only then make sure is parent is waiting until the child sets up the signal handler. With this scenario you should see the expected result.
First what is strange is you didn't get this message :
"Hello from cloned thread\n"
therefore your child tread gets terminated before it manages to setup the signal handler.
EDIT:
I just saw your comment about sleep. Try to add another variable, which is set when the sigaction gets executed. The main thread should be blocked until this variable is not set.

Parent process doesn't complete after child is terminated in C

I'm having trouble with a process forking exercise. I want to fork a child process and have it hang after announcing it has been forked, and wait for a signal to terminate, after which the parent process must announce it is terminating and then exit.
I can get the processes forked and have the parent wait for the hanging child to be killed by the signal, but it seems to kill the parent as well. I tried killing the child process specifically by its PID, but with no success.
Thanks for any help!
Code:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
void catchInt (int signum)
{
printf("\nMy sincerest apologies, master\n");
/*kill(0, SIGINT);*/
exit(0);
}
void ignoreInt (int signum)
{
wait(NULL);
}
int main () {
pid_t pid;
/* fork process */
pid = fork();
if (pid < 0) /* error handler */
{
fprintf(stderr, "Fork Failed");
exit(-1);
}
else if (pid == 0) /* child */
{
printf("Child reporting in\n");
signal(SIGINT, catchInt);
for ( ;; )
pause();
}
else /* parent */
{
/* parent will wait for the child to complete */
signal(SIGINT, ignoreInt);
wait(NULL);
printf("You're welcome\n");
exit(0);
}
}
Even assuming you fix the code so it compiles (you've not defined tempPID), there are problems:
You set the child to go to sleep until a signal arrives.
You set the parent to wait until the child dies.
So, you have a state where neither process is going to do anything more.
You probably need the parent to send a signal to the child:
kill(pid, SIGINT);
It is not clear that you need the parent to set a signal handler.
You probably want the child to set a signal handler.
You probably don't want the infinite loop in the child.
Oh, and void main() is incorrect - int main() or int main(void) or int main(int argc, char **argv) are the approved declarations for main().
And it is tidier if you return a value (0) from main(). The C99 standard does permit you to drop off the end of main() and will treat that as returning zero, but only if the function is properly declared as returning an int.
The header for wait() and relatives in POSIX is <sys/wait.h>.
And, because I'm a sucker, here's code that compiles and might even do what you want:
#include <stdio.h>
#include <signal.h>
#include <unistd.h> /* getpid() */
#include <stdlib.h>
#include <sys/wait.h>
void catchInt(int signum)
{
printf("Child's PID is %d\n", (int)getpid());
printf("My sincerest apologies, master\n");
exit(1);
}
int main()
{
pid_t pid = fork();
if (pid < 0) /* error handler */
{
fprintf(stderr, "Fork Failed");
exit(-1);
}
else if (pid == 0) /* child */
{
printf("Child reporting in\n");
signal(SIGINT, catchInt);
pause();
}
else /* parent */
{
sleep(1);
kill(pid, SIGINT);
wait(NULL);
printf("You're welcome\n");
}
return(0);
}
Just figured out what I was doing wrong, I should have realized SIGINT is sent to every process, and so the parent was simply being sent an unhandled SIGINT, causing it to exit. Thanks for all the help (my apologies on the sloppy coding, I really shouldn't wait until the program is completed to clean that up), the code's been edited above and works as intended.
Thanks again.

Resources