I am a newbie in Linux programming.I copied the code below from a book:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void ouch (int sig)
{
printf("OUCH! - I got signal %d\n", sig);
(void) signal(SIGINT, SIG_DFL);
}
int main ()
{
(void) signal(SIGINT, ouch);
while(1)
{
printf("Hello World!\n");
sleep(1);
}
}
It was expected to print something when Ctrl+C was entered.But it do nothing but print Hello World!.
EDIT:
I am so sorry that I have binded the Ctrl+C as a short-cut key for copy.
Sorry for trouble caused.
My Suggestion is don't use printf in siginal handler (ouch), it may be undefined behavior. Async-signal-safe functions: The list of safe functions that can be call in signal handler man page.
It is not safe to call all functions, such as printf, from within a signal handler.
A useful technique is to use a signal handler to set a flag and then check that flag
from the main program and print a message if required.
Reference: Beginning Linux Programming, 4th Edition,In this book exactly your code is explained, Chapter 11: Processes and Signals, page 484
An additional helpful link:
Explanation: Use reentrant functions for safer signal handling
Sorry, I can't see a question here... but I can guess what you are interested in.
printf() is a stateful function, thus not reentrant. It uses a FILE structure (variable name is 'stdin') to keep it's state. (It is like calling fprintf(stdin,format,...)).
That means, dependant on implementation and 'luck', calling printf() from a signal handler may print what you expect, but also may print nothing or may even crash or worse, smash your memory! Anything could happen.
So, just don't call functions from within a signal handler that are not explicitely marked 'signal-safe'. You will avoid lot's of headaches in the long term.
Put an fflush(stdout) in your signal handler. It was just buffered, then the second SIGINT exited the program before the buffer could be flushed.
Related
I am trying to learn Signals. I know invalid memory access will cause segfault. So, I register a signal handler for SIGSEGV signal.
#include <stdio.h>
#include <signal.h>
void sighandler(int signum)
{
printf("%s\n", __func__);
}
int main()
{
int *a = NULL;
signal(SIGSEGV, sighandler);
*a = 5;
return 0;
}
Running this code, I am continuously getting SIGSEGV Signals. I thought i should only get the signal once. Can you guys explain why I am getting signals continuously
After the SEGV handler finishes, the instruction that triggered re-executes. Since you didn't do anything to prevent the next execution from faulting, you get SEGV again, ad infinitum.
See more in this answer.
The signal handler is returning to instruction that triggered it namely *a = 5 which is causing it to loop.
You have several problems including the use of printf inside a signal handler.
There are safe and not-safe ways of dealing with this
NOTES
Using signal(2) is not recommended for signal handling in general.
Handling SIGSEGV is even more complicated because of the way the signal semantics work. Quoting from the man page:
The only portable use of signal() is to set a signal's disposition to SIG_DFL or SIG_IGN. The semantics when using signal()
to establish a signal handler vary across
systems (and POSIX.1 explicitly permits this variation); do not use it for this purpose.
POSIX.1 solved the portability mess by specifying sigaction(2), which provides explicit control of the semantics when a
signal handler is invoked; use that interface instead of signal().
So the first thing you should do is use sigaction.
Next, handling SIGSEGV is a weird beast:
How to write a signal handler to catch SIGSEGV?
and
Does linux allow any system call to be made from signal handlers?
have good answers and get into specific details. There are external links in some of the answers given there.
How to do this using signal(2)
Well :-) let's say you want to use signal(2) and you want to play with this in a weird way....
You can use sigjmpset and siglongjmp.
sigjmpset marks a point where siglongjmp should jump to. The first time sigjmpset is called (to set the point) it returns 0. When siglongjmp jumps to it, (which means it gets called again as a result of the long jump), it returns 1.
Which means we can do this:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <setjmp.h>
sigjmp_buf env;
int sigsav;
void sighandler(int signum)
{
const char msg[] = "Skipping signal\n";
write(2, msg, sizeof(msg));
siglongjmp(env, sigsav);
}
int main()
{
int *a = NULL;
signal(SIGSEGV, sighandler);
if(!sigsetjmp(env, sigsav)) {
printf("setting value of a\n");
*a = 5;
}
else {
printf("returned to sigsetjmp, but now we skip it!\n");
}
return 0;
}
Some time ago I found this exercise in C: without changing the main function, so that receiving a SIGUSR1 signal output is directed and added to a file in append mode as the first parameter. At the reception of another SIGUSR1 the output is directed to the console, and so on. How do such an exercise?
#include <stdio.h>
#include <time.h>
void redirectsetup (char *s){
}
int main (int argc, char *argv[]){
redirect setup(argv[1]);
while(1){
time_t now = time(NULL);
printf("%s",ctime(&now));
sleep(1);
}
}
I'll give you some general pointers.
You need to install a signal handler. Try typing man signal or googling "signal handler linux". As a rule your signal handler should do the minimum possible, many things are illegal in signal handlers including much of the C library. In this case, you could have it set a variable which tells you where to direct output and leave it at that.
Your main program needs to loop, sending characters to wherever the variable tells it.
One thing you might need to be careful of is a signal interrupting a system call, requiring it to be retried.
Have a go and see if you can make it work.
Doing homework with signals and fork and have a problem with the signal.
I've created the function:
void trata_sinal_int() {
char op[2];
printf("\nTerminate? (y/n)\n");
scanf("%s", op);
if (op[0] == 'y') {
printf("Bye Bye\n");
exit(0);
}
}
And in main I have:
signal(SIGINT, trata_sinal_int);
When I run this, and press CTRL ^C the function void trata_sinal_int() is called and I got the message.
If I press y program ends as expected but if I press n program still ends.
It is not returning to were he was before pressing CTRL ^C.
Is this supposed to happen?
It depends on which standard you are adhering to, but Standard C doesn't allow you to do much more than modify a variable of type volatile sig_atomic_t or call _Exit (or abort() or signal()) from a signal handler. POSIX is a lot more lenient. Your code in your signal handler, replete with user interaction, is pushing beyond the limits of what even POSIX allows. Normally, you want your signal handler function to be small and svelte.
Note that the signal handler function should be:
void trata_sinal_int(int signum)
{
This allows you to compile without casts or compiler warnings about type mismatches.
The signal() function may reset the signal handler back to default behaviour when it is invoked; classically, it is necessary to reinstate the signal handler inside the signal handler:
signal(signum, trata_sinal_int);
So far, that's all pretty generic and semi-trivial.
When you type the Control-C, the system does go back to roughly where it was when the signal was originally received. However, what happens next depends on where it was (one of the reasons you have to be so very careful inside the handler). For example, if it was in the middle of manipulating the free list pointers inside malloc(), it would return there, but if you'd reinvoked malloc() inside the handler, all hell might be breaking loose. If you were inside a system call, then your call may be interrupted (return with an error indication and errno == EINTR), or it may resume where it left off. Otherwise, it should go back to where the calculation was running.
Here's (a fixed up version of) your code built into a test rig. The pause() function waits for a signal before returning.
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
static void trata_sinal_int(int signum)
{
char op[2];
signal(signum, trata_sinal_int);
printf("\nTerminate? (y/n)\n");
scanf("%s", op);
if (op[0] == 'y')
{
printf("Bye Bye\n");
exit(0);
}
}
int main(void)
{
signal(SIGINT, trata_sinal_int);
for (int i = 0; i < 3; i++)
{
printf("Pausing\n");
pause();
printf("Continuing\n");
}
printf("Exiting\n");
return(0);
}
I should really point out that the scanf() is not very safe at all; a buffer of size 2 is an open invitation to buffer overflow. I'm also not error checking system calls.
I tested on Mac OS X 10.7.5, a BSD derivative. The chance are good that the resetting of signal() would be unnecessary on this platform, because BSD introduced 'reliable signals' a long time ago (pre-POSIX).
ISO/IEC 9899:2011 §7.14.1.1 The signal function
¶5 If the signal occurs other than as the result of calling the abort or raise function, the
behavior is undefined if the signal handler refers to any object with static or thread
storage duration that is not a lock-free atomic object other than by assigning a value to an
object declared as volatile sig_atomic_t, or the signal handler calls any function
in the standard library other than the abort function, the _Exit function, the
quick_exit function, or the signal function with the first argument equal to the
signal number corresponding to the signal that caused the invocation of the handler.
Furthermore, if such a call to the signal function results in a SIG_ERR return, the
value of errno is indeterminate.252)
252) If any signal is generated by an asynchronous signal handler, the behavior is undefined.
The references to quick_exit() are new in C2011; they were not present in C1999.
POSIX 2008
The section on Signal Concepts goes through what is and is not allowed inside a signal handler under POSIX in considerable detail.
First, your signal handler is not exactly async signal safe. In practice this is probably not a problem in your case, since I assume the main() is basically doing nothing while it is waiting for the signal. But it is definately not correct anyway.
As for why the program exits, not counting segfault:s in the signal handler due to invalid use of FILE* functions such as printf, sscanf etc, when the signal is received any system calls you are doing (or, well, most) will be interreupted with EAGAIN.
If you are using something like sleep() in main to wait for the signal to occur it will be interrupted. You are expected to restart it manually.
To avoid this you probably want to use the significantly more portable sigaction interface instead of signal. If nothing else this allows you to indicate that you want system calls to be restarted.
The reason that FILE * functions (and most other functions that use global state such as malloc and free) is not allowed in signal handlers is that you might be in the middle of another operation on the same state when the signal arrives.
This can cause segfaults or other undefined operations.
The normal 'trick' to implement this is to have a self-pipe: The signal handler will write a byte to the pipe, and your main loop will see this (usually by waiting in poll or something similar) and then act on it.
If you absolutely want to do user interaction in the signal handler you have to use write() and read(), not the FILE* functions.
While learning signal() system call, I supposed to come across the following code,
#include <stdio.h>
#include <signal.h>
void sigproc(int);
void quitproc(int);
int main(int argc,char **argv)
{
signal(SIGINT, sigproc); //Is it like a normal Call to signal()?
signal(SIGQUIT, quitproc);// This too?
printf("ctrl- c disabled use ctrl\ to quit \n");
while(1);
return 0;
}
void sigproc(int signo)
{
printf("you have pressed ctrl - c \n");
}
void quitproc(int signo)
{
printf("U cant quit\n");
// exit(0);
}
I am calling the function signal() twice in main(). But its executed only when I'm pressing Ctrl-C and Ctrl-\ keys. I thought its also like normal function call. What is actually happening in the signal handler functions?
The signal function establishes a signal handler. What it means: "When my process receives this signal, run this function instead of doing whatever the default was".
So, in your example the calls to signal don't call the function. To actually see the signals in action, do this:
Start your process in one terminal
From another terminal:
kill -INT `pidof proc`
As a side note, printf and friends aren't async-signal-safe. It might come as a shocker, but it's unsafe to use them in signal handlers.
As a side side note, even if you tagged your question Unix it's important to know that signals (and the signal function) are standard, integral parts of C. Signal handling and the signal function are described in C99 in §7.14.1.
The example code of section 10.6, the expected result is:
after several iterations, the static structure used by getpwnam will be corrupted, and the program will terminate with SIGSEGV signal.
But on my platform, Fedora 11, gcc (GCC) 4.4.0, the result is
[Langzi#Freedom apue]$ ./corrupt
in sig_alarm
I can see the output from sig_alarm only once, and the program seems hung up for some reason, but it does exist, and still running.
But when I try to use gdb to run the program, it seems OK, I will see the output from sig_alarm at regular intervals.
And from my manual, it said the signal handler will be set to SIG_DEF after the signal is handled, and system will not block the signal. So at the beginning of my signal handler I reset the signal handler.
Maybe I should use sigaction instead, but I only want to know the reason about the difference between normal running and gdb running.
Any advice and help will be appreciated.
following is my code:
#include "apue.h"
#include <pwd.h>
void sig_alarm(int signo);
int main()
{
struct passwd *pwdptr;
signal(SIGALRM, sig_alarm);
alarm(1);
for(;;) {
if ((pwdptr = getpwnam("Zhijin")) == NULL)
err_sys("getpwnam error");
if (strcmp("Zhijin", pwdptr->pw_name) != 0) {
printf("data corrupted, pw_name: %s\n", pwdptr->pw_name);
}
}
}
void sig_alarm(int signo)
{
signal(SIGALRM, sig_alarm);
struct passwd *rootptr;
printf("in sig_alarm\n");
if ((rootptr = getpwnam("root")) == NULL)
err_sys("getpwnam error");
alarm(1);
}
According to the standard, you're really not allowed to do much in a signal handler. All you are guaranteed to be able to do in the signal-handling function, without causing undefined behavior, is to call signal, and to assign a value to a volatile static object of the type sig_atomic_t.
The first few times I ran this program, on Ubuntu Linux, it looked like your call to alarm in the signal handler didn't work, so the loop in main just kept running after the first alarm. When I tried it later, the program ran the signal handler a few times, and then hung. All this is consistent with undefined behavior: the program fails, sometimes, and in various more or less interesting ways.
It is not uncommon for programs that have undefined behavior to work differently in the debugger. The debugger is a different environment, and your program and data could for example be laid out in memory in a different way, so errors can manifest themselves in a different way, or not at all.
I got the program to work by adding a variable:
volatile sig_atomic_t got_interrupt = 0;
And then I changed your signal handler to this very simple one:
void sig_alarm(int signo) {
got_interrupt = 1;
}
And then I inserted the actual work into the infinite loop in main:
if (got_interrupt) {
got_interrupt = 0;
signal(SIGALRM, sig_alarm);
struct passwd *rootptr;
printf("in sig_alarm\n");
if ((rootptr = getpwnam("root")) == NULL)
perror("getpwnam error");
alarm(1);
}
I think the "apue" you mention is the book "Advanced Programming in the UNIX Environment", which I don't have here, so I don't know if the purpose of this example is to show that you shouldn't mess around with things inside of a signal handler, or just that signals can cause problems by interrupting the normal work of the program.
According to the spec, the function getpwnam is not reentrant and is not guaranteed to be thread safe. Since you are accessing the structure in two different threads of control (signal handlers are effectively running in a different thread context), you are running into this issue. Whenever you have concurrent or parallel execution (as when using pthreads or when using a signal handler), you must be sure not to modify shared state (e.g. the structure owned by 'getpwnam'), and if you do, then appropriate locking/synchronization must be used.
Additionally, the signal function has been deprecated in favor of the sigaction function. In order to ensure portable behavior when registering signal handlers, you should always use the sigaction invocation.
Using the sigaction function, you can use the SA_RESETHAND flag to reset the default handler. You can also use the sigprocmask function to enable/disable the delivery of signals without modifying their handlers.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void sigalrm_handler(int);
int main()
{
signal(SIGALRM, sigalrm_handler);
alarm(3);
while(1)
{
}
return 0;
}
void sigalrm_handler(int sign)
{
printf("I am alive. Catch the sigalrm %d!\n",sign);
alarm(3);
}
For example, my code is runing in main doing nothing and every 3 seconds my program says im alive x)
I think that if you do as i done calling in the handler function alarm with value 3, the problem is resolved :)