Count total number of real-time signals received inside signal handler - c

I am writing a signal handler in a server where I need to receive all the signals sent by clients before returning to the main program of the server. The signals are real-time in nature. My code is given below:
static void handlerB(int signum, siginfo_t *info, void *context){
id[count] = info->si_pid;
printf("A's process ID: %d \n", (int)id[count]);
count++;
kill (pid, SIGCONT);
}
I need to wait for all the sent signals to be received the handler, so that "count" is set to the total number of signals received, before proceeding to sending SIGCONT to the main program. In other words, the handler will be called only once during execution of the program. Does anyone know how to do this? Thanks in advance!

Related

How many kill signals this program needs to be terminqted

I was given the program below in an exam and the question was how many kill signals must be sent to the process in order to terminate it. My answer was 3 signals, but the professor insisted on only 2 signals are needed to terminate the process? How is so?
static void action(int sig)
{
signal(SIGINT,SIG_DFL);
}
int main()
{
signal(SIGINT,SIG_IGN);
signal(SIGUSR1,action);
while(1)
pause();
}
You need to send SIGUSR1 to invoke the action. And all action does is set SIGINT to its default signal handler (SIG_DFL). Then you send the SIGINT, that then triggers the default handler which terminates the process.
NOTE: It must be done in that order, any attempt to send SIGINT before SIGUSR1 will be ignored because of the bind to SIG_IGN.

Signal receiver threads in C and pthread_join stalling program

I'm trying to build a basic program which has 2/3 threads. The main thread, signaler thread, and receiver thread. I'm trying to make it so the main thread starts both a signaler and receiver thread. The signaler thread is then supposed to send 10 SIGUSR1 signals to the receiver thread and increase a global counter. The receiver thread is supposed to receive the 10 signals while increasing its own counter for each signal received.
The trouble I'm having is with joining the threads back together at the end, specifically joining the receiver thread. The majority of the time the program stalls if I try to join them back together, I assume because the receiver thread hasn't finished its job (maybe it has missed signals?) and so it never finishes. I thought maybe this was the case, so I introduced a wait command in the signaler thread to slow it down, but that didn't change anything.
If I comment out the pthread_join(receiver, NULL) then the program runs, but it only catches one signal most of the time. I assume this is because the receiver thread isn't getting much time to run. (although sometimes it catches various amounts, depending on when it was preempted?)
Leaving the pthread_join(receiver, NULL) in the program makes it stall 19/20 times, but that 1/20 time the program returns 10 signals sent and 10 received. This leads me to believe it has something to do with preemption, but I don't understand why it would ever stall in the first place.
Also right now I just have the receiver thread receiving threads while the received counter is < 10. Ideally I would just want to leave it in while(1) loop, but then again I don't know how to join that back into the main thread without freezing everything.
If someone could help me figure out why signals are being missed / why the program is freezing I would be most grateful. I have a suspicion that I'm not setting up the signal mask correctly for the receiver, but I don't know how else I am supposed to do it. Here is the code:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <signal.h>
void *receivetest(void *args);
void *signaltest(void *args);
int received = 0;
int sent = 0;
pthread_t signaler;
pthread_t receiver;
sigset_t mask;
int main(){
//setting up the signal mask
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
//creation of both threads
pthread_create(&receiver, NULL, receivetest, NULL);
pthread_create(&signaler, NULL, signaltest, NULL);
pthread_join(signaler, NULL);
pthread_join(receiver, NULL);
//printing results after joining them back
printf("I'm the main function\n");
printf("Receieved: %d, sent: %d\n", received, sent);
}
void *signaltest(void *args){
int i = 0;
for(i=0;i<10;i++){ //sends 10 signals to receiver thread
pthread_kill(receiver, SIGUSR1);
sent++;
}
}
void *receivetest(void *args){
int c; //sigwait needs int
pthread_sigmask(SIG_BLOCK, &mask, NULL); //sets up the signal mask for this thread
while(received < 10){ //waits for 10 signals and increments receieved
sigwait(&mask, &c);
received++;
}
}
Signals just don't work that way. If a thread receives a signal while that same signal is already pending, nothing happens. Please use an appropriate inter-thread communication method, not signals.
You almost got it right. It is recommended to block the signals from the main thread to protect all new threads from mishandling the signal.
Any thread created after pthread_sigmask(), inherits the sigmask. The first parameter tells pthread_sigmask() what to do with the signals listed in the second parameter.
This line pthread_sigmask(SIG_BLOCK, &mask, NULL) should be placed in the main thread, not on the signal handler. Your original code will work too, but if the signal is sent to the wrong thread, it will kill the whole process.
In addition, the sender is sending signal faster than the receiver can handle. By sleeping for 1 second between each iteration, the receiver will be able to catch up.
I took the liberty and modified your code. I added some prints within the sender and receiver so you'll know what it is doing.
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void receivetest(void); //function does not return anything
void signaltest(void); // does not accept parameter either.
int received = 0;
int sent = 0;
pthread_t signaler;
pthread_t receiver;
sigset_t mask;
int main(){
//setting up the signal mask
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &mask, NULL); //sets up the signal mask for this thread
//creation of both threads
pthread_create(&receiver, NULL, (void *)receivetest, NULL);
pthread_create(&signaler, NULL, (void *)signaltest, NULL);
pthread_join(signaler, NULL);
pthread_join(receiver, NULL);
//printing results after joining them back
printf("I'm the main function\n");
printf("Receieved: %d, sent: %d\n", received, sent);
return 0;
}
void signaltest(void){
int i = 0;
for(i=0;i<10;i++){ //sends 10 signals to receiver thread
printf("Sending signal\n");
pthread_kill(receiver, SIGUSR1);
sleep(1); // Don't send signals too fast
sent++;
}
}
void receivetest(void){
int c; //sigwait needs int
while(received < 10){ //waits for 10 signals and increments receieved
sigwait(&mask, &c);
printf("Signal received\n");
received++;
}
}
Output:
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
I'm the main function
Receieved: 10, sent: 10

