问题
Here's the problem: this program should receive input from stdin and count the bytes inserted; the SIGUSR1 signal whill stop the main program and will print on file standard error how many bytes have been copied when I send the SIGUSR1.
That's how my teacher wants me to do this: in one terminal type
cat /dev/zero | ./cpinout | cat >/dev/null
while from a second terminal send signals with
kill -USR1 xxxx
where xxxx is the pid of cpinout.
I updated my previous code:
/* cpinout.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#define BUF_SIZE 1024
volatile sig_atomic_t countbyte = 0;
volatile sig_atomic_t sigcount = 0;
/* my_handler: gestore di signal */
static void sighandler(int signum) {
if(sigcount != 0)
fprintf(stderr, "Interrupted after %d byte.\n", sigcount);
sigcount = contabyte;
}
int main(void) {
int c;
char buffer[BUF_SIZE];
struct sigaction action;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
action.sa_handler = sighandler;
if(sigaction(SIGUSR1, &action, NULL) == -1) {
fprintf(stderr, "sigusr: sigaction\n");
exit(1);
}
while( c=getc(stdin) != EOF ) {
countbyte++;
fputc(c, stdout);
}
return(0);
}
回答1:
EDIT
In the comments you mentioned that you are running the command as:
cat /dev/zero | ./namefile | cat >/dev/null
The behaviour is actually fine. /dev/zero
is an endless stream of zeros, which are being sent to the program. So it's counting them up very quickly. When you interrupt, it stops and you're left with a large number.
The problem may be related to the fact that the signal handler may be called while the global variable is being updated (if this takes more than one instruction). However, the GNU documentation states that it's safe to assume that an int
is always atomic on a POSIX system.
The only other possibility I can think of is that you're calling fputc
in the loop, with printf
in the handler (it should however be safe to call printf
in a handler if it's not being called by the program). Try removing fputc
from the loop to see if it resolves the problem.
EDIT:
This appears to explain the problem. This relates to the kind of functions that are safe to call from within a signal handler:
Functions can also be nonreentrant if they use static data structures for their internal bookkeeping. The most obvious examples of such functions are the members of the stdio library (printf(), scanf(), and so on), which update internal data structures for buffered I/O. Thus, when using printf() from within a signal handler, we may sometimes see strange output—or even a program crash or data corruption— if the handler interrupts the main program in the middle of executing a call to printf() or another stdio function. (The Linux Programming Interface)
Your program is interrupting a stdio function, which seems to fit this perfectly.
Here's an alternative approach:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
int countbyte = 0; // for main program
int sigcount = 0; // for signal handler
/* my_handler: signal handler */
static void sighandler(int signum)
{
sigcount = countbyte;
}
int main(void)
{
int c;
struct sigaction sigact;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = sighandler;
sigaction(SIGUSR1, &sigact, NULL);
while ((c = getc(stdin)) != EOF) {
countbyte++;
fputc(c, stdout);
}
if (sigcount != 0) {
printf("Interrupted after %d bytes\n", sigcount);
}
return 0;
}
回答2:
Signals may only write volatile sig_atomic_t
variables according to the C89 and POSIX 7 standards:
the behavior is undefined if the signal handler refers to any object [CX] [Option Start] other than errno [Option End] with static storage duration other than by assigning a value to an object declared as volatile sig_atomic_t
Implementations often offer more, but I doubt that using non-volatile global variables or printf is something provided by yours.
来源:https://stackoverflow.com/questions/15500844/signal-handler-wont-see-global-variable