Print this page
cleanup port_free_event_local() semantics
XXXXX race between closef(portfd) and timer_delete()
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/os/port_subr.c
+++ new/usr/src/uts/common/os/port_subr.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
|
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 -#pragma ident "%Z%%M% %I% %E% SMI"
27 +/*
28 + * Copyright 2020 Joyent, Inc.
29 + */
28 30
29 31 /*
30 32 * This file containts all the functions required for interactions of
31 33 * event sources with the event port file system.
32 34 */
33 35
34 36 #include <sys/types.h>
35 37 #include <sys/conf.h>
36 38 #include <sys/stat.h>
37 39 #include <sys/errno.h>
38 40 #include <sys/kmem.h>
39 41 #include <sys/debug.h>
40 42 #include <sys/file.h>
41 43 #include <sys/sysmacros.h>
42 44 #include <sys/systm.h>
43 45 #include <sys/bitmap.h>
44 46 #include <sys/rctl.h>
45 47 #include <sys/atomic.h>
46 48 #include <sys/poll_impl.h>
47 49 #include <sys/port_impl.h>
48 50
49 51 /*
50 52 * Maximum number of elements allowed to be passed in a single call of a
51 53 * port function (port_sendn(), port_getn(). We need to allocate kernel memory
52 54 * for all of them at once, so we can't let it scale without limit.
53 55 */
54 56 uint_t port_max_list = PORT_MAX_LIST;
55 57 port_control_t port_control; /* Event port framework main structure */
56 58
57 59 /*
58 60 * Block other threads from using a port.
59 61 * We enter holding portq->portq_mutex but
60 62 * we may drop and reacquire this lock.
61 63 * Callers must deal with this fact.
62 64 */
63 65 void
64 66 port_block(port_queue_t *portq)
65 67 {
66 68 ASSERT(MUTEX_HELD(&portq->portq_mutex));
67 69
68 70 while (portq->portq_flags & PORTQ_BLOCKED)
69 71 cv_wait(&portq->portq_block_cv, &portq->portq_mutex);
70 72 portq->portq_flags |= PORTQ_BLOCKED;
71 73 }
72 74
73 75 /*
74 76 * Undo port_block(portq).
75 77 */
76 78 void
77 79 port_unblock(port_queue_t *portq)
78 80 {
79 81 ASSERT(MUTEX_HELD(&portq->portq_mutex));
80 82
81 83 portq->portq_flags &= ~PORTQ_BLOCKED;
82 84 cv_signal(&portq->portq_block_cv);
83 85 }
84 86
85 87 /*
86 88 * Called from pollwakeup(PORT_SOURCE_FD source) to determine
87 89 * if the port's fd needs to be notified of poll events. If yes,
88 90 * we mark the port indicating that pollwakeup() is referring
89 91 * it so that the port_t does not disappear. pollwakeup()
90 92 * calls port_pollwkdone() after notifying. In port_pollwkdone(),
91 93 * we clear the hold on the port_t (clear PORTQ_POLLWK_PEND).
92 94 */
93 95 int
94 96 port_pollwkup(port_t *pp)
95 97 {
96 98 int events = 0;
97 99 port_queue_t *portq;
98 100 portq = &pp->port_queue;
99 101 mutex_enter(&portq->portq_mutex);
100 102
101 103 /*
102 104 * Normally, we should not have a situation where PORTQ_POLLIN
103 105 * and PORTQ_POLLWK_PEND are set at the same time, but it is
104 106 * possible. So, in pollwakeup() we ensure that no new fd's get
105 107 * added to the pollhead between the time it notifies poll events
106 108 * and calls poll_wkupdone() where we clear the PORTQ_POLLWK_PEND flag.
107 109 */
108 110 if (portq->portq_flags & PORTQ_POLLIN &&
109 111 !(portq->portq_flags & PORTQ_POLLWK_PEND)) {
110 112 portq->portq_flags &= ~PORTQ_POLLIN;
111 113 portq->portq_flags |= PORTQ_POLLWK_PEND;
112 114 events = POLLIN;
113 115 }
114 116 mutex_exit(&portq->portq_mutex);
115 117 return (events);
116 118 }
117 119
118 120 void
119 121 port_pollwkdone(port_t *pp)
120 122 {
121 123 port_queue_t *portq;
122 124 portq = &pp->port_queue;
123 125 ASSERT(portq->portq_flags & PORTQ_POLLWK_PEND);
124 126 mutex_enter(&portq->portq_mutex);
125 127 portq->portq_flags &= ~PORTQ_POLLWK_PEND;
126 128 cv_signal(&pp->port_cv);
127 129 mutex_exit(&portq->portq_mutex);
128 130 }
129 131
130 132
131 133 /*
132 134 * The port_send_event() function is used by all event sources to submit
133 135 * trigerred events to a port. All the data required for the event management
134 136 * is already stored in the port_kevent_t structure.
135 137 * The event port internal data is stored in the port_kevent_t structure
136 138 * during the allocation time (see port_alloc_event()). The data related to
137 139 * the event itself and to the event source management is stored in the
138 140 * port_kevent_t structure between the allocation time and submit time
139 141 * (see port_init_event()).
140 142 *
141 143 * This function is often called from interrupt level.
142 144 */
143 145 void
144 146 port_send_event(port_kevent_t *pkevp)
145 147 {
146 148 port_queue_t *portq;
147 149
148 150 portq = &pkevp->portkev_port->port_queue;
149 151 mutex_enter(&portq->portq_mutex);
150 152
151 153 if (pkevp->portkev_flags & PORT_KEV_DONEQ) {
152 154 /* Event already in the port queue */
153 155 if (pkevp->portkev_source == PORT_SOURCE_FD) {
154 156 mutex_exit(&pkevp->portkev_lock);
155 157 }
156 158 mutex_exit(&portq->portq_mutex);
157 159 return;
158 160 }
159 161
160 162 /* put event in the port queue */
161 163 list_insert_tail(&portq->portq_list, pkevp);
162 164 portq->portq_nent++;
163 165
164 166 /*
165 167 * Remove the PORTQ_WAIT_EVENTS flag to indicate
166 168 * that new events are available.
167 169 */
168 170 portq->portq_flags &= ~PORTQ_WAIT_EVENTS;
169 171 pkevp->portkev_flags |= PORT_KEV_DONEQ; /* event enqueued */
170 172
171 173 if (pkevp->portkev_source == PORT_SOURCE_FD) {
172 174 mutex_exit(&pkevp->portkev_lock);
173 175 }
174 176
175 177 /* Check if thread is in port_close() waiting for outstanding events */
176 178 if (portq->portq_flags & PORTQ_CLOSE) {
177 179 /* Check if all outstanding events are already in port queue */
178 180 if (pkevp->portkev_port->port_curr <= portq->portq_nent)
179 181 cv_signal(&portq->portq_closecv);
180 182 }
181 183
182 184 if (portq->portq_getn == 0) {
183 185 /*
184 186 * No thread retrieving events -> check if enough events are
185 187 * available to satify waiting threads.
186 188 */
187 189 if (portq->portq_thread &&
188 190 (portq->portq_nent >= portq->portq_nget))
189 191 cv_signal(&portq->portq_thread->portget_cv);
190 192 }
191 193
192 194 /*
193 195 * If some thread is polling the port's fd, then notify it.
194 196 * For PORT_SOURCE_FD source, we don't need to call pollwakeup()
195 197 * here as it will result in a recursive call(PORT_SOURCE_FD source
196 198 * is pollwakeup()). Therefore pollwakeup() itself will notify the
|
↓ open down ↓ |
159 lines elided |
↑ open up ↑ |
197 199 * ports if being polled.
198 200 */
199 201 if (pkevp->portkev_source != PORT_SOURCE_FD &&
200 202 portq->portq_flags & PORTQ_POLLIN) {
201 203 port_t *pp;
202 204
203 205 portq->portq_flags &= ~PORTQ_POLLIN;
204 206 /*
205 207 * Need to save port_t for calling pollwakeup since port_getn()
206 208 * may end up freeing pkevp once portq_mutex is dropped.
209 + *
210 + * For that matter, if PORTQ_CLOSE is set, all of the port_t
211 + * may be freed upon dropping portq_mutex.
207 212 */
208 - pp = pkevp->portkev_port;
213 + pp = (portq->portq_flags & PORTQ_CLOSE) ?
214 + NULL : pkevp->portkev_port;
209 215 mutex_exit(&portq->portq_mutex);
210 - pollwakeup(&pp->port_pollhd, POLLIN);
216 + if (pp != NULL)
217 + pollwakeup(&pp->port_pollhd, POLLIN);
211 218 } else {
212 219 mutex_exit(&portq->portq_mutex);
213 220 }
214 221 }
215 222
216 223 /*
217 224 * The port_alloc_event() function has to be used by all event sources
218 225 * to request an slot for event notification.
219 226 * The slot reservation could be denied because of lack of resources.
220 227 * For that reason the event source should allocate an event slot as early
221 228 * as possible and be prepared to get an error code instead of the
222 229 * port event pointer.
223 230 * Al current event sources allocate an event slot during a system call
224 231 * entry. They return an error code to the application if an event slot
225 232 * could not be reserved.
226 233 * It is also recommended to associate the event source with the port
227 234 * before some other port function is used.
228 235 * The port argument is a file descriptor obtained by the application as
229 236 * a return value of port_create().
230 237 * Possible values of flags are:
231 238 * PORT_ALLOC_DEFAULT
232 239 * This is the standard type of port events. port_get(n) will free this
233 240 * type of event structures as soon as the events are delivered to the
234 241 * application.
235 242 * PORT_ALLOC_PRIVATE
236 243 * This type of event will be use for private use of the event source.
237 244 * The port_get(n) function will deliver events of such an structure to
238 245 * the application but it will not free the event structure itself.
239 246 * The event source must free this structure using port_free_event().
240 247 * PORT_ALLOC_CACHED
241 248 * This type of events is used when the event source helds an own
242 249 * cache.
|
↓ open down ↓ |
22 lines elided |
↑ open up ↑ |
243 250 * The port_get(n) function will deliver events of such an structure to
244 251 * the application but it will not free the event structure itself.
245 252 * The event source must free this structure using port_free_event().
246 253 */
247 254 int
248 255 port_alloc_event(int port, int flags, int source, port_kevent_t **pkevpp)
249 256 {
250 257 port_t *pp;
251 258 file_t *fp;
252 259 port_kevent_t *pkevp;
260 + int err;
253 261
254 262 if ((fp = getf(port)) == NULL)
255 263 return (EBADF);
256 264
257 265 if (fp->f_vnode->v_type != VPORT) {
258 266 releasef(port);
259 267 return (EBADFD);
260 268 }
261 269
262 270 pkevp = kmem_cache_alloc(port_control.pc_cache, KM_NOSLEEP);
263 271 if (pkevp == NULL) {
|
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
264 272 releasef(port);
265 273 return (ENOMEM);
266 274 }
267 275
268 276 /*
269 277 * port_max_events is controlled by the resource control
270 278 * process.port-max-events
271 279 */
272 280 pp = VTOEP(fp->f_vnode);
273 281 mutex_enter(&pp->port_queue.portq_mutex);
274 - if (pp->port_curr >= pp->port_max_events) {
282 +
283 + /* Two possible error conditions. */
284 + if (pp->port_queue.portq_flags & PORTQ_CLOSE)
285 + err = EBADFD; /* Mid-close. */
286 + else if (pp->port_curr >= pp->port_max_events)
287 + err = EAGAIN; /* Resources unavailabile. */
288 + else
289 + err = 0; /* Good to go! */
290 +
291 + if (err != 0) {
275 292 mutex_exit(&pp->port_queue.portq_mutex);
276 293 kmem_cache_free(port_control.pc_cache, pkevp);
277 294 releasef(port);
278 - return (EAGAIN);
295 + return (err);
279 296 }
280 297 pp->port_curr++;
281 298 mutex_exit(&pp->port_queue.portq_mutex);
282 299
283 300 bzero(pkevp, sizeof (port_kevent_t));
284 301 mutex_init(&pkevp->portkev_lock, NULL, MUTEX_DEFAULT, NULL);
285 302 pkevp->portkev_source = source;
286 303 pkevp->portkev_flags = flags;
287 304 pkevp->portkev_pid = curproc->p_pid;
288 305 pkevp->portkev_port = pp;
289 306 *pkevpp = pkevp;
290 307 releasef(port);
291 308 return (0);
292 309 }
293 310
294 311 /*
295 312 * This function is faster than the standard port_alloc_event() and
296 313 * can be used when the event source already allocated an event from
297 314 * a port.
298 315 */
299 316 int
300 317 port_dup_event(port_kevent_t *pkevp, port_kevent_t **pkevdupp, int flags)
301 318 {
302 319 int error;
303 320
304 321 error = port_alloc_event_local(pkevp->portkev_port,
305 322 pkevp->portkev_source, flags, pkevdupp);
306 323 if (error == 0)
307 324 (*pkevdupp)->portkev_pid = pkevp->portkev_pid;
308 325 return (error);
309 326 }
310 327
311 328 /*
|
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
312 329 * port_alloc_event_local() is reserved for internal use only.
313 330 * It is doing the same job as port_alloc_event() but with the event port
314 331 * pointer as the first argument.
315 332 * The check of the validity of the port file descriptor is skipped here.
316 333 */
317 334 int
318 335 port_alloc_event_local(port_t *pp, int source, int flags,
319 336 port_kevent_t **pkevpp)
320 337 {
321 338 port_kevent_t *pkevp;
339 + int err;
322 340
323 341 pkevp = kmem_cache_alloc(port_control.pc_cache, KM_NOSLEEP);
324 342 if (pkevp == NULL)
325 343 return (ENOMEM);
326 344
327 345 mutex_enter(&pp->port_queue.portq_mutex);
328 - if (pp->port_curr >= pp->port_max_events) {
346 +
347 + /* Two possible error conditions. */
348 + if (pp->port_queue.portq_flags & PORTQ_CLOSE)
349 + err = EBADFD; /* Mid-close. */
350 + else if (pp->port_curr >= pp->port_max_events)
351 + err = EAGAIN; /* Resources unavailable. */
352 + else
353 + err = 0; /* Good to go! */
354 +
355 + if (err != 0) {
329 356 mutex_exit(&pp->port_queue.portq_mutex);
330 357 kmem_cache_free(port_control.pc_cache, pkevp);
331 - return (EAGAIN);
358 + return (err);
332 359 }
333 360 pp->port_curr++;
334 361 mutex_exit(&pp->port_queue.portq_mutex);
335 362
336 363 bzero(pkevp, sizeof (port_kevent_t));
337 364 mutex_init(&pkevp->portkev_lock, NULL, MUTEX_DEFAULT, NULL);
338 365 pkevp->portkev_flags = flags;
339 366 pkevp->portkev_port = pp;
340 367 pkevp->portkev_source = source;
341 368 pkevp->portkev_pid = curproc->p_pid;
342 369 *pkevpp = pkevp;
343 370 return (0);
344 371 }
345 372
346 373 /*
347 374 * port_alloc_event_block() has the same functionality of port_alloc_event() +
348 375 * - it blocks if not enough event slots are available and
349 376 * - it blocks if not enough memory is available.
350 377 * Currently port_dispatch() is using this function to increase the
|
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
351 378 * reliability of event delivery for library event sources.
352 379 */
353 380 int
354 381 port_alloc_event_block(port_t *pp, int source, int flags,
355 382 port_kevent_t **pkevpp)
356 383 {
357 384 port_kevent_t *pkevp =
358 385 kmem_cache_alloc(port_control.pc_cache, KM_SLEEP);
359 386
360 387 mutex_enter(&pp->port_queue.portq_mutex);
388 + /*
389 + * Mid-close check needs to happen immediately before any
390 + * resource checking or cv_wait()-ing of any sort.
391 + */
392 + if (pp->port_queue.portq_flags & PORTQ_CLOSE) {
393 + mutex_exit(&pp->port_queue.portq_mutex);
394 + kmem_cache_free(port_control.pc_cache, pkevp);
395 + return (EBADFD);
396 + }
397 +
361 398 while (pp->port_curr >= pp->port_max_events) {
362 399 if (!cv_wait_sig(&pp->port_cv, &pp->port_queue.portq_mutex)) {
363 400 /* signal detected */
364 401 mutex_exit(&pp->port_queue.portq_mutex);
365 402 kmem_cache_free(port_control.pc_cache, pkevp);
366 403 return (EINTR);
367 404 }
405 +
406 + /* Oh, and we have to re-check the close state. */
407 + if (pp->port_queue.portq_flags & PORTQ_CLOSE) {
408 + mutex_exit(&pp->port_queue.portq_mutex);
409 + kmem_cache_free(port_control.pc_cache, pkevp);
410 + return (EBADFD);
411 + }
368 412 }
369 413 pp->port_curr++;
370 414 mutex_exit(&pp->port_queue.portq_mutex);
371 415
372 416 bzero(pkevp, sizeof (port_kevent_t));
373 417 mutex_init(&pkevp->portkev_lock, NULL, MUTEX_DEFAULT, NULL);
374 418 pkevp->portkev_flags = flags;
375 419 pkevp->portkev_port = pp;
376 420 pkevp->portkev_source = source;
377 421 pkevp->portkev_pid = curproc->p_pid;
378 422 *pkevpp = pkevp;
379 423 return (0);
380 424 }
381 425
382 426 /*
383 427 * Take an event out of the port queue
384 428 */
385 429 static void
386 430 port_remove_event_doneq(port_kevent_t *pkevp, port_queue_t *portq)
387 431 {
388 432 ASSERT(MUTEX_HELD(&portq->portq_mutex));
389 433 list_remove(&portq->portq_list, pkevp);
390 434 portq->portq_nent--;
391 435 pkevp->portkev_flags &= ~PORT_KEV_DONEQ;
392 436 }
393 437
394 438 /*
395 439 * The port_remove_done_event() function takes a fired event out of the
396 440 * port queue.
397 441 * Currently this function is required to cancel a fired event because
398 442 * the application is delivering new association data (see port_associate_fd()).
399 443 */
400 444 int
401 445 port_remove_done_event(port_kevent_t *pkevp)
402 446 {
403 447 port_queue_t *portq;
404 448 int removed = 0;
405 449
406 450 portq = &pkevp->portkev_port->port_queue;
407 451 mutex_enter(&portq->portq_mutex);
408 452 /* wait for port_get() or port_getn() */
409 453 port_block(portq);
410 454 if (pkevp->portkev_flags & PORT_KEV_DONEQ) {
411 455 /* event still in port queue */
412 456 if (portq->portq_getn) {
413 457 /*
414 458 * There could be still fired events in the temp queue;
415 459 * push those events back to the port queue and
416 460 * remove requested event afterwards.
417 461 */
418 462 port_push_eventq(portq);
419 463 }
420 464 /* now remove event from the port queue */
421 465 port_remove_event_doneq(pkevp, portq);
422 466 removed = 1;
423 467 }
424 468 port_unblock(portq);
425 469 mutex_exit(&portq->portq_mutex);
426 470 return (removed);
427 471 }
428 472
429 473 /*
430 474 * Return port event back to the kmem_cache.
431 475 * If the event is currently in the port queue the event itself will only
432 476 * be set as invalid. The port_get(n) function will not deliver such events
433 477 * to the application and it will return them back to the kmem_cache.
434 478 */
|
↓ open down ↓ |
57 lines elided |
↑ open up ↑ |
435 479 void
436 480 port_free_event(port_kevent_t *pkevp)
437 481 {
438 482 port_queue_t *portq;
439 483 port_t *pp;
440 484
441 485 pp = pkevp->portkev_port;
442 486 if (pp == NULL)
443 487 return;
444 488 if (pkevp->portkev_flags & PORT_ALLOC_PRIVATE) {
445 - port_free_event_local(pkevp, 0);
489 + port_free_event_local(pkevp, B_TRUE);
446 490 return;
447 491 }
448 492
449 493 portq = &pp->port_queue;
450 494 mutex_enter(&portq->portq_mutex);
451 495 port_block(portq);
452 496 if (pkevp->portkev_flags & PORT_KEV_DONEQ) {
453 497 pkevp->portkev_flags |= PORT_KEV_FREE;
454 498 pkevp->portkev_callback = NULL;
455 499 port_unblock(portq);
456 500 mutex_exit(&portq->portq_mutex);
457 501 return;
458 502 }
459 503 port_unblock(portq);
460 504
461 505 if (pkevp->portkev_flags & PORT_KEV_CACHED) {
462 506 mutex_exit(&portq->portq_mutex);
463 507 return;
464 508 }
465 509
466 510 if (--pp->port_curr < pp->port_max_events)
467 511 cv_signal(&pp->port_cv);
468 512 if (portq->portq_flags & PORTQ_CLOSE) {
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
469 513 /*
470 514 * Another thread is closing the event port.
471 515 * That thread will sleep until all allocated event
472 516 * structures returned to the event port framework.
473 517 * The portq_mutex is used to synchronize the status
474 518 * of the allocated event structures (port_curr).
475 519 */
476 520 if (pp->port_curr <= portq->portq_nent)
477 521 cv_signal(&portq->portq_closecv);
478 522 }
479 - mutex_exit(&portq->portq_mutex);
480 - port_free_event_local(pkevp, 1);
523 +
524 + /*
525 + * We're holding portq_mutex and we decremented port_curr, so don't
526 + * have port_free_event_local() do it for us.
527 + */
528 + port_free_event_local(pkevp, B_FALSE);
481 529 }
482 530
483 531 /*
484 532 * This event port internal function is used by port_free_event() and
485 533 * other port internal functions to return event structures back to the
486 534 * kmem_cache.
535 + *
536 + * If the caller already holds the portq_mutex, indicate by setting
537 + * lock_and_decrement to B_FALSE. This function MUST drop portq_mutex as
538 + * it can call pollwakeup() at its end.
487 539 */
488 540 void
489 -port_free_event_local(port_kevent_t *pkevp, int counter)
541 +port_free_event_local(port_kevent_t *pkevp, boolean_t lock_and_decrement)
490 542 {
491 543 port_t *pp = pkevp->portkev_port;
492 544 port_queue_t *portq = &pp->port_queue;
493 545 int wakeup;
494 546
495 547 pkevp->portkev_callback = NULL;
496 548 pkevp->portkev_flags = 0;
497 549 pkevp->portkev_port = NULL;
498 550 mutex_destroy(&pkevp->portkev_lock);
499 551 kmem_cache_free(port_control.pc_cache, pkevp);
500 552
501 - mutex_enter(&portq->portq_mutex);
502 - if (counter == 0) {
553 + if (lock_and_decrement) {
554 + /*
555 + * If we're entering here from outside port_event_free(),
556 + * grab the mutex. We enter here if we hadn't already
557 + * decremented-and-signaled port_curr.
558 + */
559 + mutex_enter(&portq->portq_mutex);
503 560 if (--pp->port_curr < pp->port_max_events)
504 561 cv_signal(&pp->port_cv);
505 562 }
506 - wakeup = (portq->portq_flags & PORTQ_POLLOUT);
563 + ASSERT(MUTEX_HELD(&portq->portq_mutex));
564 +
565 + /*
566 + * Don't send the POLLOUT if we're mid-close. We can only send it if
567 + * we've dropped the mutex, and if we're closing, dropping the mutex
568 + * could lead to another thread freeing pp->port_pollhd and the rest
569 + * of *pp.
570 + */
571 + wakeup = ((portq->portq_flags & (PORTQ_POLLOUT | PORTQ_CLOSE)) ==
572 + PORTQ_POLLOUT);
507 573 portq->portq_flags &= ~PORTQ_POLLOUT;
508 574 mutex_exit(&portq->portq_mutex);
509 575
510 576 /* Submit a POLLOUT event if requested */
511 577 if (wakeup)
512 578 pollwakeup(&pp->port_pollhd, POLLOUT);
513 579 }
514 580
515 581 /*
516 582 * port_init_event(port_event_t *pev, uintptr_t object, void *user,
517 583 * int (*port_callback)(void *, int *, pid_t, int, void *), void *sysarg);
518 584 * This function initializes most of the "wired" elements of the port
519 585 * event structure. This is normally being used just after the allocation
520 586 * of the port event structure.
521 587 * pkevp : pointer to the port event structure
522 588 * object : object associated with this event structure
523 589 * user : user defined pointer delivered with the association function
524 590 * port_callback:
525 591 * Address of the callback function which will be called
526 592 * - just before the event is delivered to the application.
527 593 * The callback function is called in user context and can be
528 594 * used for copyouts, e.g.
529 595 * - on close() or dissociation of the event. The sub-system
530 596 * must remove immediately every existing association of
531 597 * some object with this event.
532 598 * sysarg : event source propietary data
533 599 */
534 600 void
535 601 port_init_event(port_kevent_t *pkevp, uintptr_t object, void *user,
536 602 int (*port_callback)(void *, int *, pid_t, int, void *),
537 603 void *sysarg)
538 604 {
539 605 pkevp->portkev_object = object;
540 606 pkevp->portkev_user = user;
541 607 pkevp->portkev_callback = port_callback;
542 608 pkevp->portkev_arg = sysarg;
543 609 }
544 610
545 611 /*
546 612 * This routine removes a portfd_t from the fd cache's hash table.
547 613 */
548 614 void
549 615 port_pcache_remove_fd(port_fdcache_t *pcp, portfd_t *pfd)
550 616 {
551 617 polldat_t *lpdp;
552 618 polldat_t *cpdp;
553 619 portfd_t **bucket;
554 620 polldat_t *pdp = PFTOD(pfd);
555 621
556 622 ASSERT(MUTEX_HELD(&pcp->pc_lock));
557 623 bucket = PORT_FD_BUCKET(pcp, pdp->pd_fd);
558 624 cpdp = PFTOD(*bucket);
559 625 if (pdp == cpdp) {
560 626 *bucket = PDTOF(pdp->pd_hashnext);
561 627 if (--pcp->pc_fdcount == 0) {
562 628 /*
563 629 * signal the thread which may have blocked in
564 630 * port_close_sourcefd() on lastclose waiting
565 631 * for pc_fdcount to drop to 0.
566 632 */
567 633 cv_signal(&pcp->pc_lclosecv);
568 634 }
569 635 kmem_free(pfd, sizeof (portfd_t));
570 636 return;
571 637 }
572 638
573 639 while (cpdp != NULL) {
574 640 lpdp = cpdp;
575 641 cpdp = cpdp->pd_hashnext;
576 642 if (cpdp == pdp) {
577 643 /* polldat struct found */
578 644 lpdp->pd_hashnext = pdp->pd_hashnext;
579 645 if (--pcp->pc_fdcount == 0) {
580 646 /*
581 647 * signal the thread which may have blocked in
582 648 * port_close_sourcefd() on lastclose waiting
583 649 * for pc_fdcount to drop to 0.
584 650 */
585 651 cv_signal(&pcp->pc_lclosecv);
586 652 }
587 653 break;
588 654 }
589 655 }
590 656 ASSERT(cpdp != NULL);
591 657 kmem_free(pfd, sizeof (portfd_t));
592 658 }
593 659
594 660 /*
595 661 * The port_push_eventq() function is used to move all remaining events
596 662 * from the temporary queue used in port_get(n)() to the standard port
597 663 * queue.
598 664 */
599 665 void
600 666 port_push_eventq(port_queue_t *portq)
601 667 {
602 668 /*
603 669 * Append temporary portq_get_list to the port queue. On return
604 670 * the temporary portq_get_list is empty.
605 671 */
606 672 list_move_tail(&portq->portq_list, &portq->portq_get_list);
607 673 portq->portq_nent += portq->portq_tnent;
608 674 portq->portq_tnent = 0;
609 675 }
610 676
611 677 /*
612 678 * The port_remove_fd_object() function frees all resources associated with
613 679 * delivered portfd_t structure. Returns 1 if the port_kevent was found
614 680 * and removed from the port queue.
615 681 */
616 682 int
617 683 port_remove_fd_object(portfd_t *pfd, port_t *pp, port_fdcache_t *pcp)
618 684 {
619 685 port_queue_t *portq;
620 686 polldat_t *pdp = PFTOD(pfd);
621 687 port_kevent_t *pkevp;
622 688 int error;
623 689 int removed = 0;
624 690
625 691 ASSERT(MUTEX_HELD(&pcp->pc_lock));
626 692 if (pdp->pd_php != NULL) {
627 693 pollhead_delete(pdp->pd_php, pdp);
628 694 pdp->pd_php = NULL;
629 695 }
630 696 pkevp = pdp->pd_portev;
631 697 portq = &pp->port_queue;
632 698 mutex_enter(&portq->portq_mutex);
633 699 port_block(portq);
634 700 if (pkevp->portkev_flags & PORT_KEV_DONEQ) {
635 701 if (portq->portq_getn && portq->portq_tnent) {
636 702 /*
637 703 * move events from the temporary "get" queue
638 704 * back to the port queue
639 705 */
640 706 port_push_eventq(portq);
641 707 }
642 708 /* cleanup merged port queue */
|
↓ open down ↓ |
126 lines elided |
↑ open up ↑ |
643 709 port_remove_event_doneq(pkevp, portq);
644 710 removed = 1;
645 711 }
646 712 port_unblock(portq);
647 713 mutex_exit(&portq->portq_mutex);
648 714 if (pkevp->portkev_callback) {
649 715 (void) (*pkevp->portkev_callback)(pkevp->portkev_arg,
650 716 &error, pkevp->portkev_pid, PORT_CALLBACK_DISSOCIATE,
651 717 pkevp);
652 718 }
653 - port_free_event_local(pkevp, 0);
719 + port_free_event_local(pkevp, B_TRUE);
654 720
655 721 /* remove polldat struct */
656 722 port_pcache_remove_fd(pcp, pfd);
657 723 return (removed);
658 724 }
659 725
660 726 /*
661 727 * The port_close_fd() function dissociates a file descriptor from a port
662 728 * and removes all allocated resources.
663 729 * close(2) detects in the uf_entry_t structure that the fd is associated
664 730 * with a port (at least one port).
665 731 * The fd can be associated with several ports.
666 732 */
667 733 void
668 734 port_close_pfd(portfd_t *pfd)
669 735 {
670 736 port_t *pp;
671 737 port_fdcache_t *pcp;
672 738
673 739 /*
674 740 * the portfd_t passed in should be for this proc.
675 741 */
676 742 ASSERT(curproc->p_pid == PFTOD(pfd)->pd_portev->portkev_pid);
677 743 pp = PFTOD(pfd)->pd_portev->portkev_port;
678 744 pcp = pp->port_queue.portq_pcp;
679 745 mutex_enter(&pcp->pc_lock);
680 746 (void) port_remove_fd_object(pfd, pp, pcp);
681 747 mutex_exit(&pcp->pc_lock);
682 748 }
683 749
684 750 /*
685 751 * The port_associate_ksource() function associates an event source with a port.
686 752 * On port_close() all associated sources are requested to free all local
687 753 * resources associated with the event port.
688 754 * The association of a source with a port can only be done one time. Further
689 755 * calls of this function will only increment the reference counter.
690 756 * The allocated port_source_t structure is removed from the port as soon as
691 757 * the reference counter becomes 0.
692 758 */
693 759 /* ARGSUSED */
694 760 int
695 761 port_associate_ksource(int port, int source, port_source_t **portsrc,
696 762 void (*port_src_close)(void *, int, pid_t, int), void *arg,
697 763 int (*port_src_associate)(port_kevent_t *, int, int, uintptr_t, void *))
698 764 {
699 765 port_t *pp;
700 766 file_t *fp;
701 767 port_source_t **ps;
702 768 port_source_t *pse;
703 769
|
↓ open down ↓ |
40 lines elided |
↑ open up ↑ |
704 770 if ((fp = getf(port)) == NULL)
705 771 return (EBADF);
706 772
707 773 if (fp->f_vnode->v_type != VPORT) {
708 774 releasef(port);
709 775 return (EBADFD);
710 776 }
711 777 pp = VTOEP(fp->f_vnode);
712 778
713 779 mutex_enter(&pp->port_queue.portq_source_mutex);
780 + if (pp->port_queue.portq_scache == NULL) {
781 + /*
782 + * This event-port is mid-close.
783 + * By the time portq_scache is freed, PORTQ_CLOSE was set.
784 + */
785 + ASSERT(pp->port_queue.portq_flags & PORTQ_CLOSE);
786 + mutex_exit(&pp->port_queue.portq_source_mutex);
787 + releasef(port);
788 + /* Equivalent of a bad file descriptor at this point. */
789 + return (EBADFD);
790 + }
714 791 ps = &pp->port_queue.portq_scache[PORT_SHASH(source)];
715 792 for (pse = *ps; pse != NULL; pse = pse->portsrc_next) {
716 793 if (pse->portsrc_source == source)
717 794 break;
718 795 }
719 796
720 797 if (pse == NULL) {
721 798 /* Create association of the event source with the port */
722 799 pse = kmem_zalloc(sizeof (port_source_t), KM_NOSLEEP);
723 800 if (pse == NULL) {
724 801 mutex_exit(&pp->port_queue.portq_source_mutex);
725 802 releasef(port);
726 803 return (ENOMEM);
727 804 }
728 805 pse->portsrc_source = source;
729 806 pse->portsrc_close = port_src_close;
730 807 pse->portsrc_closearg = arg;
731 808 pse->portsrc_cnt = 1;
732 809 if (*ps)
733 810 pse->portsrc_next = (*ps)->portsrc_next;
734 811 *ps = pse;
735 812 } else {
736 813 /* entry already available, source is only requesting count */
737 814 pse->portsrc_cnt++;
738 815 }
739 816 mutex_exit(&pp->port_queue.portq_source_mutex);
740 817 releasef(port);
741 818 if (portsrc)
742 819 *portsrc = pse;
743 820 return (0);
744 821 }
745 822
746 823 /*
747 824 * The port_dissociate_ksource() function dissociates an event source from
748 825 * a port.
749 826 */
750 827 int
751 828 port_dissociate_ksource(int port, int source, port_source_t *ps)
752 829 {
753 830 port_t *pp;
754 831 file_t *fp;
755 832 port_source_t **psh;
756 833
757 834 if (ps == NULL)
758 835 return (EINVAL);
759 836
760 837 if ((fp = getf(port)) == NULL)
761 838 return (EBADF);
762 839
763 840 if (fp->f_vnode->v_type != VPORT) {
764 841 releasef(port);
765 842 return (EBADFD);
766 843 }
767 844 pp = VTOEP(fp->f_vnode);
768 845
769 846 mutex_enter(&pp->port_queue.portq_source_mutex);
770 847 if (--ps->portsrc_cnt == 0) {
771 848 /* last association removed -> free source structure */
772 849 if (ps->portsrc_prev == NULL) {
773 850 /* first entry */
774 851 psh = &pp->port_queue.portq_scache[PORT_SHASH(source)];
775 852 *psh = ps->portsrc_next;
776 853 if (ps->portsrc_next)
777 854 ps->portsrc_next->portsrc_prev = NULL;
778 855 } else {
779 856 ps->portsrc_prev->portsrc_next = ps->portsrc_next;
780 857 if (ps->portsrc_next)
781 858 ps->portsrc_next->portsrc_prev =
782 859 ps->portsrc_prev;
783 860 }
784 861 kmem_free(ps, sizeof (port_source_t));
785 862 }
786 863 mutex_exit(&pp->port_queue.portq_source_mutex);
787 864 releasef(port);
788 865 return (0);
789 866 }
790 867
791 868 void
792 869 free_fopdata(vnode_t *vp)
793 870 {
794 871 portfop_vp_t *pvp;
795 872 pvp = vp->v_fopdata;
796 873 ASSERT(pvp->pvp_femp == NULL);
797 874 mutex_destroy(&pvp->pvp_mutex);
798 875 list_destroy(&pvp->pvp_pfoplist);
799 876 kmem_free(pvp, sizeof (*pvp));
800 877 vp->v_fopdata = NULL;
801 878 }
|
↓ open down ↓ |
78 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX