How to manage debug mode of application in runtime? - c

Suppose we have application on Linux, pure C. Application consists of several functions - f1, f2 and f3, which receive a structure. One element of the structure is debug_mode, with values ON or OFF.
How can I switch debug mode in f1, f2 and f3 (for example, some printfs) when the structure has debug_mode == ON?
Should I always use if statements to check debug_mode for every incoming structure or there is some another best practise to not use always if statements?
For example, these could be traces in telecom products, where we could collect some trace data for a specified subscriber.

You can change it during runtime like this :
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#define FALSE 0
#define TRUE 1
volatile sig_atomic_t GLOBAL_DEBUG = FALSE;
void sig_handler(int signo)
{
if (signo == SIGUSR1) {
// printf("received SIGUSR1\n");
GLOBAL_DEBUG = TRUE;
} else if (signo == SIGUSR2) {
GLOBAL_DEBUG = FALSE;
// printf("received SIGUSR2\n");
}
}
int main (int argc, char **argv) {
if (signal(SIGUSR1, sig_handler) == SIG_ERR)
printf("\ncan't catch SIGUSR1\n");
if (signal(SIGUSR2, sig_handler) == SIG_ERR)
printf("\ncan't catch SIGUSR2\n");
while (TRUE) {
if (GLOBAL_DEBUG) printf ("DEBUG == TRUE\n");
printf ("Hello world\n");
sleep(1);
}
}
And the switch GLOBAL_DEBUG during runtime like this :
user#host:~ $ kill -SIGUSR2 <pid of program>
user#host:~ $ kill -SIGUSR1 <pid of program>
BTW, read signal-safety(7) (explaining why printf should be avoided inside signal handlers) and signal(7). sig_atomic_t is specified in the C11 standard (see n1570).

You could use signals (see signal(7) & signal-safety(7)), as explained in mbieren's answer. Of course you cannot call printf (or any non async-signal-safe function) from a signal handler, and the flag should be declared as volatile sig_atomic_t GLOBAL_DEBUG;
You could design your program otherwise. Perhaps your program has already some event loop (e.g. because it is a GUI application). Then you could add some RPCJSON service (or some HTTP one, or your own socket(7) or unix(7) based protocol, probably some text-based one) to your program. You'll find many libraries to help you (for example, libonion enables you to add some HTTP service to your program; so you might change the debug flag via your web server!).
You don't tell enough about your program to get more precise help.

Related

How to restore original signal handling properties in C

