Program with fork() and signal handling in c - c

Hi what I'm trying to do here is a program that starts by registing it's pid in the file server.lock then it should do a fork(). The son should say it started working than do a passive wait and arm the signal SIGUSR2, and when it receives it, it should terminate it's execution and write "goodbye cruel world". The parent should write it began and do a passive wait, and then arm the signals SIGUSR1 and SIGINT. If it receives SIGUSR1 it himself should send the signal SIGUSR2 to the son, and if it receives the signal SIGINT if it's the first time it receives it it should say it got the signal, if it's the second time it should send the signal SIGUSR2 to the son so it terminates the son's and it's execution. Now my problem is with the parent, I don't know why but the second time it receives the signal it says the error "User defined signal 2" and leaves, if somebody could explain to me what I'm doing wrong here I would very much appreciate. Here is the code. Thank you.
int p = 1;
int son;
void handle_SIGINT(int signal){
if ( p==1 ) {
p = 2;
printf("The authentication module received the signal SIGINT\n");
}else{
kill( son, SIGUSR2);
exit(0);
}
}
void handle_SIGUSR1(int signal){
kill( son, SIGUSR2);
}
void handle_SIGUSR2(int signal){
printf("Goodbye cruel world\n");
exit(0);
}
void main(){
int pid = getpid();
FILE *f = fopen("server.lock", "w");
fprintf( f, "%d", pid );
fclose(f);
int n = fork();
if ( n==0 ) {
printf("The message handling module has started\n");
signal(SIGUSR2, handle_SIGUSR2);
while(1)
pause();
}else{
printf("The authentication module has started\n");
son = getpid();
signal(SIGUSR1, handle_SIGUSR1);
signal(SIGINT, handle_SIGINT);
while(1)
pause();
}
}

Your naming confused me. It appears that your problem is your variable named son. That isn't the son aka child process. That's the parent.
The fork call returns twice. Once in the parent and once in the child. In the parent it returns the child's PID. It returns 0 in the child. You have them reversed!
You are using signal instead of sigaction. I recommend using sigaction. It is much more complicated but gives many more options as well.
The problem you're having with signal is that after the handler is called it resets the signal to default behavior. But that isn't guaranteed either. The GNU C library has it behave differently depending on if _BSD_SOURCE, _GNU_SOURCE or nothing is defined. That is to simulate how it behaved on BSD UNIX or SYSV UNIX. And that's why sigaction is a better choice, it acts the same on every POSIX system.

Related

Signals not working as intended (C language, linux)

I tried to answer this question:
Write a program C that creates two children. The second child process
is blocked until the reception of the signal SIGUSR1 sent from the
parent process. While the first child process is blocked until the
reception of the signal SIGUSR2 (that will kill him) sent from the
second child process. The parent is terminated after the termination
of his children.
However the execution is not working as intended with my code below, and only the parent printfs are displayed. Can you tell me what's wrong with my code?
My code:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
void this(int sig) {
printf("this is this");
}
int main() {
int pid = fork();
int pid2;
if (pid < 0) {
exit(-1);
} else if (pid == 0) {
printf("FIrst child is paused");
pause();
printf("ERror");
} else {
pid2 = fork();
if (pid2 < 0) {
exit(-2);
} else if (pid2 == 0) {
signal(SIGUSR1, &this);
printf("Second child is paused");
pause();
kill(pid,SIGUSR2);
printf("signal sent to first child");
} else {
printf("this is the parent");
kill(pid2, SIGUSR1);
printf("signal sent to second child");
wait(NULL);
exit(-3);
}
}
}
You make no provision to ensure that the parent's signal is delivered to the second child only when that child is ready for it. Because process startup takes some time, chances are good that the signal is indeed delivered sooner. In that case, the second child will be terminated (default disposition of SIGUSR1) or it will block indefinitely in pause() (if the signal is received after the handler is installed but before pauseing). In neither case will the second child signal the first.
Signal masks and signal dispositions are inherited across a fork, so you can address that by blocking SIGUSR1 in the parent before forking, and then using sigsuspend() in the child instead of pause(), which will enable you to atomically unblock the signal and start waiting for it.
The same is not an issue for the first child because you're looking for it to exercise the default disposition for SIGUSR2 (termination), and it does not matter for the specified behavior whether that happens before that child reaches or blocks in pause().
Additionally,
the parent waits only for one child, but the prompt seems to say that it must wait for both. Perhaps you dropped the second wait() because the parent was not terminating, but if so, that was a missed clue that one of the children was not terminating.
printf is not async-signal-safe, so calling it from a signal handler invokes undefined behavior.
you should put a newline at the end of your printf formats. This will make your output much more readable, and it will also ensure that the output is delivered to the screen promptly. That could end up being useful as you debug. Alternatively, use puts() instead of printf() since you are outputting only fixed strings. puts() will add a newline automatically.
The absence of newlines probably explains why the first child's output from before it pauses is never printed. If the second child were reaching the indefinite pause state then it would also explain why that child's pre-pause output was not being printed.

