summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2006-05-23 23:06:28 +0000
committerLennart Poettering <lennart@poettering.net>2006-05-23 23:06:28 +0000
commit23b123d361959553fc9e467dd4b605adee00f07e (patch)
tree7a14213a4a35cb96b4b220dcf1cda08c2e2c65e5
parente99afdae388018f119c16c3a331e01898ab9a90a (diff)
- use pthread_atfork() to disable open sound streams in the child after a fork.
Obviusly sound won't work in child process but at least we don't leak fds from the parent. Now any operation on the device fd in the child will result in an EBADF error, which seems somewhat clean to me. - flush our unix socket properly on RESET ioctl git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@953 fefdeb5f-60dc-0310-8127-8f9354f1896f
-rw-r--r--src/utils/padsp.c128
1 files changed, 122 insertions, 6 deletions
diff --git a/src/utils/padsp.c b/src/utils/padsp.c
index ec073a28..a69676ab 100644
--- a/src/utils/padsp.c
+++ b/src/utils/padsp.c
@@ -60,6 +60,7 @@ typedef struct fd_info fd_info;
struct fd_info {
pthread_mutex_t mutex;
int ref;
+ int unusable;
fd_info_type_t type;
int app_fd, thread_fd;
@@ -82,6 +83,7 @@ struct fd_info {
};
static int dsp_drain(fd_info *i);
+static void fd_info_remove_from_list(fd_info *i);
static pthread_mutex_t fd_infos_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t func_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -289,14 +291,101 @@ static char *client_name(char *buf, size_t n) {
return buf;
}
+static void atfork_prepare(void) {
+ fd_info *i;
+
+ debug(__FILE__": atfork_prepare() enter\n");
+
+ function_enter();
+
+ pthread_mutex_lock(&fd_infos_mutex);
+
+ for (i = fd_infos; i; i = i->next) {
+ pthread_mutex_lock(&i->mutex);
+ pa_threaded_mainloop_lock(i->mainloop);
+ }
+
+ pthread_mutex_lock(&func_mutex);
+
+
+ debug(__FILE__": atfork_prepare() exit\n");
+}
+
+static void atfork_parent(void) {
+ fd_info *i;
+
+ debug(__FILE__": atfork_parent() enter\n");
+
+ pthread_mutex_unlock(&func_mutex);
+
+ for (i = fd_infos; i; i = i->next) {
+ pa_threaded_mainloop_unlock(i->mainloop);
+ pthread_mutex_unlock(&i->mutex);
+ }
+
+ pthread_mutex_unlock(&fd_infos_mutex);
+
+ function_exit();
+
+ debug(__FILE__": atfork_parent() exit\n");
+}
+
+static void atfork_child(void) {
+ fd_info *i;
+
+ debug(__FILE__": atfork_child() enter\n");
+
+ /* We do only the bare minimum to get all fds closed */
+ pthread_mutex_init(&func_mutex, NULL);
+ pthread_mutex_init(&fd_infos_mutex, NULL);
+
+ for (i = fd_infos; i; i = i->next) {
+ pthread_mutex_init(&i->mutex, NULL);
+
+ if (i->context) {
+ pa_context_disconnect(i->context);
+ pa_context_unref(i->context);
+ i->context = NULL;
+ }
+
+ if (i->stream) {
+ pa_stream_unref(i->stream);
+ i->stream = NULL;
+ }
+
+ if (i->app_fd >= 0) {
+ close(i->app_fd);
+ i->app_fd = -1;
+ }
+
+ if (i->thread_fd >= 0) {
+ close(i->thread_fd);
+ i->thread_fd = -1;
+ }
+
+ i->unusable = 1;
+ }
+
+ function_exit();
+
+ debug(__FILE__": atfork_child() exit\n");
+}
+
+static void install_atfork(void) {
+ pthread_atfork(atfork_prepare, atfork_parent, atfork_child);
+}
+
static fd_info* fd_info_new(fd_info_type_t type, int *_errno) {
fd_info *i;
int sfds[2] = { -1, -1 };
char name[64];
+ static pthread_once_t install_atfork_once = PTHREAD_ONCE_INIT;
debug(__FILE__": fd_info_new()\n");
signal(SIGPIPE, SIG_IGN); /* Yes, ugly as hell */
+
+ pthread_once(&install_atfork_once, install_atfork);
if (!(i = malloc(sizeof(fd_info)))) {
*_errno = ENOMEM;
@@ -313,6 +402,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) {
pthread_mutex_init(&i->mutex, NULL);
i->ref = 1;
i->buf = NULL;
+ i->unusable = 0;
PA_LLIST_INIT(fd_info, i);
reset_params(i);
@@ -404,7 +494,7 @@ static fd_info* fd_info_find(int fd) {
pthread_mutex_lock(&fd_infos_mutex);
for (i = fd_infos; i; i = i->next)
- if (i->app_fd == fd) {
+ if (i->app_fd == fd && !i->unusable) {
fd_info_ref(i);
break;
}
@@ -546,7 +636,7 @@ static int create_stream(fd_info *i) {
fix_metrics(i);
- if (!(i->stream = pa_stream_new(i->context, "audio stream", &i->sample_spec, NULL))) {
+ if (!(i->stream = pa_stream_new(i->context, "Audio Stream", &i->sample_spec, NULL))) {
debug(__FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
goto fail;
}
@@ -784,6 +874,30 @@ static void success_cb(pa_stream *s, int success, void *userdata) {
pa_threaded_mainloop_signal(i->mainloop, 0);
}
+static int dsp_flush_socket(fd_info *i) {
+ int l;
+
+ if (i->thread_fd < 0)
+ return -1;
+
+ if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) {
+ debug(__FILE__": SIOCINQ: %s\n", strerror(errno));
+ return -1;
+ }
+
+ while (l > 0) {
+ char buf[1024];
+ size_t k;
+
+ k = (size_t) l > sizeof(buf) ? sizeof(buf) : (size_t) l;
+ if (read(i->thread_fd, buf, k) < 0)
+ debug(__FILE__": read(): %s\n", strerror(errno));
+ l -= k;
+ }
+
+ return 0;
+}
+
static int dsp_empty_socket(fd_info *i) {
int ret = -1;
@@ -791,7 +905,7 @@ static int dsp_empty_socket(fd_info *i) {
for (;;) {
int l;
- if (i->thread_fd < 0)
+ if (i->thread_fd < 0 || !i->stream)
break;
if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) {
@@ -861,8 +975,6 @@ static int dsp_trigger(fd_info *i) {
pa_operation *o = NULL;
int r = -1;
- fd_info_copy_data(i, 1);
-
if (!i->stream)
return 0;
@@ -926,6 +1038,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno)
case SNDCTL_DSP_SPEED: {
pa_sample_spec ss;
int valid;
+ char t[256];
debug(__FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp);
@@ -939,13 +1052,15 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno)
free_stream(i);
}
+ debug(__FILE__": ss: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec));
+
pa_threaded_mainloop_unlock(i->mainloop);
if (!valid) {
*_errno = EINVAL;
goto fail;
}
-
+
break;
}
@@ -1063,6 +1178,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno)
pa_threaded_mainloop_lock(i->mainloop);
free_stream(i);
+ dsp_flush_socket(i);
reset_params(i);
pa_threaded_mainloop_unlock(i->mainloop);