Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 26 Oct 2008 13:41:54 GMT
From:      Ed Schouten <ed@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 151950 for review
Message-ID:  <200810261341.m9QDfsuA064902@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=151950

Change 151950 by ed@ed_dull on 2008/10/26 13:41:32

	Revert clist changes. I've decided to keep it as it is now.

Affected files ...

.. //depot/projects/mpsafetty/sys/dev/dcons/dcons_os.c#4 integrate
.. //depot/projects/mpsafetty/sys/dev/kbd/kbd.c#6 integrate
.. //depot/projects/mpsafetty/sys/dev/kbdmux/kbdmux.c#6 integrate
.. //depot/projects/mpsafetty/sys/dev/usb/ugen.c#6 integrate
.. //depot/projects/mpsafetty/sys/dev/usb/uhid.c#6 integrate
.. //depot/projects/mpsafetty/sys/kern/subr_clist.c#9 integrate
.. //depot/projects/mpsafetty/sys/sys/clist.h#8 integrate
.. //depot/projects/mpsafetty/sys/sys/param.h#17 integrate

Differences ...

==== //depot/projects/mpsafetty/sys/dev/dcons/dcons_os.c#4 (text+ko) ====

@@ -126,13 +126,11 @@
 extern struct gdb_dbgport *gdb_cur;
 #endif
 
-static tsw_outwakeup_t	dcons_outwakeup;
-static tsw_free_t	dcons_free;
+static tsw_outwakeup_t dcons_outwakeup;
 
 static struct ttydevsw dcons_ttydevsw = {
 	.tsw_flags      = TF_NOPREFIX,
 	.tsw_outwakeup  = dcons_outwakeup,
-	.tsw_free	= dcons_free,
 };
 
 #if (defined(GDB) || defined(DDB)) && defined(ALT_BREAK_TO_DEBUGGER)
@@ -221,16 +219,6 @@
 }
 
 static void
-dcons_free(void *arg)
-{
-
-	/*
-	 * XXX: dcons(4) should not reuse the device name before this
-	 * function has been called!
-	 */
-}
-
-static void
 dcons_timeout(void *v)
 {
 	struct	tty *tp;

==== //depot/projects/mpsafetty/sys/dev/kbd/kbd.c#6 (text+ko) ====

@@ -558,7 +558,7 @@
 #if 0
 	bzero(&sc->gkb_q, sizeof(sc->gkb_q));
 #endif
-	clist_alloc(&sc->gkb_q, KB_QSIZE);
+	clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */
 	splx(s);
 
 	return (0);
@@ -608,7 +608,7 @@
 		splx(s);
 		return (ENXIO);
 	}