How to make two processes signalling each others continuously?

I want to simulate a game server that should continuously send and receive signals with its parent. The scenario is as follows:
Parent sends signal to game.
Game catches the signal and sends a signal to the parent.
Parent catches the signal and sends again a signal to game.
and so on...
The problem is that the stops receiving or sending after the first lap:
static int game_s;
void game()
{
printf("game\n");
signal(SIGUSR1,game);
sleep(1);
kill(getppid(),SIGUSR1);
pause();
}
void parent()
{
printf("parent\n");
signal(SIGUSR1,parent);
sleep(1);
kill(game_s,SIGUSR1);
pause();
}
void main()
{
game_s = fork();
if(game_s>0)
{
signal(SIGUSR1,parent);
sleep(1);
kill(game_s,SIGUSR1);
pause();
}
else
{
signal(SIGUSR1,game);
pause();
}
}
The output is the following:
game
parent
Why it stopped here? Shouldn't the game server catch parent's signal and print "game" again...
By default the reception of a specific signal is blocked from the moment a process received this specific signal until the related signal handler had been left.
From man 3 signal:
void (*signal(int sig, void (*func)(int)))(int);
[...]
When a signal occurs, and func points to a function, it is implementation-defined whether the equivalent of a:
signal(sig, SIG_DFL);
is executed or the implementation prevents some implementation-defined set of signals (at least including sig) from occurring until the current signal handling has completed.
To change this behaviour establish the signal handling via sigaction() instead of signal() (which one should do any ways for portability reasons).
sigaction() takes a struct sigaction. The member sa_flags of the latter should have SA_NODEFER set.
From Linux' man 2 sigaction:
SA_NODEFER
Do not prevent the signal from being received from within its own signal handler. This flag is meaningful only when establishing a signal handler.
POSIX words this differently:
SA_NODEFER
If set and sig is caught, sig shall not be added to the
thread's signal mask on entry to the signal handler
unless it is included in sa_mask. Otherwise, sig shall
always be added to the thread's signal mask on entry to
the signal handler.
Be aware that each signal handler gets it's own stack allocated each time it gets invoked, so sooner or later this recursive ping-pong ends up in an out-of-memory condition.
Use message queues, or shared memory to do this. As stated above, this will eventually run out of memory and it will crash.

Blocking new signals while in handler

