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