[TEST/REVIEW] tty reference counting patch
Poul-Henning Kamp
phk at phk.freebsd.dk
Tue Jun 8 13:42:24 GMT 2004
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 <sys/termios.h>
#include <sys/queue.h>
#include <sys/selinfo.h>
+#include <sys/_lock.h>
+#include <sys/_mutex.h>
/*
* 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 at 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.
More information about the freebsd-current
mailing list