ESP
ESP

Reputation: 45

Having trouble using sigaction with a timer in C

This is my code. As you can see it is very simple. I want the program print dots until it catches SIGPROF signal. But my program seems like it's not working. How can I fix it?

void handler(int code) {
    fprintf(stdout, "signal catched");
    exit(0);
}

int main() {
    struct itimerval new, old;
    struct sigaction newact;
    sigemptyset(&newact.sa_mask);
    newact.sa_flags = 0;
    newact.sa_handler = handler;
    sigaction(SIGPROF, &newact,NULL);
    new.it_interval.tv_usec = 0;
    new.it_interval.tv_sec = 0;
    new.it_value.tv_usec = 0;
    new.it_value.tv_sec = (long int) 3;
    setitimer(ITIMER_PROF, &new, &old);

    while (1)
    {
        fprintf(stdout, ". ");
    }
    return 0;
}

Upvotes: 0

Views: 588

Answers (2)

user3629249
user3629249

Reputation: 16540

the following proposed code:

  1. cleanly compiles
  2. performs the desired functionality
  3. does not violate the need for 'signal' handlers to only use thread safe functions

Note: new is a very poor choice for a variable name due to its' being a reserved word in C++.

When posting code, always post the needed #include statements

and now, the proposed code:

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <stdlib.h>
#include <unistd.h>


void handler(int code) 
{
    (void)code;  // to avoid compiler message about unused parameter

    write( 1, "signal catched", sizeof( "signal catched" ) );
    _exit(0);  // notice the leading underscore
}

int main( void ) // use a valid signature for `main()`
{
    struct itimerval new, old;
    struct sigaction newact;

    sigemptyset(&newact.sa_mask);
    newact.sa_flags = 0;
    newact.sa_handler = handler;
    sigaction(SIGPROF, &newact,NULL);
    new.it_interval.tv_usec = 0;
    new.it_interval.tv_sec = 0;
    new.it_value.tv_usec = 0;
    new.it_value.tv_sec = (long int) 3;
    setitimer(ITIMER_PROF, &new, &old);

    while (1)
    {
        fprintf(stdout, ". ");
    }
    return 0;
}

a typical run of the code results in:

. . . . . . . . . . . . . . . . . . . . . . . . . <several thousand characters repeating '. '> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . signal catched

Upvotes: 0

Andrew Henle
Andrew Henle

Reputation: 1

This signal handler

void handler(int code) {
    fprintf(stdout, "signal catched");
    exit(0);
}

violates the standards of 7.1.4 Use of library functions, paragraph 4:

The functions in the standard library are not guaranteed to be reentrant and may modify objects with static or thread storage duration.

And as noted in footnote 188:

Thus, a signal handler cannot, in general, call standard library functions.

POSIX does allow the calling of async-signal-safe functions from within a signal handler:

Per ** 2.4.3 Signal Actions**:

... the behavior is undefined ... if the signal handler calls any function defined in this standard other than one of the functions listed in the following table.

_Exit()
_exit()
abort()
accept()
access()
aio_error()
aio_return()
aio_suspend()
alarm()
bind()
cfgetispeed()
cfgetospeed()
cfsetispeed()
cfsetospeed()
chdir()
chmod()
chown()
clock_gettime()
close()
connect()
creat()
dup()
dup2()
execl()
execle()
execv()
execve()
faccessat()
fchdir()
fchmod()
fchmodat()
fchown()
fchownat()
fcntl()
fdatasync()
fexecve()
ffs()
fork()
fstat()
fstatat()
fsync()
ftruncate()
futimens()
getegid()
geteuid()
getgid()
getgroups()
getpeername()
getpgrp()
getpid()
getppid()
getsockname()
getsockopt()
getuid()
htonl()
htons()
kill()
link()
linkat()
listen()
longjmp()
lseek()
lstat()
memccpy()
memchr()
memcmp()
memcpy()
memmove()
memset()
mkdir()
mkdirat()
mkfifo()
mkfifoat()
mknod()
mknodat()
ntohl()
ntohs()
open()
openat()
pause()
pipe()
poll()
posix_trace_event()
pselect()
pthread_kill()
pthread_self()
pthread_sigmask()
raise()
read()
readlink()
readlinkat()
recv()
recvfrom()
recvmsg()
rename()
renameat()
rmdir()
select()
sem_post()
send()
sendmsg()
sendto()
setgid()
setpgid()
setsid()
setsockopt()
setuid()
shutdown()
sigaction()
sigaddset()
sigdelset()
sigemptyset()
sigfillset()
sigismember()
siglongjmp()
signal()
sigpause()
sigpending()
sigprocmask()
sigqueue()
sigset()
sigsuspend()
sleep()
sockatmark()
socket()
socketpair()
stat()
stpcpy()
stpncpy()
strcat()
strchr()
strcmp()
strcpy()
strcspn()
strlen()
strncat()
strncmp()
strncpy()
strnlen()
strpbrk()
strrchr()
strspn()
strstr()
strtok_r()
symlink()
symlinkat()
tcdrain()
tcflow()
tcflush()
tcgetattr()
tcgetpgrp()
tcsendbreak()
tcsetattr()
tcsetpgrp()
time()
timer_getoverrun()
timer_gettime()
timer_settime()
times()
umask()
uname()
unlink()
unlinkat()
utime()
utimensat()
utimes()
wait()
waitpid()
wcpcpy()
wcpncpy()
wcscat()
wcschr()
wcscmp()
wcscpy()
wcscspn()
wcslen()
wcsncat()
wcsncmp()
wcsncpy()
wcsnlen()
wcspbrk()
wcsrchr()
wcsspn()
wcsstr()
wcstok()
wmemchr()
wmemcmp()
wmemcpy()
wmemmove()
wmemset()
write()

Any function not in the above table may be unsafe with respect to signals.

(note that fork() is broken in glibc and is not async-signal-safe on Linux)

What's likely happening is that your signal handler interrupts the fprintf() call in this loop:

while (1)
{
    fprintf(stdout, ". ");
}

And that leads to a deadlock as the fprintf() in the main while() loop holds a lock, so when the signal handler gets called it blocks on its call to fprintf() waiting for the lock to come free - which it can't because the call to fprintf() that holds the lock was interrupted by the signal.

You also can not safely call exit() from within a signal handler.

Upvotes: 1

Related Questions