-	while (clist_usage(&sc->gkb_q) == 0) {
+	while (sc->gkb_q.c_cc == 0) {
 		if (flag & O_NONBLOCK) {
 			splx(s);
 			return (EWOULDBLOCK);
@@ -632,7 +632,7 @@
 	error = 0;
 	while (uio->uio_resid > 0) {
 		len = imin(uio->uio_resid, sizeof(buffer));
-		len = clist_read(&sc->gkb_q, buffer, len);
+		len = q_to_b(&sc->gkb_q, buffer, len);
 		if (len <= 0)
 			break;
 		error = uiomove(buffer, len, uio);
@@ -684,7 +684,7 @@
 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
 		revents =  POLLHUP;	/* the keyboard has gone */
 	} else if (events & (POLLIN | POLLRDNORM)) {
-		if (clist_usage(&sc->gkb_q) > 0)
+		if (sc->gkb_q.c_cc > 0)
 			revents = events & (POLLIN | POLLRDNORM);
 		else
 			selrecord(td, &sc->gkb_rsel);
@@ -701,7 +701,6 @@
 	u_char *cp;
 	int mode;
 	int c;
-	char cq[3];
 
 	/* assert(KBD_IS_VALID(kbd)) */
 	sc = (genkbd_softc_t *)arg;
@@ -739,8 +738,7 @@
 
 		/* store the byte as is for K_RAW and K_CODE modes */
 		if (mode != K_XLATE) {
-			cq[0] = KEYCHAR(c);
-			clist_write(&sc->gkb_q, cq, 1);
+			putc(KEYCHAR(c), &sc->gkb_q);
 			continue;
 		}
 
@@ -755,10 +753,9 @@
 				/* ignore them... */
 				continue;
 			case BTAB:	/* a backtab: ESC [ Z */
-				cq[0] = 0x1b;
-				cq[1] = '[';
-				cq[2] = 'Z';
-				clist_write(&sc->gkb_q, cq, 3);
+				putc(0x1b, &sc->gkb_q);
+				putc('[', &sc->gkb_q);
+				putc('Z', &sc->gkb_q);
 				continue;
 			}
 		}
@@ -766,24 +763,24 @@
 		/* normal chars, normal chars with the META, function keys */
 		switch (KEYFLAGS(c)) {
 		case 0:			/* a normal char */
-			cq[0] = KEYCHAR(c);
-			clist_write(&sc->gkb_q, cq, 1);
+			putc(KEYCHAR(c), &sc->gkb_q);
 			break;
 		case MKEY:		/* the META flag: prepend ESC */
-			cq[0] = 0x1b;
-			cq[1] = KEYCHAR(c);
-			clist_write(&sc->gkb_q, cq, 2);
+			putc(0x1b, &sc->gkb_q);
+			putc(KEYCHAR(c), &sc->gkb_q);
 			break;
 		case FKEY | SPCLKEY:	/* a function key, return string */
 			cp = kbdd_get_fkeystr(kbd, KEYCHAR(c), &len);
-			if (cp != NULL)
-				clist_write(&sc->gkb_q, cp, len);
+			if (cp != NULL) {
+				while (len-- >  0)
+					putc(*cp++, &sc->gkb_q);
+			}
 			break;
 		}
 	}
 
 	/* wake up sleeping/polling processes */
-	if (clist_usage(&sc->gkb_q) > 0) {
+	if (sc->gkb_q.c_cc > 0) {
 		if (sc->gkb_flags & KB_ASLEEP) {
 			sc->gkb_flags &= ~KB_ASLEEP;
 			wakeup(sc);

==== //depot/projects/mpsafetty/sys/dev/kbdmux/kbdmux.c#6 (text+ko) ====

@@ -205,7 +205,7 @@
 	callout_deactivate(&state->ks_timo);
 
 	/* queue interrupt task if needed */
-	if (clist_usage(&state->ks_inq) > 0 && !(state->ks_flags & TASK) &&
+	if (state->ks_inq.c_cc > 0 && !(state->ks_flags & TASK) &&
 	    KBDMUX_QUEUE_INTR(state) == 0)
 		state->ks_flags |= TASK;
 
@@ -224,7 +224,6 @@
 	switch (event) {
 	case KBDIO_KEYINPUT: {
 		int	c;
-		char	cq;
 
 		KBDMUX_LOCK(state);
 
@@ -247,13 +246,12 @@
 			if (!KBD_IS_BUSY(kbd))
 				continue; /* not open - discard the input */
 
-			cq = c;
-			clist_write(&state->ks_inq, &cq, 1);
+			putc(c, &state->ks_inq);
 		}
 
 		/* queue interrupt task if needed */
-		if (clist_usage(&state->ks_inq) > 0 &&
-		    !(state->ks_flags & TASK) && KBDMUX_QUEUE_INTR(state) == 0)
+		if (state->ks_inq.c_cc > 0 && !(state->ks_flags & TASK) &&
+		    KBDMUX_QUEUE_INTR(state) == 0)
 			state->ks_flags |= TASK;
 
 		KBDMUX_UNLOCK(state);
@@ -386,7 +384,8 @@
 		}
 
 		KBDMUX_LOCK_INIT(state);
-		clist_alloc(&state->ks_inq, KBDMUX_Q_SIZE);
+		clist_alloc_cblocks(&state->ks_inq,
+				KBDMUX_Q_SIZE, KBDMUX_Q_SIZE / 2);
 		TASK_INIT(&state->ks_task, 0, kbdmux_kbd_intr, (void *) kbd);
 		KBDMUX_CALLOUT_INIT(state);
 		SLIST_INIT(&state->ks_kbds);
@@ -450,7 +449,7 @@
 bad:
 	if (needfree) {
 		if (state != NULL) {
-			clist_free(&state->ks_inq);
+			clist_free_cblocks(&state->ks_inq);
 			free(state, M_KBDMUX);
 		}
 		if (keymap != NULL)
@@ -497,7 +496,8 @@
 	}
 
 	/* flush input queue */
-	clist_free(&state->ks_inq);
+	ndflush(&state->ks_inq, state->ks_inq.c_cc);
+	clist_free_cblocks(&state->ks_inq);
 
 	KBDMUX_UNLOCK(state);
 
@@ -574,15 +574,14 @@
 kbdmux_read(keyboard_t *kbd, int wait)
 {
 	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
-	char		 c;
+	int		 c;
 
 	KBDMUX_LOCK(state);
-	if (clist_read(&state->ks_inq, &c, 1) != 1) {
-		KBDMUX_UNLOCK(state);
-		return (-1);
-	}
+	c = getc(&state->ks_inq);
 	KBDMUX_UNLOCK(state);
-	kbd->kb_count++;
+
+	if (c != -1)
+		kbd->kb_count ++;
 
 	return (KBD_IS_ACTIVE(kbd)? c : -1);
 }
@@ -600,7 +599,7 @@
 		return (FALSE);
 
 	KBDMUX_LOCK(state);
-	ready = clist_usage(&state->ks_inq) > 0 ? TRUE : FALSE;
+	ready = (state->ks_inq.c_cc > 0)? TRUE : FALSE;
 	KBDMUX_UNLOCK(state);
 
 	return (ready);
@@ -614,8 +613,7 @@
 {
 	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
 	u_int		 action;
-	int		 scancode = -1, keycode;
-	char		 cq;
+	int		 scancode, keycode;
 
 	KBDMUX_LOCK(state);
 
@@ -637,7 +635,8 @@
 	}
 
 	/* see if there is something in the keyboard queue */
-	if (clist_read(&state->ks_inq, &cq, 1) == 1) {
+	scancode = getc(&state->ks_inq);
+	if (scancode == -1) {
 		if (state->ks_flags & POLLING) {
 			kbdmux_kbd_t	*k;
 
@@ -651,12 +650,11 @@
 					if (!KBD_IS_BUSY(k->kbd))
 						continue; 
 
-					cq = scancode;
-					clist_write(&state->ks_inq, &cq, 1);
+					putc(scancode, &state->ks_inq);
 				}
 			}
 
-			if (clist_usage(&state->ks_inq) > 0)
+			if (state->ks_inq.c_cc > 0)
 				goto next_code;
 		}
 
@@ -897,7 +895,7 @@
 	if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char != 0))
 		ready = TRUE;
 	else
-		ready = clist_usage(&state->ks_inq) > 0 ? TRUE : FALSE;
+		ready = (state->ks_inq.c_cc > 0)? TRUE : FALSE;
 
 	KBDMUX_UNLOCK(state);
 
@@ -1222,7 +1220,7 @@
 	state->ks_composed_char = 0;
 /*	state->ks_prefix = 0;		XXX */
 
-	clist_flush(&state->ks_inq);
+	ndflush(&state->ks_inq, state->ks_inq.c_cc);
 }
 
 static void

==== //depot/projects/mpsafetty/sys/dev/usb/ugen.c#6 (text+ko) ====

@@ -529,7 +529,9 @@
 			sce->ibuf = malloc(isize, M_USBDEV, M_WAITOK);
 			DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n",
 				     endpt, isize));
