1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2006 Lennart Poettering 5 6 PulseAudio is free software; you can redistribute it and/or modify 7 it under the terms of the GNU Lesser General Public License as published 8 by the Free Software Foundation; either version 2.1 of the License, 9 or (at your option) any later version. 10 11 PulseAudio is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public License 17 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 18***/ 19 20#ifdef HAVE_CONFIG_H 21#include <config.h> 22#endif 23 24#include <pthread.h> 25#include <errno.h> 26 27#include <pulse/xmalloc.h> 28 29#include <pulsecore/core-error.h> 30#include <pulsecore/macro.h> 31 32#include "mutex.h" 33 34struct pa_mutex { 35 pthread_mutex_t mutex; 36}; 37 38struct pa_cond { 39 pthread_cond_t cond; 40}; 41 42pa_mutex* pa_mutex_new(bool recursive, bool inherit_priority) { 43 pa_mutex *m; 44 pthread_mutexattr_t attr; 45#ifdef HAVE_PTHREAD_PRIO_INHERIT 46 int r; 47#endif 48 49 pa_assert_se(pthread_mutexattr_init(&attr) == 0); 50 51 if (recursive) 52 pa_assert_se(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) == 0); 53 54#ifdef HAVE_PTHREAD_PRIO_INHERIT 55 if (inherit_priority) { 56 r = pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT); 57 pa_assert(r == 0 || r == ENOTSUP); 58 } 59#endif 60 61 m = pa_xnew(pa_mutex, 1); 62 63#ifndef HAVE_PTHREAD_PRIO_INHERIT 64 pa_assert_se(pthread_mutex_init(&m->mutex, &attr) == 0); 65 66#else 67 if ((r = pthread_mutex_init(&m->mutex, &attr))) { 68 69 /* If this failed, then this was probably due to non-available 70 * priority inheritance. In which case we fall back to normal 71 * mutexes. */ 72 pa_assert(r == ENOTSUP && inherit_priority); 73 74 pa_assert_se(pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_NONE) == 0); 75 pa_assert_se(pthread_mutex_init(&m->mutex, &attr) == 0); 76 } 77#endif 78 79 return m; 80} 81 82void pa_mutex_free(pa_mutex *m) { 83 pa_assert(m); 84 85 pa_assert_se(pthread_mutex_destroy(&m->mutex) == 0); 86 pa_xfree(m); 87} 88 89void pa_mutex_lock(pa_mutex *m) { 90 pa_assert(m); 91 92 pa_assert_se(pthread_mutex_lock(&m->mutex) == 0); 93} 94 95bool pa_mutex_try_lock(pa_mutex *m) { 96 int r; 97 pa_assert(m); 98 99 if ((r = pthread_mutex_trylock(&m->mutex)) != 0) { 100 pa_assert(r == EBUSY); 101 return false; 102 } 103 104 return true; 105} 106 107void pa_mutex_unlock(pa_mutex *m) { 108 int err; 109 110 pa_assert(m); 111 112 if ((err = pthread_mutex_unlock(&m->mutex)) != 0) { 113 pa_log_error("pthread_mutex_unlock() failed: %s", pa_cstrerror(err)); 114 pa_assert_not_reached(); 115 } 116} 117 118pa_cond *pa_cond_new(void) { 119 pa_cond *c; 120 121 c = pa_xnew(pa_cond, 1); 122 pa_assert_se(pthread_cond_init(&c->cond, NULL) == 0); 123 return c; 124} 125 126void pa_cond_free(pa_cond *c) { 127 pa_assert(c); 128 129 pa_assert_se(pthread_cond_destroy(&c->cond) == 0); 130 pa_xfree(c); 131} 132 133void pa_cond_signal(pa_cond *c, int broadcast) { 134 pa_assert(c); 135 136 if (broadcast) 137 pa_assert_se(pthread_cond_broadcast(&c->cond) == 0); 138 else 139 pa_assert_se(pthread_cond_signal(&c->cond) == 0); 140} 141 142int pa_cond_wait(pa_cond *c, pa_mutex *m) { 143 pa_assert(c); 144 pa_assert(m); 145 146 return pthread_cond_wait(&c->cond, &m->mutex); 147} 148 149pa_mutex* pa_static_mutex_get(pa_static_mutex *s, bool recursive, bool inherit_priority) { 150 pa_mutex *m; 151 152 pa_assert(s); 153 154 /* First, check if already initialized and short cut */ 155 if ((m = pa_atomic_ptr_load(&s->ptr))) 156 return m; 157 158 /* OK, not initialized, so let's allocate, and fill in */ 159 m = pa_mutex_new(recursive, inherit_priority); 160 if ((pa_atomic_ptr_cmpxchg(&s->ptr, NULL, m))) 161 return m; 162 163 pa_mutex_free(m); 164 165 /* Him, filling in failed, so someone else must have filled in 166 * already */ 167 pa_assert_se(m = pa_atomic_ptr_load(&s->ptr)); 168 return m; 169} 170