mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	rework autospawning code to survive multiple pa_contexts in a single process
This commit is contained in:
		
							parent
							
								
									b4a566918c
								
							
						
					
					
						commit
						15cebbaceb
					
				
					 8 changed files with 595 additions and 38 deletions
				
			
		
							
								
								
									
										1
									
								
								src/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								src/.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
 | 
					lock-autospawn-test
 | 
				
			||||||
*.lo
 | 
					*.lo
 | 
				
			||||||
*.o
 | 
					*.o
 | 
				
			||||||
*.la
 | 
					*.la
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -262,7 +262,8 @@ noinst_PROGRAMS = \
 | 
				
			||||||
		envelope-test \
 | 
							envelope-test \
 | 
				
			||||||
		proplist-test \
 | 
							proplist-test \
 | 
				
			||||||
		rtstutter \
 | 
							rtstutter \
 | 
				
			||||||
		stripnul
 | 
							stripnul \
 | 
				
			||||||
 | 
							lock-autospawn-test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if HAVE_SIGXCPU
 | 
					if HAVE_SIGXCPU
 | 
				
			||||||
noinst_PROGRAMS += \
 | 
					noinst_PROGRAMS += \
 | 
				
			||||||
| 
						 | 
					@ -452,6 +453,11 @@ stripnul_LDADD = $(AM_LDADD) libpulsecore.la
 | 
				
			||||||
stripnul_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS)
 | 
					stripnul_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS)
 | 
				
			||||||
stripnul_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS)
 | 
					stripnul_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					lock_autospawn_test_SOURCES = tests/lock-autospawn-test.c
 | 
				
			||||||
 | 
					lock_autospawn_test_LDADD = $(AM_LDADD) libpulsecore.la
 | 
				
			||||||
 | 
					lock_autospawn_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS)
 | 
				
			||||||
 | 
					lock_autospawn_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
###################################
 | 
					###################################
 | 
				
			||||||
#         Client library          #
 | 
					#         Client library          #
 | 
				
			||||||
###################################
 | 
					###################################
 | 
				
			||||||
| 
						 | 
					@ -535,7 +541,8 @@ libpulse_la_SOURCES = \
 | 
				
			||||||
		pulse/xmalloc.c pulse/xmalloc.h \
 | 
							pulse/xmalloc.c pulse/xmalloc.h \
 | 
				
			||||||
		pulse/proplist.c pulse/proplist.h \
 | 
							pulse/proplist.c pulse/proplist.h \
 | 
				
			||||||
		pulse/ext-stream-restore.c pulse/ext-stream-restore.h \
 | 
							pulse/ext-stream-restore.c pulse/ext-stream-restore.h \
 | 
				
			||||||
		pulse/i18n.c pulse/i18n.h
 | 
							pulse/i18n.c pulse/i18n.h \
 | 
				
			||||||
 | 
							pulse/lock-autospawn.c pulse/lock-autospawn.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Internal stuff that is shared with libpulsecore
 | 
					# Internal stuff that is shared with libpulsecore
 | 
				
			||||||
libpulse_la_SOURCES += \
 | 
					libpulse_la_SOURCES += \
 | 
				
			||||||
| 
						 | 
					@ -731,7 +738,8 @@ libpulsecore_la_SOURCES = \
 | 
				
			||||||
		pulse/volume.c pulse/volume.h \
 | 
							pulse/volume.c pulse/volume.h \
 | 
				
			||||||
		pulse/xmalloc.c pulse/xmalloc.h \
 | 
							pulse/xmalloc.c pulse/xmalloc.h \
 | 
				
			||||||
		pulse/proplist.c pulse/proplist.h \
 | 
							pulse/proplist.c pulse/proplist.h \
 | 
				
			||||||
		pulse/i18n.c pulse/i18n.h
 | 
							pulse/i18n.c pulse/i18n.h \
 | 
				
			||||||
 | 
							pulse/lock-autospawn.c pulse/lock-autospawn.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Pure core stuff (some are shared in libpulse though).
 | 
					# Pure core stuff (some are shared in libpulse though).
 | 
				
			||||||
libpulsecore_la_SOURCES += \
 | 
					libpulsecore_la_SOURCES += \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,6 +65,7 @@
 | 
				
			||||||
#include <pulse/timeval.h>
 | 
					#include <pulse/timeval.h>
 | 
				
			||||||
#include <pulse/xmalloc.h>
 | 
					#include <pulse/xmalloc.h>
 | 
				
			||||||