Tried my best to figure this out on my own, but I really do not want to continue tampering with things that I do not fully understand. So for a programming assignment I have to do in C, I need to terminate a program upon the user entering CTRL+D key stroke via a terminal. I tried to isolate that functionality in a smaller test function, but now my CTRL+D behaves as my CTRL+C and CTRL+C does not have any effect, even outside of the program when it finishes executing. This is the program that caused this change:
#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <signal.h>
#include <stdlib.h>
void ctrlD(int sig){
printf("\n");
signal(SIGINT, SIG_DFL);
exit(0);
}
int main(){
signal(SIGINT, ctrlD);
while(1) {
printf("Hello\n");
sleep(5);
}
}
The line signal(SIGINT, SIG_DFL); was added afterward upon realizing my CTRL+C no longer worked. I thought it would return the keystrokes to their original functionalities, but to no avail. What do I do to get back the original functionalities while also making this program work with CTRL+D?
***EDIT: This question seems to have gone off the rails a bit. I get now that Ctrl+D is not a signal. Nonetheless, I no longer have the functionality of Ctrl+C anymore when attempting to use it in my MAC OS terminal, and instead Ctrl+D seems to have that exact functionality. HOW exactly can I return each to have the functionality that they had before I went on this haphazard journey?
If your intention is to restore signal's default behavior after executing handler then, pass SA_RESETHAND flag to sa_flags while registering signal action. For example.
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_RESETHAND;
act.sa_handler = some_handler;
sigaction(SIGINT, &act, NULL);
From sigaction() man
SA_RESETHAND
Restore the signal action to the default upon entry to the signal handler. This flag is meaningful only when
establishing a signal handler.
If you write a program to explore signals, it is much better to write it carefully, using proper POSIX interfaces (sigaction() instead of signal()), and avoiding undefined behaviour (using non-async-signal safe functions in a signal handler).
Consider, for example, the following program:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
static volatile sig_atomic_t sigint_count = 0;
static void catch_sigint(int signum)
{
if (signum == SIGINT)
sigint_count++;
}
static int install_sigint(void)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = catch_sigint;
act.sa_flags = 0;
if (sigaction(SIGINT, &act, NULL) == -1)
return errno;
return 0;
}
static int install_default(const int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = SIG_DFL;
act.sa_flags = 0;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
int main(void)
{
struct timespec duration;
int result;
if (install_sigint()) {
fprintf(stderr, "Cannot install SIGINT handler: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
duration.tv_sec = 5;
duration.tv_nsec = 0; /* 1/1000000000ths of a second. Nine zeroes. */
printf("Sleeping for %d seconds.\n", (int)duration.tv_sec);
fflush(stdout);
while (1) {
result = nanosleep(&duration, &duration);
if (!result)
break;
if (errno != EINTR) {
fprintf(stderr, "nanosleep() failed: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
/* nanosleep was interrupted by a delivery of a signal. */
if (sigint_count >= 3) {
/* Ctrl+C pressed three or more times. */
if (install_default(SIGINT) == -1) {
fprintf(stderr, "Cannot revert SIGINT to the default handler: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
printf("SIGINT has been reverted to the default handler.\n");
fflush(stderr);
}
}
if (sigint_count > 0)
printf("You pressed Ctrl+C %d time%s.\n", (int)sigint_count, (sigint_count > 1) ? "s" : "");
else
printf("You did not press Ctrl+C at all.\n");
return EXIT_SUCCESS;
}
The #define tells your C library (glibc in particular) that you want POSIX.1-2008 (and later) features from it.
The INT signal handler only increments a volatile sig_atomic_t counter. Note that this type may have a very small range it can represent; 0 to 127, inclusive, should be safe.
The main program waits using the POSIX nanosleep() function. On some systems, sleep() may be implemented via the SIGALRM function, so it is better avoided when using signals otherwise; nanosleep() does not interfere with signals like that at all. Plus, nanosleep() can return the amount of time remaining, if it is interrupted by a signal delivery.
In the main loop, nanosleep() will return 0, if it has slept the entire interval (but note that it may not update the remaining time to 0 in this case). If it is interrupted by the delivery of a signal, it will return -1 with errno == EINTR, and the remaining time updated. (The first pointer is to the duration of the sleep, and the second is to where the remaining time should be stored. You can use the same structure for both.)
Normally, the main loop does only one iteration. It can do more than one iteration, if it is interrupted by the delivery of a signal.
When the main loop detects that sigint_count is at least three, i.e. it has received at least three INT signals, it resets the signal handler back to default.
(Note that both the memset() and the sigemptyset() are important when clearing the struct sigaction structure. The memset() ensures that future code is backwards compatible with older code, by ensuring even padding fields are cleared. And sigemptyset() is the safe way to clear the signal mask (set of signals blocked while the handler runs).)
(In theory, memset() is not async-signal-safe, while both sigemptyset() and sigaction() are. This is why I reset the signal handler in the main program, and not in the signal handler.)
If you want to print from a signal handler, you need to use low-level I/O, because <stdio.h> functions are not async-signal safe. For example, you can use the following function to print strings to standard output:
static int wrerr(const char *p)
{
const int saved_errno = errno;
int retval = 0;
if (p) {
const char *q = p;
ssize_t n;
while (*q)
q++;
while (p < q) {
n = write(STDERR_FILENO, p, (size_t)(q - p));
if (n > 0)
p += n;
else
if (n != -1) {
retval = EIO;
break;
} else
if (errno != EINTR) {
retval = errno;
break;
}
}
}
errno = saved_errno;
return retval;
}
The above wrerr() function is async-signal safe (because it only uses async-signal safe functions itself), and it even keeps errno unchanged. (Many guides forget to mention that it is quite important for a signal handler to keep errno unchanged. Otherwise, when a function is interrupted by a signal handler, and that signal handler modifies errno, the original function will return -1 to indicate an error, but then errno is no longer EINTR!)
You can just use wrerr("INT signal!\n") if you want. The return value from wrerr() is zero if the write was successful, and an errno error code otherwise. It ignores interrupts itself.
Do note that you should not mix stderr output via fprintf() or other <stdio.h> functions with the above (except perhaps for printing error messages when the program aborts). Mixing them is not undefined behaviour, it just may yield surprising results, like wrerr() output appearing in the midst of a fprintf(stderr,...) output.
Its because of exit(0) statement in the handler, when SIGINT is raised, handler strlD gets called and you might thinking why signal(SIGINT,SIG_DFL) didn't work ? Actually it works. But your main process a.out get terminated successfully there itself by calling exit(0). remove exit(0) if you want to restore the behavior of SIGINT.
#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <signal.h>
#include <stdlib.h>
void ctrlD(int sig){
//printf("CTRL+C pressed\n");/* just to observe I added one printf
statement, Ideally there shouldn't be any printf here */
signal(SIGINT, SIG_DFL);/*restoring back to original action */
}
int main(){
signal(SIGINT, ctrlD);/*1st time when CTRL+C pressed, handler ctrlD gets called */
while(1) {
printf("Hello\n");
sleep(5);
}
return 0;
}
Also its advisable to use sigaction() instead of signal() as told here What is the difference between sigaction and signal? . Read man 2 sigaction and man 2 exit to check what exit(0) means.
Also this How to avoid using printf in a signal handler?
Edit :
void ctrlD(int sig){
/* printf("CTRL+C pressed \n"); */
signal(SIGINT, SIG_DFL); /* only one time CTRL+C works
after that SIG_DFL will terminate whole process */
}
int main(){
signal(SIGINT, ctrlD); /* if you press CTRL+C then it will go to handler
and terminate */
int ch;
while( ((ch = getchar())!=EOF) ) { /* wait or read char until CTrl+D is not pressed */
printf("Hello : %d \n",ch);/* ASCII equivalent of char */
}
return 0;
}
Thank you everyone who contributed to this question. The resources provided/linked were tremendously helpful in learning more about signals (and that EOF isn't a signal), among the other wealth of information provided.
After some more research, I found out that somehow, either through some accidental bash command gone awry, or perhaps the program posted in my original question itself, I had altered the key mappings for my terminal's stty settings. If anyone finds themselves in this oddly specific situation in the future, I hope this can be of help, as it is what fixed my problem:
Enter the command $ stty -a to see all of your terminals settings, specifically the "cchars" section.
I then saw the reversal, and fixed it like so:
$ stty intr ^C
$ stty eof ^D
Then you can run $ stty -a once again to see that the changes have properly taken effect. Once again, thanks everyone.

Catching Signals and Pausing with Character Device Drivers

I'm a student new to C Programming and am not fully understanding how signal catching works, and in line with character device drivers. I'd appreciate some help but I need to state that this is for a project that is due in my first C Programming class. So I have not posted any direct code, only an example of my initial approach.
My project needs to accept a signal input and set that signal to a variable to pass to my character device driver. Another program I've written will need to access that variable's value such that when read, it performs a certain outcome. I've tried to run my control program (<name> &) but it quits immediately. I double check by entering ps into my command prompt and the process is gone.
Basically I need my control program to pause and wait for the signal to be received. Once received, if the signal matches it will set a variable to its value. Otherwise, if it is SIGTERM it will either end or pause(), where it will wait until another signal is received that meets another condition. Currently, when I compile and run it with & it simply runs and quits. Here is an example of my code:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
static int file_state; //variable to pass to the driver for recording
void sig_handler(int sig);
void sig_handler(int sig){
while(1){
if(sig == SIGRTMIN){
printf("SIG = SIGRTMIN\n");
file_state = 0;
}else if(sig == SIGRTMIN+1){
printf("SIG = SIGRTMIN1\n");
file_state = 1;
}else if(sig == SIGTERM){
printf("Exiting\n");
exit(0); //exit
}else{
printf("SIG = %i\n", sig);
pause(); //doesn't match, pause for next signal
}
}
}
int main(){
signal(SIGINT, sig_handler);
//return 0; //tried with and without
}
I'm waiting until this daemon receives a signal to put the device driver into a particular mode. I haven't entered any write() methods yet because I'm trying to take this one step at a time where I send a signal with kill() and the proper response is returned with printf().
My problem is that I can't seem to keep this in pause() mode while I'm waiting for a signal that breaks the if loop. What's worse (other than my lack of knowledge and programming) is that I can't even keep this daemon open long enough to attempt a signal send. Once I can get this to pause and receive the signal, I plan to use the system write() method to write my file_state variable to the /dev/<filename>, which will be cross-referenced in my executable.
How far off am I? This is the final part that (I believe) I'm stuck on and I can't figure out how this should be approached. I've looked online and about 95% of the examples that delve into this contain methods we haven't learned yet. And if not, the examples are more simplistic where they do not include passing a value to a character device driver for use when another program is using the driver.
Any help is greatly appreciated.
ETA
I've updated my code so now it stays open until a signal is received. Problem is that I want this to pause() and remain open until the SIGTERM signal is received, breaking the loop and ending the program. I can't seem to get the loop correct. Even entering a conditional int variable into the while() loop still is broken when any signal is received. Here is my updated code below:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
static int file_state; //variable to pass to the driver for recording
int keep_alive = 1; //added for conditional checking to keep the while
//loop open to receive more than one signal
void sig_handler(int sig);
void sig_handler(int sig){
if(sig == SIGRTMIN){
printf("SIG = SIGRTMIN\n");
file_state = 0;
}else if(sig == SIGRTMIN+1){
printf("SIG = SIGRTMIN1\n");
file_state = 1;
}else if(sig == SIGTERM){
keep_alive = 0;
}else{
}
}
int main(){
do{
signal(SIGINT, sig_handler);
pause(); //thought pausing here would help with waiting for a new signal
}while(keep_alive == 1); //keep looping until false
return 0; //tried with and without
}
I'm trying to figure out a method to keep this process and signal catching loop alive until a specific signal is received. I can't figure it out for the life of me.
ETA 2
Discovered my issue. I wasn't paying attention and fully understanding the signal() method. The first argument requires the exact signal you are attempting to catch. I was using SIGINT which I was understanding it to be a "class" of interrupts that you wanted to catch. And then in the signal_handler() function, you would specify which type of interrupt you were catching. But, it is actually looking to catch the exact signal you are interested in. So in my example code, I should have been using:
int main(){
if(signal(SIGRMIN, sig_handler) == SIG_ERR){
printf("can't catch SIGRMIN Signal.\n")
}
...
}
I'm going to update with my new script as an answer and if anyone thinks it should be done differently or have any constructive criticisms please let me know. Thanks again!
So I found my issue, and it is working now. Below is my fixed code that produces the correct response back to the terminal when caught. I've added a for() loop to catch any other signals I'm not worried about didn't stop my process, only SIGTERM will. Look forward to getting critiqued and why I would never want to do my approach.
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
static int file_state; //variable to pass to the driver for recording
void sig_handler(int sig);
void sig_handler(int sig){
if(sig == SIGRTMIN){
printf("SIG = SIGRTMIN\n");
file_state = 0;
}else if(sig == SIGRTMIN+1){
printf("SIG = SIGRTMIN1\n");
file_state = 1;
}else if(sig == SIGTERM){
exit(0);
EXIT_SUCCESS;
}else{
printf("SIGNAL CAUGHT #%d\n", sig);
}
}
int main(){
if(signal(SIGRTMIN, sig_handler)==SIG_ERR){
printf("Unable to catch SIGRTMIN\n");
}
if(signal(SIGRTMIN+1, sig_handler)==SIG_ERR){
printf("Unable to catch SIGRTMIN+1\n");
}
if(signal(SIGTERM, sig_handler)==SIG_ERR){
printf("Unable to terminate process.\n");
}
//This for loop will catch all other signals except the un-catchable and
//other user-specified above signal #31.
int s;
for(s = 0; s < 32; s++){
signal(s, sig_handler);
}
while(1);
pause();
return 0;
}
There are 2 parts, 1st user space where generation and catching of signals occurs. This has nothing to do with kernel driver. Your code seems okay about it.
2nd is interacting with driver when signal has been caught. For char driver have a look at this link. You can simply write a value write(fd, 1, &buf); from user space program and implement corresponding write() in char driver.

Unix - Control C and Control Z signal pick up issues

I'm experimenting around with the signals offered in Unix. The two I'm focusing on at the moment is Ctrl+C and Ctrl+Z. I want to catch the signal, and display a message to the screen. I got most of it working. Like the message displays when either signal is pressed. However it seems to only work once. I want the message to display each time Ctrl+C or Ctrl+Z are pressed. Like a loop.
#include <stdio.h>
#include <signal.h>
void handler (int signal);
int main ()
{
if (signal(SIGINT, handler) == SIG_ERR)
{
write (2, "Error catching signal C \n",26);
}
if (signal(SIGTSTP, handler) == SIG_ERR)
{
write(2, "Error catching signal Z \n", 26);
}
pause();
}
void handler (int signal)
{
if (signal == SIGINT)
{
write(1, "CONTROLC \n", 11);
}
else if (signal == SIGTSTP)
{
write(1, "CONTROLZ \n", 11);
}
else
{
write(2, "error \n", 8);
}
main();
}
I attempted to use the main function so that it would restart the program again, but I'm assuming its calling main from within a signal so it behaves differently?
Whoa, don't do it that way. :)
What's happening here is that the SIGINT, for example, is masked (blocked) during the execution of the handler. So, re-invoking main from within the handler re-runs main with SIGINT blocked. Thus you see your handler fire only once per signal — it's blocked ever after. (Note that this blocking behavior is not guaranteed by signal, which is one reason you should use sigaction instead.)
The typical signal handler should do as little work as possible, using only async-signal-safe functions, if any. Think of the handler as an interruption to the ordinary flow of your process, a special asynchronous flow which can use its own stack if need be.
If you want the program to behave like a loop, code it like a loop:
static volatile sig_atomic_t flag_int;
static volatile sig_atomic_t flag_tstp;
static void handle_int(int s) { flag_int = 1; } /* register me with sigaction */
static void handle_tstp(int s) { flag_tstp = 1; } /* me, too */
...
while (1) {
pause();
if (flag_int) { printf("CONTROL C\n"); flag_int = 0; }
if (flag_tstp) { printf("CONTROL Z\n"); flag_tstp = 0; }
}
Don't call main() from your signal handler, as your program is now stuck in the signal handler, and it will not call another signal handler for the same signal again while the handler is running.
(That behavior can be changed if you use sigaction() instead of signal() though).
Also see what the pause() call does.
DESCRIPTION
pause() causes the calling process (or thread) to sleep until a signal is delivered that either terminates the process or causes the
invocation of a signal-catching function.
So, your pause(); calls waits until a signal is delivered, and then continues your program.
So, do e.g. this to keep your program running.
for(;;) {
pause();
}
Do not use signal(2), except possibly to set a given signal's disposition to SIG_DFL or SIG_IGN. Its behavior varies among different Unixes.
For portability (among POSIX systems) and better control, you should install user signal handlers via the sigaction(2) syscall. Among other things, that allows you to choose between one-shot and persistent mode when you install the handler.
If you are obligated to use signal(2), then your best bet is for the last thing the handler does to be to reinstall itself as the handler for the given signal (when that's in fact what you want).

How to read a counter from a linux C program to a bash test script?

I have a large C/C++ program on a Suse linux system. We do automated testing of it with a bash script, which sends input to the program, and reads the output. It's mainly "black-box" testing, but some tests need to know a few internal details to determine if a test has passed.
One test in particular needs to know how times the program runs a certain function (which parses a particular response message). When that function runs it issues a log and increments a counter variable. The automated test currently determines the number of invocations by grepping in the log file for the log message, and counting the number of occurrences before and after the test. This isn't ideal, because the logs (syslog-ng) aren't guaranteed, and they're frequently turned off by configuration, because they're basically debug logs.
I'm looking for a better alternative. I can change the program to enhance the testability, but it shouldn't be heavy impact to normal operation. My first thought was, I could just read the counter after each test. Something like this:
gdb --pid=$PID --batch -ex "p numServerResponseX"
That's slow when it runs, but it's good because the program doesn't need to be changed at all. With a little work, I could probably write a ptrace command to do this a little more efficiently.
But I'm wondering if there isn't a simpler way to do this. Could I write the counter to shared memory (with shm_open / mmap), and then read /dev/shm in the bash script? Is there some simpler way I could setup the counter to make it easy to read, without making it slow to increment?
Edit:
Details: The test setup is like this:
testScript <-> sipp <-> programUnderTest <-> externalServer
The bash testScript injects sip messages with sipp, and it generally determines success or failure based on the completion code from sipp. But in certain tests it needs to know the number of responses the program received from the external server. The function "processServerResponseX" processes certain responses from the external server. During the testing there isn't much traffic running, so the function is only invoked perhaps 20 times over 10 seconds. When each test ends and we want to check the counter, there should be essentially no traffic. However during normal operation, it might be invoked hundreds of times a second. The function is roughly:
unsigned long int numServerResponseX;
int processServerResponseX(DMsg_t * dMsg, AppId id)
{
if (DEBUG_ENABLED)
{
syslog(priority, "%s received %d", __func__, (int) id);
}
myMutex->getLock();
numServerResponseX++;
doLockedStuff(dMsg, id);
myMutex->releaseLock();
return doOtherStuff(dMsg, id);
}
The script currently does:
grep processServerResponseX /var/log/logfile | wc -l
and compares the value before and after. My goal is to have this work even if DEBUG_ENABLED is false, and not have it be too slow. The program is multi-threaded, and it runs on an i86_64 smp machine, so adding any long blocking function would not be a good solution.
I would have that certain function "(which parses a particular response message)" write (probably using fopen then fprintf then fclose) some textual data somewhere.
That destination could be a FIFO (see fifo(7) ...) or a temporary file in a tmpfs file system (which is a RAM file system), maybe /run/
If your C++ program is big and complex enough, you could consider adding some probing facilities (some means for an external program to query about the internal state of your C++ program) e.g. a dedicated web service (using libonion in a separate thread), or some interface to systemd, or to D-bus, or some remote procedure call service like ONC/RPC, JSON-RPC, etc etc...
You might be interested by POCOlib. Perhaps its logging framework should interest you.
As you mentioned, you might use Posix shared memory & semaphores (see shm_overview(7) and sem_overview(7) ...).
Perhaps the Linux specific eventfd(2) is what you need.... (you could code a tiny C program to be invoked by your testing bash scripts....)
You could also try to change the command line (I forgot how to do that, maybe libproc or write to /proc/self/cmdline see proc(5)...). Then ps would show it.
I personally do usually use the methods Basile Starynkevitch outlined for this, but I wanted to bring up an alternative method using realtime signals.
I am not claiming this is the best solution, but it is simple to implement and has very little overhead. The main downside is that the size of the request and response are both limited to one int (or technically, anything representable by an int or by a void *).
Basically, you use a simple helper program to send a signal to the application. The signal has a payload of one int your application can examine, and based on it, the application responds by sending the same signal back to the originator, with an int of its own as payload.
If you don't need any locking, you can use a simple realtime signal handler. When it catches a signal, it examines the siginfo_t structure. If sent via sigqueue(), the request is in the si_value member of the siginfo_t structure. The handler answers to the originating process (si_pid member of the structure) using sigqueue(), with the response. This only requires about sixty lines of code to be added to your application. Here is an example application, app1.c:
#define _POSIX_C_SOURCE 200112L
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#define INFO_SIGNAL (SIGRTMAX-1)
/* This is the counter we're interested in */
static int counter = 0;
static void responder(int signum, siginfo_t *info,
void *context __attribute__((unused)))
{
if (info && info->si_code == SI_QUEUE) {
union sigval value;
int response, saved_errno;
/* We need to save errno, to avoid interfering with
* the interrupted thread. */
saved_errno = errno;
/* Incoming signal value (int) determines
* what we respond back with. */
switch (info->si_value.sival_int) {
case 0: /* Request loop counter */
response = *(volatile int *)&counter;
break;
/* Other codes? */
default: /* Respond with -1. */
response = -1;
}
/* Respond back to signaler. */
value.sival_ptr = (void *)0L;
value.sival_int = response;
sigqueue(info->si_pid, signum, value);
/* Restore errno. This way the interrupted thread
* will not notice any change in errno. */
errno = saved_errno;
}
}
static int install_responder(const int signum)
{
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_sigaction = responder;
act.sa_flags = SA_SIGINFO;
if (sigaction(signum, &act, NULL))
return errno;
else
return 0;
}
int main(void)
{
if (install_responder(INFO_SIGNAL)) {
fprintf(stderr, "Cannot install responder signal handler: %s.\n",
strerror(errno));
return 1;
}
fprintf(stderr, "PID = %d\n", (int)getpid());
fflush(stderr);
/* The application follows.
* This one just loops at 100 Hz, printing a dot
* about once per second or so. */
while (1) {
struct timespec t;
counter++;
if (!(counter % 100)) {
putchar('.');
fflush(stdout);
}
t.tv_sec = 0;
t.tv_nsec = 10000000; /* 10ms */
nanosleep(&t, NULL);
/* Note: Since we ignore the remainder
* from the nanosleep call, we
* may sleep much shorter periods
* when a signal is delivered. */
}
return 0;
}
The above responder responds to query 0 with the counter value, and with -1 to everything else. You can add other queries simply by adding a suitable case statement in responder().
Note that locking primitives (except for sem_post()) are not async-signal safe, and thus should not be used in a signal handler. So, the above code cannot implement any locking.
Signal delivery can interrupt a thread in a blocking call. In the above application, the nanosleep() call is usually interrupted by the signal delivery, causing the sleep to be cut short. (Similarly, read() and write() calls may return -1 with errno == EINTR, if they were interrupted by signal delivery.)
If that is a problem, or you are not sure if all your code handles errno == EINTR correctly, or your counters need locking, you can use separate thread dedicated for the signal handling instead.
The dedicated thread will sleep unless a signal is delivered, and only requires a very small stack, so it really does not consume any significant resources at run time.
The target signal is blocked in all threads, with the dedicated thread waiting in sigwaitinfo(). If it catches any signals, it processes them just like above -- except that since this is a thread and not a signal handler per se, you can freely use any locking etc., and do not need to limit yourself to async-signal safe functions.
This threaded approach is slightly longer, adding almost a hundred lines of code to your application. (The differences are contained in the responder() and install_responder() functions; even the code added to main() is exactly the same as in app1.c.)
Here is app2.c:
#define _POSIX_C_SOURCE 200112L
#include <signal.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#define INFO_SIGNAL (SIGRTMAX-1)
/* This is the counter we're interested in */
static int counter = 0;
static void *responder(void *payload)
{
const int signum = (long)payload;
union sigval response;
sigset_t sigset;
siginfo_t info;
int result;
/* We wait on only one signal. */
sigemptyset(&sigset);
if (sigaddset(&sigset, signum))
return NULL;
/* Wait forever. This thread is automatically killed, when the
* main thread exits. */
while (1) {
result = sigwaitinfo(&sigset, &info);
if (result != signum) {
if (result != -1 || errno != EINTR)
return NULL;
/* A signal was delivered using *this* thread. */
continue;
}
/* We only respond to sigqueue()'d signals. */
if (info.si_code != SI_QUEUE)
continue;
/* Clear response. We don't leak stack data! */
memset(&response, 0, sizeof response);
/* Question? */
switch (info.si_value.sival_int) {
case 0: /* Counter */
response.sival_int = *(volatile int *)(&counter);
break;
default: /* Unknown; respond with -1. */
response.sival_int = -1;
}
/* Respond. */
sigqueue(info.si_pid, signum, response);
}
}
static int install_responder(const int signum)
{
pthread_t worker_id;
pthread_attr_t attrs;
sigset_t mask;
int retval;
/* Mask contains only signum. */
sigemptyset(&mask);
if (sigaddset(&mask, signum))
return errno;
/* Block signum, in all threads. */
if (sigprocmask(SIG_BLOCK, &mask, NULL))
return errno;
/* Start responder() thread with a small stack. */
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, 32768);
retval = pthread_create(&worker_id, &attrs, responder,
(void *)(long)signum);
pthread_attr_destroy(&attrs);
return errno = retval;
}
int main(void)
{
if (install_responder(INFO_SIGNAL)) {
fprintf(stderr, "Cannot install responder signal handler: %s.\n",
strerror(errno));
return 1;
}
fprintf(stderr, "PID = %d\n", (int)getpid());
fflush(stderr);
while (1) {
struct timespec t;
counter++;
if (!(counter % 100)) {
putchar('.');
fflush(stdout);
}
t.tv_sec = 0;
t.tv_nsec = 10000000; /* 10ms */
nanosleep(&t, NULL);
}
return 0;
}
For both app1.c and app2.c the application itself is the same.
The only modifications needed to the application are making sure all the necessary header files get #included, adding responder() and install_responder(), and a call to install_responder() as early as possible in main().
(app1.c and app2.c only differ in responder() and install_responder(); and in that app2.c needs pthreads.)
Both app1.c and app2.c use the signal SIGRTMAX-1, which should be unused in most applications.
app2.c approach, also has a useful side-effect you might wish to use in general: if you use other signals in your application, but don't want them to interrupt blocking I/O calls et cetera -- perhaps you have a library that was written by a third party, and does not handle EINTR correctly, but you do need to use signals in your application --, you can simply block the signals after the install_responder() call in your application. The only thread, then, where the signals are not blocked is the responder thread, and the kernel will use tat to deliver the signals. Therefore, the only thread that will ever get interrupted by the signal delivery is the responder thread, more specifically sigwaitinfo() in responder(), and it ignores any interruptions. If you use for example async I/O or timers, or this is a heavy math or data processing application, this might be useful.
Both application implementations can be queried using a very simple query program, query.c:
#define _POSIX_C_SOURCE 200112L
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <stdio.h>
int query(const pid_t process, const int signum,
const int question, int *const response)
{
sigset_t prevmask, waitset;
struct timespec timeout;
union sigval value;
siginfo_t info;
int result;
/* Value sent to the target process. */
value.sival_int = question;
/* Waitset contains only signum. */
sigemptyset(&waitset);
if (sigaddset(&waitset, signum))
return errno = EINVAL;
/* Block signum; save old mask into prevmask. */
if (sigprocmask(SIG_BLOCK, &waitset, &prevmask))
return errno;
/* Send the signal. */
if (sigqueue(process, signum, value)) {
const int saved_errno = errno;
sigprocmask(signum, &prevmask, NULL);
return errno = saved_errno;
}
while (1) {
/* Wait for a response within five seconds. */
timeout.tv_sec = 5;
timeout.tv_nsec = 0L;
/* Set si_code to an uninteresting value,
* just to be safe. */
info.si_code = SI_KERNEL;
result = sigtimedwait(&waitset, &info, &timeout);
if (result == -1) {
/* Some other signal delivered? */
if (errno == EINTR)
continue;
/* No response; fail. */
sigprocmask(SIG_SETMASK, &prevmask, NULL);
return errno = ETIMEDOUT;
}
/* Was this an interesting signal? */
if (result == signum && info.si_code == SI_QUEUE) {
if (response)
*response = info.si_value.sival_int;
/* Return success. */
sigprocmask(SIG_SETMASK, &prevmask, NULL);
return errno = 0;
}
}
}
int main(int argc, char *argv[])
{
pid_t pid;
int signum, question, response;
long value;
char dummy;
if (argc < 3 || argc > 4 ||
!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s PID SIGNAL [ QUERY ]\n", argv[0]);
fprintf(stderr, "\n");
return 1;
}
if (sscanf(argv[1], " %ld %c", &value, &dummy) != 1) {
fprintf(stderr, "%s: Invalid process ID.\n", argv[1]);
return 1;
}
pid = (pid_t)value;
if (pid < (pid_t)1 || value != (long)pid) {
fprintf(stderr, "%s: Invalid process ID.\n", argv[1]);
return 1;
}
if (sscanf(argv[2], "SIGRTMIN %ld %c", &value, &dummy) == 1)
signum = SIGRTMIN + (int)value;
else
if (sscanf(argv[2], "SIGRTMAX %ld %c", &value, &dummy) == 1)
signum = SIGRTMAX + (int)value;
else
if (sscanf(argv[2], " %ld %c", &value, &dummy) == 1)
signum = value;
else {
fprintf(stderr, "%s: Unknown signal.\n", argv[2]);
return 1;
}
if (signum < SIGRTMIN || signum > SIGRTMAX) {
fprintf(stderr, "%s: Not a realtime signal.\n", argv[2]);
return 1;
}
/* Clear the query union. */
if (argc > 3) {
if (sscanf(argv[3], " %d %c", &question, &dummy) != 1) {
fprintf(stderr, "%s: Invalid query.\n", argv[3]);
return 1;
}
} else
question = 0;
if (query(pid, signum, question, &response)) {
switch (errno) {
case EINVAL:
fprintf(stderr, "%s: Invalid signal.\n", argv[2]);
return 1;
case EPERM:
fprintf(stderr, "Signaling that process was not permitted.\n");
return 1;
case ESRCH:
fprintf(stderr, "No such process.\n");
return 1;
case ETIMEDOUT:
fprintf(stderr, "No response.\n");
return 1;
default:
fprintf(stderr, "Failed: %s.\n", strerror(errno));
return 1;
}
}
printf("%d\n", response);
return 0;
}
Note that I did not hardcode the signal number here; use SIGRTMAX-1 on the command line for app1.c and app2.c. (You can change it. query.c does understand SIGRTMIN+n too. You must use a realtime signal, SIGRTMIN+0 to SIGRTMAX-0, inclusive.)
You can compile all three programs using
gcc -Wall -O3 app1.c -o app1
gcc -Wall -O3 app2.c -lpthread -o app2
gcc -Wall -O3 query.c -o query
Both ./app1 and ./app2 print their PIDs, so you don't need to look for it. (You can find the PID using e.g. ps -o pid= -C app1 or ps -o pid= -C app2, though.)
If you run ./app1 or ./app2 in one shell (or both in separate shells), you can see them outputting the dots at about once per second. The counter increases every 1/100th of a second. (Press Ctrl+C to stop.)
If you run ./query PID SIGRTMAX-1 in another shell in the same directory on the same machine, you can see the counter value.
An example run on my machine:
A$ ./app1
PID = 28519
...........
B$ ./query 28519 SIGRTMAX-1
11387
C$ ./app2
PID = 28522
...
B$ ./query 28522 SIGRTMAX -1
371
As mentioned, the downside of this mechanism is that the response is limited to one int (or technically an int or a void *). There are ways around that, however, by also using some of the methods Basile Starynkevich outlined. Typically, the signal is then just a notification for the application that it should update the state stored in a file, shared memory segment, or wherever. I recommend using the dedicated thread approach for that, as it has very little overheads, and minimal impact on the application itself.
Any questions?
A hard-coded systemtap solution could look like:
% cat FOO.stp
global counts
probe process("/path/to/your/binary").function("CertainFunction") { counts[pid()] <<< 1 }
probe process("/path/to/your/binary").end { println ("pid %d count %sd", pid(), #count(counts[pid()]))
delete counts[pid()] }
# stap FOO.stp
pid 42323 count 112
pid 2123 count 0
... etc, until interrupted
Thanks for the responses. There is lots of good information in the other answers. However, here's what I did. First I tweaked the program to add a counter in a shm file:
struct StatsCounter {
char counterName[8];
unsigned long int counter;
};
StatsCounter * stats;
void initStatsCounter()
{
int fd = shm_open("TestStats", O_RDWR|O_CREAT, 0);
if (fd == -1)
{
syslog(priority, "%s:: Initialization Failed", __func__);
stats = (StatsCounter *) malloc(sizeof(StatsCounter));
}
else
{
// For now, just one StatsCounter is used, but it could become an array.
ftruncate(fd, sizeof(StatsCounter));
stats = (StatsCounter *) mmap(NULL, sizeof(StatsCounter),
PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
}
// Initialize names. Pad them to 7 chars (save room for \0).
snprintf(stats[0].counterName, sizeof(stats[0].counterName), "nRespX ");
stats[0].counter = 0;
}
And changed processServerResponseX to increment stats[0].counter in the locked section. Then I changed the script to parse the shm file with "hexdump":
hexdump /dev/shm/TestStats -e ' 1/8 "%s " 1/8 "%d\n"'
This will then show something like this:
nRespX 23
This way I can extend this later if I want to also look at response Y, ...
Not sure if there are mutual exclusion problems with hexdump if it accessed the file while it was being changed. But in my case, I don't think it matters, because the script only calls it before and after the test, it should not be in the middle of an update.

Why no output on console on signal handling?

I was trying this program from Advance Programming in Unix Environment.
#include<stdio.h>
#include<signal.h>
static void handler(int sig){
if(sig == SIGUSR1)
printf("handled user1 signal");
else if(sig == SIGUSR2)
printf("handles user2 signal");
else
printf("unkown signal");
}
int main(){
if(signal(SIGUSR1, handler) == SIG_ERR)
printf("can't handle signal SIGUSR1");
if(signal(SIGUSR2, handler) == SIG_ERR)
printf("can't handle signal SIGUSR2");
for(;;)
pause();
return 0;
}
I am using Ubuntu 11.10. I compile the program with gcc and then run a.out as indicated in the book.
$./a.out&
[1]+ 1345
$ kill -USR1 1345
But there is no output printed. The program keeps running in backgound and I have to kill it.
Other things I have tried:
Tried handling SIGINT to see if running program in background is causing problems. Still no output.
Downloaded latest release of FreeBSD and tried the same program on it, but with same problem.
I put a printf statement before setting signal handler:
int main(){
printf("printf is working...");
//exit(0);
if(signal(SIGUSR1, handler) == SIG_ERR)
...
when exit() is commented, there is no output. When I uncomment it, the output is printed.
Please tell me what am I doing wrong in this?
PS: Don't suggest using sigaction(). I am learning Unix Programming, not building any practical application.
The output from printf is buffered. That means it's stored in memory until flushed to the output. The best way to flush text in printf is to end the text with a newline. You can also flush manually with the fflush function.
However, you should be cautioned that using output functions like printf and fflush is not considered safe in signal handlers.

Resources