From owner-svn-src-all@FreeBSD.ORG Thu Dec 11 21:44:03 2008 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5B7631065672; Thu, 11 Dec 2008 21:44:03 +0000 (UTC) (envelope-from ed@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 4A1388FC18; Thu, 11 Dec 2008 21:44:03 +0000 (UTC) (envelope-from ed@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id mBBLi3MB077428; Thu, 11 Dec 2008 21:44:03 GMT (envelope-from ed@svn.freebsd.org) Received: (from ed@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id mBBLi3sY077427; Thu, 11 Dec 2008 21:44:03 GMT (envelope-from ed@svn.freebsd.org) Message-Id: <200812112144.mBBLi3sY077427@svn.freebsd.org> From: Ed Schouten Date: Thu, 11 Dec 2008 21:44:03 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r185942 - head/sys/kern X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 11 Dec 2008 21:44:03 -0000 Author: ed Date: Thu Dec 11 21:44:02 2008 New Revision: 185942 URL: http://svn.freebsd.org/changeset/base/185942 Log: Add kqueue()-support to pseudo-terminal master devices. One thing I didn't expect many applications to use, was kqueue() on pseudo-terminal master devices. There are applications that use kqueue() on the TTY itself (rtorrent, etc). That doesn't mean we shouldn't implement this. Libraries like libevent use kqueue() by default, which means they wouldn't be able to use kqueue(). The old TTY layer implements a very broken version of kqueue() by performing the actual polling on the TTY device. Discussed with: peter Modified: head/sys/kern/tty_pts.c Modified: head/sys/kern/tty_pts.c ============================================================================== --- head/sys/kern/tty_pts.c Thu Dec 11 21:08:14 2008 (r185941) +++ head/sys/kern/tty_pts.c Thu Dec 11 21:44:02 2008 (r185942) @@ -254,6 +254,14 @@ done: ttydisc_rint_done(tp); } static int +ptsdev_truncate(struct file *fp, off_t length, struct ucred *active_cred, + struct thread *td) +{ + + return (EINVAL); +} + +static int ptsdev_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *active_cred, struct thread *td) { @@ -423,6 +431,94 @@ ptsdev_poll(struct file *fp, int events, return (revents); } +/* + * kqueue support. + */ + +static void +pts_kqops_read_detach(struct knote *kn) +{ + struct file *fp = kn->kn_fp; + struct tty *tp = fp->f_data; + struct pts_softc *psc = tty_softc(tp); + + knlist_remove(&psc->pts_outpoll.si_note, kn, 0); +} + +static int +pts_kqops_read_event(struct knote *kn, long hint) +{ + struct file *fp = kn->kn_fp; + struct tty *tp = fp->f_data; + struct pts_softc *psc = tty_softc(tp); + + if (psc->pts_flags & PTS_FINISHED) { + kn->kn_flags |= EV_EOF; + return (1); + } else { + kn->kn_data = ttydisc_getc_poll(tp); + return (kn->kn_data > 0); + } +} + +static void +pts_kqops_write_detach(struct knote *kn) +{ + struct file *fp = kn->kn_fp; + struct tty *tp = fp->f_data; + struct pts_softc *psc = tty_softc(tp); + + knlist_remove(&psc->pts_inpoll.si_note, kn, 0); +} + +static int +pts_kqops_write_event(struct knote *kn, long hint) +{ + struct file *fp = kn->kn_fp; + struct tty *tp = fp->f_data; + struct pts_softc *psc = tty_softc(tp); + + if (psc->pts_flags & PTS_FINISHED) { + kn->kn_flags |= EV_EOF; + return (1); + } else { + kn->kn_data = ttydisc_rint_poll(tp); + return (kn->kn_data > 0); + } +} + +static struct filterops pts_kqops_read = + { 1, NULL, pts_kqops_read_detach, pts_kqops_read_event }; +static struct filterops pts_kqops_write = + { 1, NULL, pts_kqops_write_detach, pts_kqops_write_event }; + +static int +ptsdev_kqfilter(struct file *fp, struct knote *kn) +{ + struct tty *tp = fp->f_data; + struct pts_softc *psc = tty_softc(tp); + int error = 0; + + tty_lock(tp); + + switch (kn->kn_filter) { + case EVFILT_READ: + kn->kn_fop = &pts_kqops_read; + knlist_add(&psc->pts_outpoll.si_note, kn, 1); + break; + case EVFILT_WRITE: + kn->kn_fop = &pts_kqops_write; + knlist_add(&psc->pts_inpoll.si_note, kn, 1); + break; + default: + error = EINVAL; + break; + } + + tty_unlock(tp); + return (error); +} + static int ptsdev_stat(struct file *fp, struct stat *sb, struct ucred *active_cred, struct thread *td) @@ -475,8 +571,10 @@ ptsdev_close(struct file *fp, struct thr static struct fileops ptsdev_ops = { .fo_read = ptsdev_read, .fo_write = ptsdev_write, + .fo_truncate = ptsdev_truncate, .fo_ioctl = ptsdev_ioctl, .fo_poll = ptsdev_poll, + .fo_kqfilter = ptsdev_kqfilter, .fo_stat = ptsdev_stat, .fo_close = ptsdev_close, .fo_flags = DFLAG_PASSABLE, @@ -493,6 +591,7 @@ ptsdrv_outwakeup(struct tty *tp) cv_broadcast(&psc->pts_outwait); selwakeup(&psc->pts_outpoll); + KNOTE_LOCKED(&psc->pts_outpoll.si_note, 0); } static void @@ -502,6 +601,7 @@ ptsdrv_inwakeup(struct tty *tp) cv_broadcast(&psc->pts_inwait); selwakeup(&psc->pts_inpoll); + KNOTE_LOCKED(&psc->pts_inpoll.si_note, 0); } static int @@ -566,6 +666,9 @@ ptsdrv_free(void *softc) chgptscnt(psc->pts_uidinfo, -1, 0); uifree(psc->pts_uidinfo); + knlist_destroy(&psc->pts_inpoll.si_note); + knlist_destroy(&psc->pts_outpoll.si_note); + #ifdef PTS_EXTERNAL /* Destroy master device as well. */ if (psc->pts_cdev != NULL) @@ -618,6 +721,8 @@ pts_alloc(int fflags, struct thread *td, uihold(uid); tp = tty_alloc(&pts_class, psc, NULL); + knlist_init(&psc->pts_inpoll.si_note, tp->t_mtx, NULL, NULL, NULL); + knlist_init(&psc->pts_outpoll.si_note, tp->t_mtx, NULL, NULL, NULL); /* Expose the slave device as well. */ tty_makedev(tp, td->td_ucred, "pts/%u", psc->pts_unit); @@ -656,6 +761,8 @@ pts_alloc_external(int fflags, struct th uihold(uid); tp = tty_alloc(&pts_class, psc, NULL); + knlist_init(&psc->pts_inpoll.si_note, tp->t_mtx, NULL, NULL, NULL); + knlist_init(&psc->pts_outpoll.si_note, tp->t_mtx, NULL, NULL, NULL); /* Expose the slave device as well. */ tty_makedev(tp, td->td_ucred, "%s", name);