From owner-freebsd-current@FreeBSD.ORG Tue Jun 8 13:42:24 2004 Return-Path: Delivered-To: freebsd-current@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id AB05716A4CE for ; Tue, 8 Jun 2004 13:42:24 +0000 (GMT) Received: from critter.freebsd.dk (critter.freebsd.dk [212.242.86.163]) by mx1.FreeBSD.org (Postfix) with ESMTP id A251043D45 for ; Tue, 8 Jun 2004 13:42:23 +0000 (GMT) (envelope-from phk@phk.freebsd.dk) Received: from critter.freebsd.dk (localhost [127.0.0.1]) by critter.freebsd.dk (8.12.11/8.12.11) with ESMTP id i58DgMJ6048247 for ; Tue, 8 Jun 2004 15:42:22 +0200 (CEST) (envelope-from phk@phk.freebsd.dk) To: current@freebsd.org From: Poul-Henning Kamp Date: Tue, 08 Jun 2004 15:42:22 +0200 Message-ID: <48246.1086702142@critter.freebsd.dk> Subject: [TEST/REVIEW] tty reference counting patch X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 08 Jun 2004 13:42:24 -0000 This patch adds reference counting to struct tty and adds the ability to free a struct tty back to the system again. The PTY driver has been modified to use this. I have left in two annoying printfs which track the reference counts per tty. Just remove them when you tire of them. If you provoke a problem with this patch I'll be interested in the output from them however. Poul-Henning Index: kern/kern_proc.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_proc.c,v retrieving revision 1.203 diff -u -r1.203 kern_proc.c --- kern/kern_proc.c 22 May 2004 23:11:44 -0000 1.203 +++ kern/kern_proc.c 8 Jun 2004 12:42:43 -0000 @@ -469,6 +469,8 @@ SESS_UNLOCK(savesess); PGRP_UNLOCK(pgrp); if (savesess->s_count == 0) { + if (savesess->s_ttyp != NULL) + ttyrel(savesess->s_ttyp); mtx_destroy(&savesess->s_mtx); FREE(pgrp->pg_session, M_SESSION); } Index: kern/tty.c =================================================================== RCS file: /home/ncvs/src/sys/kern/tty.c,v retrieving revision 1.216 diff -u -r1.216 tty.c --- kern/tty.c 7 Jun 2004 20:45:45 -0000 1.216 +++ kern/tty.c 8 Jun 2004 12:46:47 -0000 @@ -212,7 +212,8 @@ /* * list of struct tty where pstat(8) can pick it up with sysctl */ -static SLIST_HEAD(, tty) tty_list; +static LIST_HEAD(, tty) tty_list = LIST_HEAD_INITIALIZER(&tty_list); +static struct mtx tty_list_mutex; static int drainwait = 5*60; SYSCTL_INT(_kern, OID_AUTO, drainwait, CTLFLAG_RW, &drainwait, @@ -229,6 +230,7 @@ s = spltty(); tp->t_dev = device; if (!ISSET(tp->t_state, TS_ISOPEN)) { + ttyref(tp); SET(tp->t_state, TS_ISOPEN); if (ISSET(tp->t_cflag, CLOCAL)) SET(tp->t_state, TS_CONNECTED); @@ -270,6 +272,7 @@ tp->t_pgrp = NULL; tp->t_session = NULL; tp->t_state = 0; + ttyrel(tp); splx(s); return (0); } @@ -1065,6 +1068,7 @@ tp->t_session = p->p_session; tp->t_pgrp = p->p_pgrp; SESS_LOCK(p->p_session); + ttyref(tp); p->p_session->s_ttyp = tp; SESS_UNLOCK(p->p_session); PROC_LOCK(p); @@ -2631,22 +2635,67 @@ } /* + * Gain a reference to a TTY + */ +int +ttyref(struct tty *tp) +{ + int i; + + mtx_lock(&tp->t_mtx); + KASSERT(tp->t_refcnt > 0, + ("ttyref(): tty refcnt is %d (%s)", + tp->t_refcnt, devtoname(tp->t_dev))); + i = ++tp->t_refcnt; + printf("ttyref(%s -> %d)\n", devtoname(tp->t_dev), tp->t_refcnt); + mtx_unlock(&tp->t_mtx); + return (i); +} + +/* + * Drop a reference to a TTY + */ +int +ttyrel(struct tty *tp) +{ + int i; + + mtx_lock(&tp->t_mtx); + KASSERT(tp->t_refcnt > 0, + ("ttyrel(): tty refcnt is %d (%s)", + tp->t_refcnt, devtoname(tp->t_dev))); + i = tp->t_refcnt--; + printf("ttyrel(%s -> %d)\n", devtoname(tp->t_dev), tp->t_refcnt); + mtx_unlock(&tp->t_mtx); + return (i); +} + +/* * Allocate a tty struct. Clists in the struct will be allocated by * ttyopen(). */ struct tty * ttymalloc(struct tty *tp) { + static int once; + + if (!once) { + mtx_init(&tty_list_mutex, "ttylist", NULL, MTX_DEF); + once++; + } if (tp) return(tp); tp = malloc(sizeof *tp, M_TTYS, M_WAITOK | M_ZERO); tp->t_timeout = -1; - SLIST_INSERT_HEAD(&tty_list, tp, t_list); + mtx_init(&tp->t_mtx, "tty", NULL, MTX_DEF); + tp->t_refcnt = 1; + mtx_lock(&tty_list_mutex); + LIST_INSERT_HEAD(&tty_list, tp, t_list); + mtx_unlock(&tty_list_mutex); return (tp); } -#if 0 /* XXX not yet usable: session leader holds a ref (see kern_exit.c). */ /* * Free a tty struct. Clists in the struct should have been freed by * ttyclose(). @@ -2654,9 +2703,15 @@ void ttyfree(struct tty *tp) { + + if (ttyrel(tp) != 0) + return; + mtx_lock(&tty_list_mutex); + LIST_REMOVE(tp, t_list); + mtx_unlock(&tty_list_mutex); + mtx_destroy(&tp->t_mtx); free(tp, M_TTYS); } -#endif /* 0 */ static int sysctl_kern_ttys(SYSCTL_HANDLER_ARGS) @@ -2665,7 +2720,7 @@ struct xtty xt; int error; - SLIST_FOREACH(tp, &tty_list, t_list) { + LIST_FOREACH(tp, &tty_list, t_list) { bzero(&xt, sizeof xt); xt.xt_size = sizeof xt; #define XT_COPY(field) xt.xt_##field = tp->t_##field Index: kern/tty_pty.c =================================================================== RCS file: /home/ncvs/src/sys/kern/tty_pty.c,v retrieving revision 1.119 diff -u -r1.119 tty_pty.c --- kern/tty_pty.c 4 Jun 2004 16:02:56 -0000 1.119 +++ kern/tty_pty.c 8 Jun 2004 13:35:55 -0000 @@ -61,7 +61,6 @@ static void ptsstart(struct tty *tp); static void ptsstop(struct tty *tp, int rw); static void ptcwakeup(struct tty *tp, int flag); -static dev_t ptyinit(dev_t cdev); static d_open_t ptsopen; static d_close_t ptsclose; @@ -98,9 +97,11 @@ .d_poll = ptcpoll, .d_name = "ptc", .d_maj = CDEV_MAJOR_C, - .d_flags = D_TTY | D_NEEDGIANT, + .d_flags = D_NEEDGIANT, }; +static char *names = "pqrsPQRS"; + #define BUFSIZ 100 /* Chunk size iomoved to/from user */ struct pt_ioctl { @@ -119,42 +120,6 @@ #define PF_NOSTOP 0x40 #define PF_UCNTL 0x80 /* user control mode */ -static char *names = "pqrsPQRS"; -/* - * This function creates and initializes a pts/ptc pair - * - * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] - * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] - * - * XXX: define and add mapping of upper minor bits to allow more - * than 256 ptys. - */ -static dev_t -ptyinit(dev_t devc) -{ - dev_t devs; - struct pt_ioctl *pt; - int n; - - n = minor(devc); - /* For now we only map the lower 8 bits of the minor */ - if (n & ~0xff) - return (NODEV); - - devc->si_flags &= ~SI_CHEAPCLONE; - - pt = malloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO); - pt->devs = devs = make_dev(&pts_cdevsw, n, - UID_ROOT, GID_WHEEL, 0666, "tty%c%r", names[n / 32], n % 32); - pt->devc = devc; - - pt->pt_tty = ttymalloc(pt->pt_tty); - devs->si_drv1 = devc->si_drv1 = pt; - devs->si_tty = devc->si_tty = pt->pt_tty; - pt->pt_tty->t_dev = devs; - return (devc); -} - /*ARGSUSED*/ static int ptsopen(dev, flag, devtype, td) @@ -328,6 +293,7 @@ } } + static int ptcopen(dev, flag, devtype, td) dev_t dev; @@ -335,25 +301,42 @@ struct thread *td; { struct tty *tp; - struct pt_ioctl *pti; + struct pt_ioctl *pt; + u_int n; + + if (dev->si_drv1 != NULL) + return (EIO); /* XXX: EBUSY ?? */ + + n = minor(dev); + + /* For now we only map the lower 8 bits of the minor */ + if (n & ~0xff) + return (ENXIO); + + pt = malloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO); + pt->devs = make_dev(&pts_cdevsw, n, + UID_ROOT, GID_WHEEL, 0666, "tty%c%r", + names[n / 32], n % 32); + pt->devc = dev; + pt->devs->si_drv1 = pt; + pt->devc->si_drv1 = pt; + + tp = ttymalloc(NULL); + pt->pt_tty = tp; + pt->devs->si_tty = pt->pt_tty; + pt->devc->si_tty = pt->pt_tty; + pt->pt_tty->t_dev = pt->devs; - if (!dev->si_drv1) - ptyinit(dev); - if (!dev->si_drv1) - return(ENXIO); - tp = dev->si_tty; - if (tp->t_oproc) - return (EIO); tp->t_timeout = -1; tp->t_oproc = ptsstart; tp->t_stop = ptsstop; (void)ttyld_modem(tp, 1); tp->t_lflag &= ~EXTPROC; - pti = dev->si_drv1; - pti->pt_prison = td->td_ucred->cr_prison; - pti->pt_flags = 0; - pti->pt_send = 0; - pti->pt_ucntl = 0; + + pt->pt_prison = td->td_ucred->cr_prison; + pt->pt_flags = 0; + pt->pt_send = 0; + pt->pt_ucntl = 0; return (0); } @@ -365,8 +348,10 @@ struct thread *td; { struct tty *tp; + struct pt_ioctl *pt; - tp = dev->si_tty; + pt = dev->si_drv1; + tp = pt->pt_tty; (void)ttyld_modem(tp, 0); /* @@ -384,6 +369,10 @@ } tp->t_oproc = 0; /* mark closed */ + ttyfree(tp); + destroy_dev(pt->devs); + free(pt, M_PTY); + dev->si_drv1 = NULL; return (0); } Index: sys/tty.h =================================================================== RCS file: /home/ncvs/src/sys/sys/tty.h,v retrieving revision 1.77 diff -u -r1.77 tty.h --- sys/tty.h 4 Jun 2004 21:55:55 -0000 1.77 +++ sys/tty.h 8 Jun 2004 12:26:43 -0000 @@ -49,6 +49,8 @@ #include #include #include +#include +#include /* * Clists are character lists, which is a variable length linked list @@ -110,7 +112,10 @@ int t_olowat; /* Low water mark for output. */ speed_t t_ospeedwat; /* t_ospeed override for watermarks. */ int t_gen; /* Generation number. */ - SLIST_ENTRY(tty) t_list; /* Global chain of ttys for pstat(8) */ + LIST_ENTRY(tty) t_list; /* Global chain of ttys for pstat(8) */ + + struct mtx t_mtx; + int t_refcnt; }; #define t_cc t_termios.c_cc @@ -307,6 +312,8 @@ struct tty *ttymalloc(struct tty *tp); int ttymodem(struct tty *tp, int flag); int ttyopen(dev_t device, struct tty *tp); +int ttyref(struct tty *tp); +int ttyrel(struct tty *tp); int ttysleep(struct tty *tp, void *chan, int pri, char *wmesg, int timo); int ttywait(struct tty *tp); int unputc(struct clist *q); -- Poul-Henning Kamp | UNIX since Zilog Zeus 3.20 phk@FreeBSD.ORG | TCP/IP since RFC 956 FreeBSD committer | BSD since 4.3-tahoe Never attribute to malice what can adequately be explained by incompetence.