client:
static void get_bit(int pid, char c)
{
int bit;
int n;
int i;
n = 7;
i = 0;
while (n >= 0)
{
bit = (c >> n) & 1;
if (bit == 0)
kill(pid, SIGUSR1);
else
kill(pid, SIGUSR2);
usleep(50);
n--;
}
}
server:
static void sighandler(int sig, siginfo_t *info, void *context)
{
static int i = 0;
static pid_t client_pid = 0;
static unsigned char c = 0;
(void)context;
if (!client_pid)
client_pid = info->si_pid;
c |= (sig == SIGUSR2);
if (++i == 8)
{
i = 0;
if (!c)
{
kill(client_pid, SIGUSR2);
client_pid = 0;
return ;
}
ft_putchar_fd(c, 1);
c = 0;
kill(client_pid, SIGUSR1);
}
else
c <<= 1;
}
int main(int argc, char *argv[])
{
int pid;
struct sigaction act;
sigset_t set;
pid = getpid();
memset(&act, 0, sizeof act);
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGUSR2);
act.sa_mask = set;
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = sighandler;
ft_putnbr_fd(pid, 1);
write(1, "\n", 1);
sigaction(SIGUSR1, &act, NULL);
sigaction(SIGUSR2, &act, NULL);
while (1)
{
pause();
}
return (0);
}
Although I use masking, when the usleep gives a low value on the client, the signals are mixed. processing one signal(s) without processing another
The client sends the bits of the character sequentially and the server collects these bits
if bit is 1 SIGUSR2 is 0 then SIGUSR1 is used
If the signal is 1, the char is shifted to the left and the bit is collected and if it is done 8 times, 1 character is obtained.
Since the client sends the bits asynchronously, each event does not seem to run sequentially, or more than one event is running at the same time, so the same handler function is running more than once at the same time and the events overlap because they run almost simultaneously.
so the usleep is used and the other bit is sent during this time, usually after the event has finished (not guaranteed).
I used sa_mask to prevent this and I know that one of the 2 events must complete itself before it receives a signal. that is, when a signal comes to sigusr2 or sigusr1, if a signal has already been captured, blocked signals are processed after that signal is processed.
but it didn't work, when I run the program, I get good output for a while, then probably due to conflict in the handler, the bits get mixed up and print different characters.
to test https://github.com/murmurlab/ecole42kocaeli/tree/main/42cursus/mini_talk
$ make
$ ./server
> PID
$ ./client PID "$(cat a)"
allowed functions in my project
◦ signal
◦ sigemptyset
◦ sigaddset
◦ sigaction
◦ kill
◦ getpid
◦ pause
◦ sleep
◦ usleep
◦ exit
edit:
A sensible solution might be to send bits when the client receives a feedback signal from each server.
Related
I'm trying to write a program that simulates communication between a server and a client using two processes, the server, and the client:
We will first start the server then the client (with arguments ./client [SERVER PID] [Message]), I'm allowed to send string Message to the server using just UNIX signals, so I'm using two signals SIGUSR1 and SIGUSR2 to send the value of the characters in binary, and then convert it back to char in the server and display it: so here's my client's code:
#include <minitalk_client.h>
void send_message_to_server(pid_t ppid, const unsigned char *msg)
{
unsigned char mask;
int i;
ft_putstr("Sending message `");
ft_putstr((const char *)msg);
ft_putstr("` to server: ");
ft_putnbr(ppid);
ft_putchar('\n');
while (*msg)
{
mask = 1 << 7;
while (mask)
{
if (*msg & mask)
kill(ppid, SIGUSR1);
else
kill(ppid, SIGUSR2);
usleep(300);
mask >>= 1;
}
msg++;
}
i = -1;
while (++i < 8)
{
kill(ppid, SIGUSR2);
usleep(300);
}
}
int main(int argc, char **argv)
{
int ppid;
if (argc != 3)
{
write(2, "Invalid arguments\n", 18);
return (1);
}
ppid = ft_atoi(argv[1]);
send_message_to_server(ppid, (const unsigned char *)argv[2]);
return (0);
}
and the server:
#include <minitalk_server.h>
void sig_handler(int sig)
{
static unsigned char character;
static unsigned char mask = 1 << 7;
static bool is_new_message = true;
if (is_new_message)
{
ft_putstr("Received message from client: ");
is_new_message = false;
}
if (sig == SIGUSR1)
character |= mask;
mask >>= 1;
if (!mask)
{
if (character)
ft_putchar(character);
else
{
ft_putchar('\n');
is_new_message = true;
}
character = 0;
mask = 1 << 7;
}
}
int main(void)
{
struct sigaction act;
const pid_t pid = getpid();
sigemptyset(&act.sa_mask);
act.sa_handler = sig_handler;
sigaction(SIGUSR1, &act, 0);
sigaction(SIGUSR2, &act, 0);
ft_putstr("Started minitalk server with pid: ");
ft_putnbr(pid);
ft_putchar('\n');
while (1)
pause();
return (0);
}
So my code works but I have a problem with sleep when I don't wait enough time some signals don't get caught and it does things like this:
Suspendisse consectetur consequaa�#������\#����#����#��������#�����\#��������#������#����#��#���������#������\#�����#���#������#���������X
and I don't want to wait too much because that makes my program too slow, so is there a way to put signals in "queue" so that when I want to send multiple signals in a loop, there is no need to wait between each one?
(I know that signals are not the best method to do that but it's a school project and I'm only allowed to do that)
Since
I don't want to wait too much because that makes my program too slow
, it makes sense to ask
is there a way to put signals in "queue" so that when I want to send multiple signals in a loop, there is no need to wait between each one?
. But in fact no, SIGUSR1, SIGUSR2, and the other ordinary signals do not queue. Thus, not only can you have at most one of each pending at a time, but if you do have both a SIGUSR1 and a SIGUSR2 pending at the same time, then the order in which they are delivered is unspecified, and may differ from the order in which the client raised them.
But there may be another alternative for speeding the interaction and making it more reliable, while still relying only on signals for communication. By setting the SA_SIGINFO flag when you register the handler, you can use a handler that accepts three arguments, with the second being a pointer to a siginfo_t, a structure containing information about the signal. That information includes the PID of the process that sent it. You could use that to enable the server to acknowledge receipt of each signal by sending a signal back to the client. The client would then wait for acknowledgement of each signal before sending the next.
The server would do something along these lines:
void sig_handler(int sig, siginfo_t *info, void *ignore) {
// ...
kill(info->si_pid, SIGUSR1);
}
int main(void) {
struct sigaction act = { .sa_sigaction = sig_handler, .flags = SA_SIGINFO };
sigemptyset(&act.sa_mask);
sigaction(SIGUSR1, &act, 0);
sigaction(SIGUSR2, &act, 0);
// ...
}
If you want to pursue this then I leave the client-side modifications to you, but I do suggest that you consider that side (at least) receiving the signals synchronously via sigwait() instead of asynchronously via a signal handler.
Maybe try to send signals back and forth.
For example:
The server waits for a signal from the client
The client sends the signal then waits for the server's confirmation
The server receives the signal and then sends a confirmation signal
Then the communication starts, you send the message bit by bit with each bit sent a confirmation from the server before continuing (using the same mechanism as above)
Once the message is sent the client sends a different signal which tell the server the message is over
Don't forget to make the signals pending using masks to prevent the server and the client waiting for each other indefinitely.
I have the following code:
//includes...
#define SIG_INT 0
//prints out <Text> when SIG_INT is received from siginfo_t*
void handler(int, siginfo_t*, void*);
int main()
{
pid_t ambulance1 = 0;
pid_t ambulance2 = 0;
struct sigaction sigact;
sigact.sa_sigaction = handler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO;
sigaction(SIGUSR1, &sigact, NULL);
ambulance1 = fork();
if(ambulance1 > 0) {
ambulance2 = fork();
if(ambulance2 > 0) { // parent
int status;
waitpid(ambulance1, &status, 0);
waitpid(ambulance2, &status, 0);
printf("HQ went home!\n");
}
}
if(ambulance1 == 0 || ambulance2 == 0) {
union sigval signalValueInt;
signalValueInt.sival_int = SIG_INT;
sigqueue(getppid(), SIGUSR1, signalValueInt);
printf("Ambulance[%d] ended.\n", getpid());
}
return 0;
}
What happens is: sometimes the second ambulance's sigqueue(getppid(), SIGUSR1, signalValueInt); doesn't get received, and the output is something like the following:
Ambulance[20050] ended. // main() prints out this
Ambulance[20051] ended. // main() prints out this
// handler() prints out this with write() ONLY ONCE!
HQ went home! // main() prints out this
I know that the signal is lost, because the two signals arrived too quickly after one another, and the operating sys. thinks it's an error-duplicate, so it gets ignored.
My question is:
Is there a way to tell the operating system not to do that?
I wouldn't like to use two different signals (ex.: SIGUSR1 and SIGUSR2) for the same purpose, and I also wouldn't like to use delay in one of the child process.
The answer is in the manual page of signal(7).
But breafly:
if a standard signal arrives (like SIGUSR1) while the handler is running it will get ignored by the operating system.
if a real-time signal arrives (like SIGRTMIN) while handler is running it will be processed after the handler is done running.
I am trying to copy the contents from one file to another, with SIGINT the program gets interrupted to print the number of bytes copied. I tried to use the sigprocmask while the flag initialization, flag check, and flag clear to avoid a race condition. But I don't know how to check whether this sigprocmask works or not. I have been trying to find out quite a long time for this.
void signal_handler(int num)
{
flag = 1;
}
int main()
{
signal(SIGINT, signal_handler);
ret = sigaddset(&set, SIGINT);
/* Code for
* copying the bytes from one file to another
*/
sigprocmask(SIG_BLOCK, &set, NULL);
if (flag == 1)
printf("The number of bytes copied are :%llu\n", bytes);
flag = 0;
sigprocmask(SIG_UNBLOCK, &set, NULL);
}
}
It should work as you expect. The only thing you need to ensure is that flag is of type volatile sig_atomic_t to avoid data race on flag.
Here's an example. The loop prints the value of bytes continuously (it'd wrap around at some point when bytes reaches UINT64_MAX). You can repeatedly send SIGINT to test.
#include <stdio.h>
#include <signal.h>
#include <inttypes.h>
volatile sig_atomic_t flag = 0;
void signal_handler(int num)
{
flag = 1;
}
int main(void)
{
uint64_t bytes = 0;
sigset_t set;
signal(SIGINT, signal_handler);
int ret = sigaddset(&set, SIGINT);
while(1) {
bytes++;
sigprocmask(SIG_BLOCK, &set, NULL);
if (flag == 1)
printf("The number of bytes copied are :%" PRIu64 "\n", bytes);
flag = 0;
sigprocmask(SIG_UNBLOCK, &set, NULL);
}
}
Learning about signals, and I was wondering about the subtle differences between the process signal mask, a blocked signal set, a signal handler, and a blocked signal.
The questions involve (on Debian):
sigprocmask(2)
sigsetops(3) related functions
Each process has it's own signal mask (a long which contains the signals being blocked). And a signal set can be obtained by calling sigprocmask(2) with a NULL argument for the *set variable, will result in the old process mask to be put into *oldset, unchanged:
#include <string.h>
#include <signal.h>
void show_signals(const sigset_t exmask)
{
int exsignals[43];
exsignals[0] = SIGABRT;
exsignals[1] = SIGALRM;
exsignals[2] = SIGBUS;
exsignals[3] = SIGCHLD;
exsignals[4] = SIGCONT;
#ifdef SIGEMT
exsignals[5] = SIGEMT;
#else
exsignals[5] = -1;
#endif
exsignals[6] = SIGFPE;
#ifdef SIGFREEZE
exsignals[7] = SIGFREEZE;
#else
exsignals[7] = -1;
#endif
exsignals[8] = SIGHUP;
exsignals[9] = SIGILL;
#ifdef SIGINFO
exsignals[10] = SIGINFO;
#else
exsignals[10] = -1;
#endif
exsignals[11] = SIGINT;
exsignals[12] = SIGIO;
exsignals[13] = SIGIOT;
#ifdef SIGJVM1
exsignals[14] = SIGJVM1;
#else
exsignals[14] = -1;
#endif
#ifdef SIGJVM2
exsignals[15] = SIGJVM2;
#else
exsignals[15] = -1;
#endif
exsignals[16] = SIGKILL;
#ifdef SIGLOST
exsignals[17] = SIGLOST;
#else
exsignals[17] = -1;
#endif
#ifdef SIGLWP
exsignals[18] = SIGLWP;
#else
exsignals[18] = -1;
#endif
exsignals[19] = SIGPIPE;
exsignals[20] = SIGPOLL;
exsignals[21] = SIGPROF;
exsignals[22] = SIGPWR;
exsignals[23] = SIGQUIT;
exsignals[24] = SIGSEGV;
exsignals[25] = SIGSTKFLT;
exsignals[26] = SIGSTOP;
exsignals[27] = SIGSYS;
exsignals[28] = SIGTERM;
#ifdef SIGTHAW
exsignals[29] = SIGTHAW;
#else
exsignals[29] = -1;
#endif
#ifdef SIGTHR
exsignals[30] = SIGTHR;
#else
exsignals[30] = -1;
#endif
exsignals[31] = SIGTRAP;
exsignals[32] = SIGTSTP;
exsignals[33] = SIGTTIN;
exsignals[34] = SIGTTOU;
exsignals[35] = SIGURG;
exsignals[36] = SIGUSR1;
exsignals[37] = SIGUSR2;
exsignals[38] = SIGVTALRM;
#ifdef SIGWAITING
exsignals[39] = SIGWAITING;
#else
exsignals[39] = -1;
#endif
exsignals[40] = SIGWINCH;
exsignals[41] = SIGXCPU;
exsignals[42] = SIGXFSZ;
#ifdef SIGXRES
exsignals[43] = SIGXRES;
#else
exsignals[43] = -1;
#endif
int exsignals_n = 0;
for (;exsignals_n < 43; exsignals_n++) {
if (exsignals[exsignals_n] == -1) continue;
static char *exsignal_name;
exsignal_name = strsignal(exsignals[exsignals_n]);
switch(sigismember(&exmask, exsignals[exsignals_n]))
{
case 0: break;
case 1: printf("YES %s\n", exsignal_name); break;
case -1: printf("could not obtain signal\n"); break;
default: printf("UNEXPECTED for %s return\n", exsignal_name); break;
}
}
}
const sigset_t getmask(void)
{
static sigset_t retmask;
if ((sigprocmask(SIG_SETMASK, NULL, &retmask)) == -1)
printf("could not obtain process signal mask\n");
return retmask;
}
At the beginning of my program, I realize that the process signal mask, has not blocked any signals. I then place a signal handler into the program.
static void sig_abrt(int signo)
{
printf("Caught SIGABRT\n");
}
int main(void)
{
show_signals(getmask());
signal(SIGABRT, sig_abrt);
show_signals(getmask());
return 0;
}
So now there is a signal handler for SIGABRT, but if I were to call sigprocmask(2) again, as above, SIGABRT will not be in the process signal mask. I tried checking with sigismember(3), but the process signal mask will only be modified once I have called sigaddset(3) or another function which modifies the signal mask.
If I block SIGABRT with sigaddset(3), will the signal handler sig_abrt not receive the call when the SIGABRT is delivered? Does it mean that the signal mask affects which signals are delivered? What is the difference?
Also, is there a way to block a signal in a process without using the sigsetops(3) and sigprocmask(2) functions?
Each process has it's [sic] own signal mask (a long which contains the signals being blocked)
Well, no. The signal mask is actually thread-specific. (In a multithreaded program, you must use pthread_sigmask() to manipulate the signal mask for the current thread; in a single-threaded program, you can use sigprocmask().)
Also, it's not "a long". It is of type sigset_t, which might be an array, structure, or union type. In any case, one should consider it simply as an unordered bit set, one bit per signal.
So now there is a signal handler for SIGABRT, but SIGABRT will not be in the process signal mask.
Correct. Whether or not you have assigned a signal handler or not, does not affect the signal mask at all.
If I block SIGABRT with sigaddset(3), will the signal handler sig_abrt not receive the call when the SIGABRT is delivered? Does it mean that the signal mask affects which signals are delivered? What is the difference?
If all your threads block SIGABRT, it will not be delivered until either the signal is unblocked (removed from the signal mask). If the signal is consumed using sigwait(), sigwaitinfo(), or sigtimedwait(), the signal handler will not be invoked at all.
A short summary:
Signals can be directed to a process group (kill() with pid == 0 or pid == -pgid), a specific process (pid), or a specific thread in a specific process (pthread_kill() within the same process, tgkill system call in Linux in general).
If a signal is directed to a process group, each process in that group receives "a copy" of the signal.
The signal mask defines whether signals are blocked, or delivered immediately.
In each process, each signal
can have a signal handler, or
be ignored (SIG_IGN "handler"), or
have the default disposition (ignored (Ign), terminates the process with (Core) or without (Term) a core dump; or it can stop (Stop) or continue (Cont) the execution of the target thread or process). See man 7 signal for details.
If some, but not all threads, block a signal, and the signal is not targeted to a specific thread, the kernel directs the signal to one of the threads that are not blocking the signal (at random).
There are two ways of catching a signal:
Using a signal handler. The signal gets delivered to a signal handler only when the signal is not blocked. If the signal is blocked, the delivery of the signal is pending until not blocked (or caught by the other option below).
sigwait(), sigwaitinfo(), or sigtimedwait(). These functions check if any signals are pending, and if so, "catch" it. The set of signals they check is defined by a function parameter of sigset_t type.
When the kernel sends/forwards a signal to a process, it first checks if the process has a thread that is not blocking that signal. If there is such a thread, it delivers it via that thread. (If the signal has a signal handler, that signal handler gets invoked in that thread; otherwise, the effect is dictated by the signal disposition.)
If the signal is blocked, the kernel leaves it pending for the process.
If the process calls sigwait(), sigwaitinfo(), or sigtimedwait() with the pending signal in the specified signals set, it receives the information on that signal, and the signal is caught. (It will no longer be pending, and it will not cause a signal handler to be invoked; it is "consumed".)
If the process changes its signal mask, so that the pending signal becomes unblocked, it is delivered by the kernel (just as if it was sent at that point in time).
Also, is there a way to block a signal in a process without using the sigsetops(3) and sigprocmask(2) functions?
No. (You can implement your own sigsetops() and a syscall wrapper for sigprocmask(), but that's about it.)
Here is an example program, example.c, you can use for exploring signal handlers, catching signals, and the signal mask, in a single-threaded process:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <errno.h>
/* Async-signal safe write-to-standard error function.
Keeps errno unchanged. Do not use stderr otherwise!
*/
static int wrerrpp(const char *ptr, const char *end)
{
const int saved_errno = errno;
ssize_t chars;
while (ptr < end) {
chars = write(STDERR_FILENO, ptr, (size_t)(end - ptr));
if (chars > 0)
ptr += chars;
else
if (chars != -1) {
errno = saved_errno;
return EIO;
} else
if (errno != EINTR) {
const int retval = errno;
errno = saved_errno;
return retval;
}
}
errno = saved_errno;
return 0;
}
/* Write the supplied string to standard error.
Async-signal safe. Keeps errno unchanged.
Do not mix with stderr!
*/
static int wrerr(const char *ptr)
{
if (!ptr)
return 0;
else {
const char *end = ptr;
/* strlen() is not async-signal safe, so
find the end of the string the hard way. */
while (*end)
end++;
return wrerrpp(ptr, end);
}
}
/* Write the supplied long to standard error.
Async-signal safe. Keeps errno unchanged.
Do not mix with stderr!
*/
static int wrerrnum(const long value)
{
unsigned long u = (value < 0) ? (unsigned long)-value : (unsigned long)value;
char buf[40];
char *ptr = buf + sizeof buf;
char *const end = buf + sizeof buf;
do {
*(--ptr) = '0' + (u % 10uL);
u /= 10uL;
} while (u > 0uL);
if (value < 0)
*(--ptr) = '-';
return wrerrpp(ptr, end);
}
/* Async-signal safe variant of strsignal().
Only covers a small subset of all signals.
Returns NULL if the signal name is not known. */
static const char *signal_name(const int signum)
{
switch (signum) {
case SIGHUP: return "HUP";
case SIGINT: return "INT";
case SIGQUIT: return "QUIT";
case SIGKILL: return "KILL";
case SIGSEGV: return "SEGV";
case SIGTERM: return "TERM";
case SIGUSR1: return "USR1";
case SIGUSR2: return "USR2";
case SIGCHLD: return "CHLD";
case SIGCONT: return "CONT";
case SIGSTOP: return "STOP";
default: return NULL;
}
}
/* Signal handler that reports its delivery immediately,
but does nothing else.
*/
static void report_signal(int signum, siginfo_t *info, void *ctx)
{
const char *sname = signal_name(signum);
wrerr("report_signal(): Received signal ");
if (sname)
wrerr(sname);
else
wrerrnum(signum);
if (info->si_pid) {
wrerr(" from process ");
wrerrnum(info->si_pid);
wrerr(".\n");
} else
wrerr(" from kernel or terminal.\n");
}
/* Install report_signal() handler.
*/
static int install_report_signal(const int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_sigaction = report_signal;
act.sa_flags = SA_SIGINFO;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
int main(void)
{
sigset_t mask;
siginfo_t info;
const char *name;
int signum;
if (install_report_signal(SIGINT) ||
install_report_signal(SIGCONT)) {
const char *errmsg = strerror(errno);
wrerr("Cannot install signal handlers: ");
wrerr(errmsg);
wrerr(".\n");
return EXIT_FAILURE;
}
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGUSR2);
sigaddset(&mask, SIGHUP);
sigaddset(&mask, SIGTERM);
sigprocmask(SIG_SETMASK, &mask, NULL);
printf("Process %ld is ready to receive signals! Run\n", (long)getpid());
printf("\tkill -USR1 %ld\n", (long)getpid());
printf("\tkill -USR2 %ld\n", (long)getpid());
printf("\tkill -HUP %ld\n", (long)getpid());
printf("\tkill -TERM %ld\n", (long)getpid());
printf("in another terminal; press Ctrl+C in this terminal; or press Ctrl+Z and run\n");
printf("\tfg\n");
printf("in this terminal.\n");
fflush(stdout);
/* Almost same as blocked mask, just without SIGUSR1 and SIGUSR2. */
sigemptyset(&mask);
sigaddset(&mask, SIGHUP);
sigaddset(&mask, SIGTERM);
do {
do {
signum = sigwaitinfo(&mask, &info);
} while (signum == -1 && errno == EINTR);
if (signum == -1) {
const char *errmsg = strerror(errno);
wrerr("sigwaitinfo(): ");
wrerr(errmsg);
wrerr(".\n");
return EXIT_FAILURE;
}
name = signal_name(signum);
if (name)
printf("main(): Received signal %s from ", name);
else
printf("main(): Received signal %d from ", signum);
if (info.si_pid == 0)
printf("kernel or terminal.\n");
else
printf("process %ld.\n", (long)info.si_pid);
fflush(stdout);
} while (signum != SIGTERM);
return EXIT_SUCCESS;
}
Compile it using for example
gcc -Wall -O2 example.c -o example
I suggest you prepare two terminals. In one terminal, run the compiled program, using
./example
and observe its output. It will be something like
Process 843 is ready to receive signals! Run
kill -USR1 843
kill -USR2 843
kill -HUP 843
kill -TERM 843
in another terminal; press Ctrl+C in this terminal; or press Ctrl+Z and run
fg
in this terminal.
The KILL and STOP signals cannot be caught. KILL will always kill the process, and STOP will always stop ("pause") the process.
If you press Ctrl+C in that terminal, the kernel will send an INT signal to the process. (This will be delivered via the report_signal() signal handler.)
If you press Ctrl+Z in that terminal, the kernel will send a STOP signal to the process. The shell detects this, pushing ./example under job control, and lets you input new shell commands. The fg command brings ./example back to foreground, with the shell sending it the CONT signal, so that ./example will continue execution.
USR1 and USR2 signals are blocked, so they are never delivered to the report_signal() signal handler.
HUP and TERM signals are also blocked, but they are received by the main thread via sigwaitinfo().
The program exits, when it receives a TERM signal.
I compiled the program. Starting it and waiting. I open the other terminal, and kill the any running program with command "kill pid" or "kill -15 pid" or "kill -SIGTERM pid" (replace PID with the actual process ID). The killed program is exit, but can't trap SIGTERM to print "done.".
I copy code here: https://airtower.wordpress.com/2010/06/16/catch-sigterm-exit-gracefully/.
Can I help you? I am appreciated all answers.
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
volatile sig_atomic_t done = 0;
void term(int signum)
{
done = 1;
}
int main(int argc, char *argv[])
{
struct sigaction action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_handler = term;
sigaction(SIGTERM, &action, NULL);
int loop = 0;
while (!done)
{
int t = sleep(3);
/* sleep returns the number of seconds left if
* interrupted */
while (t > 0)
{
printf("Loop run was interrupted with %d "
"sec to go, finishing...\n", t);
t = sleep(t);
}
printf("Finished loop run %d.\n", loop++);
}
printf("done.\n");
return 0;
}
You need to setup your signal handler correctly in order to handle signals you want to catch. This is how I do my signal handler:
static void handle_signal(int signum); //in header, then implement
//in the source file
struct sigaction myaction;
myaction.sa_handler = handle_signal;
myaction.sa_flags = 0; //or whatever flags you want but do it here so the signals you register see these flags
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGTERM);
sigaction(SIGTERM, &myaction, NULL);
myaction.sa_mask = mask;
I am able to catch SIGTERM as well as all the other signals I register there (to sigaddset and sigaction).