7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * This file containts all the functions required for interactions of
31 * event sources with the event port file system.
32 */
33
34 #include <sys/types.h>
35 #include <sys/conf.h>
36 #include <sys/stat.h>
37 #include <sys/errno.h>
38 #include <sys/kmem.h>
39 #include <sys/debug.h>
40 #include <sys/file.h>
41 #include <sys/sysmacros.h>
42 #include <sys/systm.h>
43 #include <sys/bitmap.h>
44 #include <sys/rctl.h>
45 #include <sys/atomic.h>
46 #include <sys/poll_impl.h>
47 #include <sys/port_impl.h>
187 if (portq->portq_thread &&
188 (portq->portq_nent >= portq->portq_nget))
189 cv_signal(&portq->portq_thread->portget_cv);
190 }
191
192 /*
193 * If some thread is polling the port's fd, then notify it.
194 * For PORT_SOURCE_FD source, we don't need to call pollwakeup()
195 * here as it will result in a recursive call(PORT_SOURCE_FD source
196 * is pollwakeup()). Therefore pollwakeup() itself will notify the
197 * ports if being polled.
198 */
199 if (pkevp->portkev_source != PORT_SOURCE_FD &&
200 portq->portq_flags & PORTQ_POLLIN) {
201 port_t *pp;
202
203 portq->portq_flags &= ~PORTQ_POLLIN;
204 /*
205 * Need to save port_t for calling pollwakeup since port_getn()
206 * may end up freeing pkevp once portq_mutex is dropped.
207 */
208 pp = pkevp->portkev_port;
209 mutex_exit(&portq->portq_mutex);
210 pollwakeup(&pp->port_pollhd, POLLIN);
211 } else {
212 mutex_exit(&portq->portq_mutex);
213 }
214 }
215
216 /*
217 * The port_alloc_event() function has to be used by all event sources
218 * to request an slot for event notification.
219 * The slot reservation could be denied because of lack of resources.
220 * For that reason the event source should allocate an event slot as early
221 * as possible and be prepared to get an error code instead of the
222 * port event pointer.
223 * Al current event sources allocate an event slot during a system call
224 * entry. They return an error code to the application if an event slot
225 * could not be reserved.
226 * It is also recommended to associate the event source with the port
227 * before some other port function is used.
228 * The port argument is a file descriptor obtained by the application as
229 * a return value of port_create().
233 * type of event structures as soon as the events are delivered to the
234 * application.
235 * PORT_ALLOC_PRIVATE
236 * This type of event will be use for private use of the event source.
237 * The port_get(n) function will deliver events of such an structure to
238 * the application but it will not free the event structure itself.
239 * The event source must free this structure using port_free_event().
240 * PORT_ALLOC_CACHED
241 * This type of events is used when the event source helds an own
242 * cache.
243 * The port_get(n) function will deliver events of such an structure to
244 * the application but it will not free the event structure itself.
245 * The event source must free this structure using port_free_event().
246 */
247 int
248 port_alloc_event(int port, int flags, int source, port_kevent_t **pkevpp)
249 {
250 port_t *pp;
251 file_t *fp;
252 port_kevent_t *pkevp;
253
254 if ((fp = getf(port)) == NULL)
255 return (EBADF);
256
257 if (fp->f_vnode->v_type != VPORT) {
258 releasef(port);
259 return (EBADFD);
260 }
261
262 pkevp = kmem_cache_alloc(port_control.pc_cache, KM_NOSLEEP);
263 if (pkevp == NULL) {
264 releasef(port);
265 return (ENOMEM);
266 }
267
268 /*
269 * port_max_events is controlled by the resource control
270 * process.port-max-events
271 */
272 pp = VTOEP(fp->f_vnode);
273 mutex_enter(&pp->port_queue.portq_mutex);
274 if (pp->port_curr >= pp->port_max_events) {
275 mutex_exit(&pp->port_queue.portq_mutex);
276 kmem_cache_free(port_control.pc_cache, pkevp);
277 releasef(port);
278 return (EAGAIN);
279 }
280 pp->port_curr++;
281 mutex_exit(&pp->port_queue.portq_mutex);
282
283 bzero(pkevp, sizeof (port_kevent_t));
284 mutex_init(&pkevp->portkev_lock, NULL, MUTEX_DEFAULT, NULL);
285 pkevp->portkev_source = source;
286 pkevp->portkev_flags = flags;
287 pkevp->portkev_pid = curproc->p_pid;
288 pkevp->portkev_port = pp;
289 *pkevpp = pkevp;
290 releasef(port);
291 return (0);
292 }
293
294 /*
295 * This function is faster than the standard port_alloc_event() and
296 * can be used when the event source already allocated an event from
297 * a port.
298 */
302 int error;
303
304 error = port_alloc_event_local(pkevp->portkev_port,
305 pkevp->portkev_source, flags, pkevdupp);
306 if (error == 0)
307 (*pkevdupp)->portkev_pid = pkevp->portkev_pid;
308 return (error);
309 }
310
311 /*
312 * port_alloc_event_local() is reserved for internal use only.
313 * It is doing the same job as port_alloc_event() but with the event port
314 * pointer as the first argument.
315 * The check of the validity of the port file descriptor is skipped here.
316 */
317 int
318 port_alloc_event_local(port_t *pp, int source, int flags,
319 port_kevent_t **pkevpp)
320 {
321 port_kevent_t *pkevp;
322
323 pkevp = kmem_cache_alloc(port_control.pc_cache, KM_NOSLEEP);
324 if (pkevp == NULL)
325 return (ENOMEM);
326
327 mutex_enter(&pp->port_queue.portq_mutex);
328 if (pp->port_curr >= pp->port_max_events) {
329 mutex_exit(&pp->port_queue.portq_mutex);
330 kmem_cache_free(port_control.pc_cache, pkevp);
331 return (EAGAIN);
332 }
333 pp->port_curr++;
334 mutex_exit(&pp->port_queue.portq_mutex);
335
336 bzero(pkevp, sizeof (port_kevent_t));
337 mutex_init(&pkevp->portkev_lock, NULL, MUTEX_DEFAULT, NULL);
338 pkevp->portkev_flags = flags;
339 pkevp->portkev_port = pp;
340 pkevp->portkev_source = source;
341 pkevp->portkev_pid = curproc->p_pid;
342 *pkevpp = pkevp;
343 return (0);
344 }
345
346 /*
347 * port_alloc_event_block() has the same functionality of port_alloc_event() +
348 * - it blocks if not enough event slots are available and
349 * - it blocks if not enough memory is available.
350 * Currently port_dispatch() is using this function to increase the
351 * reliability of event delivery for library event sources.
352 */
353 int
354 port_alloc_event_block(port_t *pp, int source, int flags,
355 port_kevent_t **pkevpp)
356 {
357 port_kevent_t *pkevp =
358 kmem_cache_alloc(port_control.pc_cache, KM_SLEEP);
359
360 mutex_enter(&pp->port_queue.portq_mutex);
361 while (pp->port_curr >= pp->port_max_events) {
362 if (!cv_wait_sig(&pp->port_cv, &pp->port_queue.portq_mutex)) {
363 /* signal detected */
364 mutex_exit(&pp->port_queue.portq_mutex);
365 kmem_cache_free(port_control.pc_cache, pkevp);
366 return (EINTR);
367 }
368 }
369 pp->port_curr++;
370 mutex_exit(&pp->port_queue.portq_mutex);
371
372 bzero(pkevp, sizeof (port_kevent_t));
373 mutex_init(&pkevp->portkev_lock, NULL, MUTEX_DEFAULT, NULL);
374 pkevp->portkev_flags = flags;
375 pkevp->portkev_port = pp;
376 pkevp->portkev_source = source;
377 pkevp->portkev_pid = curproc->p_pid;
378 *pkevpp = pkevp;
379 return (0);
380 }
381
382 /*
383 * Take an event out of the port queue
384 */
385 static void
386 port_remove_event_doneq(port_kevent_t *pkevp, port_queue_t *portq)
387 {
388 ASSERT(MUTEX_HELD(&portq->portq_mutex));
425 mutex_exit(&portq->portq_mutex);
426 return (removed);
427 }
428
429 /*
430 * Return port event back to the kmem_cache.
431 * If the event is currently in the port queue the event itself will only
432 * be set as invalid. The port_get(n) function will not deliver such events
433 * to the application and it will return them back to the kmem_cache.
434 */
435 void
436 port_free_event(port_kevent_t *pkevp)
437 {
438 port_queue_t *portq;
439 port_t *pp;
440
441 pp = pkevp->portkev_port;
442 if (pp == NULL)
443 return;
444 if (pkevp->portkev_flags & PORT_ALLOC_PRIVATE) {
445 port_free_event_local(pkevp, 0);
446 return;
447 }
448
449 portq = &pp->port_queue;
450 mutex_enter(&portq->portq_mutex);
451 port_block(portq);
452 if (pkevp->portkev_flags & PORT_KEV_DONEQ) {
453 pkevp->portkev_flags |= PORT_KEV_FREE;
454 pkevp->portkev_callback = NULL;
455 port_unblock(portq);
456 mutex_exit(&portq->portq_mutex);
457 return;
458 }
459 port_unblock(portq);
460
461 if (pkevp->portkev_flags & PORT_KEV_CACHED) {
462 mutex_exit(&portq->portq_mutex);
463 return;
464 }
465
466 if (--pp->port_curr < pp->port_max_events)
467 cv_signal(&pp->port_cv);
468 if (portq->portq_flags & PORTQ_CLOSE) {
469 /*
470 * Another thread is closing the event port.
471 * That thread will sleep until all allocated event
472 * structures returned to the event port framework.
473 * The portq_mutex is used to synchronize the status
474 * of the allocated event structures (port_curr).
475 */
476 if (pp->port_curr <= portq->portq_nent)
477 cv_signal(&portq->portq_closecv);
478 }
479 mutex_exit(&portq->portq_mutex);
480 port_free_event_local(pkevp, 1);
481 }
482
483 /*
484 * This event port internal function is used by port_free_event() and
485 * other port internal functions to return event structures back to the
486 * kmem_cache.
487 */
488 void
489 port_free_event_local(port_kevent_t *pkevp, int counter)
490 {
491 port_t *pp = pkevp->portkev_port;
492 port_queue_t *portq = &pp->port_queue;
493 int wakeup;
494
495 pkevp->portkev_callback = NULL;
496 pkevp->portkev_flags = 0;
497 pkevp->portkev_port = NULL;
498 mutex_destroy(&pkevp->portkev_lock);
499 kmem_cache_free(port_control.pc_cache, pkevp);
500
501 mutex_enter(&portq->portq_mutex);
502 if (counter == 0) {
503 if (--pp->port_curr < pp->port_max_events)
504 cv_signal(&pp->port_cv);
505 }
506 wakeup = (portq->portq_flags & PORTQ_POLLOUT);
507 portq->portq_flags &= ~PORTQ_POLLOUT;
508 mutex_exit(&portq->portq_mutex);
509
510 /* Submit a POLLOUT event if requested */
511 if (wakeup)
512 pollwakeup(&pp->port_pollhd, POLLOUT);
513 }
514
515 /*
516 * port_init_event(port_event_t *pev, uintptr_t object, void *user,
517 * int (*port_callback)(void *, int *, pid_t, int, void *), void *sysarg);
518 * This function initializes most of the "wired" elements of the port
519 * event structure. This is normally being used just after the allocation
520 * of the port event structure.
521 * pkevp : pointer to the port event structure
522 * object : object associated with this event structure
523 * user : user defined pointer delivered with the association function
524 * port_callback:
525 * Address of the callback function which will be called
526 * - just before the event is delivered to the application.
633 port_block(portq);
634 if (pkevp->portkev_flags & PORT_KEV_DONEQ) {
635 if (portq->portq_getn && portq->portq_tnent) {
636 /*
637 * move events from the temporary "get" queue
638 * back to the port queue
639 */
640 port_push_eventq(portq);
641 }
642 /* cleanup merged port queue */
643 port_remove_event_doneq(pkevp, portq);
644 removed = 1;
645 }
646 port_unblock(portq);
647 mutex_exit(&portq->portq_mutex);
648 if (pkevp->portkev_callback) {
649 (void) (*pkevp->portkev_callback)(pkevp->portkev_arg,
650 &error, pkevp->portkev_pid, PORT_CALLBACK_DISSOCIATE,
651 pkevp);
652 }
653 port_free_event_local(pkevp, 0);
654
655 /* remove polldat struct */
656 port_pcache_remove_fd(pcp, pfd);
657 return (removed);
658 }
659
660 /*
661 * The port_close_fd() function dissociates a file descriptor from a port
662 * and removes all allocated resources.
663 * close(2) detects in the uf_entry_t structure that the fd is associated
664 * with a port (at least one port).
665 * The fd can be associated with several ports.
666 */
667 void
668 port_close_pfd(portfd_t *pfd)
669 {
670 port_t *pp;
671 port_fdcache_t *pcp;
672
673 /*
694 int
695 port_associate_ksource(int port, int source, port_source_t **portsrc,
696 void (*port_src_close)(void *, int, pid_t, int), void *arg,
697 int (*port_src_associate)(port_kevent_t *, int, int, uintptr_t, void *))
698 {
699 port_t *pp;
700 file_t *fp;
701 port_source_t **ps;
702 port_source_t *pse;
703
704 if ((fp = getf(port)) == NULL)
705 return (EBADF);
706
707 if (fp->f_vnode->v_type != VPORT) {
708 releasef(port);
709 return (EBADFD);
710 }
711 pp = VTOEP(fp->f_vnode);
712
713 mutex_enter(&pp->port_queue.portq_source_mutex);
714 ps = &pp->port_queue.portq_scache[PORT_SHASH(source)];
715 for (pse = *ps; pse != NULL; pse = pse->portsrc_next) {
716 if (pse->portsrc_source == source)
717 break;
718 }
719
720 if (pse == NULL) {
721 /* Create association of the event source with the port */
722 pse = kmem_zalloc(sizeof (port_source_t), KM_NOSLEEP);
723 if (pse == NULL) {
724 mutex_exit(&pp->port_queue.portq_source_mutex);
725 releasef(port);
726 return (ENOMEM);
727 }
728 pse->portsrc_source = source;
729 pse->portsrc_close = port_src_close;
730 pse->portsrc_closearg = arg;
731 pse->portsrc_cnt = 1;
732 if (*ps)
733 pse->portsrc_next = (*ps)->portsrc_next;
|
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright 2020 Joyent, Inc.
29 */
30
31 /*
32 * This file containts all the functions required for interactions of
33 * event sources with the event port file system.
34 */
35
36 #include <sys/types.h>
37 #include <sys/conf.h>
38 #include <sys/stat.h>
39 #include <sys/errno.h>
40 #include <sys/kmem.h>
41 #include <sys/debug.h>
42 #include <sys/file.h>
43 #include <sys/sysmacros.h>
44 #include <sys/systm.h>
45 #include <sys/bitmap.h>
46 #include <sys/rctl.h>
47 #include <sys/atomic.h>
48 #include <sys/poll_impl.h>
49 #include <sys/port_impl.h>
189 if (portq->portq_thread &&
190 (portq->portq_nent >= portq->portq_nget))
191 cv_signal(&portq->portq_thread->portget_cv);
192 }
193
194 /*
195 * If some thread is polling the port's fd, then notify it.
196 * For PORT_SOURCE_FD source, we don't need to call pollwakeup()
197 * here as it will result in a recursive call(PORT_SOURCE_FD source
198 * is pollwakeup()). Therefore pollwakeup() itself will notify the
199 * ports if being polled.
200 */
201 if (pkevp->portkev_source != PORT_SOURCE_FD &&
202 portq->portq_flags & PORTQ_POLLIN) {
203 port_t *pp;
204
205 portq->portq_flags &= ~PORTQ_POLLIN;
206 /*
207 * Need to save port_t for calling pollwakeup since port_getn()
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.
212 */
213 pp = (portq->portq_flags & PORTQ_CLOSE) ?
214 NULL : pkevp->portkev_port;
215 mutex_exit(&portq->portq_mutex);
216 if (pp != NULL)
217 pollwakeup(&pp->port_pollhd, POLLIN);
218 } else {
219 mutex_exit(&portq->portq_mutex);
220 }
221 }
222
223 /*
224 * The port_alloc_event() function has to be used by all event sources
225 * to request an slot for event notification.
226 * The slot reservation could be denied because of lack of resources.
227 * For that reason the event source should allocate an event slot as early
228 * as possible and be prepared to get an error code instead of the
229 * port event pointer.
230 * Al current event sources allocate an event slot during a system call
231 * entry. They return an error code to the application if an event slot
232 * could not be reserved.
233 * It is also recommended to associate the event source with the port
234 * before some other port function is used.
235 * The port argument is a file descriptor obtained by the application as
236 * a return value of port_create().
240 * type of event structures as soon as the events are delivered to the
241 * application.
242 * PORT_ALLOC_PRIVATE
243 * This type of event will be use for private use of the event source.
244 * The port_get(n) function will deliver events of such an structure to
245 * the application but it will not free the event structure itself.
246 * The event source must free this structure using port_free_event().
247 * PORT_ALLOC_CACHED
248 * This type of events is used when the event source helds an own
249 * cache.
250 * The port_get(n) function will deliver events of such an structure to
251 * the application but it will not free the event structure itself.
252 * The event source must free this structure using port_free_event().
253 */
254 int
255 port_alloc_event(int port, int flags, int source, port_kevent_t **pkevpp)
256 {
257 port_t *pp;
258 file_t *fp;
259 port_kevent_t *pkevp;
260 int err;
261
262 if ((fp = getf(port)) == NULL)
263 return (EBADF);
264
265 if (fp->f_vnode->v_type != VPORT) {
266 releasef(port);
267 return (EBADFD);
268 }
269
270 pkevp = kmem_cache_alloc(port_control.pc_cache, KM_NOSLEEP);
271 if (pkevp == NULL) {
272 releasef(port);
273 return (ENOMEM);
274 }
275
276 /*
277 * port_max_events is controlled by the resource control
278 * process.port-max-events
279 */
280 pp = VTOEP(fp->f_vnode);
281 mutex_enter(&pp->port_queue.portq_mutex);
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) {
292 mutex_exit(&pp->port_queue.portq_mutex);
293 kmem_cache_free(port_control.pc_cache, pkevp);
294 releasef(port);
295 return (err);
296 }
297 pp->port_curr++;
298 mutex_exit(&pp->port_queue.portq_mutex);
299
300 bzero(pkevp, sizeof (port_kevent_t));
301 mutex_init(&pkevp->portkev_lock, NULL, MUTEX_DEFAULT, NULL);
302 pkevp->portkev_source = source;
303 pkevp->portkev_flags = flags;
304 pkevp->portkev_pid = curproc->p_pid;
305 pkevp->portkev_port = pp;
306 *pkevpp = pkevp;
307 releasef(port);
308 return (0);
309 }
310
311 /*
312 * This function is faster than the standard port_alloc_event() and
313 * can be used when the event source already allocated an event from
314 * a port.
315 */
319 int error;
320
321 error = port_alloc_event_local(pkevp->portkev_port,
322 pkevp->portkev_source, flags, pkevdupp);
323 if (error == 0)
324 (*pkevdupp)->portkev_pid = pkevp->portkev_pid;
325 return (error);
326 }
327
328 /*
329 * port_alloc_event_local() is reserved for internal use only.
330 * It is doing the same job as port_alloc_event() but with the event port
331 * pointer as the first argument.
332 * The check of the validity of the port file descriptor is skipped here.
333 */
334 int
335 port_alloc_event_local(port_t *pp, int source, int flags,
336 port_kevent_t **pkevpp)
337 {
338 port_kevent_t *pkevp;
339 int err;
340
341 pkevp = kmem_cache_alloc(port_control.pc_cache, KM_NOSLEEP);
342 if (pkevp == NULL)
343 return (ENOMEM);
344
345 mutex_enter(&pp->port_queue.portq_mutex);
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) {
356 mutex_exit(&pp->port_queue.portq_mutex);
357 kmem_cache_free(port_control.pc_cache, pkevp);
358 return (err);
359 }
360 pp->port_curr++;
361 mutex_exit(&pp->port_queue.portq_mutex);
362
363 bzero(pkevp, sizeof (port_kevent_t));
364 mutex_init(&pkevp->portkev_lock, NULL, MUTEX_DEFAULT, NULL);
365 pkevp->portkev_flags = flags;
366 pkevp->portkev_port = pp;
367 pkevp->portkev_source = source;
368 pkevp->portkev_pid = curproc->p_pid;
369 *pkevpp = pkevp;
370 return (0);
371 }
372
373 /*
374 * port_alloc_event_block() has the same functionality of port_alloc_event() +
375 * - it blocks if not enough event slots are available and
376 * - it blocks if not enough memory is available.
377 * Currently port_dispatch() is using this function to increase the
378 * reliability of event delivery for library event sources.
379 */
380 int
381 port_alloc_event_block(port_t *pp, int source, int flags,
382 port_kevent_t **pkevpp)
383 {
384 port_kevent_t *pkevp =
385 kmem_cache_alloc(port_control.pc_cache, KM_SLEEP);
386
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
398 while (pp->port_curr >= pp->port_max_events) {
399 if (!cv_wait_sig(&pp->port_cv, &pp->port_queue.portq_mutex)) {
400 /* signal detected */
401 mutex_exit(&pp->port_queue.portq_mutex);
402 kmem_cache_free(port_control.pc_cache, pkevp);
403 return (EINTR);
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 }
412 }
413 pp->port_curr++;
414 mutex_exit(&pp->port_queue.portq_mutex);
415
416 bzero(pkevp, sizeof (port_kevent_t));
417 mutex_init(&pkevp->portkev_lock, NULL, MUTEX_DEFAULT, NULL);
418 pkevp->portkev_flags = flags;
419 pkevp->portkev_port = pp;
420 pkevp->portkev_source = source;
421 pkevp->portkev_pid = curproc->p_pid;
422 *pkevpp = pkevp;
423 return (0);
424 }
425
426 /*
427 * Take an event out of the port queue
428 */
429 static void
430 port_remove_event_doneq(port_kevent_t *pkevp, port_queue_t *portq)
431 {
432 ASSERT(MUTEX_HELD(&portq->portq_mutex));
469 mutex_exit(&portq->portq_mutex);
470 return (removed);
471 }
472
473 /*
474 * Return port event back to the kmem_cache.
475 * If the event is currently in the port queue the event itself will only
476 * be set as invalid. The port_get(n) function will not deliver such events
477 * to the application and it will return them back to the kmem_cache.
478 */
479 void
480 port_free_event(port_kevent_t *pkevp)
481 {
482 port_queue_t *portq;
483 port_t *pp;
484
485 pp = pkevp->portkev_port;
486 if (pp == NULL)
487 return;
488 if (pkevp->portkev_flags & PORT_ALLOC_PRIVATE) {
489 port_free_event_local(pkevp, B_TRUE);
490 return;
491 }
492
493 portq = &pp->port_queue;
494 mutex_enter(&portq->portq_mutex);
495 port_block(portq);
496 if (pkevp->portkev_flags & PORT_KEV_DONEQ) {
497 pkevp->portkev_flags |= PORT_KEV_FREE;
498 pkevp->portkev_callback = NULL;
499 port_unblock(portq);
500 mutex_exit(&portq->portq_mutex);
501 return;
502 }
503 port_unblock(portq);
504
505 if (pkevp->portkev_flags & PORT_KEV_CACHED) {
506 mutex_exit(&portq->portq_mutex);
507 return;
508 }
509
510 if (--pp->port_curr < pp->port_max_events)
511 cv_signal(&pp->port_cv);
512 if (portq->portq_flags & PORTQ_CLOSE) {
513 /*
514 * Another thread is closing the event port.
515 * That thread will sleep until all allocated event
516 * structures returned to the event port framework.
517 * The portq_mutex is used to synchronize the status
518 * of the allocated event structures (port_curr).
519 */
520 if (pp->port_curr <= portq->portq_nent)
521 cv_signal(&portq->portq_closecv);
522 }
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);
529 }
530
531 /*
532 * This event port internal function is used by port_free_event() and
533 * other port internal functions to return event structures back to the
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.
539 */
540 void
541 port_free_event_local(port_kevent_t *pkevp, boolean_t lock_and_decrement)
542 {
543 port_t *pp = pkevp->portkev_port;
544 port_queue_t *portq = &pp->port_queue;
545 int wakeup;
546
547 pkevp->portkev_callback = NULL;
548 pkevp->portkev_flags = 0;
549 pkevp->portkev_port = NULL;
550 mutex_destroy(&pkevp->portkev_lock);
551 kmem_cache_free(port_control.pc_cache, pkevp);
552
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);
560 if (--pp->port_curr < pp->port_max_events)
561 cv_signal(&pp->port_cv);
562 }
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);
573 portq->portq_flags &= ~PORTQ_POLLOUT;
574 mutex_exit(&portq->portq_mutex);
575
576 /* Submit a POLLOUT event if requested */
577 if (wakeup)
578 pollwakeup(&pp->port_pollhd, POLLOUT);
579 }
580
581 /*
582 * port_init_event(port_event_t *pev, uintptr_t object, void *user,
583 * int (*port_callback)(void *, int *, pid_t, int, void *), void *sysarg);
584 * This function initializes most of the "wired" elements of the port
585 * event structure. This is normally being used just after the allocation
586 * of the port event structure.
587 * pkevp : pointer to the port event structure
588 * object : object associated with this event structure
589 * user : user defined pointer delivered with the association function
590 * port_callback:
591 * Address of the callback function which will be called
592 * - just before the event is delivered to the application.
699 port_block(portq);
700 if (pkevp->portkev_flags & PORT_KEV_DONEQ) {
701 if (portq->portq_getn && portq->portq_tnent) {
702 /*
703 * move events from the temporary "get" queue
704 * back to the port queue
705 */
706 port_push_eventq(portq);
707 }
708 /* cleanup merged port queue */
709 port_remove_event_doneq(pkevp, portq);
710 removed = 1;
711 }
712 port_unblock(portq);
713 mutex_exit(&portq->portq_mutex);
714 if (pkevp->portkev_callback) {
715 (void) (*pkevp->portkev_callback)(pkevp->portkev_arg,
716 &error, pkevp->portkev_pid, PORT_CALLBACK_DISSOCIATE,
717 pkevp);
718 }
719 port_free_event_local(pkevp, B_TRUE);
720
721 /* remove polldat struct */
722 port_pcache_remove_fd(pcp, pfd);
723 return (removed);
724 }
725
726 /*
727 * The port_close_fd() function dissociates a file descriptor from a port
728 * and removes all allocated resources.
729 * close(2) detects in the uf_entry_t structure that the fd is associated
730 * with a port (at least one port).
731 * The fd can be associated with several ports.
732 */
733 void
734 port_close_pfd(portfd_t *pfd)
735 {
736 port_t *pp;
737 port_fdcache_t *pcp;
738
739 /*
760 int
761 port_associate_ksource(int port, int source, port_source_t **portsrc,
762 void (*port_src_close)(void *, int, pid_t, int), void *arg,
763 int (*port_src_associate)(port_kevent_t *, int, int, uintptr_t, void *))
764 {
765 port_t *pp;
766 file_t *fp;
767 port_source_t **ps;
768 port_source_t *pse;
769
770 if ((fp = getf(port)) == NULL)
771 return (EBADF);
772
773 if (fp->f_vnode->v_type != VPORT) {
774 releasef(port);
775 return (EBADFD);
776 }
777 pp = VTOEP(fp->f_vnode);
778
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 }
791 ps = &pp->port_queue.portq_scache[PORT_SHASH(source)];
792 for (pse = *ps; pse != NULL; pse = pse->portsrc_next) {
793 if (pse->portsrc_source == source)
794 break;
795 }
796
797 if (pse == NULL) {
798 /* Create association of the event source with the port */
799 pse = kmem_zalloc(sizeof (port_source_t), KM_NOSLEEP);
800 if (pse == NULL) {
801 mutex_exit(&pp->port_queue.portq_source_mutex);
802 releasef(port);
803 return (ENOMEM);
804 }
805 pse->portsrc_source = source;
806 pse->portsrc_close = port_src_close;
807 pse->portsrc_closearg = arg;
808 pse->portsrc_cnt = 1;
809 if (*ps)
810 pse->portsrc_next = (*ps)->portsrc_next;
|