=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/aucat/abuf.c,v retrieving revision 1.25 retrieving revision 1.26 diff -u -r1.25 -r1.26 --- src/usr.bin/aucat/abuf.c 2013/11/18 17:37:45 1.25 +++ src/usr.bin/aucat/abuf.c 2015/01/21 08:43:55 1.26 @@ -1,6 +1,6 @@ -/* $OpenBSD: abuf.c,v 1.25 2013/11/18 17:37:45 ratchov Exp $ */ +/* $OpenBSD: abuf.c,v 1.26 2015/01/21 08:43:55 ratchov Exp $ */ /* - * Copyright (c) 2008 Alexandre Ratchov + * Copyright (c) 2008-2012 Alexandre Ratchov * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,205 +15,85 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* - * Simple byte fifo. It has one reader and one writer. The abuf - * structure is used to interconnect audio processing units (aproc - * structures). + * Simple byte fifo. * * The abuf data is split in two parts: (1) valid data available to the reader * (2) space available to the writer, which is not necessarily unused. It works * as follows: the write starts filling at offset (start + used), once the data * is ready, the writer adds to used the count of bytes available. */ -/* - * TODO - * - * use blocks instead of frames for WOK and ROK macros. If necessary - * (unlikely) define reader block size and writer blocks size to - * ease pipe/socket implementation - */ -#include -#include #include #include #include #include "abuf.h" -#include "aparams.h" -#include "aproc.h" -#include "conf.h" -#ifdef DEBUG -#include "dbg.h" -#endif +#include "utils.h" -void abuf_dump(struct abuf *); -int abuf_flush_do(struct abuf *); -int abuf_fill_do(struct abuf *); -void abuf_eof_do(struct abuf *); -void abuf_hup_do(struct abuf *); - #ifdef DEBUG void -abuf_dbg(struct abuf *buf) +abuf_log(struct abuf *buf) { - if (buf->wproc) { - aproc_dbg(buf->wproc); - } else { - dbg_puts("none"); - } - dbg_puts(buf->inuse ? "=>" : "->"); - if (buf->rproc) { - aproc_dbg(buf->rproc); - } else { - dbg_puts("none"); - } + log_putu(buf->start); + log_puts("+"); + log_putu(buf->used); + log_puts("/"); + log_putu(buf->len); } +#endif void -abuf_dump(struct abuf *buf) +abuf_init(struct abuf *buf, unsigned int len) { - abuf_dbg(buf); - dbg_puts(": used = "); - dbg_putu(buf->used); - dbg_puts("/"); - dbg_putu(buf->len); - dbg_puts(" start = "); - dbg_putu(buf->start); - dbg_puts("\n"); -} -#endif - -struct abuf * -abuf_new(unsigned int nfr, struct aparams *par) -{ - struct abuf *buf; - unsigned int len, bpf; - - bpf = aparams_bpf(par); - len = nfr * bpf; - buf = malloc(sizeof(struct abuf) + len); - if (buf == NULL) { -#ifdef DEBUG - dbg_puts("couldn't allocate abuf of "); - dbg_putu(nfr); - dbg_puts("fr * "); - dbg_putu(bpf); - dbg_puts("bpf\n"); - dbg_panic(); -#else - err(1, "malloc"); -#endif - } - buf->bpf = bpf; - buf->cmin = par->cmin; - buf->cmax = par->cmax; - buf->inuse = 0; - - /* - * fill fifo pointers - */ - buf->len = nfr; + buf->data = xmalloc(len); + buf->len = len; buf->used = 0; buf->start = 0; - buf->rproc = NULL; - buf->wproc = NULL; - buf->duplex = NULL; - return buf; } void -abuf_del(struct abuf *buf) +abuf_done(struct abuf *buf) { - if (buf->duplex) - buf->duplex->duplex = NULL; -#ifdef DEBUG - if (buf->rproc || buf->wproc) { - abuf_dbg(buf); - dbg_puts(": can't delete referenced buffer\n"); - dbg_panic(); - } - if (ABUF_ROK(buf)) { - /* - * XXX: we should call abort(), here. - * However, poll() doesn't seem to return POLLHUP, - * so the reader is never destroyed; instead it appears - * as blocked. Fix file_poll(), if fixable, and add - * a call to abord() here. - */ - if (debug_level >= 3) { - abuf_dbg(buf); - dbg_puts(": deleting non-empty buffer, used = "); - dbg_putu(buf->used); - dbg_puts("\n"); +#ifdef DEBUG + if (buf->used > 0) { + if (log_level >= 3) { + log_puts("deleting non-empty buffer, used = "); + log_putu(buf->used); + log_puts("\n"); } } #endif - free(buf); + xfree(buf->data); + buf->data = (void *)0xdeadbeef; } /* - * Clear buffer contents. + * return the reader pointer and the number of bytes available */ -void -abuf_clear(struct abuf *buf) -{ -#ifdef DEBUG - if (debug_level >= 3) { - abuf_dbg(buf); - dbg_puts(": cleared\n"); - } -#endif - buf->used = 0; - buf->start = 0; -} - -/* - * Get a pointer to the readable block at the given offset. - */ unsigned char * -abuf_rgetblk(struct abuf *buf, unsigned int *rsize, unsigned int ofs) +abuf_rgetblk(struct abuf *buf, int *rsize) { - unsigned int count, start, used; + int count; - start = buf->start + ofs; - used = buf->used - ofs; - if (start >= buf->len) - start -= buf->len; -#ifdef DEBUG - if (start >= buf->len || used > buf->used) { - abuf_dump(buf); - dbg_puts(": rgetblk: bad ofs = "); - dbg_putu(ofs); - dbg_puts("\n"); - dbg_panic(); - } -#endif - count = buf->len - start; - if (count > used) - count = used; + count = buf->len - buf->start; + if (count > buf->used) + count = buf->used; *rsize = count; - return (unsigned char *)buf + sizeof(struct abuf) + start * buf->bpf; + return buf->data + buf->start; } /* - * Discard the block at the start postion. + * discard "count" bytes at the start postion. */ void -abuf_rdiscard(struct abuf *buf, unsigned int count) +abuf_rdiscard(struct abuf *buf, int count) { #ifdef DEBUG - if (count > buf->used) { - abuf_dump(buf); - dbg_puts(": rdiscard: bad count = "); - dbg_putu(count); - dbg_puts("\n"); - dbg_panic(); + if (count < 0 || count > buf->used) { + log_puts("abuf_rdiscard: bad count = "); + log_putu(count); + log_puts("\n"); + panic(); } - if (debug_level >= 4) { - abuf_dbg(buf); - dbg_puts(": discard("); - dbg_putu(count); - dbg_puts(")\n"); - } #endif buf->used -= count; buf->start += count; @@ -222,404 +102,37 @@ } /* - * Commit the data written at the end postion. + * advance the writer pointer by "count" bytes */ void -abuf_wcommit(struct abuf *buf, unsigned int count) +abuf_wcommit(struct abuf *buf, int count) { #ifdef DEBUG - if (count > (buf->len - buf->used)) { - abuf_dump(buf); - dbg_puts(": rdiscard: bad count = "); - dbg_putu(count); - dbg_puts("\n"); - dbg_panic(); + if (count < 0 || count > (buf->len - buf->used)) { + log_puts("abuf_wcommit: bad count = "); + log_putu(count); + log_puts("\n"); + panic(); } - if (debug_level >= 4) { - abuf_dbg(buf); - dbg_puts(": commit("); - dbg_putu(count); - dbg_puts(")\n"); - } #endif buf->used += count; } /* - * Get a pointer to the writable block at offset ofs. + * get writer pointer and the number of bytes writable */ unsigned char * -abuf_wgetblk(struct abuf *buf, unsigned int *rsize, unsigned int ofs) +abuf_wgetblk(struct abuf *buf, int *rsize) { - unsigned int end, avail, count; + int end, avail, count; - - end = buf->start + buf->used + ofs; + end = buf->start + buf->used; if (end >= buf->len) end -= buf->len; -#ifdef DEBUG - if (end >= buf->len) { - abuf_dump(buf); - dbg_puts(": wgetblk: bad ofs = "); - dbg_putu(ofs); - dbg_puts("\n"); - dbg_panic(); - } -#endif - avail = buf->len - (buf->used + ofs); + avail = buf->len - buf->used; count = buf->len - end; if (count > avail) - count = avail; + count = avail; *rsize = count; - return (unsigned char *)buf + sizeof(struct abuf) + end * buf->bpf; -} - -/* - * Flush buffer either by dropping samples or by calling the aproc - * call-back to consume data. Return 0 if blocked, 1 otherwise. - */ -int -abuf_flush_do(struct abuf *buf) -{ - struct aproc *p; - - p = buf->rproc; - if (!p) - return 0; -#ifdef DEBUG - if (debug_level >= 4) { - aproc_dbg(p); - dbg_puts(": in\n"); - } -#endif - return p->ops->in(p, buf); -} - -/* - * Fill the buffer either by generating silence or by calling the aproc - * call-back to provide data. Return 0 if blocked, 1 otherwise. - */ -int -abuf_fill_do(struct abuf *buf) -{ - struct aproc *p; - - p = buf->wproc; - if (!p) - return 0; -#ifdef DEBUG - if (debug_level >= 4) { - aproc_dbg(p); - dbg_puts(": out\n"); - } -#endif - return p->ops->out(p, buf); -} - -/* - * Notify the reader that there will be no more input (producer - * disappeared) and destroy the buffer. - */ -void -abuf_eof_do(struct abuf *buf) -{ - struct aproc *p; - - p = buf->rproc; - if (p) { - buf->rproc = NULL; - LIST_REMOVE(buf, ient); - buf->inuse++; -#ifdef DEBUG - if (debug_level >= 4) { - aproc_dbg(p); - dbg_puts(": eof\n"); - } -#endif - p->ops->eof(p, buf); - buf->inuse--; - } - abuf_del(buf); -} - -/* - * Notify the writer that the buffer has no more consumer, - * and destroy the buffer. - */ -void -abuf_hup_do(struct abuf *buf) -{ - struct aproc *p; - - if (ABUF_ROK(buf)) { -#ifdef DEBUG - if (debug_level >= 3) { - abuf_dbg(buf); - dbg_puts(": hup: lost "); - dbg_putu(buf->used); - dbg_puts(" bytes\n"); - } -#endif - buf->used = 0; - } - p = buf->wproc; - if (p != NULL) { - buf->wproc = NULL; - LIST_REMOVE(buf, oent); - buf->inuse++; -#ifdef DEBUG - if (debug_level >= 3) { - aproc_dbg(p); - dbg_puts(": hup\n"); - } -#endif - p->ops->hup(p, buf); - buf->inuse--; - } - abuf_del(buf); -} - -/* - * Notify the read end of the buffer that there is input available - * and that data can be processed again. - */ -int -abuf_flush(struct abuf *buf) -{ - if (buf->inuse) { -#ifdef DEBUG - if (debug_level >= 4) { - abuf_dbg(buf); - dbg_puts(": flush blocked (inuse)\n"); - } -#endif - } else { - buf->inuse++; - for (;;) { - if (!abuf_flush_do(buf)) - break; - } - buf->inuse--; - if (ABUF_HUP(buf)) { - abuf_hup_do(buf); - return 0; - } - } - return 1; -} - -/* - * Notify the write end of the buffer that there is room and data can be - * written again. This routine can only be called from the out() - * call-back of the reader. - * - * Return 1 if the buffer was filled, and 0 if eof condition occured. The - * reader must detach the buffer on EOF condition, since its aproc->eof() - * call-back will never be called. - */ -int -abuf_fill(struct abuf *buf) -{ - if (buf->inuse) { -#ifdef DEBUG - if (debug_level >= 4) { - abuf_dbg(buf); - dbg_puts(": fill blocked (inuse)\n"); - } -#endif - } else { - buf->inuse++; - for (;;) { - if (!abuf_fill_do(buf)) - break; - } - buf->inuse--; - if (ABUF_EOF(buf)) { - abuf_eof_do(buf); - return 0; - } - } - return 1; -} - -/* - * Run a read/write loop on the buffer until either the reader or the - * writer blocks, or until the buffer reaches eofs. We can not get hup here, - * since hup() is only called from terminal nodes, from the main loop. - * - * NOTE: The buffer may disappear (ie. be free()ed) if eof is reached, so - * do not keep references to the buffer or to its writer or reader. - */ -void -abuf_run(struct abuf *buf) -{ - int canfill = 1, canflush = 1; - - if (buf->inuse) { -#ifdef DEBUG - if (debug_level >= 4) { - abuf_dbg(buf); - dbg_puts(": run blocked (inuse)\n"); - } -#endif - return; - } - buf->inuse++; - for (;;) { - if (canfill) { - if (!abuf_fill_do(buf)) - canfill = 0; - else - canflush = 1; - } else if (canflush) { - if (!abuf_flush_do(buf)) - canflush = 0; - else - canfill = 1; - } else - break; - } - buf->inuse--; - if (ABUF_EOF(buf)) { - abuf_eof_do(buf); - return; - } - if (ABUF_HUP(buf)) { - abuf_hup_do(buf); - return; - } -} - -/* - * Notify the reader that there will be no more input (producer - * disappeared). The buffer is flushed and eof() is called only if all - * data is flushed. - */ -void -abuf_eof(struct abuf *buf) -{ -#ifdef DEBUG - if (debug_level >= 3) { - abuf_dbg(buf); - dbg_puts(": eof requested\n"); - } - if (buf->wproc == NULL) { - abuf_dbg(buf); - dbg_puts(": eof, no writer\n"); - dbg_panic(); - } -#endif - LIST_REMOVE(buf, oent); - buf->wproc = NULL; - if (buf->rproc != NULL) { - if (!abuf_flush(buf)) - return; - if (ABUF_ROK(buf)) { - /* - * Could not flush everything, the reader will - * have a chance to delete the abuf later. - */ -#ifdef DEBUG - if (debug_level >= 3) { - abuf_dbg(buf); - dbg_puts(": eof, blocked (drain)\n"); - } -#endif - return; - } - } - if (buf->inuse) { -#ifdef DEBUG - if (debug_level >= 3) { - abuf_dbg(buf); - dbg_puts(": eof, blocked (inuse)\n"); - } -#endif - return; - } - abuf_eof_do(buf); -} - -/* - * Notify the writer that the buffer has no more consumer, - * and that no more data will accepted. - */ -void -abuf_hup(struct abuf *buf) -{ -#ifdef DEBUG - if (debug_level >= 3) { - abuf_dbg(buf); - dbg_puts(": hup requested\n"); - } - if (buf->rproc == NULL) { - abuf_dbg(buf); - dbg_puts(": hup, no reader\n"); - dbg_panic(); - } -#endif - buf->rproc = NULL; - LIST_REMOVE(buf, ient); - if (buf->wproc != NULL) { - if (buf->inuse) { -#ifdef DEBUG - if (debug_level >= 3) { - abuf_dbg(buf); - dbg_puts(": eof, blocked (inuse)\n"); - } -#endif - return; - } - } - abuf_hup_do(buf); -} - -/* - * Notify the reader of the change of its real-time position - */ -void -abuf_ipos(struct abuf *buf, int delta) -{ - struct aproc *p = buf->rproc; - - if (p && p->ops->ipos) { - buf->inuse++; -#ifdef DEBUG - if (debug_level >= 4) { - aproc_dbg(p); - dbg_puts(": ipos delta = "); - dbg_puti(delta); - dbg_puts("\n"); - } -#endif - p->ops->ipos(p, buf, delta); - buf->inuse--; - } - if (ABUF_HUP(buf)) - abuf_hup_do(buf); -} - -/* - * Notify the writer of the change of its real-time position - */ -void -abuf_opos(struct abuf *buf, int delta) -{ - struct aproc *p = buf->wproc; - - if (p && p->ops->opos) { - buf->inuse++; -#ifdef DEBUG - if (debug_level >= 4) { - aproc_dbg(p); - dbg_puts(": opos delta = "); - dbg_puti(delta); - dbg_puts("\n"); - } -#endif - p->ops->opos(p, buf, delta); - buf->inuse--; - } - if (ABUF_HUP(buf)) - abuf_hup_do(buf); + return buf->data + end; }