Why SIGKILL is not handled by my signal handler and sometime leads to account logout

I wrote the following code with the following intention:
The child sends SIGKILL signal to the parent and then the parent will handle it using the handler. The handler just increment the counter.
int counter = 0;
void handler(int sig) {
counter++;
sleep(1); /* Do some work in the handler */
return;
}
int main() {
int i;
//signal(SIGUSR2, handler);
signal(SIGKILL, handler);
if (fork() == 0) { /* Child */
for (i = 0; i < 5; i++) {
//kill(getppid(), SIGUSR2);
kill(getppid(), SIGKILL);
printf("sent SIGKILL to parent %d\n", getppid());
}
exit(0);
}
wait(NULL);
printf("counter=%d\n", counter);
exit(0);
}
However, the first kind of output I get is:
sent SIGKILL to parent 8371
sent SIGKILL to parent 8371
sent SIGKILL to parent 8371
sent SIGKILL to parent 8371
sent SIGKILL to parent 8371
Killed
Apparently, the SIGKILL kills the parent process. Why does this happen since my handler does not kill the parent?
Another non-deterministic, but very high probability event (~50%) is that on my ubuntu 14.04 64-bit machine. If I execute this code, I will get automatically logout from the account. Why would this happen?
Have your read the manual of signal() ?
First:
The behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux. Avoid its use: use sigaction(2) instead. See Portability below.
Second:
The signals SIGKILL and SIGSTOP cannot be caught or ignored.

pthreads and signal handling C ending early

