If a socket is set: fcntl(sock, F_SETOWN, getpid()) and fcntl(sock, F_SETFL,O_ASYNC) when a connection arrives a SIGIO signal should be delivered to the appropriate process. Under FreeBSD 11.2 and prior releases, this works. Under FreeBSD 12.0-RELEASE, no signal is delivered. This is the case with at least TCP and UNIX domain sockets. Duplicate by compiling and running the attached source code. "telnet 127.0.0.1 2666" to tickle the code with an incoming connection. Expected behavior is for the signal handler to fire and print "signalfired(): SIGIO fired" to stderr. Under FreeBSD 11.2 and prior (back to at least FreeBSD 2 the code that relied on this worked), this works. Under FreeBSD 12.0-RELEASE the signal is not delivered. #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <signal.h> #include <errno.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> static void signalfired() { fprintf(stderr,"signalfired(): SIGIO fired\n"); } int main(void) { int sock; struct sockaddr_in sin = { AF_INET }; /* socket address */ sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(2666); sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); exit(1); } if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0){ perror("bind"); exit(1); } if (signal(SIGIO,(void *) signalfired)) { perror("trapping signal"); exit(1); } if (fcntl(sock, F_SETOWN, getpid()) == -1) { perror("fcntl(F_SETOWN)"); exit(1); } if (fcntl(sock, F_SETFL, O_ASYNC) == -1) { perror("fcntl(F_SETFL)"); exit(1); } if (listen(sock, 10) < 0) { perror("listen"); exit(1); } fprintf(stderr,"sleeping, test by \"telnet localhost %d\"\n",2666); sleep(10000); }
It looks like this is fallout from the split between dataflow and listening sockets done in r319722. Listening sockets now take a completely separate path through solisten_wakeup(), which unlike sowakeup() does not pend SIGIO for SS_ASYNC sockets.
Created attachment 200584 [details] proposed patch
I've rebuilt 12.0-RELEASE from sources with this tiny edit and can confirm that (1) the minimum case source code works as expected, and (2) the application I was debugging that brought the problem to my attention now works. Thanks!
A commit references this bug: Author: jah Date: Sun Jan 13 20:33:55 UTC 2019 New revision: 343005 URL: https://svnweb.freebsd.org/changeset/base/343005 Log: Handle SIGIO for listening sockets r319722 separated struct socket and parts of the socket I/O path into listening-socket-specific and dataflow-socket-specific pieces. Listening socket connection notifications are now handled by solisten_wakeup() instead of sowakeup(), but solisten_wakeup() does not currently post SIGIO to the owning process. PR: 234258 Reported by: Kenneth Adelman MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D18664 Changes: head/sys/kern/uipc_socket.c
A commit references this bug: Author: jah Date: Mon Jan 21 08:24:49 UTC 2019 New revision: 343254 URL: https://svnweb.freebsd.org/changeset/base/343254 Log: MFC r343005: Handle SIGIO for listening sockets r319722 separated struct socket and parts of the socket I/O path into listening-socket-specific and dataflow-socket-specific pieces. Listening socket connection notifications are now handled by solisten_wakeup() instead of sowakeup(), but solisten_wakeup() does not currently post SIGIO to the owning process. PR: 234258 Changes: _U stable/12/ stable/12/sys/kern/uipc_socket.c