I have a parent process that manages a child (fork, execve). I created a handler in the parent to catch SIGCHLD signals from the child in order to call waitpid() and take appropriate action such as restarting the child.
I understood from the manual page for sigaction() that, while inside a signal handler, further signals of the same type would be blocked by default. I definitely wish for this behaviour so I decided to test it.
I put a sleep (my own implementation using clock_nanosleep() in a loop which resumes when interrupted) at the end of the signal handler and sent a SIGINT to the child. This duly made it quit and sent SIGCHLD to the parent. I logged the fact and started my sleep for 10 seconds. Now, I sent another SIGINT to the new child (sighandler restarted it first time) and was surprised to see another log and sleep happen.
How can this be? When I attached using a debugger to the parent it clearly showed two different threads interrupted to call my signal handler, both now sat in sleep. If that keeps up I will run out of threads!
I understand putting long sleeps into a signal handler is a daft thing to do but it does illustrate the point; I expected to see the second signal marked as pending in /proc/[PID]/status but instead it's delivered.
Here's the relevant bits of my code:
Set up the SIGCHLD handler:
typedef struct SigActType {
struct sigaction act;
int retval;
void (*func)(int);
}SigActType;
static SigActType sigActList[64];
public void setChildHandler(void (*func)(int)) {
SigActType *sat = &sigActList[SIGCHLD];
sat->act.sa_sigaction = sigchldHandler;
sigemptyset(&sat->act.sa_mask);
sigaddset (&sat->act.sa_mask, SIGTERM);
sigaddset (&sat->act.sa_mask, SIGINT);
sigaddset (&sat->act.sa_mask, SIGCHLD);
sat->act.sa_flags = SA_SIGINFO;
sat->retval = 0;
sat->func = func;
sigaction(SIGCHLD, &sat->act, NULL);
}
static void sigchldHandler(int sig, siginfo_t *si, void *thing) {
SigActType *sat = &sigActList[SIGCHLD];
if (sat->func) {
sat->func(si->si_pid);
}
}
and using this:
int main(int argc, char **argv) {
setChildHandler(manageChildSignals);
...
}
static void manageChildSignals(int d) {
if ((pid = waitpid(-1, &stat, WAIT_MYPGRP)) > 0) {
... restart child if appropriate
}
printf("start of pause...\n");
mySleep(10);
printf("end of pause...\n");
}
Stdout clearly shows:
(when I type kill -2 [PID]
start of pause
(when the new child is started and I type kill -2 [NEWPID]
start of pause
...10 seconds slide past...
end of pause
end of pause
I am puzzled as to why this happens. As you can see I even added SIGCHLD to the block mask for sigaction() to try to encourage it to do the right thing.
Any pointers most welcome!
signals of the same type would be blocked by default.
Yes, but only for the thread sigaction() is called from.
From man sigaction (bold emphasis by me):
sa_mask specifies a mask of signals which should be blocked (i.e.,
added to the signal mask of the thread in which the signal handler is
invoked) during execution of the signal handler.
As signal dispostion is per process any other thread not blocking the signal in question might receive it, that is get interupted and process it.
If this behaviour is not what you want you should perhaps modify the design of the way your program handles signals in such a way that per default all signals are blocked for each thread, and only one specifiy thread has signal reception unblocked.
Update:
Signals masks are inherited from the parent thread by the child thread.
If signal handling shall be done by one specific thread only, have the main thread block all signals prior to creating any other thread. Then create one specfic thread to do the signal handling, and have this thread unblock the signals to be handled. This concept also allows models like one thread per signal.
In a mutlithreaded environment use pthread_sigmask() to mask signals on a per thread base.
Please note that the behaviour of sigprocmask() in a multithreaded process is unspecified, use pthread_sigmask() then.

signal handler function keeps looping

My function created to handle the SIGINT signal is stuck in a constant loop. The idea is to make CTRL-C ignored by the parent process but sent to the child process (and they handle it as default). What happens is when I press CTRL-C, the signal handler function is called but gets stuck in an endless loop. The kill call is supposed to send SIGTERM to all process in the process group except for the sender process. Any help would be appreciated.
the function code is:
void intHandler(int signum) {
kill(0, SIGTERM);
}
the function call code (in main) is:
(void) sigset(SIGINT, intHandler);
From the kill man page.
If pid is 0, sig shall be sent to all processes (excluding an unspecified set of system processes) whose process group ID is equal to the process group ID of the sender, and for which the process has permission to send a signal.
Nothing about not sending the signal to the sender, so you most likely want something like:
void intHandler(int signum) {
sigset(SIGINT, SIG_DFL);
kill(0, SIGTERM);
}
This will reset your signal handler in the sender to default before sending the SIGTERM to all members of the process group.

Resources