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
5 * 1.0 of the CDDL.
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 (c) 2015 Joyent, Inc. All rights reserved.
14 */
15
16 /*
17 * Support for the eventfd facility, a Linux-borne facility for user-generated
18 * file descriptor-based events.
19 */
20
21 #include <sys/ddi.h>
22 #include <sys/sunddi.h>
23 #include <sys/eventfd.h>
24 #include <sys/conf.h>
25 #include <sys/vmem.h>
26 #include <sys/sysmacros.h>
27 #include <sys/filio.h>
28 #include <sys/stat.h>
29 #include <sys/file.h>
30
31 struct eventfd_state;
32 typedef struct eventfd_state eventfd_state_t;
33
34 struct eventfd_state {
35 kmutex_t efd_lock; /* lock protecting state */
36 boolean_t efd_semaphore; /* boolean: sema. semantics */
37 kcondvar_t efd_cv; /* condvar */
38 pollhead_t efd_pollhd; /* poll head */
39 uint64_t efd_value; /* value */
40 eventfd_state_t *efd_next; /* next state on global list */
41 };
42
43 /*
44 * Internal global variables.
45 */
46 static kmutex_t eventfd_lock; /* lock protecting state */
47 static dev_info_t *eventfd_devi; /* device info */
48 static vmem_t *eventfd_minor; /* minor number arena */
49 static void *eventfd_softstate; /* softstate pointer */
50 static eventfd_state_t *eventfd_state; /* global list of state */
51
52 /*ARGSUSED*/
53 static int
54 eventfd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
55 {
56 eventfd_state_t *state;
57 major_t major = getemajor(*devp);
58 minor_t minor = getminor(*devp);
59
109 return (EINTR);
110 }
111 }
112
113 /*
114 * We have a non-zero value and we own the lock; our behavior now
115 * depends on whether or not EFD_SEMAPHORE was set when the eventfd
116 * was created.
117 */
118 val = oval = state->efd_value;
119
120 if (state->efd_semaphore) {
121 state->efd_value--;
122 val = 1;
123 } else {
124 state->efd_value = 0;
125 }
126
127 err = uiomove(&val, sizeof (val), UIO_READ, uio);
128
129 mutex_exit(&state->efd_lock);
130
131 if (oval == EVENTFD_VALMAX) {
132 cv_broadcast(&state->efd_cv);
133 pollwakeup(&state->efd_pollhd, POLLWRNORM | POLLOUT);
134 }
135
136 return (err);
137 }
138
139 /*ARGSUSED*/
140 static int
141 eventfd_write(dev_t dev, struct uio *uio, cred_t *credp)
142 {
143 eventfd_state_t *state;
144 minor_t minor = getminor(dev);
145 uint64_t val, oval;
146 int err;
147
148 if (uio->uio_resid < sizeof (val))
149 return (EINVAL);
150
151 if ((err = uiomove(&val, sizeof (val), UIO_WRITE, uio)) != 0)
152 return (err);
153
154 if (val > EVENTFD_VALMAX)
155 return (EINVAL);
156
157 state = ddi_get_soft_state(eventfd_softstate, minor);
158
159 mutex_enter(&state->efd_lock);
160
161 while (val > EVENTFD_VALMAX - state->efd_value) {
162 if (uio->uio_fmode & (FNDELAY|FNONBLOCK)) {
163 mutex_exit(&state->efd_lock);
164 return (EAGAIN);
165 }
166
167 if (!cv_wait_sig_swap(&state->efd_cv, &state->efd_lock)) {
168 mutex_exit(&state->efd_lock);
169 return (EINTR);
170 }
171 }
172
173 /*
174 * We now know that we can add the value without overflowing.
175 */
176 state->efd_value = (oval = state->efd_value) + val;
177
178 mutex_exit(&state->efd_lock);
179
180 if (oval == 0) {
181 cv_broadcast(&state->efd_cv);
182 pollwakeup(&state->efd_pollhd, POLLRDNORM | POLLIN);
183 }
184
185 return (0);
186 }
187
188 /*ARGSUSED*/
189 static int
190 eventfd_poll(dev_t dev, short events, int anyyet, short *reventsp,
191 struct pollhead **phpp)
192 {
193 eventfd_state_t *state;
194 minor_t minor = getminor(dev);
195 short revents = 0;
196
197 state = ddi_get_soft_state(eventfd_softstate, minor);
198
199 mutex_enter(&state->efd_lock);
200
201 if (state->efd_value > 0)
|
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
5 * 1.0 of the CDDL.
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 2016 Joyent, Inc.
14 */
15
16 /*
17 * Support for the eventfd facility, a Linux-borne facility for user-generated
18 * file descriptor-based events.
19 */
20
21 #include <sys/ddi.h>
22 #include <sys/sunddi.h>
23 #include <sys/eventfd.h>
24 #include <sys/conf.h>
25 #include <sys/vmem.h>
26 #include <sys/sysmacros.h>
27 #include <sys/filio.h>
28 #include <sys/stat.h>
29 #include <sys/file.h>
30
31 struct eventfd_state;
32 typedef struct eventfd_state eventfd_state_t;
33
34 struct eventfd_state {
35 kmutex_t efd_lock; /* lock protecting state */
36 boolean_t efd_semaphore; /* boolean: sema. semantics */
37 kcondvar_t efd_cv; /* condvar */
38 pollhead_t efd_pollhd; /* poll head */
39 uint64_t efd_value; /* value */
40 size_t efd_bwriters; /* count of blocked writers */
41 eventfd_state_t *efd_next; /* next state on global list */
42 };
43
44 /*
45 * Internal global variables.
46 */
47 static kmutex_t eventfd_lock; /* lock protecting state */
48 static dev_info_t *eventfd_devi; /* device info */
49 static vmem_t *eventfd_minor; /* minor number arena */
50 static void *eventfd_softstate; /* softstate pointer */
51 static eventfd_state_t *eventfd_state; /* global list of state */
52
53 /*ARGSUSED*/
54 static int
55 eventfd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
56 {
57 eventfd_state_t *state;
58 major_t major = getemajor(*devp);
59 minor_t minor = getminor(*devp);
60
110 return (EINTR);
111 }
112 }
113
114 /*
115 * We have a non-zero value and we own the lock; our behavior now
116 * depends on whether or not EFD_SEMAPHORE was set when the eventfd
117 * was created.
118 */
119 val = oval = state->efd_value;
120
121 if (state->efd_semaphore) {
122 state->efd_value--;
123 val = 1;
124 } else {
125 state->efd_value = 0;
126 }
127
128 err = uiomove(&val, sizeof (val), UIO_READ, uio);
129
130 /*
131 * Wake any writers blocked on this eventfd as this read operation may
132 * have created adequate capacity for their values.
133 */
134 if (state->efd_bwriters != 0) {
135 cv_broadcast(&state->efd_cv);
136 }
137 mutex_exit(&state->efd_lock);
138
139 /*
140 * It is necessary to emit POLLOUT events only when the eventfd
141 * transitions from EVENTFD_VALMAX to a lower value. At all other
142 * times, it is already considered writable by poll.
143 */
144 if (oval == EVENTFD_VALMAX) {
145 pollwakeup(&state->efd_pollhd, POLLWRNORM | POLLOUT);
146 }
147
148 return (err);
149 }
150
151 /*ARGSUSED*/
152 static int
153 eventfd_write(dev_t dev, struct uio *uio, cred_t *credp)
154 {
155 eventfd_state_t *state;
156 minor_t minor = getminor(dev);
157 uint64_t val, oval;
158 int err;
159
160 if (uio->uio_resid < sizeof (val))
161 return (EINVAL);
162
163 if ((err = uiomove(&val, sizeof (val), UIO_WRITE, uio)) != 0)
164 return (err);
165
166 if (val > EVENTFD_VALMAX)
167 return (EINVAL);
168
169 state = ddi_get_soft_state(eventfd_softstate, minor);
170
171 mutex_enter(&state->efd_lock);
172
173 while (val > EVENTFD_VALMAX - state->efd_value) {
174 if (uio->uio_fmode & (FNDELAY|FNONBLOCK)) {
175 mutex_exit(&state->efd_lock);
176 return (EAGAIN);
177 }
178
179 state->efd_bwriters++;
180 if (!cv_wait_sig_swap(&state->efd_cv, &state->efd_lock)) {
181 state->efd_bwriters--;
182 mutex_exit(&state->efd_lock);
183 return (EINTR);
184 }
185 state->efd_bwriters--;
186 }
187
188 /*
189 * We now know that we can add the value without overflowing.
190 */
191 state->efd_value = (oval = state->efd_value) + val;
192
193 /*
194 * If the value was previously "empty", notify blocked readers that
195 * data is available.
196 */
197 if (oval == 0) {
198 cv_broadcast(&state->efd_cv);
199 }
200 mutex_exit(&state->efd_lock);
201
202 /*
203 * Notify pollers as well if the eventfd is now readable.
204 */
205 if (oval == 0) {
206 pollwakeup(&state->efd_pollhd, POLLRDNORM | POLLIN);
207 }
208
209 return (0);
210 }
211
212 /*ARGSUSED*/
213 static int
214 eventfd_poll(dev_t dev, short events, int anyyet, short *reventsp,
215 struct pollhead **phpp)
216 {
217 eventfd_state_t *state;
218 minor_t minor = getminor(dev);
219 short revents = 0;
220
221 state = ddi_get_soft_state(eventfd_softstate, minor);
222
223 mutex_enter(&state->efd_lock);
224
225 if (state->efd_value > 0)
|