[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v0.9.11-89-g15cebba
Lennart Poettering
gitmailer-noreply at 0pointer.de
Fri Aug 8 18:49:48 PDT 2008
This is an automated email from the git hooks/post-receive script. It was
generated because of a push to the "PulseAudio Sound Server" repository.
The master branch has been updated
from 75b28e97fa612d9dfdad60e37f6901a8923b92f4 (commit)
- Log -----------------------------------------------------------------
15cebba... rework autospawning code to survive multiple pa_contexts in a single process
b4a5669... print reason when we fail to kill a running daemon
ee4c350... set errno properly in all functions from pid.c
d8119af... set errno properly in all functions from core-util.c
9cf1a4e... add locale support to pa_parse_boolean()
c4d32ec... set errno properly in all cases
6df029a... make sure we don't crash if pa_thread_join() is called more than once on the same pa_thread object
40ff5fa... add compatibility with older PA socket paths
-----------------------------------------------------------------------
Summary of changes:
src/.gitignore | 1 +
src/Makefile.am | 14 +-
src/daemon/main.c | 38 ++-
src/pulse/context.c | 141 +++++++--
src/pulse/internal.h | 7 +-
src/pulse/lock-autospawn.c | 329 ++++++++++++++++++++
.../proplist-util.h => pulse/lock-autospawn.h} | 11 +-
src/pulse/util.c | 17 +-
src/pulsecore/core-util.c | 153 ++++++++--
src/pulsecore/pid.c | 21 +-
src/pulsecore/thread-posix.c | 9 +-
src/tests/lock-autospawn-test.c | 109 +++++++
12 files changed, 774 insertions(+), 76 deletions(-)
create mode 100644 src/pulse/lock-autospawn.c
copy src/{pulsecore/proplist-util.h => pulse/lock-autospawn.h} (75%)
create mode 100644 src/tests/lock-autospawn-test.c
-----------------------------------------------------------------------
commit 40ff5fa06f4c9749e4bee9a8c2b18fe50e1210ab
Author: Lennart Poettering <lennart at poettering.net>
Date: Thu Aug 7 02:39:58 2008 +0200
add compatibility with older PA socket paths
diff --git a/src/pulse/context.c b/src/pulse/context.c
index 5be4078..bdd519a 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -776,7 +776,7 @@ finish:
}
-static char *get_legacy_runtime_dir(void) {
+static char *get_old_legacy_runtime_dir(void) {
char *p, u[128];
struct stat st;
@@ -798,6 +798,28 @@ static char *get_legacy_runtime_dir(void) {
return p;
}
+static char *get_very_old_legacy_runtime_dir(void) {
+ char *p, h[128];
+ struct stat st;
+
+ if (!pa_get_home_dir(h, sizeof(h)))
+ return NULL;
+
+ p = pa_sprintf_malloc("%s/.pulse", h);
+
+ if (stat(p, &st) < 0) {
+ pa_xfree(p);
+ return NULL;
+ }
+
+ if (st.st_uid != getuid()) {
+ pa_xfree(p);
+ return NULL;
+ }
+
+ return p;
+}
+
int pa_context_connect(
pa_context *c,
const char *server,
@@ -849,8 +871,16 @@ int pa_context_connect(
/* The system wide instance */
c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET);
- /* The old per-user instance path. This is supported only to ease upgrades */
- if ((legacy_dir = get_legacy_runtime_dir())) {
+ /* The very old per-user instance path (< 0.9.11). This is supported only to ease upgrades */
+ if ((legacy_dir = get_very_old_legacy_runtime_dir())) {
+ char *p = pa_sprintf_malloc("%s" PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET, legacy_dir);
+ c->server_list = pa_strlist_prepend(c->server_list, p);
+ pa_xfree(p);
+ pa_xfree(legacy_dir);
+ }
+
+ /* The old per-user instance path (< 0.9.12). This is supported only to ease upgrades */
+ if ((legacy_dir = get_old_legacy_runtime_dir())) {
char *p = pa_sprintf_malloc("%s" PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET, legacy_dir);
c->server_list = pa_strlist_prepend(c->server_list, p);
pa_xfree(p);
commit 6df029a1b1e56e0909e8b7f3991c24a70d9d3c33
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Aug 8 22:31:24 2008 +0200
make sure we don't crash if pa_thread_join() is called more than once on the same pa_thread object
diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c
index 20ed16d..ade398f 100644
--- a/src/pulsecore/thread-posix.c
+++ b/src/pulsecore/thread-posix.c
@@ -41,6 +41,7 @@ struct pa_thread {
pa_thread_func_t thread_func;
void *userdata;
pa_atomic_t running;
+ pa_bool_t joined;
};
struct pa_tls {
@@ -82,6 +83,7 @@ pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) {
t = pa_xnew(pa_thread, 1);
t->thread_func = thread_func;
t->userdata = userdata;
+ t->joined = FALSE;
pa_atomic_store(&t->running, 0);
if (pthread_create(&t->id, NULL, internal_thread_func, t) < 0) {
@@ -115,7 +117,12 @@ void pa_thread_free(pa_thread *t) {
int pa_thread_join(pa_thread *t) {
pa_assert(t);
+ pa_assert(t->thread_func);
+
+ if (t->joined)
+ return -1;
+ t->joined = TRUE;
return pthread_join(t->id, NULL);
}
@@ -132,6 +139,7 @@ pa_thread* pa_thread_self(void) {
t->id = pthread_self();
t->thread_func = NULL;
t->userdata = NULL;
+ t->joined = TRUE;
pa_atomic_store(&t->running, 2);
PA_STATIC_TLS_SET(current_thread, t);
@@ -192,4 +200,3 @@ void *pa_tls_set(pa_tls *t, void *userdata) {
pa_assert_se(pthread_setspecific(t->key, userdata) == 0);
return r;
}
-
commit c4d32ec8048075c7ccd979594b041335ebbcd51d
Author: Lennart Poettering <lennart at poettering.net>
Date: Sat Aug 9 03:44:46 2008 +0200
set errno properly in all cases
diff --git a/src/pulse/util.c b/src/pulse/util.c
index f785a2e..44fad4a 100644
--- a/src/pulse/util.c
+++ b/src/pulse/util.c
@@ -95,12 +95,15 @@ char *pa_get_user_name(char *s, size_t l) {
#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */
DWORD size = sizeof(buf);
- if (!GetUserName(buf, &size))
+ if (!GetUserName(buf, &size)) {
+ errno = ENOENT;
return NULL;
+ }
p = buf;
#else /* HAVE_PWD_H */
+
return NULL;
#endif /* HAVE_PWD_H */
}
@@ -138,6 +141,8 @@ char *pa_get_home_dir(char *s, size_t l) {
return pa_strlcpy(s, e, l);
#ifdef HAVE_PWD_H
+
+ errno = 0;
#ifdef HAVE_GETPWUID_R
if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
#else
@@ -145,11 +150,16 @@ char *pa_get_home_dir(char *s, size_t l) {
* that do not support getpwuid_r. */
if ((r = getpwuid(getuid())) == NULL) {
#endif
+ if (!errno)
+ errno = ENOENT;
+
return NULL;
}
return pa_strlcpy(s, r->pw_dir, l);
#else /* HAVE_PWD_H */
+
+ errno = ENOENT;
return NULL;
#endif
}
@@ -200,6 +210,7 @@ char *pa_get_binary_name(char *s, size_t l) {
}
#endif
+ errno = ENOENT;
return NULL;
}
@@ -249,8 +260,8 @@ int pa_msleep(unsigned long t) {
#elif defined(HAVE_NANOSLEEP)
struct timespec ts;
- ts.tv_sec = t/1000;
- ts.tv_nsec = (t % 1000) * 1000000;
+ ts.tv_sec = t/1000UL;
+ ts.tv_nsec = (t % 1000UL) * 1000000UL;
return nanosleep(&ts, NULL);
#else
commit 9cf1a4e5c4e319c34c1eef722162c0d67997e312
Author: Lennart Poettering <lennart at poettering.net>
Date: Sat Aug 9 03:46:23 2008 +0200
add locale support to pa_parse_boolean()
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index b2c91e4..dcceec9 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -40,6 +40,8 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <dirent.h>
+#include <regex.h>
+#include <langinfo.h>
#ifdef HAVE_STRTOF_L
#include <locale.h>
@@ -679,15 +681,48 @@ void pa_reset_priority(void) {
#endif
}
+static int match(const char *expr, const char *v) {
+ int k;
+ regex_t re;
+
+ if (regcomp(&re, expr, REG_NOSUB|REG_EXTENDED) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((k = regexec(&re, v, 0, NULL, 0)) == 0)
+ return 1;
+ else if (k == REG_NOMATCH)
+ return 0;
+
+ errno = EINVAL;
+ return -1;
+}
+
/* Try to parse a boolean string value.*/
int pa_parse_boolean(const char *v) {
+ const char *expr;
+ int r;
pa_assert(v);
+ /* First we check language independant */
if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
return 1;
else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
return 0;
+ /* And then we check language dependant */
+ if ((expr = nl_langinfo(YESEXPR)))
+ if (expr[0])
+ if ((r = match(expr, v)) > 0)
+ return 1;
+
+ if ((expr = nl_langinfo(NOEXPR)))
+ if (expr[0])
+ if ((r = match(expr, v)) > 0)
+ return 0;
+
+ errno = EINVAL;
return -1;
}
commit d8119afeefbe624ac320d2d71290d3e125e49010
Author: Lennart Poettering <lennart at poettering.net>
Date: Sat Aug 9 03:46:46 2008 +0200
set errno properly in all functions from core-util.c
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index dcceec9..0717ff1 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -113,6 +113,8 @@ int pa_set_root(HANDLE handle) {
strcpy(library_path, PULSE_ROOTENV "=");
+ /* FIXME: Needs to set errno */
+
if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH))
return 0;
@@ -170,7 +172,7 @@ void pa_make_fd_cloexec(int fd) {
/** Creates a directory securely */
int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
struct stat st;
- int r;
+ int r, saved_errno;
pa_assert(dir);
@@ -222,7 +224,10 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
return 0;
fail:
+ saved_errno = errno;
rmdir(dir);
+ errno = saved_errno;
+
return -1;
}
@@ -232,6 +237,7 @@ char *pa_parent_dir(const char *fn) {
if ((slash = (char*) pa_path_get_filename(dir)) == dir) {
pa_xfree(dir);
+ errno = ENOENT;
return NULL;
}
@@ -548,6 +554,8 @@ int pa_make_realtime(int rtprio) {
pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i.", sp.sched_priority);
return 0;
#else
+
+ errno = ENOTSUP;
return -1;
#endif
}
@@ -655,6 +663,7 @@ int pa_raise_priority(int nice_level) {
if (nice_level < 0) {
if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) {
pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
+ errno = EPERM;
return .-1;
} else
pa_log_info("Successfully gained high priority class.");
@@ -910,11 +919,18 @@ static int is_group(gid_t gid, const char *name) {
#else
n = -1;
#endif
- if (n < 0) n = 512;
+ if (n < 0)
+ n = 512;
+
data = pa_xmalloc(n);
+ errno = 0;
if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) {
- pa_log("getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno));
+ pa_log("getgrgid_r(%u): %s", (unsigned) gid, pa_cstrerror(errno));
+
+ if (!errno)
+ errno = ENOENT;
+
goto finish;
}
@@ -925,8 +941,14 @@ finish:
#else
/* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not
* support getgrgid_r. */
+
+ errno = 0;
if ((result = getgrgid(gid)) == NULL) {
pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno));
+
+ if (!errno)
+ errno = ENOENT;
+
goto finish;
}
@@ -942,7 +964,7 @@ finish:
int pa_own_uid_in_group(const char *name, gid_t *gid) {
GETGROUPS_T *gids, tgid;
int n = sysconf(_SC_NGROUPS_MAX);
- int r = -1, i;
+ int r = -1, i, k;
pa_assert(n > 0);
@@ -954,14 +976,19 @@ int pa_own_uid_in_group(const char *name, gid_t *gid) {
}
for (i = 0; i < n; i++) {
- if (is_group(gids[i], name) > 0) {
+
+ if ((k = is_group(gids[i], name)) < 0)
+ goto finish;
+ else if (k > 0) {
*gid = gids[i];
r = 1;
goto finish;
}
}
- if (is_group(tgid = getgid(), name) > 0) {
+ if ((k = is_group(tgid = getgid(), name)) < 0)
+ goto finish;
+ else if (k > 0) {
*gid = tgid;
r = 1;
goto finish;
@@ -989,13 +1016,20 @@ int pa_uid_in_group(uid_t uid, const char *name) {
p_n = sysconf(_SC_GETPW_R_SIZE_MAX);
p_buf = pa_xmalloc(p_n);
- if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
+ errno = 0;
+ if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) {
+
+ if (!errno)
+ errno = ENOENT;
+
goto finish;
+ }
r = 0;
for (i = gr->gr_mem; *i; i++) {
struct passwd pwbuf, *pw;
+ errno = 0;
if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw)
continue;
@@ -1022,8 +1056,14 @@ gid_t pa_get_gid_of_group(const char *name) {
g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
g_buf = pa_xmalloc(g_n);
- if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
+ errno = 0;
+ if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) {
+
+ if (!errno)
+ errno = ENOENT;
+
goto finish;
+ }
ret = gr->gr_gid;
@@ -1049,19 +1089,23 @@ int pa_check_in_group(gid_t g) {
#else /* HAVE_GRP_H */
int pa_own_uid_in_group(const char *name, gid_t *gid) {
+ errno = ENOSUP;
return -1;
}
int pa_uid_in_group(uid_t uid, const char *name) {
+ errno = ENOSUP;
return -1;
}
gid_t pa_get_gid_of_group(const char *name) {
+ errno = ENOSUP;
return (gid_t) -1;
}
int pa_check_in_group(gid_t g) {
+ errno = ENOSUP;
return -1;
}
@@ -1102,6 +1146,8 @@ int pa_lock_fd(int fd, int b) {
return 0;
pa_log("%slock failed: 0x%08X", !b ? "un" : "", GetLastError());
+
+ /* FIXME: Needs to set errno! */
#endif
return -1;
@@ -1168,8 +1214,11 @@ int pa_lock_lockfile(const char *fn) {
fail:
- if (fd >= 0)
+ if (fd >= 0) {
+ int saved_errno = errno;
pa_close(fd);
+ errno = saved_errno;
+ }
return -1;
}
@@ -1215,6 +1264,7 @@ static char *get_pulse_home(void) {
if (st.st_uid != getuid()) {
pa_log_error("Home directory %s not ours.", h);
+ errno = EACCES;
return NULL;
}
@@ -1367,6 +1417,7 @@ char *pa_get_runtime_dir(void) {
/* Make sure that this actually makes sense */
if (!pa_is_path_absolute(p)) {
pa_log_error("Path %s in link %s is not absolute.", p, k);
+ errno = ENOENT;
goto fail;
}
@@ -1458,6 +1509,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
#ifdef OS_IS_WIN32
if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
+ /* FIXME: Needs to set errno! */
return NULL;
fn = buf;
#endif
@@ -1488,6 +1540,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
#ifdef OS_IS_WIN32
if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) {
+ /* FIXME: Needs to set errno! */
pa_xfree(lfn);
return NULL;
}
@@ -1516,6 +1569,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
#ifdef OS_IS_WIN32
if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
+ /* FIXME: Needs to set errno! */
return NULL;
global = buf;
#endif
@@ -1527,9 +1581,9 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
return f;
}
- } else
- errno = ENOENT;
+ }
+ errno = ENOENT;
return NULL;
}
@@ -1546,6 +1600,7 @@ char *pa_find_config_file(const char *global, const char *local, const char *env
#ifdef OS_IS_WIN32
if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
+ /* FIXME: Needs to set errno! */
return NULL;
fn = buf;
#endif
@@ -1571,6 +1626,7 @@ char *pa_find_config_file(const char *global, const char *local, const char *env
#ifdef OS_IS_WIN32
if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) {
+ /* FIXME: Needs to set errno! */
pa_xfree(lfn);
return NULL;
}
@@ -1595,14 +1651,16 @@ char *pa_find_config_file(const char *global, const char *local, const char *env
if (global) {
#ifdef OS_IS_WIN32
if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
+ /* FIXME: Needs to set errno! */
return NULL;
global = buf;
#endif
if (access(global, R_OK) == 0)
return pa_xstrdup(global);
- } else
- errno = ENOENT;
+ }
+
+ errno = ENOENT;
return NULL;
}
@@ -1639,6 +1697,7 @@ static int hexc(char c) {
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
+ errno = EINVAL;
return -1;
}
@@ -1777,11 +1836,16 @@ int pa_atoi(const char *s, int32_t *ret_i) {
errno = 0;
l = strtol(s, &x, 0);
- if (!x || *x || errno != 0)
+ if (!x || *x || errno) {
+ if (!errno)
+ errno = EINVAL;
return -1;
+ }
- if ((int32_t) l != l)
+ if ((int32_t) l != l) {
+ errno = ERANGE;
return -1;
+ }
*ret_i = (int32_t) l;
@@ -1799,11 +1863,16 @@ int pa_atou(const char *s, uint32_t *ret_u) {
errno = 0;
l = strtoul(s, &x, 0);
- if (!x || *x || errno != 0)
+ if (!x || *x || errno) {
+ if (!errno)
+ errno = EINVAL;
return -1;
+ }
- if ((uint32_t) l != l)
+ if ((uint32_t) l != l) {
+ errno = ERANGE;
return -1;
+ }
*ret_u = (uint32_t) l;
@@ -1821,7 +1890,6 @@ static void c_locale_destroy(void) {
int pa_atod(const char *s, double *ret_d) {
char *x = NULL;
double f;
- int r = 0;
pa_assert(s);
pa_assert(ret_d);
@@ -1847,12 +1915,15 @@ int pa_atod(const char *s, double *ret_d) {
f = strtod(s, &x);
}
- if (!x || *x || errno != 0)
- r = -1;
- else
- *ret_d = f;
+ if (!x || *x || errno) {
+ if (!errno)
+ errno = EINVAL;
+ return -1;
+ }
- return r;
+ *ret_d = f;
+
+ return 0;
}
/* Same as snprintf, but guarantees NUL-termination on every platform */
@@ -1956,6 +2027,7 @@ void *pa_will_need(const void *p, size_t l) {
if (rlim.rlim_cur < PA_PAGE_SIZE) {
pa_log_debug("posix_madvise() failed (or doesn't exist), resource limits don't allow mlock(), can't page in data: %s", pa_cstrerror(r));
+ errno = EPERM;
return (void*) p;
}
commit ee4c350de76b2ba94b3cceb247201036dcac7a18
Author: Lennart Poettering <lennart at poettering.net>
Date: Sat Aug 9 03:47:18 2008 +0200
set errno properly in all functions from pid.c
diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c
index addb17c..81148da 100644
--- a/src/pulsecore/pid.c
+++ b/src/pulsecore/pid.c
@@ -73,6 +73,7 @@ static pid_t read_pid(const char *fn, int fd) {
if (pa_atou(t, &pid) < 0) {
pa_log_warn("Failed to parse PID file '%s'", fn);
+ errno = EINVAL;
return (pid_t) -1;
}
@@ -110,7 +111,7 @@ static int open_pid_file(const char *fn, int mode) {
goto fail;
}
- /* Does the file still exist in the file system? When ye, w're done, otherwise restart */
+ /* Does the file still exist in the file system? When yes, we're done, otherwise restart */
if (st.st_nlink >= 1)
break;
@@ -131,8 +132,10 @@ static int open_pid_file(const char *fn, int mode) {
fail:
if (fd >= 0) {
+ int saved_errno = errno;
pa_lock_fd(fd, 0);
pa_close(fd);
+ errno = saved_errno;
}
return -1;
@@ -154,8 +157,11 @@ static int proc_name_ours(pid_t pid, const char *procname) {
char stored[64];
if (!(fgets(stored, sizeof(stored), f))) {
+ int saved_errno = feof(f) ? EINVAL : errno;
pa_log_info("Failed to read from %s: %s", bn, feof(f) ? "EOF" : pa_cstrerror(errno));
fclose(f);
+
+ errno = saved_errno;
return -1;
}
@@ -342,8 +348,13 @@ int pa_pid_file_kill(int sig, pid_t *pid, const char *procname) {
if (!(fn = pa_runtime_path("pid")))
goto fail;
- if ((fd = open_pid_file(fn, O_RDONLY)) < 0)
+ if ((fd = open_pid_file(fn, O_RDONLY)) < 0) {
+
+ if (errno == ENOENT)
+ errno = ESRCH;
+
goto fail;
+ }
if ((*pid = read_pid(fn, fd)) == (pid_t) -1)
goto fail;
@@ -354,8 +365,10 @@ int pa_pid_file_kill(int sig, pid_t *pid, const char *procname) {
if ((ours = proc_name_ours(*pid, procname)) < 0)
goto fail;
- if (!ours)
+ if (!ours) {
+ errno = ESRCH;
goto fail;
+ }
}
ret = kill(*pid, sig);
@@ -363,8 +376,10 @@ int pa_pid_file_kill(int sig, pid_t *pid, const char *procname) {
fail:
if (fd >= 0) {
+ int saved_errno = errno;
pa_lock_fd(fd, 0);
pa_close(fd);
+ errno = saved_errno;
}
#ifdef __linux__
commit b4a566918cc6fbf2d5e66ae354275d36fbe8d13a
Author: Lennart Poettering <lennart at poettering.net>
Date: Sat Aug 9 03:47:59 2008 +0200
print reason when we fail to kill a running daemon
diff --git a/src/daemon/main.c b/src/daemon/main.c
index ab43832..9cdcb6c 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -606,7 +606,7 @@ int main(int argc, char *argv[]) {
case PA_CMD_KILL:
if (pa_pid_file_kill(SIGINT, NULL, "pulseaudio") < 0)
- pa_log(_("Failed to kill daemon."));
+ pa_log(_("Failed to kill daemon: %s"), pa_cstrerror(errno));
else
retval = 0;
commit 15cebbacebf27703848afb18883fad7984349f04
Author: Lennart Poettering <lennart at poettering.net>
Date: Sat Aug 9 03:49:42 2008 +0200
rework autospawning code to survive multiple pa_contexts in a single process
diff --git a/src/.gitignore b/src/.gitignore
index 6902eb9..543f4e8 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,3 +1,4 @@
+lock-autospawn-test
*.lo
*.o
*.la
diff --git a/src/Makefile.am b/src/Makefile.am
index 29a6ef4..21584ad 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -262,7 +262,8 @@ noinst_PROGRAMS = \
envelope-test \
proplist-test \
rtstutter \
- stripnul
+ stripnul \
+ lock-autospawn-test
if HAVE_SIGXCPU
noinst_PROGRAMS += \
@@ -452,6 +453,11 @@ stripnul_LDADD = $(AM_LDADD) libpulsecore.la
stripnul_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS)
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 #
###################################
@@ -535,7 +541,8 @@ libpulse_la_SOURCES = \
pulse/xmalloc.c pulse/xmalloc.h \
pulse/proplist.c pulse/proplist.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
libpulse_la_SOURCES += \
@@ -731,7 +738,8 @@ libpulsecore_la_SOURCES = \
pulse/volume.c pulse/volume.h \
pulse/xmalloc.c pulse/xmalloc.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).
libpulsecore_la_SOURCES += \
diff --git a/src/daemon/main.c b/src/daemon/main.c
index 9cdcb6c..c6fb3c6 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -65,6 +65,7 @@
#include <pulse/timeval.h>
#include <pulse/xmalloc.h>
#include <pulse/i18n.h>
+#include <pulse/lock-autospawn.h>
#include <pulsecore/winsock.h>
#include <pulsecore/core-error.h>
@@ -95,8 +96,6 @@
#include "ltdl-bind-now.h"
#include "polkit.h"
-#define AUTOSPAWN_LOCK "autospawn.lock"
-
#ifdef HAVE_LIBWRAP
/* Only one instance of these variables */
int allow_severity = LOG_INFO;
@@ -346,7 +345,8 @@ int main(int argc, char *argv[]) {
struct timeval win32_tv;
#endif
char *lf = NULL;
- int autospawn_lock_fd = -1;
+ int autospawn_fd = -1;
+ pa_bool_t autospawn_locked = FALSE;
#if defined(__linux__) && defined(__OPTIMIZE__)
/*
@@ -656,8 +656,17 @@ int main(int argc, char *argv[]) {
* first take the autospawn lock to make things
* synchronous. */
- lf = pa_runtime_path(AUTOSPAWN_LOCK);
- autospawn_lock_fd = pa_lock_lockfile(lf);
+ if ((autospawn_fd = pa_autospawn_lock_init()) < 0) {
+ 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) {
@@ -703,12 +712,15 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (autospawn_lock_fd >= 0) {
+ if (autospawn_fd >= 0) {
/* The lock file is unlocked from the parent, so we need
* to close it in the child */
- pa_close(autospawn_lock_fd);
- autospawn_lock_fd = -1;
+ pa_autospawn_lock_release();
+ pa_autospawn_lock_done(TRUE);
+
+ autospawn_locked = FALSE;
+ autospawn_fd = -1;
}
pa_assert_se(pa_close(daemon_pipe[0]) == 0);
@@ -917,8 +929,12 @@ int main(int argc, char *argv[]) {
finish:
- if (autospawn_lock_fd >= 0)
- pa_unlock_lockfile(lf, autospawn_lock_fd);
+ if (autospawn_fd >= 0) {
+ if (autospawn_locked)
+ pa_autospawn_lock_release();
+
+ pa_autospawn_lock_done(FALSE);
+ }
if (lf)
pa_xfree(lf);
diff --git a/src/pulse/context.c b/src/pulse/context.c
index bdd519a..00236b9 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -54,6 +54,7 @@
#include <pulse/utf8.h>
#include <pulse/util.h>
#include <pulse/i18n.h>
+#include <pulse/lock-autospawn.h>
#include <pulsecore/winsock.h>
#include <pulsecore/core-error.h>
@@ -81,8 +82,6 @@
#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);
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
};
-static void unlock_autospawn_lock_file(pa_context *c) {
+static void unlock_autospawn(pa_context *c) {
pa_assert(c);
- if (c->autospawn_lock_fd >= 0) {
- char *lf;
+ if (c->autospawn_fd >= 0) {
- if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK)))
- pa_log_warn(_("Cannot unlock autospawn because runtime path is no more."));
+ if (c->autospawn_locked)
+ pa_autospawn_lock_release();
- pa_unlock_lockfile(lf, c->autospawn_lock_fd);
- pa_xfree(lf);
+ if (c->autospawn_event)
+ 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);
@@ -174,11 +176,15 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
c->is_local = FALSE;
c->server_list = 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_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
#ifdef SIGPIPE
pa_check_signal_is_blocked(SIGPIPE);
@@ -246,7 +252,7 @@ static void context_free(pa_context *c) {
context_unlink(c);
- unlock_autospawn_lock_file(c);
+ unlock_autospawn(c);
if (c->record_streams)
pa_dynarray_free(c->record_streams, NULL, NULL);
@@ -674,7 +680,7 @@ static int context_connect_spawn(pa_context *c) {
c->is_local = TRUE;
- unlock_autospawn_lock_file(c);
+ unlock_autospawn(c);
io = pa_iochannel_new(c->mainloop, fds[0], fds[0]);
setup_context(c, io);
@@ -686,7 +692,7 @@ static int context_connect_spawn(pa_context *c) {
fail:
pa_close_pipe(fds);
- unlock_autospawn_lock_file(c);
+ unlock_autospawn(c);
pa_context_unref(c);
@@ -768,13 +774,46 @@ static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userd
goto finish;
}
- unlock_autospawn_lock_file(c);
+ unlock_autospawn(c);
setup_context(c, io);
finish:
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) {
char *p, u[128];
@@ -847,6 +886,7 @@ int pa_context_connect(
pa_context_fail(c, PA_ERR_INVALIDSERVER);
goto finish;
}
+
} else {
char *d, *ufn;
static char *legacy_dir;
@@ -895,21 +935,40 @@ int pa_context_connect(
/* Wrap the connection attempts in a single transaction for sane autospawn locking */
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);
goto finish;
}
- pa_assert(c->autospawn_lock_fd <= 0);
- c->autospawn_lock_fd = pa_lock_lockfile(lf);
- pa_xfree(lf);
-
if (api)
c->spawn_api = *api;
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;
+ }
+
}
}
diff --git a/src/pulse/internal.h b/src/pulse/internal.h
index bfe888e..26fb04d 100644
--- a/src/pulse/internal.h
+++ b/src/pulse/internal.h
@@ -75,9 +75,12 @@ struct pa_context {
pa_mempool *mempool;
pa_bool_t is_local:1;
- pa_bool_t do_autospawn: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_strlist *server_list;
diff --git a/src/pulse/lock-autospawn.c b/src/pulse/lock-autospawn.c
new file mode 100644
index 0000000..33a5311
--- /dev/null
+++ b/src/pulse/lock-autospawn.c
@@ -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);
+}
diff --git a/src/pulse/lock-autospawn.h b/src/pulse/lock-autospawn.h
new file mode 100644
index 0000000..c04c4bd
--- /dev/null
+++ b/src/pulse/lock-autospawn.h
@@ -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
diff --git a/src/tests/lock-autospawn-test.c b/src/tests/lock-autospawn-test.c
new file mode 100644
index 0000000..cb3dc87
--- /dev/null
+++ b/src/tests/lock-autospawn-test.c
@@ -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;
+}
--
hooks/post-receive
PulseAudio Sound Server
More information about the pulseaudio-commits
mailing list