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>