1169311Srwatson/*- 2169311Srwatson * Copyright (c) 2007 Robert N. M. Watson 3169311Srwatson * All rights reserved. 4169311Srwatson * 5169311Srwatson * Redistribution and use in source and binary forms, with or without 6169311Srwatson * modification, are permitted provided that the following conditions 7169311Srwatson * are met: 8169311Srwatson * 1. Redistributions of source code must retain the above copyright 9169311Srwatson * notice, this list of conditions and the following disclaimer. 10169311Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11169311Srwatson * notice, this list of conditions and the following disclaimer in the 12169311Srwatson * documentation and/or other materials provided with the distribution. 13169311Srwatson * 14169311Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15169311Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16169311Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17169311Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18169311Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19169311Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20169311Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21169311Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22169311Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23169311Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24169311Srwatson * SUCH DAMAGE. 25169311Srwatson * 26169311Srwatson * $FreeBSD$ 27169311Srwatson */ 28169311Srwatson 29169311Srwatson/* 30169311Srwatson * Sockets serialize I/O in each direction in order to avoid interlacing of 31169311Srwatson * I/O by multiple processes or threcvs recving or sending the socket. This 32169311Srwatson * is done using some form of kernel lock (varies by kernel version), called 33169311Srwatson * "sblock" in FreeBSD. However, to avoid unkillable processes waiting on 34169311Srwatson * I/O that may be entirely controlled by a remote network endpoint, that 35169311Srwatson * lock acquisition must be interruptible. 36169311Srwatson * 37169311Srwatson * To test this, set up a local domain stream socket pair and a set of three 38169311Srwatson * processes. Two processes block in recv(), the first on sbwait (wait for 39169311Srwatson * I/O), and the second on the sblock waiting for the first to finish. A 40169311Srwatson * third process is responsible for signalling the second process, then 41169311Srwatson * writing to the socket. Depending on the error returned in the second 42169311Srwatson * process, we can tell whether the sblock wait was interrupted, or if 43169311Srwatson * instead the process only woke up when the write was performed. 44169311Srwatson */ 45169311Srwatson 46169311Srwatson#include <sys/socket.h> 47169311Srwatson 48169311Srwatson#include <err.h> 49169311Srwatson#include <errno.h> 50169311Srwatson#include <signal.h> 51169311Srwatson#include <stdio.h> 52169311Srwatson#include <stdlib.h> 53169311Srwatson#include <unistd.h> 54169311Srwatson 55169311Srwatsonstatic int interrupted; 56169311Srwatsonstatic void 57169311Srwatsonsignal_handler(int signum) 58169311Srwatson{ 59169311Srwatson 60169311Srwatson interrupted++; 61169311Srwatson} 62169311Srwatson 63169311Srwatson/* 64169311Srwatson * Process that will perform a blocking recv on a UNIX domain socket. This 65169311Srwatson * should return one byte of data. 66169311Srwatson */ 67169311Srwatsonstatic void 68169311Srwatsonblocking_recver(int fd) 69169311Srwatson{ 70169311Srwatson ssize_t len; 71169311Srwatson char ch; 72169311Srwatson 73169311Srwatson len = recv(fd, &ch, sizeof(ch), 0); 74169311Srwatson if (len < 0) 75169311Srwatson err(-1, "FAIL: blocking_recver: recv"); 76169311Srwatson if (len == 0) 77169311Srwatson errx(-1, "FAIL: blocking_recver: recv: eof"); 78169311Srwatson if (len != 1) 79243313Semaste errx(-1, "FAIL: blocking_recver: recv: %zd bytes", len); 80169311Srwatson if (interrupted) 81169311Srwatson errx(-1, "FAIL: blocking_recver: interrupted wrong pid"); 82169311Srwatson} 83169311Srwatson 84169311Srwatson/* 85169311Srwatson * Process that will perform a locking recv on a UNIX domain socket. 86169311Srwatson * 87169311Srwatson * This is where we figure out if the test worked or not. If it has failed, 88169311Srwatson * then recv() will return EOF, as the close() arrives before the signal, 89169311Srwatson * meaning that the wait for the sblock was not interrupted; if it has 90169311Srwatson * succeeded, we get EINTR as the signal interrupts the lock request. 91169311Srwatson */ 92169311Srwatsonstatic void 93169311Srwatsonlocking_recver(int fd) 94169311Srwatson{ 95169311Srwatson ssize_t len; 96169311Srwatson char ch; 97169311Srwatson 98169311Srwatson if (sleep(1) < 0) 99169311Srwatson err(-1, "FAIL: locking_recver: sleep"); 100169311Srwatson len = recv(fd, &ch, sizeof(ch), 0); 101169311Srwatson if (len < 0 && errno != EINTR) 102169311Srwatson err(-1, "FAIL: locking_recver: recv"); 103169311Srwatson if (len < 0 && errno == EINTR) { 104169311Srwatson fprintf(stderr, "PASS\n"); 105169311Srwatson exit(0); 106169311Srwatson } 107169311Srwatson if (len == 0) 108169311Srwatson errx(-1, "FAIL: locking_recver: recv: eof"); 109169311Srwatson if (!interrupted) 110169311Srwatson errx(-1, "FAIL: locking_recver: not interrupted"); 111169311Srwatson} 112169311Srwatson 113169311Srwatsonstatic void 114169311Srwatsonsignaller(pid_t locking_recver_pid, int fd) 115169311Srwatson{ 116169311Srwatson ssize_t len; 117169311Srwatson char ch; 118169311Srwatson 119169311Srwatson if (sleep(2) < 0) { 120169311Srwatson warn("signaller sleep(2)"); 121169311Srwatson return; 122169311Srwatson } 123169311Srwatson if (kill(locking_recver_pid, SIGHUP) < 0) { 124169311Srwatson warn("signaller kill(%d)", locking_recver_pid); 125169311Srwatson return; 126169311Srwatson } 127169311Srwatson if (sleep(1) < 0) { 128169311Srwatson warn("signaller sleep(1)"); 129169311Srwatson return; 130169311Srwatson } 131169311Srwatson len = send(fd, &ch, sizeof(ch), 0); 132169311Srwatson if (len < 0) { 133169311Srwatson warn("signaller send"); 134169311Srwatson return; 135169311Srwatson } 136169311Srwatson if (len != sizeof(ch)) { 137243313Semaste warnx("signaller send ret %zd", len); 138169311Srwatson return; 139169311Srwatson } 140169311Srwatson if (close(fd) < 0) { 141169311Srwatson warn("signaller close"); 142169311Srwatson return; 143169311Srwatson } 144169311Srwatson if (sleep(1) < 0) { 145169311Srwatson warn("signaller sleep(1)"); 146169311Srwatson return; 147169311Srwatson } 148169311Srwatson} 149169311Srwatson 150169311Srwatsonint 151169311Srwatsonmain(int argc, char *argv[]) 152169311Srwatson{ 153169311Srwatson int error, fds[2], recver_fd, sender_fd; 154169311Srwatson pid_t blocking_recver_pid; 155169311Srwatson pid_t locking_recver_pid; 156169311Srwatson struct sigaction sa; 157169311Srwatson 158169311Srwatson if (sigaction(SIGHUP, NULL, &sa) < 0) 159169311Srwatson err(-1, "FAIL: sigaction(SIGHUP, NULL, &sa)"); 160169311Srwatson 161169311Srwatson sa.sa_handler = signal_handler; 162169311Srwatson if (sa.sa_flags & SA_RESTART) 163169311Srwatson printf("SIGHUP restartable by default (cleared)\n"); 164169311Srwatson sa.sa_flags &= ~SA_RESTART; 165169311Srwatson 166169311Srwatson if (sigaction(SIGHUP, &sa, NULL) < 0) 167169311Srwatson err(-1, "FAIL: sigaction(SIGHUP, &sa, NULL)"); 168169311Srwatson 169169311Srwatson#if 0 170169311Srwatson if (signal(SIGHUP, signal_handler) == SIG_ERR) 171169311Srwatson err(-1, "FAIL: signal(SIGHUP)"); 172169311Srwatson#endif 173169311Srwatson 174169311Srwatson if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) < 0) 175169311Srwatson err(-1, "FAIL: socketpair(PF_LOCAL, SOGK_STREAM, 0)"); 176169311Srwatson 177169311Srwatson sender_fd = fds[0]; 178169311Srwatson recver_fd = fds[1]; 179169311Srwatson 180169311Srwatson blocking_recver_pid = fork(); 181169311Srwatson if (blocking_recver_pid < 0) 182169311Srwatson err(-1, "FAIL: fork"); 183169311Srwatson if (blocking_recver_pid == 0) { 184169311Srwatson close(sender_fd); 185169311Srwatson blocking_recver(recver_fd); 186169311Srwatson exit(0); 187169311Srwatson } 188169311Srwatson 189169311Srwatson locking_recver_pid = fork(); 190169311Srwatson if (locking_recver_pid < 0) { 191169311Srwatson error = errno; 192169311Srwatson kill(blocking_recver_pid, SIGKILL); 193169311Srwatson errno = error; 194169311Srwatson err(-1, "FAIL: fork"); 195169311Srwatson } 196169311Srwatson if (locking_recver_pid == 0) { 197169311Srwatson close(sender_fd); 198169311Srwatson locking_recver(recver_fd); 199169311Srwatson exit(0); 200169311Srwatson } 201169311Srwatson 202169311Srwatson signaller(locking_recver_pid, sender_fd); 203169311Srwatson 204169311Srwatson kill(blocking_recver_pid, SIGKILL); 205169311Srwatson kill(locking_recver_pid, SIGKILL); 206169311Srwatson exit(0); 207169311Srwatson} 208