/* ARGSUSED */ static int port_fd_callback(void *arg, int *events, pid_t pid, int flag, void *evp) { portfd_t *pfd = (portfd_t *)arg; polldat_t *pdp = PFTOD(pfd); port_fdcache_t *pcp; file_t *fp; int error; ASSERT((pdp != NULL) && (events != NULL)); switch (flag) { case PORT_CALLBACK_DEFAULT: if (curproc->p_pid != pid) { /* * Check if current process is allowed to retrieve * events from this fd. */ fp = getf(pdp->pd_fd); if (fp == NULL) { error = EACCES; /* deny delivery of events */ break; } releasef(pdp->pd_fd); if (fp != pdp->pd_fp) { error = EACCES; /* deny delivery of events */ break; } } *events = pdp->pd_portev->portkev_events; /* update events */ error = 0; break; case PORT_CALLBACK_DISSOCIATE: error = 0; break; case PORT_CALLBACK_CLOSE: /* remove polldat/portfd struct */ pdp->pd_portev = NULL; pcp = (port_fdcache_t *)pdp->pd_pcache; mutex_enter(&pcp->pc_lock); pdp->pd_fp = NULL; pdp->pd_events = 0; if (pdp->pd_php != NULL) { pollhead_delete(pdp->pd_php, pdp); pdp->pd_php = NULL; } port_pcache_remove_fd(pcp, pfd); mutex_exit(&pcp->pc_lock); error = 0; break; default: error = EINVAL; break; } return (error); }
/* * Remove the fd from the event port cache. */ static void port_remove_fd_local(portfd_t *pfd, port_fdcache_t *pcp) { polldat_t *pdp = PFTOD(pfd); ASSERT(MUTEX_HELD(&pcp->pc_lock)); pdp->pd_fp = NULL; if (pdp->pd_php != NULL) { pollhead_delete(pdp->pd_php, pdp); pdp->pd_php = NULL; } port_free_event_local(pdp->pd_portev, 0); /* remove polldat struct */ port_pcache_remove_fd(pcp, pfd); }
/* * The port_remove_fd_object() function frees all resources associated with * delivered portfd_t structure. Returns 1 if the port_kevent was found * and removed from the port queue. */ int port_remove_fd_object(portfd_t *pfd, port_t *pp, port_fdcache_t *pcp) { port_queue_t *portq; polldat_t *pdp = PFTOD(pfd); port_kevent_t *pkevp; int error; int removed = 0; ASSERT(MUTEX_HELD(&pcp->pc_lock)); if (pdp->pd_php != NULL) { pollhead_delete(pdp->pd_php, pdp); pdp->pd_php = NULL; } pkevp = pdp->pd_portev; portq = &pp->port_queue; mutex_enter(&portq->portq_mutex); port_block(portq); if (pkevp->portkev_flags & PORT_KEV_DONEQ) { if (portq->portq_getn && portq->portq_tnent) { /* * move events from the temporary "get" queue * back to the port queue */ port_push_eventq(portq); } /* cleanup merged port queue */ port_remove_event_doneq(pkevp, portq); removed = 1; } port_unblock(portq); mutex_exit(&portq->portq_mutex); if (pkevp->portkev_callback) { (void) (*pkevp->portkev_callback)(pkevp->portkev_arg, &error, pkevp->portkev_pid, PORT_CALLBACK_DISSOCIATE, pkevp); } port_free_event_local(pkevp, 0); /* remove polldat struct */ port_pcache_remove_fd(pcp, pfd); return (removed); }
/* * Associate event port polldat_t structure with sub-system pointer to * a polhead_t structure. */ static int port_bind_pollhead(pollhead_t **php, polldat_t *pdp, short *revents) { int error; file_t *fp; /* * During re-association of a fd with a port the pd_php pointer * is still the same as at the first association time. */ if (pdp->pd_php == *php) return (0); /* already associated */ /* polldat_t associated with another pollhead_t pointer */ if (pdp->pd_php != NULL) pollhead_delete(pdp->pd_php, pdp); /* * Before pollhead_insert() pollwakeup() will not detect a polldat * entry in the ph_list and the event notification will disappear. * This happens because polldat_t is still not associated with * the pointer to the pollhead_t structure. */ pollhead_insert(*php, pdp); /* * From now on event notification can be detected in pollwakeup(), * Use VOP_POLL() again to check the current status of the event. */ pdp->pd_php = *php; fp = pdp->pd_fp; curthread->t_pollcache = (pollcache_t *)pdp->pd_pcache; error = VOP_POLL(fp->f_vnode, pdp->pd_events, 0, revents, php); curthread->t_pollcache = NULL; return (error); }