This program is supposed to
The parent simply waits indefinitely for any child to return (hint, waitpid).
b. The child sets up two signal handlers (hint, signal) and goes to sleep for 5 minutes.
i. The first signal handler listens for the USR1 signal, and upon receiving it:
1. Creates a thread (hint, pthread_create).
a. Basically, all that the thread needs to do is “say hello” and sleep for 60
seconds.
ii. The second signal handler listens for the USR2 signal, and upon receiving it:
1. Destroys the thread (hint, pthread_cancel).
When this program receives the first signal to create the thread, it outputs
"[thread] sleeping for 1 m[thread] sleeping for 1 minute"
and then ends, it never waits for the 2nd signal, what am i doing wrong?
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
pthread_t thread;
void* temp()
{
printf("[thread] hello professor\n");
printf("[thread] sleeping for 1 minute\n");
sleep(60);
}
void handle_USR1(int x)
{
int s;
printf("[signal] creating the thread\n");
s = pthread_create(&thread, NULL, &temp, NULL);
}
void handle_USR2(int x)
{
int s;
printf("[signal] destroying the thread\n");
s = pthread_cancel(thread);
}
int main(void)
{
int status = 0;
if(fork() != 0)
{
printf("[parent] waiting.....\n");
waitpid(-1, &status, 0);
}
else
{
printf("[child] to create the thread: kill -USR1 %d\n", getpid());
printf("[child] to end the thread: kill -USR2 %d\n", getpid());
printf("[child] setting up signal handlers\n");
signal(SIGUSR1, handle_USR1);
signal(SIGUSR2, handle_USR2);
printf("[child] waiting for signals\n");
sleep(300);
}
return (0);
}
As Charlie Burns pointed out, both processes eventually exit as a consequence of the signal, but for different reasons.
Child
During its sleep, the child is blocked in a system call (the actual system call is nanosleep, used to implement the sleep() function). When a process receives a signal while in a system call, the corresponding signal handler is executed and the system call returns an error, EINTR, which means it has been interrupted and couldn't fulfill its duty. You can then decide if you want to restart the system call or not. Upon receiving SIGUSR1, the nanosleep system call executed by the child is interrupted, the handler is executed and sleep() returns immediately. Notice what man 3 sleep says about the return value of sleep():
Zero if the requested time has elapsed, or the number of seconds left to sleep, if the call was interrupted by a signal handler.
The correct way would be for the child to check for the return value of sleep (number of seconds left to sleep), and sleep again for that duration.
Parent
Unlike what Charlie Burns pointed out, waitpid() in the parent does not return because of the child receiving a signal. It returns because of the child exiting. It would return because of the child IF the child did not handle the signal, and thus was killed by it (an unhandled signal causes the process to die). You can (and should) check that using the WIFEXITED macro and its companions as described in man 2 waitpid. The example at the bottom of this man page is very good:
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) {
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");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
Basically, what this code does is wait on the child until it has exited normally or has exited because of an unhandled signal. In your case, it would be a good idea for the parent to check the status variable to make sure that waitpid returned because of the event it expects (a child exiting) and not something else.
Place a pthread_join after your pthread_create.
Ok, I see what is going on.
When you send a signal, without otherwise directing it to a particular thread by masking, any thread within a process can get it. When SIGUSR1 gets delivered main in the child gets blown out of the sleep and the main thread terminates killing the thread created in the handler.
There are plenty of questions here covering how to direct signals to a single thread and/or using sigaction to restart a system call if that is also a direction you want to go in to resolve it.

Signal handling in C

I am figuring how signals work in C.
Here is one of the examples taken from old exams:
#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<errno.h>
//#include <sys/types.h>
void handler1(int sig) {
printf("Phantom");
exit(0);
}
int main()
{
pid_t pid1;
signal(SIGUSR1, handler1); //installing signal handler
if((pid1 = fork()) == 0) { //forking
printf("Ghost");
exit(0);
}
kill(pid1, SIGUSR1);
printf("Ninja");
return 0;
}
So far, GCC gives me two answers Ghost Ninja & Ninja Phantom. Could it produce Ghost Phantom Ninja or any other combination made of 3 names ?
One way I see it could possibly produce 3 names is:
Fork, run in Child, print Ghost, exit(0) => in Parent, accept/process signal and from signal Handler print Phantom, kill child, print Ninja. But I am not sure if my "theory" holds the ground.
Also, would the kill(pid1, SIGUSR1) invoke handler() ?
Thanks !
Let's examine this line-by line. Set up a signal handler, then fork. The child prints "Ghost" and exits. The parent makes the child print "Phantom" and exit. Then the parent prints "Ninja".
So you've really got a race condition. If the parent fires its SIGUSR1 before the child prints "Ghost", then you'll get Phantom Ninja, or perhaps Ninja Phantom (does kill block?)
But, if you can't get the signal off in time, then you'll get Ghost Ninja as the child finishes before the parent signals. I don't think the reverse is possible.
Now it is conceivable that the signal could be exactly on time to hit between the printf and the exit, in which case Ghost would finish, followed by Phantom then Ninja - or the reverse again, I think.
It's really finicky and sensitive to OS timing.
#Everyone - not tested! Feel free to contradict me, but I'll be as interested to know why as the OP.
Lets mark the lines with line numbers first as follows:
signal(SIGUSR1, handler1); //installing signal handler ---- 1
if((pid1 = fork()) == 0) { //forking ---- 2
printf("Ghost"); ---- 3
exit(0); ---- 4
}
kill(pid1, SIGUSR1); ---- 5
printf("Ninja"); ---- 6
Now with the above code, if
Child executes first and
if 3 is executed first, then child is suspended and parent starts executing with 5. This will print GhostPhantomNinja
However, a definite order can not be determined.
You have two non deterministic factors here, which are both depends on the OS: when will the context switching occur, and when will the signal arrive.
Since you can't control those, I'd answer that any order is possible. Try inserting wait() between command and see if you get the desired results.
//#include <sys/types.h>
#include<stdlib.h>
void handler1(int sig) {
printf("Phantom\n");
waitpid(-1,NULL,0);
//sexit(0);
}
int main()
{
pid_t pid1;
signal(SIGUSR1, handler1); //installing signal handler
printf("my pid is %d ha ha parent..\n",getpid());
//if((pid1 = fork()) == 0) { //forking
pid1=fork();
if(pid1==0)//in childe processs
{
printf("my pid is %d ha ha child..\n",getpid());
printf("Ghost\n");
sleep(6);
exit(0);
}
else{
//sleep(4);
kill(pid1, SIGUSR1);
sleep(3);
printf("Ninja\n");
return 0;
}
}

calling ptrace inside a ptraced Linux process

Someone added to the Wikipedia "ptrace" article claiming that, on Linux, a ptraced process couldn't itself ptrace another process. I'm trying to determine if (and if so why) that's the case. Below is a simple program I contrived to test this. My program fails (the sub sub process doesn't run properly) but I'm pretty convinced it's my error and not something fundamental.
In essence the initial process A forks process B which in turn forks C. A ptraces its child B, B ptraces its child C. Once they're set up, all three processes are written to just print A,B, or C to stdout once every second.
In practice what happens is that A and B work fine, but C prints only once and then gets stuck. Checking with ps -eo pid,cmd,wchan shows C stuck in kernel function ptrace_stop while the rest are in hrtimer_nanosleep where I'd expect all three to be.
Very occasionally all three do work (so the program prints Cs as well as As and Bs), which leads me to believe there's some race condition in the initial setup.
My guesses as to what might be wrong are:
something to do with A seeing a SIGCHLD related to B seeing a SIGCHLD to do with a signal to C, and wait(2) reporting both as coming from B (but a hacky call of PTRACE_CONT to both pids doesn't fix things)?
C should be ptraced by B - has C inherited the ptrace by A instead (and B's call to ptrace neither errored nor overwrote this)?
Can anyone figure out what I'm doing wrong? Thanks.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
static void a(){
while(1){
printf ("A\n");
fflush(stdout);
sleep(1);
}
}
static void b(){
while(1){
printf ("B\n");
fflush(stdout);
sleep(1);
}
}
static void c(){
while(1){
printf ("C\n");
fflush(stdout);
sleep(1);
}
}
static void sigchld_handler(int sig){
int result;
pid_t child_pid = wait(NULL); // find who send us this SIGCHLD
printf("SIGCHLD on %d\n", child_pid);
result=ptrace(PTRACE_CONT, child_pid, sig, NULL);
if(result) {
perror("continuing after SIGCHLD");
}
}
int main(int argc,
char **argv){
pid_t mychild_pid;
int result;
printf("pidA = %d\n", getpid());
signal(SIGCHLD, sigchld_handler);
mychild_pid = fork();
if (mychild_pid) {
printf("pidB = %d\n", mychild_pid);
result = ptrace(PTRACE_ATTACH, mychild_pid, NULL, NULL);
if(result==-1){
perror("outer ptrace");
}
a();
}
else {
mychild_pid = fork();
if (mychild_pid) {
printf("pidC = %d\n", mychild_pid);
result = ptrace(PTRACE_ATTACH, mychild_pid, NULL, NULL);
if(result==-1){
perror("inner ptrace");
}
b();
}
else {
c();
}
}
return 0;
}
You are indeed seeing a race condition. You can cause it to happen repeatably by putting sleep(1); immediately before the second fork() call.
The race condition is caused because process A is not correctly passing signals on to process B. That means that if process B starts tracing process C after process A has started tracing process B, process B never gets the SIGCHLD signal indicating that process C has stopped, so it can never continue it.
To fix the problem, you just need to fix your SIGCHLD handler:
static void sigchld_handler(int sig){
int result, status;
pid_t child_pid = wait(&status); // find who send us this SIGCHLD
printf("%d received SIGCHLD on %d\n", getpid(), child_pid);
if (WIFSTOPPED(status))
{
result=ptrace(PTRACE_CONT, child_pid, 0, WSTOPSIG(status));
if(result) {
perror("continuing after SIGCHLD");
}
}
}
It is "possible" to perform some ptrace functionalities on a child process that invokes ptrace itself. The real difficulty is that a tracer process becomes the parent of the tracee when attached to the latter. And if your tracer process wants to trace all behaviors from all (direct and indirect) child processes (i.e. like when a debugger program needs to debug a multi-threaded program), it naturally breaks the original process hierarchy, and all inter-process/inter-thread communications (i.e. thread synchronization, signal sending / receiving, ...) among all child processes needs to be emulated / multiplexed by the tracer process. It is still "possible", but much more difficult and inefficient.

Resources