Print this page
cleanup port_free_event_local() semantics
XXXXX race between closef(portfd) and timer_delete()


   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;