#include <pulse/i18n.h>
 | 
					#include <pulse/i18n.h>
 | 
				
			||||||
 | 
					#include <pulse/lock-autospawn.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pulsecore/winsock.h>
 | 
					#include <pulsecore/winsock.h>
 | 
				
			||||||
#include <pulsecore/core-error.h>
 | 
					#include <pulsecore/core-error.h>
 | 
				
			||||||
| 
						 | 
					@ -95,8 +96,6 @@
 | 
				
			||||||
#include "ltdl-bind-now.h"
 | 
					#include "ltdl-bind-now.h"
 | 
				
			||||||
#include "polkit.h"
 | 
					#include "polkit.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define AUTOSPAWN_LOCK "autospawn.lock"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_LIBWRAP
 | 
					#ifdef HAVE_LIBWRAP
 | 
				
			||||||
/* Only one instance of these variables */
 | 
					/* Only one instance of these variables */
 | 
				
			||||||
int allow_severity = LOG_INFO;
 | 
					int allow_severity = LOG_INFO;
 | 
				
			||||||
| 
						 | 
					@ -346,7 +345,8 @@ int main(int argc, char *argv[]) {
 | 
				
			||||||
    struct timeval win32_tv;
 | 
					    struct timeval win32_tv;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    char *lf = NULL;
 | 
					    char *lf = NULL;
 | 
				
			||||||
    int autospawn_lock_fd = -1;
 | 
					    int autospawn_fd = -1;
 | 
				
			||||||
 | 
					    pa_bool_t autospawn_locked = FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(__linux__) && defined(__OPTIMIZE__)
 | 
					#if defined(__linux__) && defined(__OPTIMIZE__)
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
| 
						 | 
					@ -656,8 +656,17 @@ int main(int argc, char *argv[]) {
 | 
				
			||||||
         * first take the autospawn lock to make things
 | 
					         * first take the autospawn lock to make things
 | 
				
			||||||
         * synchronous. */
 | 
					         * synchronous. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        lf = pa_runtime_path(AUTOSPAWN_LOCK);
 | 
					        if ((autospawn_fd = pa_autospawn_lock_init()) < 0) {
 | 
				
			||||||
        autospawn_lock_fd = pa_lock_lockfile(lf);
 | 
					            pa_log("Failed to initialize autospawn lock");
 | 
				
			||||||
 | 
					            goto finish;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ((pa_autospawn_lock_acquire(TRUE) < 0)) {
 | 
				
			||||||
 | 
					            pa_log("Failed to acquire autospawn lock");
 | 
				
			||||||
 | 
					            goto finish;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        autospawn_locked = TRUE;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (conf->daemonize) {
 | 
					    if (conf->daemonize) {
 | 
				
			||||||
| 
						 | 
					@ -703,12 +712,15 @@ int main(int argc, char *argv[]) {
 | 
				
			||||||
            goto finish;
 | 
					            goto finish;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (autospawn_lock_fd >= 0) {
 | 
					        if (autospawn_fd >= 0) {
 | 
				
			||||||
            /* The lock file is unlocked from the parent, so we need
 | 
					            /* The lock file is unlocked from the parent, so we need
 | 
				
			||||||
             * to close it in the child */
 | 
					             * to close it in the child */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            pa_close(autospawn_lock_fd);
 | 
					            pa_autospawn_lock_release();
 | 
				
			||||||
            autospawn_lock_fd = -1;
 | 
					            pa_autospawn_lock_done(TRUE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            autospawn_locked = FALSE;
 | 
				
			||||||
 | 
					            autospawn_fd = -1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        pa_assert_se(pa_close(daemon_pipe[0]) == 0);
 | 
					        pa_assert_se(pa_close(daemon_pipe[0]) == 0);
 | 
				
			||||||
| 
						 | 
					@ -917,8 +929,12 @@ int main(int argc, char *argv[]) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
finish:
 | 
					finish:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (autospawn_lock_fd >= 0)
 | 
					    if (autospawn_fd >= 0) {
 | 
				
			||||||
        pa_unlock_lockfile(lf, autospawn_lock_fd);
 | 
					        if (autospawn_locked)
 | 
				
			||||||
 | 
					            pa_autospawn_lock_release();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pa_autospawn_lock_done(FALSE);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (lf)
 | 
					    if (lf)
 | 
				
			||||||
        pa_xfree(lf);
 | 
					        pa_xfree(lf);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,6 +54,7 @@
 | 
				
			||||||
#include <pulse/utf8.h>
 | 
					#include <pulse/utf8.h>
 | 
				
			||||||
#include <pulse/util.h>
 | 
					#include <pulse/util.h>
 | 
				
			||||||
#include <pulse/i18n.h>
 | 
					#include <pulse/i18n.h>
 | 
				
			||||||
 | 
					#include <pulse/lock-autospawn.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pulsecore/winsock.h>
 | 
					#include <pulsecore/winsock.h>
 | 
				
			||||||
#include <pulsecore/core-error.h>
 | 
					#include <pulsecore/core-error.h>
 | 
				
			||||||
| 
						 | 
					@ -81,8 +82,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "context.h"
 | 
					#include "context.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define AUTOSPAWN_LOCK "autospawn.lock"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 | 
					void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
 | 
					static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
 | 
				
			||||||
| 
						 | 
					@ -100,20 +99,23 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
 | 
				
			||||||
    [PA_COMMAND_EXTENSION] = pa_command_extension
 | 
					    [PA_COMMAND_EXTENSION] = pa_command_extension
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void unlock_autospawn_lock_file(pa_context *c) {
 | 
					static void unlock_autospawn(pa_context *c) {
 | 
				
			||||||
    pa_assert(c);
 | 
					    pa_assert(c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (c->autospawn_lock_fd >= 0) {
 | 
					    if (c->autospawn_fd >= 0) {
 | 
				
			||||||
        char *lf;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK)))
 | 
					        if (c->autospawn_locked)
 | 
				
			||||||
            pa_log_warn(_("Cannot unlock autospawn because runtime path is no more."));
 | 
					            pa_autospawn_lock_release();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        pa_unlock_lockfile(lf, c->autospawn_lock_fd);
 | 
					        if (c->autospawn_event)
 | 
				
			||||||
        pa_xfree(lf);
 | 
					            c->mainloop->io_free(c->autospawn_event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        c->autospawn_lock_fd = -1;
 | 
					        pa_autospawn_lock_done(FALSE);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c->autospawn_locked = FALSE;
 | 
				
			||||||
 | 
					    c->autospawn_fd = -1;
 | 
				
			||||||
 | 
					    c->autospawn_event = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void context_free(pa_context *c);
 | 
					static void context_free(pa_context *c);
 | 
				
			||||||
| 
						 | 
					@ -174,11 +176,15 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
 | 
				
			||||||
    c->is_local = FALSE;
 | 
					    c->is_local = FALSE;
 | 
				
			||||||
    c->server_list = NULL;
 | 
					    c->server_list = NULL;
 | 
				
			||||||
    c->server = NULL;
 | 
					    c->server = NULL;
 | 
				
			||||||
    c->autospawn_lock_fd = -1;
 | 
					
 | 
				
			||||||
    memset(&c->spawn_api, 0, sizeof(c->spawn_api));
 | 
					 | 
				
			||||||
    c->do_autospawn = FALSE;
 | 
					 | 
				
			||||||
    c->do_shm = FALSE;
 | 
					    c->do_shm = FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c->do_autospawn = FALSE;
 | 
				
			||||||
 | 
					    c->autospawn_fd = -1;
 | 
				
			||||||
 | 
					    c->autospawn_locked = FALSE;
 | 
				
			||||||
 | 
					    c->autospawn_event = NULL;
 | 
				
			||||||
 | 
					    memset(&c->spawn_api, 0, sizeof(c->spawn_api));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef MSG_NOSIGNAL
 | 
					#ifndef MSG_NOSIGNAL
 | 
				
			||||||
#ifdef SIGPIPE
 | 
					#ifdef SIGPIPE
 | 
				
			||||||
    pa_check_signal_is_blocked(SIGPIPE);
 | 
					    pa_check_signal_is_blocked(SIGPIPE);
 | 
				
			||||||
| 
						 | 
					@ -246,7 +252,7 @@ static void context_free(pa_context *c) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    context_unlink(c);
 | 
					    context_unlink(c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unlock_autospawn_lock_file(c);
 | 
					    unlock_autospawn(c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (c->record_streams)
 | 
					    if (c->record_streams)
 | 
				
			||||||
        pa_dynarray_free(c->record_streams, NULL, NULL);
 | 
					        pa_dynarray_free(c->record_streams, NULL, NULL);
 | 
				
			||||||
| 
						 | 
					@ -674,7 +680,7 @@ static int context_connect_spawn(pa_context *c) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    c->is_local = TRUE;
 | 
					    c->is_local = TRUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unlock_autospawn_lock_file(c);
 | 
					    unlock_autospawn(c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    io = pa_iochannel_new(c->mainloop, fds[0], fds[0]);
 | 
					    io = pa_iochannel_new(c->mainloop, fds[0], fds[0]);
 | 
				
			||||||
    setup_context(c, io);
 | 
					    setup_context(c, io);
 | 
				
			||||||
| 
						 | 
					@ -686,7 +692,7 @@ static int context_connect_spawn(pa_context *c) {
 | 
				
			||||||
fail:
 | 
					fail:
 | 
				
			||||||
    pa_close_pipe(fds);
 | 
					    pa_close_pipe(fds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unlock_autospawn_lock_file(c);
 | 
					    unlock_autospawn(c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_context_unref(c);
 | 
					    pa_context_unref(c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -768,13 +774,46 @@ static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userd
 | 
				
			||||||
        goto finish;
 | 
					        goto finish;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unlock_autospawn_lock_file(c);
 | 
					    unlock_autospawn(c);
 | 
				
			||||||
    setup_context(c, io);
 | 
					    setup_context(c, io);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
finish:
 | 
					finish:
 | 
				
			||||||
    pa_context_unref(c);
 | 
					    pa_context_unref(c);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void autospawn_cb(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
 | 
				
			||||||
 | 
					    pa_context *c = userdata;
 | 
				
			||||||
 | 
					    int k;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert(a);
 | 
				
			||||||
 | 
					    pa_assert(e);
 | 
				
			||||||
 | 
					    pa_assert(fd >= 0);
 | 
				
			||||||
 | 
					    pa_assert(events = PA_IO_EVENT_INPUT);
 | 
				
			||||||
 | 
					    pa_assert(c);
 | 
				
			||||||
 | 
					    pa_assert(e == c->autospawn_event);
 | 
				
			||||||
 | 
					    pa_assert(fd == c->autospawn_fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_context_ref(c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Check whether we can get the lock right now*/
 | 
				
			||||||
 | 
					    if ((k = pa_autospawn_lock_acquire(FALSE)) < 0) {
 | 
				
			||||||
 | 
					        pa_context_fail(c, PA_ERR_ACCESS);
 | 
				
			||||||
 | 
					        goto finish;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (k > 0) {
 | 
				
			||||||
 | 
					        /* So we got it, rock on! */
 | 
				
			||||||
 | 
					        c->autospawn_locked = TRUE;
 | 
				
			||||||
 | 
					        try_next_connection(c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        c->mainloop->io_free(c->autospawn_event);
 | 
				
			||||||
 | 
					        c->autospawn_event = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					finish:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_context_unref(c);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char *get_old_legacy_runtime_dir(void) {
 | 
					static char *get_old_legacy_runtime_dir(void) {
 | 
				
			||||||
    char *p, u[128];
 | 
					    char *p, u[128];
 | 
				
			||||||
| 
						 | 
					@ -847,6 +886,7 @@ int pa_context_connect(
 | 
				
			||||||
            pa_context_fail(c, PA_ERR_INVALIDSERVER);
 | 
					            pa_context_fail(c, PA_ERR_INVALIDSERVER);
 | 
				
			||||||
            goto finish;
 | 
					            goto finish;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        char *d, *ufn;
 | 
					        char *d, *ufn;
 | 
				
			||||||
        static char *legacy_dir;
 | 
					        static char *legacy_dir;
 | 
				
			||||||
| 
						 | 
					@ -895,21 +935,40 @@ int pa_context_connect(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Wrap the connection attempts in a single transaction for sane autospawn locking */
 | 
					        /* Wrap the connection attempts in a single transaction for sane autospawn locking */
 | 
				
			||||||
        if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) {
 | 
					        if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) {
 | 
				
			||||||
            char *lf;
 | 
					            int k;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) {
 | 
					            pa_assert(c->autospawn_fd < 0);
 | 
				
			||||||
 | 
					            pa_assert(!c->autospawn_locked);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* Start the locking procedure */
 | 
				
			||||||
 | 
					            if ((c->autospawn_fd = pa_autospawn_lock_init()) < 0) {
 | 
				
			||||||
                pa_context_fail(c, PA_ERR_ACCESS);
 | 
					                pa_context_fail(c, PA_ERR_ACCESS);
 | 
				
			||||||
                goto finish;
 | 
					                goto finish;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            pa_assert(c->autospawn_lock_fd <= 0);
 | 
					 | 
				
			||||||
            c->autospawn_lock_fd = pa_lock_lockfile(lf);
 | 
					 | 
				
			||||||
            pa_xfree(lf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (api)
 | 
					            if (api)
 | 
				
			||||||
                c->spawn_api = *api;
 | 
					                c->spawn_api = *api;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            c->do_autospawn = TRUE;
 | 
					            c->do_autospawn = TRUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* Check whether we can get the lock right now*/
 | 
				
			||||||
 | 
					            if ((k = pa_autospawn_lock_acquire(FALSE)) < 0) {
 | 
				
			||||||
 | 
					                pa_context_fail(c, PA_ERR_ACCESS);
 | 
				
			||||||
 | 
					                goto finish;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (k > 0)
 | 
				
			||||||
 | 
					                /* So we got it, rock on! */
 | 
				
			||||||
 | 
					                c->autospawn_locked = TRUE;
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                /* Hmm, we didn't get it, so let's wait for it */
 | 
				
			||||||
 | 
					                c->autospawn_event = c->mainloop->io_new(c->mainloop, c->autospawn_fd, PA_IO_EVENT_INPUT, autospawn_cb, c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                pa_context_set_state(c, PA_CONTEXT_CONNECTING);
 | 
				
			||||||
 | 
					                r = 0;
 | 
				
			||||||
 | 
					                goto finish;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,9 +75,12 @@ struct pa_context {
 | 
				
			||||||
    pa_mempool *mempool;
 | 
					    pa_mempool *mempool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_bool_t is_local:1;
 | 
					    pa_bool_t is_local:1;
 | 
				
			||||||
    pa_bool_t do_autospawn:1;
 | 
					 | 
				
			||||||
    pa_bool_t do_shm:1;
 | 
					    pa_bool_t do_shm:1;
 | 
				
			||||||
    int autospawn_lock_fd;
 | 
					
 | 
				
			||||||
 | 
					    pa_bool_t do_autospawn:1;
 | 
				
			||||||
 | 
					    pa_bool_t autospawn_locked:1;
 | 
				
			||||||
 | 
					    int autospawn_fd;
 | 
				
			||||||
 | 
					    pa_io_event *autospawn_event;
 | 
				
			||||||
    pa_spawn_api spawn_api;
 | 
					    pa_spawn_api spawn_api;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_strlist *server_list;
 | 
					    pa_strlist *server_list;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										329
									
								
								src/pulse/lock-autospawn.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										329
									
								
								src/pulse/lock-autospawn.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,329 @@
 | 
				
			||||||
 | 
					/***
 | 
				
			||||||
 | 
					  This file is part of PulseAudio.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Copyright 2008 Lennart Poettering
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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,
 | 
				
			||||||
 | 
					  or (at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PulseAudio is distributed in the hope that it will be useful, but
 | 
				
			||||||
 | 
					  WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 | 
				
			||||||
 | 
					  General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  You should have received a copy of the GNU Lesser General Public License
 | 
				
			||||||
 | 
					  along with PulseAudio; if not, write to the Free Software
 | 
				
			||||||
 | 
					  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
				
			||||||
 | 
					  USA.
 | 
				
			||||||
 | 
					***/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_CONFIG_H
 | 
				
			||||||
 | 
					#include <config.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <sys/poll.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <pthread.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <pulse/i18n.h>
 | 
				
			||||||
 | 
					#include <pulse/xmalloc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <pulsecore/mutex.h>
 | 
				
			||||||
 | 
					#include <pulsecore/thread.h>
 | 
				
			||||||
 | 
					#include <pulsecore/core-util.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "lock-autospawn.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* So, why do we have this complex code here with threads and pipes
 | 
				
			||||||
 | 
					 * and stuff? For two reasons: POSIX file locks are per-process, not
 | 
				
			||||||
 | 
					 * per-file descriptor. That means that two contexts within the same
 | 
				
			||||||
 | 
					 * process that try to create the autospawn lock might end up assuming
 | 
				
			||||||
 | 
					 * they both managed to lock the file. And then, POSIX locking
 | 
				
			||||||
 | 
					 * operations are synchronous. If two contexts run from the same event
 | 
				
			||||||
 | 
					 * loop it must be made sure that they do not block each other, but
 | 
				
			||||||
 | 
					 * that the locking operation can happen asynchronously. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define AUTOSPAWN_LOCK "autospawn.lock"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static pa_mutex *mutex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static unsigned n_ref = 0;
 | 
				
			||||||
 | 
					static int lock_fd = -1;
 | 
				
			||||||
 | 
					static pa_mutex *lock_fd_mutex = NULL;
 | 
				
			||||||
 | 
					static pa_bool_t taken = FALSE;
 | 
				
			||||||
 | 
					static pa_thread *thread;
 | 
				
			||||||
 | 
					static int pipe_fd[2] = { -1, -1 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void destroy_mutex(void) PA_GCC_DESTRUCTOR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ref(void) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (n_ref > 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pa_assert(pipe_fd[0] >= 0);
 | 
				
			||||||
 | 
					        pa_assert(pipe_fd[1] >= 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        n_ref++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert(lock_fd < 0);
 | 
				
			||||||
 | 
					    pa_assert(!lock_fd_mutex);
 | 
				
			||||||
 | 
					    pa_assert(!taken);
 | 
				
			||||||
 | 
					    pa_assert(!thread);
 | 
				
			||||||
 | 
					    pa_assert(pipe_fd[0] < 0);
 | 
				
			||||||
 | 
					    pa_assert(pipe_fd[1] < 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (pipe(pipe_fd) < 0)
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lock_fd_mutex = pa_mutex_new(FALSE, FALSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_make_fd_cloexec(pipe_fd[0]);
 | 
				
			||||||
 | 
					    pa_make_fd_cloexec(pipe_fd[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_make_fd_nonblock(pipe_fd[1]);
 | 
				
			||||||
 | 
					    pa_make_fd_nonblock(pipe_fd[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    n_ref = 1;
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void unref(pa_bool_t after_fork) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert(n_ref > 0);
 | 
				
			||||||
 | 
					    pa_assert(pipe_fd[0] >= 0);
 | 
				
			||||||
 | 
					    pa_assert(pipe_fd[1] >= 0);
 | 
				
			||||||
 | 
					    pa_assert(lock_fd_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    n_ref--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (n_ref > 0)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert(!taken);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (thread) {
 | 
				
			||||||
 | 
					        pa_thread_free(thread);
 | 
				
			||||||
 | 
					        thread = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_mutex_lock(lock_fd_mutex);
 | 
				
			||||||
 | 
					    if (lock_fd >= 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (after_fork)
 | 
				
			||||||
 | 
					            pa_close(lock_fd);
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            char *lf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK)))
 | 
				
			||||||
 | 
					                pa_log_warn(_("Cannot access autospawn lock."));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            pa_unlock_lockfile(lf, lock_fd);
 | 
				
			||||||
 | 
					            pa_xfree(lf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            lock_fd = -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pa_mutex_unlock(lock_fd_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_mutex_free(lock_fd_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_close(pipe_fd[0]);
 | 
				
			||||||
 | 
					    pa_close(pipe_fd[1]);
 | 
				
			||||||
 | 
					    pipe_fd[0] = pipe_fd[1] = -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ping(void) {
 | 
				
			||||||
 | 
					    ssize_t s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert(pipe_fd[1] >= 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (;;) {
 | 
				
			||||||
 | 
					        char x = 'x';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ((s = write(pipe_fd[1], &x, 1)) == 1)
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pa_assert(s < 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (errno == EAGAIN)
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pa_assert(errno == EINTR);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void wait_for_ping(void) {
 | 
				
			||||||
 | 
					    ssize_t s;
 | 
				
			||||||
 | 
					    char x;
 | 
				
			||||||
 | 
					    struct pollfd pfd;
 | 
				
			||||||
 | 
					    int k;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert(pipe_fd[0] >= 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(&pfd, 0, sizeof(pfd));
 | 
				
			||||||
 | 
					    pfd.fd = pipe_fd[0];
 | 
				
			||||||
 | 
					    pfd.events = POLLIN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((k = poll(&pfd, 1, -1)) != 1) {
 | 
				
			||||||
 | 
					        pa_assert(k < 0);
 | 
				
			||||||
 | 
					        pa_assert(errno == EINTR);
 | 
				
			||||||
 | 
					    } else if ((s = read(pipe_fd[0], &x, 1)) != 1) {
 | 
				
			||||||
 | 
					        pa_assert(s < 0);
 | 
				
			||||||
 | 
					        pa_assert(errno == EAGAIN);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void empty_pipe(void) {
 | 
				
			||||||
 | 
					    char x[16];
 | 
				
			||||||
 | 
					    ssize_t s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert(pipe_fd[0] >= 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((s = read(pipe_fd[0], &x, sizeof(x))) < 1) {
 | 
				
			||||||
 | 
					        pa_assert(s < 0);
 | 
				
			||||||
 | 
					        pa_assert(errno == EAGAIN);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void thread_func(void *u) {
 | 
				
			||||||
 | 
					    int fd;
 | 
				
			||||||
 | 
					    char *lf;
 | 
				
			||||||
 | 
					    sigset_t fullset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* No signals in this thread please */
 | 
				
			||||||
 | 
					    sigfillset(&fullset);
 | 
				
			||||||
 | 
					    pthread_sigmask(SIG_BLOCK, &fullset, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) {
 | 
				
			||||||
 | 
					        pa_log_warn(_("Cannot access autospawn lock."));
 | 
				
			||||||
 | 
					        goto finish;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((fd = pa_lock_lockfile(lf)) < 0)
 | 
				
			||||||
 | 
					        goto finish;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_mutex_lock(lock_fd_mutex);
 | 
				
			||||||
 | 
					    pa_assert(lock_fd < 0);
 | 
				
			||||||
 | 
					    lock_fd = fd;
 | 
				
			||||||
 | 
					    pa_mutex_unlock(lock_fd_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					finish:
 | 
				
			||||||
 | 
					    pa_xfree(lf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ping();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int start_thread(void) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!thread)
 | 
				
			||||||
 | 
					        if (!(thread = pa_thread_new(thread_func, NULL)))
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void create_mutex(void) {
 | 
				
			||||||
 | 
					    PA_ONCE_BEGIN {
 | 
				
			||||||
 | 
					        mutex = pa_mutex_new(FALSE, FALSE);
 | 
				
			||||||
 | 
					    } PA_ONCE_END;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void destroy_mutex(void) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (mutex)
 | 
				
			||||||
 | 
					        pa_mutex_free(mutex);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int pa_autospawn_lock_init(void) {
 | 
				
			||||||
 | 
					    int ret = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    create_mutex();
 | 
				
			||||||
 | 
					    pa_mutex_lock(mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ref() < 0)
 | 
				
			||||||
 | 
					        ret = -1;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        ret = pipe_fd[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_mutex_unlock(mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int pa_autospawn_lock_acquire(pa_bool_t block) {
 | 
				
			||||||
 | 
					    int ret = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    create_mutex();
 | 
				
			||||||
 | 
					    pa_mutex_lock(mutex);
 | 
				
			||||||
 | 
					    pa_assert(n_ref >= 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_mutex_lock(lock_fd_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (;;) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        empty_pipe();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (lock_fd >= 0 && !taken) {
 | 
				
			||||||
 | 
					            taken = TRUE;
 | 
				
			||||||
 | 
					            ret = 1;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (lock_fd < 0)
 | 
				
			||||||
 | 
					            if (start_thread() < 0)
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!block) {
 | 
				
			||||||
 | 
					            ret = 0;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pa_mutex_unlock(lock_fd_mutex);
 | 
				
			||||||
 | 
					        pa_mutex_unlock(mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wait_for_ping();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pa_mutex_lock(mutex);
 | 
				
			||||||
 | 
					        pa_mutex_lock(lock_fd_mutex);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_mutex_unlock(lock_fd_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_mutex_unlock(mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pa_autospawn_lock_release(void) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    create_mutex();
 | 
				
			||||||
 | 
					    pa_mutex_lock(mutex);
 | 
				
			||||||
 | 
					    pa_assert(n_ref >= 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert(taken);
 | 
				
			||||||
 | 
					    taken = FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ping();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_mutex_unlock(mutex);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pa_autospawn_lock_done(pa_bool_t after_fork) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    create_mutex();
 | 
				
			||||||
 | 
					    pa_mutex_lock(mutex);
 | 
				
			||||||
 | 
					    pa_assert(n_ref >= 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unref(after_fork);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_mutex_unlock(mutex);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										32
									
								
								src/pulse/lock-autospawn.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/pulse/lock-autospawn.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,32 @@
 | 
				
			||||||
 | 
					#ifndef foopulselockautospawnhfoo
 | 
				
			||||||
 | 
					#define foopulselockautospawnhfoo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***
 | 
				
			||||||
 | 
					  This file is part of PulseAudio.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Copyright 2008 Lennart Poettering
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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.1 of the
 | 
				
			||||||
 | 
					  License, or (at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PulseAudio is distributed in the hope that it will be useful, but
 | 
				
			||||||
 | 
					  WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 | 
				
			||||||
 | 
					  Lesser General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  You should have received a copy of the GNU Lesser General Public
 | 
				
			||||||
 | 
					  License along with PulseAudio; if not, write to the Free Software
 | 
				
			||||||
 | 
					  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
				
			||||||
 | 
					  USA.
 | 
				
			||||||
 | 
					***/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <pulsecore/macro.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int pa_autospawn_lock_init(void);
 | 
				
			||||||
 | 
					int pa_autospawn_lock_acquire(pa_bool_t block);
 | 
				
			||||||
 | 
					void pa_autospawn_lock_release(void);
 | 
				
			||||||
 | 
					void pa_autospawn_lock_done(pa_bool_t after_fork);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										109
									
								
								src/tests/lock-autospawn-test.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/tests/lock-autospawn-test.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,109 @@
 | 
				
			||||||
 | 
					/***
 | 
				
			||||||
 | 
					  This file is part of PulseAudio.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Copyright 2008 Lennart Poettering
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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,
 | 
				
			||||||
 | 
					  or (at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PulseAudio is distributed in the hope that it will be useful, but
 | 
				
			||||||
 | 
					  WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 | 
				
			||||||
 | 
					  General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  You should have received a copy of the GNU Lesser General Public License
 | 
				
			||||||
 | 
					  along with PulseAudio; if not, write to the Free Software
 | 
				
			||||||
 | 
					  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
				
			||||||
 | 
					  USA.
 | 
				
			||||||
 | 
					***/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_CONFIG_H
 | 
				
			||||||
 | 
					#include <config.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/poll.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <pulsecore/macro.h>
 | 
				
			||||||
 | 
					#include <pulsecore/thread.h>
 | 
				
			||||||
 | 
					#include <pulse/lock-autospawn.h>
 | 
				
			||||||
 | 
					#include <pulse/util.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void thread_func(void*k) {
 | 
				
			||||||
 | 
					    pa_assert_se(pa_autospawn_lock_init() >= 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_log("%i, Trying to acquire lock.", PA_PTR_TO_INT(k));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert_se(pa_autospawn_lock_acquire(TRUE) > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_log("%i, Got the lock!, Sleeping for 5s", PA_PTR_TO_INT(k));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_msleep(5000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_log("%i, Releasing", PA_PTR_TO_INT(k));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_autospawn_lock_release();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_autospawn_lock_done(FALSE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void thread_func2(void *k) {
 | 
				
			||||||
 | 
					    int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert_se((fd = pa_autospawn_lock_init()) >= 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_log("%i, Trying to acquire lock.", PA_PTR_TO_INT(k));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (;;) {
 | 
				
			||||||
 | 
					        struct pollfd pollfd;
 | 
				
			||||||
 | 
					        int j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ((j = pa_autospawn_lock_acquire(FALSE)) > 0)
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pa_assert(j == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        memset(&pollfd, 0, sizeof(pollfd));
 | 
				
			||||||
 | 
					        pollfd.fd = fd;
 | 
				
			||||||
 | 
					        pollfd.events = POLLIN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pa_assert_se(poll(&pollfd, 1, -1) == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pa_log("%i, woke up", PA_PTR_TO_INT(k));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_log("%i, Got the lock!, Sleeping for 5s", PA_PTR_TO_INT(k));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_msleep(5000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_log("%i, Releasing", PA_PTR_TO_INT(k));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_autospawn_lock_release();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_autospawn_lock_done(FALSE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char**argv) {
 | 
				
			||||||
 | 
					    pa_thread *a, *b, *c, *d;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert_se((a = pa_thread_new(thread_func, PA_INT_TO_PTR(1))));
 | 
				
			||||||
 | 
					    pa_assert_se((b = pa_thread_new(thread_func2, PA_INT_TO_PTR(2))));
 | 
				
			||||||
 | 
					    pa_assert_se((c = pa_thread_new(thread_func2, PA_INT_TO_PTR(3))));
 | 
				
			||||||
 | 
					    pa_assert_se((d = pa_thread_new(thread_func, PA_INT_TO_PTR(4))));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_thread_join(a);
 | 
				
			||||||
 | 
					    pa_thread_join(b);
 | 
				
			||||||
 | 
					    pa_thread_join(c);
 | 
				
			||||||
 | 
					    pa_thread_join(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_thread_free(a);
 | 
				
			||||||
 | 
					    pa_thread_free(b);
 | 
				
			||||||
 | 
					    pa_thread_free(c);
 | 
				
			||||||
 | 
					    pa_thread_free(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_log("End");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue