Hello, I can confirm that this bug also affects pulseaudio on squeeze while not affecting lenny. When commands are read from stdin (e.g. "echo info | pacmd") pacmd handles the closing of stdin incorrectly and enters an endless poll()-loop. The referenced Ubuntu-bug only provides a workaround by replacing all occurences of "echo <something> | pacmd" by "pacmd <something>". This is insufficient since it still leaves the regression, thus breaking other previously working code.
Also, I have ported and tested the upstream patch for the problem. Please see the attached patch which fixes the problem for me. It's, up to some small differences, the same as upstream commit 609a005b77b5dc691271f48351bd39e3eecb7dc9. Ciao, Alexander Wuerstlein.
--- pacmd.c.orig 2009-11-23 23:22:41.000000000 +0100 +++ pacmd.c 2011-02-10 16:53:34.000000000 +0100 @@ -45,13 +45,6 @@ int main(int argc, char*argv[]) { - enum { - WATCH_STDIN, - WATCH_STDOUT, - WATCH_SOCKET, - N_WATCH - }; - pid_t pid ; int fd = -1; int ret = 1, i; @@ -60,7 +53,11 @@ size_t ibuf_index, ibuf_length, obuf_index, obuf_length; char *cli; pa_bool_t ibuf_eof, obuf_eof, ibuf_closed, obuf_closed; - struct pollfd pollfd[N_WATCH]; + + struct pollfd pollfd[3]; + struct pollfd *watch_socket, *watch_stdin, *watch_stdout; + + int stdin_type = 0, stdout_type = 0, fd_type = 0; setlocale(LC_ALL, ""); bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR); @@ -128,32 +125,53 @@ ibuf_eof = TRUE; } - pa_zero(pollfd); - - pollfd[WATCH_STDIN].fd = STDIN_FILENO; - pollfd[WATCH_STDOUT].fd = STDOUT_FILENO; - pollfd[WATCH_SOCKET].fd = fd; - for (;;) { + struct pollfd *p; + if (ibuf_eof && obuf_eof && ibuf_length <= 0 && obuf_length <= 0) break; - pollfd[WATCH_STDIN].events = pollfd[WATCH_STDOUT].events = pollfd[WATCH_SOCKET].events = 0; + if (ibuf_length <= 0 && ibuf_eof && !ibuf_closed) { + shutdown(fd, SHUT_WR); + ibuf_closed = TRUE; + } - if (obuf_length > 0) - pollfd[WATCH_STDOUT].events |= POLLOUT; - else if (!obuf_eof) - pollfd[WATCH_SOCKET].events |= POLLIN; - - if (ibuf_length > 0) - pollfd[WATCH_SOCKET].events |= POLLOUT; - else if (!ibuf_eof) - pollfd[WATCH_STDIN].events |= POLLIN; + if (obuf_length <= 0 && obuf_eof && !obuf_closed) { + shutdown(fd, SHUT_RD); + obuf_closed = TRUE; + } + + pa_zero(pollfd); + + p = pollfd; - if (poll(pollfd, N_WATCH, -1) < 0) { + if (ibuf_length > 0 || (!obuf_eof && obuf_length <= 0)) { + watch_socket = p++; + watch_socket->fd = fd; + watch_socket->events = + (ibuf_length > 0 ? POLLOUT : 0) | + (!obuf_eof && obuf_length <= 0 ? POLLIN : 0); + } else + watch_socket = NULL; + + if (!ibuf_eof && ibuf_length <= 0) { + watch_stdin = p++; + watch_stdin->fd = STDIN_FILENO; + watch_stdin->events = POLLIN; + } else + watch_stdin = NULL; + + if (obuf_length > 0) { + watch_stdout = p++; + watch_stdout->fd = STDOUT_FILENO; + watch_stdout->events = POLLOUT; + } else + watch_stdout = NULL; + + if (poll(pollfd, p-pollfd, -1) < 0) { if (errno == EINTR) continue; @@ -162,82 +180,80 @@ goto fail; } - if (pollfd[WATCH_STDIN].revents & POLLIN) { - ssize_t r; - pa_assert(!ibuf_length); - - if ((r = pa_read(STDIN_FILENO, ibuf, sizeof(ibuf), NULL)) <= 0) { - if (r < 0) { - pa_log(_("read(): %s"), strerror(errno)); - goto fail; + if (watch_stdin) { + if (watch_stdin->revents & POLLIN) { + ssize_t r; + pa_assert(ibuf_length <= 0); + + if ((r = pa_read(STDIN_FILENO, ibuf, sizeof(ibuf), &stdin_type)) <= 0) { + if (r < 0) { + pa_log(_("read(): %s"), strerror(errno)); + goto fail; + } + + ibuf_eof = TRUE; + } else { + ibuf_length = (size_t) r; + ibuf_index = 0; } - + } else if (watch_stdin->revents & POLLHUP) ibuf_eof = TRUE; - } else { - ibuf_length = (size_t) r; - ibuf_index = 0; - } } - if (pollfd[WATCH_SOCKET].revents & POLLIN) { - ssize_t r; - pa_assert(!obuf_length); - - if ((r = pa_read(fd, obuf, sizeof(obuf), NULL)) <= 0) { - if (r < 0) { - pa_log(_("read(): %s"), strerror(errno)); - goto fail; + if (watch_socket) { + if (watch_socket->revents & POLLIN) { + ssize_t r; + pa_assert(obuf_length <= 0); + + if ((r = pa_read(fd, obuf, sizeof(obuf), &fd_type)) <= 0) { + if (r < 0) { + pa_log(_("read(): %s"), strerror(errno)); + goto fail; + } + + obuf_eof = TRUE; + } else { + obuf_length = (size_t) r; + obuf_index = 0; } - + } else if (watch_socket->revents & POLLHUP) obuf_eof = TRUE; - } else { - obuf_length = (size_t) r; - obuf_index = 0; - } } - if (pollfd[WATCH_STDOUT].revents & POLLHUP) { - obuf_eof = TRUE; - obuf_length = 0; - } else if (pollfd[WATCH_STDOUT].revents & POLLOUT) { - ssize_t r; - pa_assert(obuf_length); - - if ((r = pa_write(STDOUT_FILENO, obuf + obuf_index, obuf_length, NULL)) < 0) { - pa_log(_("write(): %s"), strerror(errno)); - goto fail; - } + if (watch_stdout) { + if (watch_stdout->revents & POLLHUP) { + obuf_eof = TRUE; + obuf_length = 0; + } else if (watch_stdout->revents & POLLOUT) { + ssize_t r; + pa_assert(obuf_length > 0); - obuf_length -= (size_t) r; - obuf_index += obuf_index; - } + if ((r = pa_write(STDOUT_FILENO, obuf + obuf_index, obuf_length, &stdout_type)) < 0) { + pa_log(_("write(): %s"), strerror(errno)); + goto fail; + } - if (pollfd[WATCH_SOCKET].revents & POLLHUP) { - ibuf_eof = TRUE; - ibuf_length = 0; - } if (pollfd[WATCH_SOCKET].revents & POLLOUT) { - ssize_t r; - pa_assert(ibuf_length); - - if ((r = pa_write(fd, ibuf + ibuf_index, ibuf_length, NULL)) < 0) { - pa_log(_("write(): %s"), strerror(errno)); - goto fail; + obuf_length -= (size_t) r; + obuf_index += obuf_index; } - - ibuf_length -= (size_t) r; - ibuf_index += obuf_index; } - if (ibuf_length <= 0 && ibuf_eof && !ibuf_closed) { - pa_close(STDIN_FILENO); - shutdown(fd, SHUT_WR); - ibuf_closed = TRUE; - } + if (watch_socket) { + if (watch_socket->revents & POLLHUP) { + ibuf_eof = TRUE; + ibuf_length = 0; + } if (watch_socket->revents & POLLOUT) { + ssize_t r; + pa_assert(ibuf_length > 0); - if (obuf_length <= 0 && obuf_eof && !obuf_closed) { - shutdown(fd, SHUT_RD); - pa_close(STDOUT_FILENO); - obuf_closed = TRUE; + if ((r = pa_write(fd, ibuf + ibuf_index, ibuf_length, &fd_type)) < 0) { + pa_log(_("write(): %s"), strerror(errno)); + goto fail; + } + + ibuf_length -= (size_t) r; + ibuf_index += obuf_index; + } } }