xref: /illumos-gate/usr/src/test/os-tests/tests/poll/poll_close_test.c (revision fb435c17bdaed70a42c2571b9cfc8dc57c80f6b4)
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