-			clist_alloc(&sce->q, UGEN_IBSIZE);
+			if ((clist_alloc_cblocks(&sce->q, UGEN_IBSIZE,
+			    UGEN_IBSIZE), 0) == -1)
+				return (ENOMEM);
 			err = usbd_open_pipe_intr(sce->iface,
 				  edesc->bEndpointAddress,
 				  USBD_SHORT_XFER_OK, &sce->pipeh, sce,
@@ -537,7 +539,7 @@
 				  USBD_DEFAULT_INTERVAL);
 			if (err) {
 				free(sce->ibuf, M_USBDEV);
-				clist_free(&sce->q);
+				clist_free_cblocks(&sce->q);
 				return (EIO);
 			}
 			DPRINTFN(5, ("ugenopen: interrupt open done\n"));
@@ -647,7 +649,8 @@
 
 		switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
 		case UE_INTERRUPT:
-			clist_free(&sce->q);
+			ndflush(&sce->q, sce->q.c_cc);
+			clist_free_cblocks(&sce->q);
 			break;
 		case UE_ISOCHRONOUS:
 			for (i = 0; i < UGEN_NISOREQS; ++i)
@@ -660,7 +663,7 @@
 		if (sce->ibuf != NULL) {
 			free(sce->ibuf, M_USBDEV);
 			sce->ibuf = NULL;
-			clist_free(&sce->q);
+			clist_free_cblocks(&sce->q);
 		}
 	}
 	sc->sc_is_open[endpt] = 0;
