static int nm_poll(vnode_t *vp, short events, int anyyet, short *reventsp, pollhead_t **phpp, caller_context_t *ct) { return (VOP_POLL(VTONM(vp)->nm_filevp, events, anyyet, reventsp, phpp, ct)); }
/*ARGSUSED*/ int cttypoll(dev_t dev, int events, struct proc *p) { struct vnode *ttyvp = cttyvp(p); if (ttyvp == NULL) /* try operation to get EOF/failure */ return (seltrue(dev, events, p)); return (VOP_POLL(ttyvp, events, p)); }
/*ARGSUSED*/ static int cttypoll(dev_t dev, int events, struct lwp *l) { struct vnode *ttyvp = cttyvp(l->l_proc); if (ttyvp == NULL) return (seltrue(dev, events, l)); return (VOP_POLL(ttyvp, events)); }
int RUMP_VOP_POLL(struct vnode *vp, int events) { int error; rump_schedule(); error = VOP_POLL(vp, events); rump_unschedule(); return error; }
static int unionfs_poll(void *v) { struct vop_poll_args *ap = v; struct unionfs_node *unp; struct unionfs_node_status *unsp; struct vnode *ovp; vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); unp = VTOUNIONFS(ap->a_vp); unionfs_get_node_status(unp, &unsp); ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); unionfs_tryrem_node_status(unp, unsp); VOP_UNLOCK(ap->a_vp); if (ovp == NULLVP) return (EBADF); return (VOP_POLL(ovp, ap->a_events)); }
/* * 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); }
/* * File table vnode poll routine. */ int vn_poll(struct file *fp, int events, struct proc *p) { return (VOP_POLL(((struct vnode *)fp->f_data), events, p)); }
/* * File table vnode poll routine. */ static int vn_poll(file_t *fp, int events) { return (VOP_POLL(fp->f_data, events)); }
/* * port_associate_fd() * This function associates new file descriptors with a port or * reactivate already associated file descriptors. * The reactivation also updates the events types to be checked and the * attached user pointer. * Per port a cache is used to store associated file descriptors. * Internally the VOP_POLL interface is used to poll for existing events. * The VOP_POLL interface can also deliver a pointer to a pollhead_t structure * which is used to enqueue polldat_t structures with pending events. * If VOP_POLL immediately returns valid events (revents) then those events * will be submitted to the event port with port_send_event(). * Otherwise VOP_POLL does not return events but it delivers a pointer to a * pollhead_t structure. In such a case the corresponding file system behind * VOP_POLL will use the pollwakeup() function to notify about exisiting * events. */ int port_associate_fd(port_t *pp, int source, uintptr_t object, int events, void *user) { port_fdcache_t *pcp; int fd; struct pollhead *php = NULL; portfd_t *pfd; polldat_t *pdp; file_t *fp; port_kevent_t *pkevp; short revents; int error = 0; pcp = pp->port_queue.portq_pcp; if (object > (uintptr_t)INT_MAX) return (EBADFD); fd = object; if ((fp = getf(fd)) == NULL) return (EBADFD); mutex_enter(&pcp->pc_lock); if (pcp->pc_hash == NULL) { /* * This is the first time that a fd is being associated with * the current port: * - create PORT_SOURCE_FD cache * - associate PORT_SOURCE_FD source with the port */ error = port_associate_ksource(pp->port_fd, PORT_SOURCE_FD, NULL, port_close_sourcefd, pp, NULL); if (error) { mutex_exit(&pcp->pc_lock); releasef(fd); return (error); } /* create polldat cache */ pcp->pc_hashsize = PORTHASH_START; pcp->pc_hash = kmem_zalloc(pcp->pc_hashsize * sizeof (portfd_t *), KM_SLEEP); pfd = NULL; } else { /* Check if the fd/fp is already associated with the port */ pfd = port_cache_lookup_fp(pcp, fd, fp); } if (pfd == NULL) { /* * new entry * Allocate a polldat_t structure per fd * The use of the polldat_t structure to cache file descriptors * is required to be able to share the pollwakeup() function * with poll(2) and devpoll(7d). */ pfd = kmem_zalloc(sizeof (portfd_t), KM_SLEEP); pdp = PFTOD(pfd); pdp->pd_fd = fd; pdp->pd_fp = fp; pdp->pd_pcache = (void *)pcp; /* Allocate a port event structure per fd */ error = port_alloc_event_local(pp, source, PORT_ALLOC_CACHED, &pdp->pd_portev); if (error) { kmem_free(pfd, sizeof (portfd_t)); releasef(fd); mutex_exit(&pcp->pc_lock); return (error); } pkevp = pdp->pd_portev; pkevp->portkev_callback = port_fd_callback; pkevp->portkev_arg = pfd; /* add portfd_t entry to the cache */ port_cache_insert_fd(pcp, pdp); pkevp->portkev_object = fd; pkevp->portkev_user = user; /* * Add current port to the file descriptor interested list * The members of the list are notified when the file descriptor * is closed. */ addfd_port(fd, pfd); } else { /* * The file descriptor is already associated with the port */ pdp = PFTOD(pfd); pkevp = pdp->pd_portev; /* * Check if the re-association happens before the last * submitted event of the file descriptor was retrieved. * Clear the PORT_KEV_VALID flag if set. No new events * should get submitted after this flag is cleared. */ mutex_enter(&pkevp->portkev_lock); if (pkevp->portkev_flags & PORT_KEV_VALID) { pkevp->portkev_flags &= ~PORT_KEV_VALID; } if (pkevp->portkev_flags & PORT_KEV_DONEQ) { mutex_exit(&pkevp->portkev_lock); /* * Remove any events that where already fired * for this fd and are still in the port queue. */ port_remove_done_event(pkevp); } else { mutex_exit(&pkevp->portkev_lock); } pkevp->portkev_user = user; } mutex_enter(&pkevp->portkev_lock); pkevp->portkev_events = 0; /* no fired events */ pdp->pd_events = events; /* events associated */ /* * allow new events. */ pkevp->portkev_flags |= PORT_KEV_VALID; mutex_exit(&pkevp->portkev_lock); /* * do VOP_POLL and cache this poll fd. * * XXX - pollrelock() logic needs to know * which pollcache lock to grab. It'd be a * cleaner solution if we could pass pcp as * an arguement in VOP_POLL interface instead * of implicitly passing it using thread_t * struct. On the other hand, changing VOP_POLL * interface will require all driver/file system * poll routine to change. */ curthread->t_pollcache = (pollcache_t *)pcp; error = VOP_POLL(fp->f_vnode, events, 0, &revents, &php); curthread->t_pollcache = NULL; /* * To keep synchronization between VOP_POLL above and * pollhead_insert below, it is necessary to * call VOP_POLL() again (see port_bind_pollhead()). */ if (error) { /* dissociate the fd from the port */ delfd_port(fd, pfd); port_remove_fd_local(pfd, pcp); releasef(fd); mutex_exit(&pcp->pc_lock); return (error); } if (php != NULL) { /* * No events delivered yet. * Bind pollhead pointer with current polldat_t structure. * Sub-system will call pollwakeup() later with php as * argument. */ error = port_bind_pollhead(&php, pdp, &revents); if (error) { delfd_port(fd, pfd); port_remove_fd_local(pfd, pcp); releasef(fd); mutex_exit(&pcp->pc_lock); return (error); } } /* * Check if new events where detected and no events have been * delivered. The revents was already set after the VOP_POLL * above or it was updated in port_bind_pollhead(). */ mutex_enter(&pkevp->portkev_lock); if (revents && (pkevp->portkev_flags & PORT_KEV_VALID)) { ASSERT((pkevp->portkev_flags & PORT_KEV_DONEQ) == 0); pkevp->portkev_flags &= ~PORT_KEV_VALID; revents = revents & (pdp->pd_events | POLLHUP | POLLERR); /* send events to the event port */ pkevp->portkev_events = revents; /* * port_send_event will release the portkev_lock mutex. */ port_send_event(pkevp); } else { mutex_exit(&pkevp->portkev_lock); } releasef(fd); mutex_exit(&pcp->pc_lock); return (error); }