is there any way to register multiple timer to a single process? I have tried following code, yet without success. (Use "gcc -lrt" to compile it...). Program output nothing, which should atleast print "test". Is it possibly due to the dependence to linking to rt?
#define TT_SIGUSR1 (SIGRTMAX)
#define TT_SIGUSR2 (SIGRTMAX - 1)
#define TIME_INTERVAL_1 1
#define TIME_INTERVAL_2 2
#include <signal.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <linux/unistd.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sched.h>
#include <signal.h>
#include <setjmp.h>
#include <errno.h>
#include <assert.h>
timer_t create_timer(int signo) {
timer_t timerid;
struct sigevent se;
se.sigev_signo = signo;
if (timer_create(CLOCK_REALTIME, &se, &timerid) == -1) {
fprintf(stderr, "Failed to create timer\n");
exit(-1);
}
return timerid;
}
void set_timer(timer_t timerid, int seconds) {
struct itimerspec timervals;
timervals.it_value.tv_sec = seconds;
timervals.it_value.tv_nsec = 0;
timervals.it_interval.tv_sec = seconds;
timervals.it_interval.tv_nsec = 0;
if (timer_settime(timerid, 0, &timervals, NULL) == -1) {
fprintf(stderr, "Failed to start timer\n");
exit(-1);
}
return;
}
void install_sighandler2(int signo, void(*handler)(int)) {
struct sigaction sigact;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO;
//register the Signal Handler
sigact.sa_sigaction = handler;
// Set up sigaction to catch signal first timer
if (sigaction(signo, &sigact, NULL) == -1)
{
printf("sigaction failed");
return -1;
}
}
void install_sighandler(int signo, void(*handler)(int)) {
sigset_t set;
struct sigaction act;
/* Setup the handler */
act.sa_handler = handler;
act.sa_flags = SA_RESTART;
sigaction(signo, &act, 0);
/* Unblock the signal */
sigemptyset(&set);
sigaddset(&set, signo);
sigprocmask(SIG_UNBLOCK, &set, NULL);
return;
}
void signal_handler(int signo) {
printf("receiving sig %d", signo);
}
int main()
{
printf("test");
timer_t timer1 = create_timer(TT_SIGUSR1);
timer_t timer2 = create_timer(TT_SIGUSR2);
set_timer(timer1, TIME_INTERVAL_1);
set_timer(timer2, TIME_INTERVAL_2);
install_sighandler2(TT_SIGUSR1, signal_handler);
install_sighandler(TT_SIGUSR2, signal_handler);
while (1)
;
return 0;
}
missing in create_timer: se.sigev_notify=SIGEV_SIGNAL;
two install_sighandler methods. Install_sighandler2 has a compler warning about mismatching pointer types.
while (1) will hog your processor, sleep.
#define TT_SIGUSR1 (SIGUSR1)
#define TT_SIGUSR2 (SIGUSR2)
#define TIME_INTERVAL_1 1
#define TIME_INTERVAL_2 2
#include <signal.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <linux/unistd.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sched.h>
#include <signal.h>
#include <setjmp.h>
#include <errno.h>
#include <assert.h>
#include <stdlib.h>
timer_t create_timer(int signo) {
timer_t timerid;
struct sigevent se;
se.sigev_notify=SIGEV_SIGNAL;
se.sigev_signo = signo;
if (timer_create(CLOCK_REALTIME, &se, &timerid) == -1) {
perror("Failed to create timer");
exit(-1);
}
return timerid;
}
void set_timer(timer_t timerid, int seconds) {
struct itimerspec timervals;
timervals.it_value.tv_sec = seconds;
timervals.it_value.tv_nsec = 0;
timervals.it_interval.tv_sec = seconds;
timervals.it_interval.tv_nsec = 0;
if (timer_settime(timerid, 0, &timervals, NULL) == -1) {
perror("Failed to start timer");
exit(-1);
}
return;
}
void install_sighandler(int signo, void(*handler)(int)) {
sigset_t set;
struct sigaction act;
/* Setup the handler */
act.sa_handler = handler;
act.sa_flags = SA_RESTART;
sigaction(signo, &act, 0);
/* Unblock the signal */
sigemptyset(&set);
sigaddset(&set, signo);
sigprocmask(SIG_UNBLOCK, &set, NULL);
return;
}
void signal_handler(int signo) {
printf("receiving sig %d\n", signo);
}
int main()
{
printf("test\n");
timer_t timer1 = create_timer(TT_SIGUSR1);
timer_t timer2 = create_timer(TT_SIGUSR2);
install_sighandler(TT_SIGUSR1, signal_handler);
install_sighandler(TT_SIGUSR2, signal_handler);
set_timer(timer1, TIME_INTERVAL_1);
set_timer(timer2, TIME_INTERVAL_2);
while (1) sleep(1);
return 0;
}
Related
I am having a parent process play that creates a fork and runs foo using execl
Code for play.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
if (fork() == 0) {
execl("./foo", "", NULL);
} else {
wait(0);
write(STDOUT_FILENO, "in parent after waiting", 5);
}
printf("outside everything");
return 0;
}
Code for foo.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void signal_handler() {
write(STDOUT_FILENO, "\nBye!\n", 6);
exit(1);
}
int main() {
struct sigaction sa;
sa.sa_handler = signal_handler;
sigaction(SIGINT, &sa, NULL);
while (1) {
printf("Wasting time...%d \n", getpid());
sleep(1);
}
return 0;
}
My questions are,
Why aren't the print statements after the wait(0) statement executed?
Why isn't the signal handler in the child process triggered when Ctrl + C?
You should ensure that the sa_flags and sa_mask fields of struct sigaction are set. You can initialize them — struct sigaction sa = { 0 }; will probably do the job. Or you can use sigemptyset(&sa.sa_mask); and sa.sa_flags = 0; to assign values. Or you can set them to some non-zero value. Not setting sa_flags means you've no idea what operation you requested. You also need a signal handler in play.c. You need to ignore SIGINT before the fork(), then in the child re-enable the signal before executing foo. The write() in the parent does not print much; it may once have printed "\nBar!\n" or something.
Here's some working code.
play.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
struct sigaction sa = { 0 };
sa.sa_handler = SIG_IGN;
sigaction(SIGINT, &sa, NULL);
if (fork() == 0)
{
sa.sa_handler = SIG_DFL;
sigaction(SIGINT, &sa, NULL);
execl("./foo", "", NULL);
exit(1);
}
else
{
wait(0);
printf("in parent after waiting\n");
}
printf("outside everything\n");
return 0;
}
foo.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void signal_handler(int signum)
{
char message[] = "\nBye (XX)\n";
message[6] = signum / 10 + '0';
message[7] = signum % 10 + '0';
write(STDOUT_FILENO, message, sizeof(message) - 1);
exit(1);
}
int main(void)
{
struct sigaction sa = { 0 };
sa.sa_handler = signal_handler;
sigaction(SIGINT, &sa, NULL);
while (1)
{
printf("Wasting time...%d \n", getpid());
sleep(1);
}
return 0;
}
Example output
$ play
Wasting time...11383
Wasting time...11383
Wasting time...11383
Wasting time...11383
^C
Bye (02)
in parent after waiting
outside everything
$
If I have something like this.
#include <signal.h>
#include <stdio.h>
void signalquit(int sig)
{
printf("\nQuitting..\n");
(void)signal(SIGINT, SIG_DFL);
//How to return?
}
int main(void)
{
(void)signal(SIGINT, signalquit);
while (1)
{
//Something...
}
//Continue here after quit with "Control + C"
return 0;
}
How can I return to my main function after the while loop and after quitting with Control + C? Thanks for your answers!
How to leave endless loop by signal?
By flagging that your are done.
#include <stdlib.h> /* for EXIT_XXX macros */
#include <signal.h>
volatile sig_atomic_t flag = 0;
void signalquit(int sig)
{
flag = 1;
signal(sig, SIG_DFL);
return; /* Optional for void-functions */
}
int main(void)
{
signal(SIGINT, signalquit);
while (!flag)
{
//Something...
}
return EXIT_SUCCESS;
}
Please note that not every function may be called from a signal handler. printf() for example is not guaranteed to by async-signal-safe.
To find a list of functions to be guaranteed by POSIX to be async-signal-safe scroll down here.
Your code uses the signal() function, which for historical reason is highly unportable.
A portable approach would use the function sigaction() like for example below:
#include <stdlib.h> /* for EXIT_XXX macros */
#include <stdio.h> /* for perror() */
#include <signal.h>
volatile sig_atomic_t flag = 0;
int set_sig_handler(int sig, void(*handler)(int))
{
struct sigaction sa = {0};
sa.sa_handler = handler;
return sigaction(sig, sa, NULL);
}
void signalquit(int sig)
{
flag = 1;
if (-1 == set_sig_handler(sig, SIG_DFL))
{
flag = 2;
}
}
int main(void)
{
if (-1 == set_sig_handler(SIGINT, signalquit))
{
perror("set_sig_handler() failed");
return EXIT_FAILURE;
}
while (!flag)
{
//Something...
}
if (2 == flag)
{
perror("set_sig_handler() in signal handler failed");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
As pointed out by pilcrow an even simpler approach is to explicitly install the handler for single use only by specifying the SA_RESETHAND flag.
#include <stdlib.h> /* for EXIT_XXX macros */
#include <stdio.h> /* for perror() */
#include <signal.h>
volatile sig_atomic_t flag = 0;
void signalquit(int sig)
{
flag = 1;
}
int main(void)
{
{
struct sigaction sa = {0};
sa.sa_handler = signalquit;
sa.sa_flags = SA_RESETHAND;
if (-1 == sigaction(SIGINT, sa, NULL))
{
perror("sigaction() failed");
return EXIT_FAILURE;
}
}
while (!flag)
{
//Something...
}
return EXIT_SUCCESS;
}
I'm supposed to write a program which creates 2 processes, connects between them with a pipe, and after a given time will end both processes and terminate.
one of the programs will write to the pipe, and the other will read from it and print it to STDOUT.
the reading process will be called first, then the pid will be passed to the second process so it will give SIGUSR1 signals to the first process, to tell it to read.
for some reason i never see the output in the terminal of the first process,
further more, it doesn't even print the line:"trying to exec1\n" which is where i call "execlp" for the process that prints.
here is the code for the 3 programs:
the main program:
#define STDERR 2
#define STDOUT 1
#define STDIN 0
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <signal.h>
#include <stdio.h>
void alarmHandler(int sig);
void systemError();
char * intToString(int num , char number[4]);
static pid_t processId1, processId2;
int main(int argc, char ** argv){
pid_t pid1, pid2;
sigset_t block_mask1;
struct sigaction exitSig;
sigfillset(&block_mask1);
exitSig.sa_handler = alarmHandler;
exitSig.sa_mask = block_mask1;
exitSig.sa_flags = 0;
sigaction(SIGALRM, &exitSig, NULL);
if (argc < 2){
systemError();
} else {
int x = atoi(argv[1]);
alarm(x);
}
int fields[2];
if (pipe(fields)){
systemError();
}
if ((pid1 = fork()) == 0){
printf("trying to exec1\n");
close(STDIN);
dup(fields[0]);
close(fields[0]);
close(fields[1]);
if(execlp("./ex2_inp", "./ex2_inp", NULL)){
systemError();
}
} else {
processId1 = pid1;
if ((pid2 = fork()) == 0){
char number[350];
printf("trying to exec2\n");
close(STDOUT);
dup(fields[1]);
close(fields[0]);
close(fields[1]);
char * pidString = intToString(processId1, number);
if(execlp("./ex2_upd","./ex2_upd",pidString, NULL)){
systemError();
}
} else{
processId2 = pid2;
}
}
close(fields[0]);
close(fields[1]);
pause();
return 1;
}
/***********************
* handler for alarm signal
*************************/
void alarmHandler(int sig){
kill(processId2, SIGINT);
kill(processId1, SIGINT);
exit(1);
}
/***********************
* turn pid to string
*************************/
char * intToString(int num , char number[350]){
sprintf(number, "%d", num);
return number;
}
ex2_inp:
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <signal.h>
#include <stdio.h>
void exitHandler(int sig);
void printHandler(int sig);
int main(int argc, char * argv[]){
sigset_t block_mask1, block_mask2;
struct sigaction exitSig, print;
sigfillset(&block_mask1);
sigfillset(&block_mask2);
exitSig.sa_handler = exitHandler;
print.sa_handler = printHandler;
print.sa_mask = block_mask2;
exitSig.sa_mask = block_mask1;
exitSig.sa_flags = 0;
print.sa_flags = 0;
sigaction(SIGINT, &exitSig, NULL);
sigaction(SIGUSR1, &print, NULL);
pause();
return 1;
}
void exitHandler(int sig){
printf("exiting1!\n");
close(1);
exit(1);
}
void printHandler(int sig){
char * buffer[80];
read(1, buffer, 80);
printf("%s", buffer);
}
ex2_upd:
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <signal.h>
#include <stdio.h>
void exitHandler(int sig);
int main(int argc, char * argv[]){
sigset_t block_mask1;
struct sigaction exitSig;
sigfillset(&block_mask1);
exitSig.sa_handler = exitHandler;
exitSig.sa_mask = block_mask1;
exitSig.sa_flags = 0;
sigaction(SIGINT, &exitSig, NULL);
printf("2's message\n");
kill(atoi(argv[1]), SIGUSR1);
pause();
return 1;
}
void exitHandler(int sig){
printf("exiting2!\n");
close(0);
exit(1);
}
thanks
ex2_upd.c:
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <signal.h>
#include <stdio.h>
void exitHandler(int sig);
int main(int argc, char * argv[]){
sigset_t block_mask1;
struct sigaction exitSig;
sigfillset(&block_mask1);
exitSig.sa_handler = exitHandler;
exitSig.sa_mask = block_mask1;
exitSig.sa_flags = 0;
sigaction(SIGINT, &exitSig, NULL);
printf("2's message\n");
kill(atoi(argv[1]), SIGUSR1);
sleep(1); /* This was pause - causing ex2_inp read() to wait forever, since read() on pipe needs to either fill buffer or END_OF_FILE, unless we make the filedescriptor in the read-end non-blocking via fcntl() */
return 1;
}
void exitHandler(int sig){
printf("exiting2!\n");
close(0);
exit(1);
}
ex2_inp.c:
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <signal.h>
#include <stdio.h>
void exitHandler(int sig);
void printHandler(int sig);
int main(int argc, char * argv[]){
sigset_t block_mask1, block_mask2;
struct sigaction exitSig, print;
sigfillset(&block_mask1);
sigfillset(&block_mask2);
exitSig.sa_handler = exitHandler;
print.sa_handler = printHandler;
print.sa_mask = block_mask2;
exitSig.sa_mask = block_mask1;
exitSig.sa_flags = 0;
print.sa_flags = 0;
sigaction(SIGINT, &exitSig, NULL);
sigaction(SIGUSR1, &print, NULL);
pause();
return 1;
}
void exitHandler(int sig){
printf("exiting1!\n");
close(1);
exit(1);
}
void printHandler(int sig){
char buffer[80]; /* removed * */
read(0, buffer, 80); /* stdin is fd=0, not 1 */
printf("-> %s <-\n", buffer); /* added \n, forces new-line */
}
I am making a program containing a "Server.c" which waits a client to send it a SIGUSR1 msg 10 times, then dies, and a "client.c" which sends a SIGUSR1 msg to the server.
The problem is that if I try to access the siginfo_t* info, I get a segmentation fault.
Note that this is being tested on a Debian ssh server on which I do not have high permissions.
Node that this code works fine on Ubuntu.
Can siginfo_t *info fail due to permission issues? Or is there another issue causing this portability problem. As far as I know libc should be fairly standard throughout any linux distro, possibly unix.
Any Ideas?
Thanks
server.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
int counter = 0;
pid_t *clients = 0;
void on_signal(int signo, siginfo_t *info, void * context)
{
puts("SIGNAL RECEIVED");
assert(clients);
clients[counter] = info->si_pid;
++counter;
}
int main()
{
struct sigaction action;
sigset_t set;
int recieveflag = 0;
clients = (pid_t*)malloc(10 * sizeof(pid_t));
sigemptyset(&set);
sigaddset(&set, SA_SIGINFO);
memset(&action, 0, sizeof(struct sigaction));
action.sa_sigaction = on_signal;
sigaction(SIGUSR1, &action, 0);
while (counter < 10) {
//sigprocmask(SIG_BLOCK, &set, 0);
sigsuspend(&set);
}
puts("I'm done!");
return 0;
}
client.c:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
int main(int argc, const char** argv)
{
int server_id;
assert(argc == 2);
server_id = atoi(argv[1]);
assert(server_id > 0);
kill(server_id, SIGUSR1);
return 0;
}
I tried editing server.c to:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
int counter = 0;
pid_t *clients = 0;
void on_signal(int sig)
{
puts("SIGNAL RECEIVED");
}
int main()
{
struct sigaction action;
sigset_t set;
int recieveflag = 0;
clients = (pid_t*)malloc(10 * sizeof(pid_t));
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
memset(&action, 0, sizeof(struct sigaction));
action.sa_flags = SA_SIGINFO;
action.sa_handler = on_signal;
sigaction(SIGUSR1, &action, 0);
while (counter < 10) {
sigprocmask(SIG_BLOCK, &set, 0);
sigsuspend(&set);
++counter;
}
puts("I'm done!");
return 0;
}
now it no longer receives the SIGUSR1 event at all.
The basic behavior of sigaction is to call a simple callback like : void (*sa_handler)(int);. So if you want to use the sigaction handle with 3 parameters void (*sa_sigaction)(int, siginfo_t *, void *);, you must set the sa_flags field of your struct sigaction with the flag SA_SIGINFO. Take a look of the man page : http://www.kernel.org/doc/man-pages/online/pages/man2/sigaction.2.html who is clear.
I am trying to have two timers in my system for two different purpose but I dont understand why it doesnt work. Can somebody help me?Also, Should the handler code be a bare minumum so the tasks themselves dont interfere with the tick? Also can I define separate handler?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <netinet/in.h>
#include <linux/socket.h>
#include <time.h>
#define SIGTIMER (SIGRTMAX)
#define SIG SIGUSR1
static timer_t tid;
static timer_t tid2;
void SignalHandler(int, siginfo_t*, void* );
timer_t SetTimer(int, int, int);
int main(int argc, char *argv[]) {
struct sigaction sigact;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO;
sigact.sa_sigaction = SignalHandler;
// set up sigaction to catch signal
if (sigaction(SIGTIMER, &sigact, NULL) == -1) {
perror("sigaction failed");
exit( EXIT_FAILURE );
}
// Establish a handler to catch CTRL+c and use it for exiting.
sigaction(SIGINT, &sigact, NULL);
tid=SetTimer(SIGTIMER, 1000, 1);
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = SignalHandler;
// set up sigaction to catch signal
if (sigaction(SIG, &sa, NULL) == -1) {
perror("sa failed");
exit( EXIT_FAILURE );
}
// Establish a handler to catch CTRL+c and use it for exiting.
sigaction(SIGINT, &sa, NULL);
tid2=SetTimer(SIG, 1000, 3);
for(;;);
return 0;
}
void SignalHandler(int signo, siginfo_t* info, void* context)
{
if (signo == SIGTIMER) {
printf("Command Caller has ticked\n");
}else if (signo == SIG) {
printf("Data Caller has ticked\n");
} else if (signo == SIGINT) {
timer_delete(tid);
perror("Crtl+c cached!");
exit(1); // exit if CRTL/C is issued
}
}
timer_t SetTimer(int signo, int sec, int mode)
{
static struct sigevent sigev;
static timer_t tid;
static struct itimerspec itval;
static struct itimerspec oitval;
// Create the POSIX timer to generate signo
sigev.sigev_notify = SIGEV_SIGNAL;
sigev.sigev_signo = signo;
sigev.sigev_value.sival_ptr = &tid;
if (timer_create(CLOCK_REALTIME, &sigev, &tid) == 0) {
itval.it_value.tv_sec = sec / 1000;
itval.it_value.tv_nsec = (long)(sec % 1000) * (1000000L);
if (mode == 1) {
itval.it_interval.tv_sec = itval.it_value.tv_sec;
itval.it_interval.tv_nsec = itval.it_value.tv_nsec;
}
else {
itval.it_interval.tv_sec = 0;
itval.it_interval.tv_nsec = 0;
}
if (timer_settime(tid, 0, &itval, &oitval) != 0) {
perror("time_settime error!");
}
}
else {
perror("timer_create error!");
return NULL;
}
return tid;
}
When you define your second timer with this tid2=SetTimer(SIG, 1000, 3);, your code configure this timer to be a one-shot-timer
if (mode == 1) {
itval.it_interval.tv_sec = itval.it_value.tv_sec; // here you arm the timer periodically (that's the meaning of it_interval
itval.it_interval.tv_nsec = itval.it_value.tv_nsec;
}
else {
itval.it_interval.tv_sec = 0; // here you arm the timer once
itval.it_interval.tv_nsec = 0;
}
If you configure the second timer with a mode=1, like this tid2=SetTimer(SIG, 1000, 4);, you'll obtain this on your console :
Command Caller has ticked
Data Caller has ticked
Command Caller has ticked
Data Caller has ticked
Command Caller has ticked
Data Caller has ticked
^CCrtl+c cached!: Success
And you can use different handlers for your timers because you're using different signals to catch their expiration.