mirror of https://github.com/mkerrisk/man-pages
signalfd.2: Rewrite the text on epoll semantics
I also verified the behavior reported by Andrew Clayton with the program below. $ ./epoll_signalfd PID of parent: 5661 PID of child: 5662 epoll_wait() returned 0 PID 5662: got signal 10 Successfully read signal, even though epoll_wait() didn't say FD was ready! 8x----8x----8x----8x----8x----8x----8x----8x----8x----8x----8x----8x---- /* epoll_signalfd.c */ #include <sys/signalfd.h> #include <signal.h> #include <sys/epoll.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) static void signalTest(int sfd, int epfd) { struct signalfd_siginfo fdsi; struct epoll_event rev; int ready; ssize_t s; usleep(50000); ready = epoll_wait(epfd, &rev, 1, 0); if (ready == -1) errExit("epoll_wait"); printf("epoll_wait() returned %d\n", ready); s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo)); if (s != sizeof(struct signalfd_siginfo)) errExit("read"); printf("PID %ld: got signal %d\n", (long) getpid(), fdsi.ssi_signo); if (ready == 0 && s > 0) printf("Successfully read signal, even though epoll_wait() " "didn't say FD was ready!\n"); } int main(int argc, char *argv[]) { struct epoll_event ev; sigset_t mask; int sfd, epfd; sigfillset(&mask); sigdelset(&mask, SIGINT); if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) errExit("sigprocmask"); sfd = signalfd(-1, &mask, SFD_NONBLOCK); if (sfd == -1) errExit("signalfd"); epfd = epoll_create(5); if (epfd == -1) errExit("epoll_create"); ev.data.fd = sfd; ev.events = EPOLLIN; if (epoll_ctl(epfd, EPOLL_CTL_ADD, sfd, &ev) == -1) errExit("epoll_ctl"); switch (fork()) { case -1: errExit("fork"); case 0: printf("PID of child: %ld\n", (long) getpid()); raise(SIGUSR1); signalTest(sfd, epfd); break; default: printf("PID of parent: %ld\n", (long) getpid()); wait(NULL); break; } exit(EXIT_SUCCESS); } 8x----8x----8x----8x----8x----8x----8x----8x----8x----8x----8x----8x---- Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
parent
e95f6bf482
commit
b892d64f4f
|
@ -261,23 +261,33 @@ itself and the signals that are directed to the process
|
|||
(i.e., the entire thread group).
|
||||
(A thread will not be able to read signals that are directed
|
||||
to other threads in the process.)
|
||||
.\"
|
||||
.SS epoll(7) semantics
|
||||
If you add a signalfd file descriptor to
|
||||
.BR epoll(7)
|
||||
then
|
||||
.BR epoll_wait(2)
|
||||
will only return events for signals received by the process that did
|
||||
the
|
||||
.BR epoll_ctl(2).
|
||||
If you then
|
||||
.BR fork(2),
|
||||
say by calling
|
||||
.BR daemon(3),
|
||||
then you will find that you don't get any notifications for sent
|
||||
signals. For this to work, you need to add the signalfd file
|
||||
descriptor to
|
||||
.BR epoll(7)
|
||||
after forking.
|
||||
If a process adds (via
|
||||
.BR epoll_ctl (2))
|
||||
a signalfd file descriptor to an
|
||||
.BR epoll (7)
|
||||
instance, then
|
||||
.BR epoll_wait (2)
|
||||
returns events only for signals sent to that process.
|
||||
In particular, if the process then uses
|
||||
.BR fork ()
|
||||
to create a child process, then the child will be able to
|
||||
.BR read (2)
|
||||
signals that are sent to it using the signalfd file descriptor, but
|
||||
.BR epoll_wait (2)
|
||||
will
|
||||
.B not
|
||||
indicate that the signalfd file descriptor is ready.
|
||||
In this scenario, a possible workaround is that after the
|
||||
.BR fork (2),
|
||||
the child process can close the signalfd file descriptor that it inherited
|
||||
from the parent process and then create another signalfd file descriptor
|
||||
and add it to the epoll instance.
|
||||
Alternatively, the parent and the child could delay creating their
|
||||
(separate) signalfd file descriptors and adding them to the
|
||||
epoll instance until after the call to
|
||||
.BR fork (2).
|
||||
.SH RETURN VALUE
|
||||
On success,
|
||||
.BR signalfd ()
|
||||
|
|
Loading…
Reference in New Issue