@@ -704,7 +707,7 @@
 	case UE_INTERRUPT:
 		/* Block until activity occurred. */
 		s = splusb();
-		while (clist_usage(&sce->q) == 0) {
+		while (sce->q.c_cc == 0) {
 			if (flag & O_NONBLOCK) {
 				splx(s);
 				return (EWOULDBLOCK);
@@ -727,14 +730,13 @@
 		splx(s);
 
 		/* Transfer as many chunks as possible. */
-		while ((n = clist_usage(&sce->q)) > 0 &&
-		    uio->uio_resid > 0 && !error) {
-			n = min(n, uio->uio_resid);
+		while (sce->q.c_cc > 0 && uio->uio_resid > 0 && !error) {
+			n = min(sce->q.c_cc, uio->uio_resid);
 			if (n > sizeof(buffer))
 				n = sizeof(buffer);
 
 			/* Remove a small chunk from the input queue. */
-			clist_read(&sce->q, buffer, n);
+			q_to_b(&sce->q, buffer, n);
 			DPRINTFN(5, ("ugenread: got %d chars\n", n));
 
 			/* Copy the data to the user process. */
@@ -1025,7 +1027,7 @@
 	DPRINTFN(5, ("          data = %02x %02x %02x\n",
 		     ibuf[0], ibuf[1], ibuf[2]));
 
-	clist_write(&sce->q, ibuf, count);
+	(void)b_to_q(ibuf, count, &sce->q);
 
 	if (sce->state & UGEN_ASLP) {
 		sce->state &= ~UGEN_ASLP;
@@ -1539,13 +1541,13 @@
 	switch (edesc->bmAttributes & UE_XFERTYPE) {
 	case UE_INTERRUPT:
 		if (sce_in != NULL && (events & (POLLIN | POLLRDNORM))) {
-			if (clist_usage(&sce_in->q) > 0)
+			if (sce_in->q.c_cc > 0)
 				revents |= events & (POLLIN | POLLRDNORM);
 			else
 				selrecord(p, &sce_in->rsel);
 		}
 		if (sce_out != NULL && (events & (POLLOUT | POLLWRNORM))) {
-			if (clist_usage(&sce_out->q) > 0)
+			if (sce_out->q.c_cc > 0)
 				revents |= events & (POLLOUT | POLLWRNORM);
 			else
 				selrecord(p, &sce_out->rsel);

==== //depot/projects/mpsafetty/sys/dev/usb/uhid.c#6 (text+ko) ====

@@ -390,7 +390,7 @@
 		return;
 	}
 
-	clist_write(&sc->sc_q, sc->sc_ibuf, sc->sc_isize);
+	(void) b_to_q(sc->sc_ibuf, sc->sc_isize, &sc->sc_q);
 
 	if (sc->sc_state & UHID_ASLP) {
 		sc->sc_state &= ~UHID_ASLP;
@@ -425,7 +425,7 @@
 		return (EBUSY);
 	sc->sc_state |= UHID_OPEN;
 
-	clist_alloc(&sc->sc_q, UHID_BSIZE);
+	clist_alloc_cblocks(&sc->sc_q, UHID_BSIZE, UHID_BSIZE);
 	sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
 	sc->sc_obuf = malloc(sc->sc_osize, M_USBDEV, M_WAITOK);
 
@@ -465,7 +465,8 @@
 	usbd_close_pipe(sc->sc_intrpipe);
 	sc->sc_intrpipe = 0;
 
-	clist_free(&sc->sc_q);
+	ndflush(&sc->sc_q, sc->sc_q.c_cc);
+	clist_free_cblocks(&sc->sc_q);
 
 	free(sc->sc_ibuf, M_USBDEV);
 	free(sc->sc_obuf, M_USBDEV);
@@ -499,7 +500,7 @@
 	}
 
 	s = splusb();
-	while (clist_usage(&sc->sc_q) == 0) {
+	while (sc->sc_q.c_cc == 0) {
 		if (flag & O_NONBLOCK) {
 			splx(s);
 			return (EWOULDBLOCK);
@@ -523,14 +524,13 @@
 	splx(s);
 
 	/* Transfer as many chunks as possible. */
-	while ((length = clist_usage(&sc->sc_q)) > 0 &&
-	    uio->uio_resid > 0 && !error) {
-		length = min(length, uio->uio_resid);
+	while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0 && !error) {
+		length = min(sc->sc_q.c_cc, uio->uio_resid);
 		if (length > sizeof(buffer))
 			length = sizeof(buffer);
 
 		/* Remove a small chunk from the input queue. */
-		clist_read(&sc->sc_q, buffer, length);
+		(void) q_to_b(&sc->sc_q, buffer, length);
 		DPRINTFN(5, ("uhidread: got %lu chars\n", (u_long)length));
 
 		/* Copy the data to the user process. */
@@ -744,7 +744,7 @@
 	if (events & (POLLOUT | POLLWRNORM))
 		revents |= events & (POLLOUT | POLLWRNORM);
 	if (events & (POLLIN | POLLRDNORM)) {
-		if (clist_usage(&sc->sc_q) > 0)
+		if (sc->sc_q.c_cc > 0)
 			revents |= events & (POLLIN | POLLRDNORM);
 		else
 			selrecord(p, &sc->sc_rsel);

==== //depot/projects/mpsafetty/sys/kern/subr_clist.c#9 (text+ko) ====

@@ -1,12 +1,13 @@
 /*-
- * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
+ * Copyright (c) 1994, David Greenman
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
@@ -24,43 +25,509 @@
  * SUCH DAMAGE.
  */
 
+/*
+ * clist support routines
+ */
+
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: src/sys/kern/subr_clist.c,v 1.48 2008/09/21 18:12:18 ed Exp $");
 
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
 #include <sys/clist.h>
 
+static void clist_init(void *);
+SYSINIT(clist, SI_SUB_CLIST, SI_ORDER_FIRST, clist_init, NULL);
+
+static MALLOC_DEFINE(M_CLIST, "clist", "clist queue blocks");
+
+static struct cblock *cfreelist = 0;
+int cfreecount = 0;
+static int cslushcount;
+static int ctotcount;
+
+#ifndef INITIAL_CBLOCKS
+#define	INITIAL_CBLOCKS 50
+#endif
+
+static struct cblock *cblock_alloc(void);
+static void cblock_alloc_cblocks(int number);
+static void cblock_free(struct cblock *cblockp);
+static void cblock_free_cblocks(int number);
+
+#include "opt_ddb.h"
+#ifdef DDB
+#include <ddb/ddb.h>
+
+DB_SHOW_COMMAND(cbstat, cbstat)
+{
+	int cbsize = CBSIZE;
+
+	printf(
+	"tot = %d (active = %d, free = %d (reserved = %d, slush = %d))\n",
+	       ctotcount * cbsize, ctotcount * cbsize - cfreecount, cfreecount,
+	       cfreecount - cslushcount * cbsize, cslushcount * cbsize);
+}
+#endif /* DDB */
+
+/*
+ * Called from init_main.c
+ */
+/* ARGSUSED*/
+static void
+clist_init(void *dummy)
+{
+	/*
+	 * Allocate an initial base set of cblocks as a 'slush'.
+	 * We allocate non-slush cblocks with each initial tty_open() and
+	 * deallocate them with each tty_close().
+	 * We should adjust the slush allocation.  This can't be done in
+	 * the i/o routines because they are sometimes called from
+	 * interrupt handlers when it may be unsafe to call malloc().
+	 */
+	cblock_alloc_cblocks(cslushcount = INITIAL_CBLOCKS);
+}
+
+/*
+ * Remove a cblock from the cfreelist queue and return a pointer
+ * to it.
+ */
+static __inline struct cblock *
+cblock_alloc(void)
+{
+	struct cblock *cblockp;
+
+	cblockp = cfreelist;
+	if (cblockp == NULL)
+		panic("clist reservation botch");
+	cfreelist = cblockp->c_next;
+	cblockp->c_next = NULL;
+	cfreecount -= CBSIZE;
+	return (cblockp);
+}
+
+/*
+ * Add a cblock to the cfreelist queue.
+ */
+static __inline void
+cblock_free(struct cblock *cblockp)
+{
+	cblockp->c_next = cfreelist;
+	cfreelist = cblockp;
+	cfreecount += CBSIZE;
+}
+
+/*
+ * Allocate some cblocks for the cfreelist queue.
+ */
+static void
+cblock_alloc_cblocks(int number)
+{
+	int i;
+	struct cblock *cbp;
+
+	for (i = 0; i < number; ++i) {
+		cbp = malloc(sizeof *cbp, M_CLIST, M_NOWAIT);
+		if (cbp == NULL) {
+			printf(
+"cblock_alloc_cblocks: M_NOWAIT malloc failed, trying M_WAITOK\n");
+			cbp = malloc(sizeof *cbp, M_CLIST, M_WAITOK);
+		}
+		/*
+		 * Freed cblocks have zero quotes and garbage elsewhere.
+		 * Set the may-have-quote bit to force zeroing the quotes.
+		 */
+		cblock_free(cbp);
+	}
+	ctotcount += number;
+}
+
+/*
+ * Set the cblock allocation policy for a clist.
+ * Must be called in process context at spltty().
+ */
 void
-clist_alloc(struct clist *cl, size_t len)
+clist_alloc_cblocks(struct clist *clistp, int ccmax, int ccreserved)
+{
+	int dcbr;
+
+	/*
+	 * Allow for wasted space at the head.
+	 */
+	if (ccmax != 0)
+		ccmax += CBSIZE - 1;
+	if (ccreserved != 0)
+		ccreserved += CBSIZE - 1;
+
+	clistp->c_cbmax = roundup(ccmax, CBSIZE) / CBSIZE;
+	dcbr = roundup(ccreserved, CBSIZE) / CBSIZE - clistp->c_cbreserved;
+	if (dcbr >= 0)
+		cblock_alloc_cblocks(dcbr);
+	else {
+		if (clistp->c_cbreserved + dcbr < clistp->c_cbcount)
+			dcbr = clistp->c_cbcount - clistp->c_cbreserved;
+		cblock_free_cblocks(-dcbr);
+	}
+	clistp->c_cbreserved += dcbr;
+}
+
+/*
+ * Free some cblocks from the cfreelist queue back to the
+ * system malloc pool.
+ */
+static void
+cblock_free_cblocks(int number)
 {
+	int i;
+
+	for (i = 0; i < number; ++i)
+		free(cblock_alloc(), M_CLIST);
+	ctotcount -= number;
 }
 
+/*
+ * Free the cblocks reserved for a clist.
+ * Must be called at spltty().
+ */
 void
-clist_free(struct clist *cl)
+clist_free_cblocks(struct clist *clistp)
+{
+	if (clistp->c_cbcount != 0)
+		panic("freeing active clist cblocks");
+	cblock_free_cblocks(clistp->c_cbreserved);
+	clistp->c_cbmax = 0;
+	clistp->c_cbreserved = 0;
+}
+
+/*
+ * Get a character from the head of a clist.
+ */
+int
+getc(struct clist *clistp)
 {
+	int chr = -1;
+	int s;
+	struct cblock *cblockp;
+
+	s = spltty();
+
+	/* If there are characters in the list, get one */
+	if (clistp->c_cc) {
+		cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND);
+		chr = (u_char)*clistp->c_cf;
+
+		/*
+		 * Advance to next character.
+		 */
+		clistp->c_cf++;
+		clistp->c_cc--;
+		/*
+		 * If we have advanced the 'first' character pointer
+		 * past the end of this cblock, advance to the next one.
+		 * If there are no more characters, set the first and
+		 * last pointers to NULL. In either case, free the
+		 * current cblock.
+		 */
+		if ((clistp->c_cf >= (char *)(cblockp+1)) || (clistp->c_cc == 0)) {
+			if (clistp->c_cc > 0) {
+				clistp->c_cf = cblockp->c_next->c_info;
+			} else {
+				clistp->c_cf = clistp->c_cl = NULL;
+			}
+			cblock_free(cblockp);
+			if (--clistp->c_cbcount >= clistp->c_cbreserved)
+				++cslushcount;
+		}
+	}
+
+	splx(s);
+	return (chr);
 }
 
-size_t
-clist_read(struct clist *cl, void *buf, size_t len)
+/*
+ * Copy 'amount' of chars, beginning at head of clist 'clistp' to
+ * destination linear buffer 'dest'. Return number of characters
+ * actually copied.
+ */
+int
+q_to_b(struct clist *clistp, char *dest, int amount)
+{
+	struct cblock *cblockp;
+	struct cblock *cblockn;
+	char *dest_orig = dest;
+	int numc;
+	int s;
+
+	s = spltty();
+
+	while (clistp && amount && (clistp->c_cc > 0)) {
+		cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND);
+		cblockn = cblockp + 1; /* pointer arithmetic! */
+		numc = min(amount, (char *)cblockn - clistp->c_cf);
+		numc = min(numc, clistp->c_cc);
+		bcopy(clistp->c_cf, dest, numc);
+		amount -= numc;
+		clistp->c_cf += numc;
+		clistp->c_cc -= numc;
+		dest += numc;
+		/*
+		 * If this cblock has been emptied, advance to the next
+		 * one. If there are no more characters, set the first
+		 * and last pointer to NULL. In either case, free the
+		 * current cblock.
+		 */
+		if ((clistp->c_cf >= (char *)cblockn) || (clistp->c_cc == 0)) {
+			if (clistp->c_cc > 0) {
+				clistp->c_cf = cblockp->c_next->c_info;
+			} else {
+				clistp->c_cf = clistp->c_cl = NULL;
+			}
+			cblock_free(cblockp);
+			if (--clistp->c_cbcount >= clistp->c_cbreserved)
+				++cslushcount;
+		}
+	}
+
+	splx(s);
+	return (dest - dest_orig);
+}
+
+/*
+ * Flush 'amount' of chars, beginning at head of clist 'clistp'.
+ */
+void
+ndflush(struct clist *clistp, int amount)
 {
+	struct cblock *cblockp;
+	struct cblock *cblockn;
+	int numc;
+	int s;
+
+	s = spltty();
+
+	while (amount && (clistp->c_cc > 0)) {
+		cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND);
+		cblockn = cblockp + 1; /* pointer arithmetic! */
+		numc = min(amount, (char *)cblockn - clistp->c_cf);
+		numc = min(numc, clistp->c_cc);
+		amount -= numc;
+		clistp->c_cf += numc;
+		clistp->c_cc -= numc;
+		/*
+		 * If this cblock has been emptied, advance to the next
+		 * one. If there are no more characters, set the first
+		 * and last pointer to NULL. In either case, free the
+		 * current cblock.
+		 */
+		if ((clistp->c_cf >= (char *)cblockn) || (clistp->c_cc == 0)) {
+			if (clistp->c_cc > 0) {
+				clistp->c_cf = cblockp->c_next->c_info;
+			} else {
+				clistp->c_cf = clistp->c_cl = NULL;
+			}
+			cblock_free(cblockp);
+			if (--clistp->c_cbcount >= clistp->c_cbreserved)
+				++cslushcount;
+		}
+	}
 
-	return (0);
+	splx(s);
 }
 
-size_t
-clist_write(struct clist *cl, const void *buf, size_t len)
+/*
+ * Add a character to the end of a clist. Return -1 is no
+ * more clists, or 0 for success.
+ */
+int
+putc(char chr, struct clist *clistp)
 {
+	struct cblock *cblockp;
+	int s;
+
+	s = spltty();
+
+	if (clistp->c_cl == NULL) {
+		if (clistp->c_cbreserved < 1) {
+			splx(s);
+			printf("putc to a clist with no reserved cblocks\n");
+			return (-1);		/* nothing done */
+		}
+		cblockp = cblock_alloc();
+		clistp->c_cbcount = 1;
+		clistp->c_cf = clistp->c_cl = cblockp->c_info;
+		clistp->c_cc = 0;
+	} else {
+		cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
+		if (((intptr_t)clistp->c_cl & CROUND) == 0) {
+			struct cblock *prev = (cblockp - 1);
+
+			if (clistp->c_cbcount >= clistp->c_cbreserved) {
+				if (clistp->c_cbcount >= clistp->c_cbmax
+				    || cslushcount <= 0) {
+					splx(s);
+					return (-1);
+				}
+				--cslushcount;
+			}
+			cblockp = cblock_alloc();
+			clistp->c_cbcount++;
+			prev->c_next = cblockp;
+			clistp->c_cl = cblockp->c_info;
+		}
+	}
+
+	*clistp->c_cl++ = chr;
+	clistp->c_cc++;
 
+	splx(s);
 	return (0);
 }
 
-size_t
-clist_usage(struct clist *cl)
+/*
+ * Copy data from linear buffer to clist chain. Return the
+ * number of characters not copied.
+ */
+int
+b_to_q(char *src, int amount, struct clist *clistp)
 {
+	struct cblock *cblockp;
+	int numc, s;
+
+	/*
+	 * Avoid allocating an initial cblock and then not using it.
+	 * c_cc == 0 must imply c_cbount == 0.
+	 */
+	if (amount <= 0)
+		return (amount);
+
+	s = spltty();
+
+	/*
+	 * If there are no cblocks assigned to this clist yet,
+	 * then get one.
+	 */
+	if (clistp->c_cl == NULL) {
+		if (clistp->c_cbreserved < 1) {
+			splx(s);
+			printf("b_to_q to a clist with no reserved cblocks.\n");
+			return (amount);	/* nothing done */
+		}
+		cblockp = cblock_alloc();
+		clistp->c_cbcount = 1;
+		clistp->c_cf = clistp->c_cl = cblockp->c_info;
+		clistp->c_cc = 0;
+	} else {
+		cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
+	}
+
+	while (amount) {
+		/*
+		 * Get another cblock if needed.
+		 */
+		if (((intptr_t)clistp->c_cl & CROUND) == 0) {
+			struct cblock *prev = cblockp - 1;
+
+			if (clistp->c_cbcount >= clistp->c_cbreserved) {
+				if (clistp->c_cbcount >= clistp->c_cbmax
+				    || cslushcount <= 0) {
+					splx(s);
+					return (amount);
+				}
+				--cslushcount;
+			}
+			cblockp = cblock_alloc();
+			clistp->c_cbcount++;
+			prev->c_next = cblockp;
+			clistp->c_cl = cblockp->c_info;
+		}
+
+		/*
+		 * Copy a chunk of the linear buffer up to the end
+		 * of this cblock.
+		 */
+		numc = min(amount, (char *)(cblockp + 1) - clistp->c_cl);
+		bcopy(src, clistp->c_cl, numc);
+
+		/*
+		 * ...and update pointer for the next chunk.
+		 */
+		src += numc;
+		clistp->c_cl += numc;
+		clistp->c_cc += numc;
+		amount -= numc;
+		/*
+		 * If we go through the loop again, it's always
+		 * for data in the next cblock, so by adding one (cblock),
+		 * (which makes the pointer 1 beyond the end of this
+		 * cblock) we prepare for the assignment of 'prev'
+		 * above.
+		 */
+		cblockp += 1;
+
+	}
 
-	return (0);
+	splx(s);
+	return (amount);
 }
 
-void
-clist_flush(struct clist *cl)
+/*
+ * "Unput" a character from a clist.
+ */
+int
+unputc(struct clist *clistp)
 {
+	struct cblock *cblockp = 0, *cbp = 0;
+	int s;
+	int chr = -1;
+
+
+	s = spltty();
+
+	if (clistp->c_cc) {
+		--clistp->c_cc;
+		--clistp->c_cl;
+
+		chr = (u_char)*clistp->c_cl;
+
+		cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
+
+		/*
+		 * If all of the characters have been unput in this
+		 * cblock, then find the previous one and free this
+		 * one.
+		 */
+		if (clistp->c_cc && (clistp->c_cl <= (char *)cblockp->c_info)) {
+			cbp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND);
+
+			while (cbp->c_next != cblockp)
+				cbp = cbp->c_next;
+
+			/*
+			 * When the previous cblock is at the end, the 'last'
+			 * pointer always points (invalidly) one past.
+			 */
+			clistp->c_cl = (char *)(cbp+1);
+			cblock_free(cblockp);
+			if (--clistp->c_cbcount >= clistp->c_cbreserved)
+				++cslushcount;
+			cbp->c_next = NULL;
+		}
+	}
+
+	/*
+	 * If there are no more characters on the list, then
+	 * free the last cblock.
+	 */
+	if ((clistp->c_cc == 0) && clistp->c_cl) {
+		cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
+		cblock_free(cblockp);
+		if (--clistp->c_cbcount >= clistp->c_cbreserved)

>>> TRUNCATED FOR MAIL (1000 lines) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200810261341.m9QDfsuA064902>