1*d7159b37SAndy Fiddaman /*
2*d7159b37SAndy Fiddaman  * This file and its contents are supplied under the terms of the
3*d7159b37SAndy Fiddaman  * Common Development and Distribution License ("CDDL"), version 1.0.
4*d7159b37SAndy Fiddaman  * You may only use this file in accordance with the terms of version
5*d7159b37SAndy Fiddaman  * 1.0 of the CDDL.
6*d7159b37SAndy Fiddaman  *
7*d7159b37SAndy Fiddaman  * A full copy of the text of the CDDL should have accompanied this
8*d7159b37SAndy Fiddaman  * source.  A copy of the CDDL is also available via the Internet at
9*d7159b37SAndy Fiddaman  * http://www.illumos.org/license/CDDL.
10*d7159b37SAndy Fiddaman  */
11*d7159b37SAndy Fiddaman 
12*d7159b37SAndy Fiddaman /*
13*d7159b37SAndy Fiddaman  * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
14*d7159b37SAndy Fiddaman  */
15*d7159b37SAndy Fiddaman 
16*d7159b37SAndy Fiddaman #include <err.h>
17*d7159b37SAndy Fiddaman #include <errno.h>
18*d7159b37SAndy Fiddaman #include <limits.h>
19*d7159b37SAndy Fiddaman #include <stdio.h>
20*d7159b37SAndy Fiddaman #include <stdlib.h>
21*d7159b37SAndy Fiddaman #include <sys/debug.h>
22*d7159b37SAndy Fiddaman #include <sys/eventfd.h>
23*d7159b37SAndy Fiddaman #include <unistd.h>
24*d7159b37SAndy Fiddaman 
25*d7159b37SAndy Fiddaman static int
readn(int fd,uint_t n)26*d7159b37SAndy Fiddaman readn(int fd, uint_t n)
27*d7159b37SAndy Fiddaman {
28*d7159b37SAndy Fiddaman 	uint_t i;
29*d7159b37SAndy Fiddaman 	int failures = 0;
30*d7159b37SAndy Fiddaman 
31*d7159b37SAndy Fiddaman 	for (i = 0; i < n; i++) {
32*d7159b37SAndy Fiddaman 		eventfd_t v = 0xdeadbeef;
33*d7159b37SAndy Fiddaman 		int ret;
34*d7159b37SAndy Fiddaman 
35*d7159b37SAndy Fiddaman 		ret = eventfd_read(fd, &v);
36*d7159b37SAndy Fiddaman 		if (ret != 0) {
37*d7159b37SAndy Fiddaman 			warn("Reading %u/%u got ret %d (expected 0)",
38*d7159b37SAndy Fiddaman 			    i + 1, n, ret);
39*d7159b37SAndy Fiddaman 			failures++;
40*d7159b37SAndy Fiddaman 		} else if (v != 1) {
41*d7159b37SAndy Fiddaman 			warnx("Reading %u/%u got value %"PRIu64" (expected 1)",
42*d7159b37SAndy Fiddaman 			    i + 1, n, v);
43*d7159b37SAndy Fiddaman 			failures++;
44*d7159b37SAndy Fiddaman 		}
45*d7159b37SAndy Fiddaman 	}
46*d7159b37SAndy Fiddaman 
47*d7159b37SAndy Fiddaman 	return (failures);
48*d7159b37SAndy Fiddaman }
49*d7159b37SAndy Fiddaman 
50*d7159b37SAndy Fiddaman static int
check_nosem(int fd)51*d7159b37SAndy Fiddaman check_nosem(int fd)
52*d7159b37SAndy Fiddaman {
53*d7159b37SAndy Fiddaman 	eventfd_t v = 0xdeadbeef;
54*d7159b37SAndy Fiddaman 	int failures = 0;
55*d7159b37SAndy Fiddaman 	int ret;
56*d7159b37SAndy Fiddaman 
57*d7159b37SAndy Fiddaman 	ret = eventfd_read(fd, &v);
58*d7159b37SAndy Fiddaman 
59*d7159b37SAndy Fiddaman 	if (ret != -1) {
60*d7159b37SAndy Fiddaman 		warnx("no semaphores read got ret %d (expected -1)", ret);
61*d7159b37SAndy Fiddaman 		failures++;
62*d7159b37SAndy Fiddaman 	}
63*d7159b37SAndy Fiddaman 
64*d7159b37SAndy Fiddaman 	if (errno != EAGAIN) {
65*d7159b37SAndy Fiddaman 		warn("no semaphores read expected EAGAIN but got");
66*d7159b37SAndy Fiddaman 		failures++;
67*d7159b37SAndy Fiddaman 	}
68*d7159b37SAndy Fiddaman 
69*d7159b37SAndy Fiddaman 	if (v != 0xdeadbeef) {
70*d7159b37SAndy Fiddaman 		warnx("no semaphores read modified value to %"PRIx64, v);
71*d7159b37SAndy Fiddaman 		failures++;
72*d7159b37SAndy Fiddaman 	}
73*d7159b37SAndy Fiddaman 
74*d7159b37SAndy Fiddaman 	return (failures);
75*d7159b37SAndy Fiddaman }
76*d7159b37SAndy Fiddaman 
77*d7159b37SAndy Fiddaman static int
check_badwrite(int fd)78*d7159b37SAndy Fiddaman check_badwrite(int fd)
79*d7159b37SAndy Fiddaman {
80*d7159b37SAndy Fiddaman 	int failures = 0;
81*d7159b37SAndy Fiddaman 	int ret;
82*d7159b37SAndy Fiddaman 
83*d7159b37SAndy Fiddaman 	ret = eventfd_write(fd, ULLONG_MAX);
84*d7159b37SAndy Fiddaman 
85*d7159b37SAndy Fiddaman 	if (ret != -1) {
86*d7159b37SAndy Fiddaman 		warnx("bad write got ret %d (expected -1)", ret);
87*d7159b37SAndy Fiddaman 		failures++;
88*d7159b37SAndy Fiddaman 	}
89*d7159b37SAndy Fiddaman 
90*d7159b37SAndy Fiddaman 	if (errno != EINVAL) {
91*d7159b37SAndy Fiddaman 		warn("bad write expected EINVAL but got");
92*d7159b37SAndy Fiddaman 		failures++;
93*d7159b37SAndy Fiddaman 	}
94*d7159b37SAndy Fiddaman 
95*d7159b37SAndy Fiddaman 	return (failures);
96*d7159b37SAndy Fiddaman }
97*d7159b37SAndy Fiddaman 
98*d7159b37SAndy Fiddaman int
main(void)99*d7159b37SAndy Fiddaman main(void)
100*d7159b37SAndy Fiddaman {
101*d7159b37SAndy Fiddaman 	int fd, failures = 0;
102*d7159b37SAndy Fiddaman 
103*d7159b37SAndy Fiddaman 	/* Test eventfd semaphore semantics */
104*d7159b37SAndy Fiddaman 	fd = eventfd(2, EFD_NONBLOCK | EFD_CLOEXEC | EFD_SEMAPHORE);
105*d7159b37SAndy Fiddaman 	if (fd == -1)
106*d7159b37SAndy Fiddaman 		err(EXIT_FAILURE, "Could not create eventfd semaphore");
107*d7159b37SAndy Fiddaman 
108*d7159b37SAndy Fiddaman 	/* Consume the available semaphores */
109*d7159b37SAndy Fiddaman 	failures += readn(fd, 2);
110*d7159b37SAndy Fiddaman 
111*d7159b37SAndy Fiddaman 	/* The next read should return -1/EAGAIN */
112*d7159b37SAndy Fiddaman 	failures += check_nosem(fd);
113*d7159b37SAndy Fiddaman 
114*d7159b37SAndy Fiddaman 	/* Return two + three semaphores */
115*d7159b37SAndy Fiddaman 	if (eventfd_write(fd, 2) != 0) {
116*d7159b37SAndy Fiddaman 		warn("Error while returning two semaphores");
117*d7159b37SAndy Fiddaman 		failures++;
118*d7159b37SAndy Fiddaman 	}
119*d7159b37SAndy Fiddaman 	if (eventfd_write(fd, 3) != 0) {
120*d7159b37SAndy Fiddaman 		warn("Error while returning three semaphores");
121*d7159b37SAndy Fiddaman 		failures++;
122*d7159b37SAndy Fiddaman 	}
123*d7159b37SAndy Fiddaman 
124*d7159b37SAndy Fiddaman 	/* Consume the available semaphores */
125*d7159b37SAndy Fiddaman 	failures += readn(fd, 5);
126*d7159b37SAndy Fiddaman 
127*d7159b37SAndy Fiddaman 	/* The next read should return -1/EAGAIN */
128*d7159b37SAndy Fiddaman 	failures += check_nosem(fd);
129*d7159b37SAndy Fiddaman 
130*d7159b37SAndy Fiddaman 	/*
131*d7159b37SAndy Fiddaman 	 * Check that a writing too large a value results in an error from
132*d7159b37SAndy Fiddaman 	 * eventfd_write() - testing that an error from the underlying write()
133*d7159b37SAndy Fiddaman 	 * is passed back.
134*d7159b37SAndy Fiddaman 	 */
135*d7159b37SAndy Fiddaman 	failures += check_badwrite(fd);
136*d7159b37SAndy Fiddaman 
137*d7159b37SAndy Fiddaman 	VERIFY0(close(fd));
138*d7159b37SAndy Fiddaman 
139*d7159b37SAndy Fiddaman 	return (failures == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
140*d7159b37SAndy Fiddaman }