PERFORCE change 151950 for review
Ed Schouten
ed at FreeBSD.org
Sun Oct 26 13:41:54 UTC 2008
http://perforce.freebsd.org/chv.cgi?CH=151950
Change 151950 by ed at 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 at 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) <<<
More information about the p4-projects
mailing list