1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version 1.0
5 * (the "License").
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2026 Oxide Computer Company
14 */
15
16 /*
17 * Verify that closing one of two descriptors for the same STREAMS vnode does
18 * not confuse poll cache state belonging to the other descriptor. On DEBUG
19 * kernels, checkwfdlist() used to assert that every same-process entry on the
20 * vnode's pollhead appears on the closing descriptor's per-fd fpollinfo list,
21 * panicking on this pattern. Non-DEBUG builds compile the check out. Keeping
22 * both polling threads alive while one descriptor is closed exercises the
23 * necessary check.
24 */
25
26 #include <poll.h>
27 #include <pthread.h>
28 #include <stdlib.h>
29 #include <sys/debug.h>
30 #include <unistd.h>
31
32 typedef struct poll_arg {
33 int pa_fd;
34 pthread_barrier_t *pa_ready;
35 pthread_barrier_t *pa_done;
36 } poll_arg_t;
37
38 static void
barrier_wait(pthread_barrier_t * barrier)39 barrier_wait(pthread_barrier_t *barrier)
40 {
41 int ret = pthread_barrier_wait(barrier);
42
43 VERIFY(ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD);
44 }
45
46 static void *
poller(void * arg)47 poller(void *arg)
48 {
49 poll_arg_t *pa = arg;
50 struct pollfd pfd = {
51 .fd = pa->pa_fd,
52 .events = POLLIN
53 };
54
55 VERIFY0(poll(&pfd, 1, 0));
56 VERIFY0(pfd.revents);
57
58 barrier_wait(pa->pa_ready);
59 barrier_wait(pa->pa_done);
60
61 return (NULL);
62 }
63
64 int
main(void)65 main(void)
66 {
67 pthread_barrier_t ready, done;
68 pthread_t threads[2];
69 poll_arg_t args[2];
70 int pipefds[2];
71
72 VERIFY0(pipe(pipefds));
73 args[0].pa_fd = pipefds[0];
74 args[1].pa_fd = dup(pipefds[0]);
75 VERIFY3S(args[1].pa_fd, >=, 0);
76
77 VERIFY0(pthread_barrier_init(&ready, NULL, 3));
78 VERIFY0(pthread_barrier_init(&done, NULL, 3));
79
80 for (uint_t i = 0; i < 2; i++) {
81 args[i].pa_ready = &ready;
82 args[i].pa_done = &done;
83 VERIFY0(pthread_create(&threads[i], NULL, poller, &args[i]));
84 }
85
86 barrier_wait(&ready);
87 VERIFY0(close(args[0].pa_fd));
88 barrier_wait(&done);
89
90 for (uint_t i = 0; i < 2; i++)
91 VERIFY0(pthread_join(threads[i], NULL));
92
93 VERIFY0(pthread_barrier_destroy(&ready));
94 VERIFY0(pthread_barrier_destroy(&done));
95 VERIFY0(close(args[1].pa_fd));
96 VERIFY0(close(pipefds[1]));
97
98 return (EXIT_SUCCESS);
99 }
100