X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/264385aae4683a47b15aa37a3949796be72870d1..647d49165373790d4a49240b69a30fb23f27aa3b:/src/pulsecore/ioline.c diff --git a/src/pulsecore/ioline.c b/src/pulsecore/ioline.c index 6d11e4fc..ead9ebdf 100644 --- a/src/pulsecore/ioline.c +++ b/src/pulsecore/ioline.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -7,7 +5,7 @@ PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, + by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but @@ -32,8 +30,9 @@ #include -#include +#include #include +#include #include #include #include @@ -49,7 +48,6 @@ struct pa_ioline { pa_iochannel *io; pa_defer_event *defer_event; pa_mainloop_api *mainloop; - int dead; char *wbuf; size_t wbuf_length, wbuf_index, wbuf_valid_length; @@ -57,10 +55,14 @@ struct pa_ioline { char *rbuf; size_t rbuf_length, rbuf_index, rbuf_valid_length; - void (*callback)(pa_ioline*io, const char *s, void *userdata); + pa_ioline_cb_t callback; void *userdata; - int defer_close; + pa_ioline_drain_cb_t drain_callback; + void *drain_userdata; + + bool dead:1; + bool defer_close:1; }; static void io_callback(pa_iochannel*io, void *userdata); @@ -73,7 +75,6 @@ pa_ioline* pa_ioline_new(pa_iochannel *io) { l = pa_xnew(pa_ioline, 1); PA_REFCNT_INIT(l); l->io = io; - l->dead = 0; l->wbuf = NULL; l->wbuf_length = l->wbuf_index = l->wbuf_valid_length = 0; @@ -84,12 +85,16 @@ pa_ioline* pa_ioline_new(pa_iochannel *io) { l->callback = NULL; l->userdata = NULL; + l->drain_callback = NULL; + l->drain_userdata = NULL; + l->mainloop = pa_iochannel_get_mainloop_api(io); l->defer_event = l->mainloop->defer_new(l->mainloop, defer_callback, l); l->mainloop->defer_enable(l->defer_event, 0); - l->defer_close = 0; + l->dead = false; + l->defer_close = false; pa_iochannel_set_callback(io, io_callback, l); @@ -130,7 +135,7 @@ void pa_ioline_close(pa_ioline *l) { pa_assert(l); pa_assert(PA_REFCNT_VALUE(l) >= 1); - l->dead = 1; + l->dead = true; if (l->io) { pa_iochannel_free(l->io); @@ -166,11 +171,13 @@ void pa_ioline_puts(pa_ioline *l, const char *c) { /* In case the allocated buffer is too small, enlarge it. */ if (l->wbuf_valid_length + len > l->wbuf_length) { size_t n = l->wbuf_valid_length+len; - char *new = pa_xmalloc(n); + char *new = pa_xnew(char, (unsigned) n); + if (l->wbuf) { memcpy(new, l->wbuf+l->wbuf_index, l->wbuf_valid_length); pa_xfree(l->wbuf); } + l->wbuf = new; l->wbuf_length = n; l->wbuf_index = 0; @@ -191,15 +198,29 @@ void pa_ioline_puts(pa_ioline *l, const char *c) { } } -void pa_ioline_set_callback(pa_ioline*l, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata) { +void pa_ioline_set_callback(pa_ioline*l, pa_ioline_cb_t callback, void *userdata) { pa_assert(l); pa_assert(PA_REFCNT_VALUE(l) >= 1); + if (l->dead) + return; + l->callback = callback; l->userdata = userdata; } -static void failure(pa_ioline *l, int process_leftover) { +void pa_ioline_set_drain_callback(pa_ioline*l, pa_ioline_drain_cb_t callback, void *userdata) { + pa_assert(l); + pa_assert(PA_REFCNT_VALUE(l) >= 1); + + if (l->dead) + return; + + l->drain_callback = callback; + l->drain_userdata = userdata; +} + +static void failure(pa_ioline *l, bool process_leftover) { pa_assert(l); pa_assert(PA_REFCNT_VALUE(l) >= 1); pa_assert(!l->dead); @@ -263,7 +284,7 @@ static int do_read(pa_ioline *l) { pa_assert(l); pa_assert(PA_REFCNT_VALUE(l) >= 1); - while (!l->dead && pa_iochannel_is_readable(l->io)) { + while (l->io && !l->dead && pa_iochannel_is_readable(l->io)) { ssize_t r; size_t len; @@ -282,7 +303,7 @@ static int do_read(pa_ioline *l) { memmove(l->rbuf, l->rbuf+l->rbuf_index, l->rbuf_valid_length); } else { /* Enlarge the buffer */ - char *new = pa_xmalloc(n); + char *new = pa_xnew(char, (unsigned) n); if (l->rbuf_valid_length) memcpy(new, l->rbuf+l->rbuf_index, l->rbuf_valid_length); pa_xfree(l->rbuf); @@ -305,17 +326,17 @@ static int do_read(pa_ioline *l) { if (r < 0 && errno != ECONNRESET) { pa_log("read(): %s", pa_cstrerror(errno)); - failure(l, 0); + failure(l, false); } else - failure(l, 1); + failure(l, true); return -1; } - l->rbuf_valid_length += r; + l->rbuf_valid_length += (size_t) r; /* Look if a line has been terminated in the newly read data */ - scan_for_lines(l, l->rbuf_valid_length - r); + scan_for_lines(l, l->rbuf_valid_length - (size_t) r); } return 0; @@ -328,29 +349,29 @@ static int do_write(pa_ioline *l) { pa_assert(l); pa_assert(PA_REFCNT_VALUE(l) >= 1); - while (!l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length) { + while (l->io && !l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length > 0) { - if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) <= 0) { + if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) { - if (r < 0 && errno == EAGAIN) - return 0; - - if (r < 0 && errno != EPIPE) + if (errno != EPIPE) pa_log("write(): %s", pa_cstrerror(errno)); - failure(l, 0); + failure(l, false); return -1; } - l->wbuf_index += r; - l->wbuf_valid_length -= r; + l->wbuf_index += (size_t) r; + l->wbuf_valid_length -= (size_t) r; /* A shortcut for the next time */ if (l->wbuf_valid_length == 0) l->wbuf_index = 0; } + if (l->wbuf_valid_length <= 0 && l->drain_callback) + l->drain_callback(l, l->drain_userdata); + return 0; } @@ -370,7 +391,7 @@ static void do_work(pa_ioline *l) { do_write(l); if (l->defer_close && !l->wbuf_valid_length) - failure(l, 1); + failure(l, true); pa_ioline_unref(l); } @@ -400,7 +421,7 @@ void pa_ioline_defer_close(pa_ioline *l) { pa_assert(l); pa_assert(PA_REFCNT_VALUE(l) >= 1); - l->defer_close = 1; + l->defer_close = true; if (!l->wbuf_valid_length) l->mainloop->defer_enable(l->defer_event, 1); @@ -420,3 +441,25 @@ void pa_ioline_printf(pa_ioline *l, const char *format, ...) { pa_ioline_puts(l, t); pa_xfree(t); } + +pa_iochannel* pa_ioline_detach_iochannel(pa_ioline *l) { + pa_iochannel *r; + + pa_assert(l); + + if (!l->io) + return NULL; + + r = l->io; + l->io = NULL; + + pa_iochannel_set_callback(r, NULL, NULL); + + return r; +} + +bool pa_ioline_is_drained(pa_ioline *l) { + pa_assert(l); + + return l->wbuf_valid_length <= 0; +}