4 This file is part of PulseAudio.
6 Copyright 2006 Lennart Poettering
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as
10 published by the Free Software Foundation; either version 2.1 of the
11 License, or (at your option) any later version.
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
31 #include <pulsecore/atomic.h>
32 #include <pulsecore/log.h>
33 #include <pulsecore/thread.h>
34 #include <pulsecore/macro.h>
35 #include <pulsecore/core-util.h>
36 #include <pulse/xmalloc.h>
40 /* For debugging purposes we can define _Y to put and extra thread
41 * yield between each operation. */
46 #define _Y pa_thread_yield()
48 #define _Y do { } while(0)
53 pa_fdsem *read_fdsem, *write_fdsem;
54 pa_shmasyncq_data *data;
57 static int is_power_of_two(unsigned size) {
58 return !(size & (size - 1));
61 static int reduce(pa_shmasyncq *l, int value) {
62 return value & (unsigned) (l->n_elements - 1);
65 static pa_atomic_t* get_cell(pa_shmasyncq *l, unsigned i) {
66 pa_assert(i < l->data->n_elements);
68 return (pa_atomic_t*) ((uint8*t) l->data + PA_ALIGN(sizeof(pa_shmasyncq_data)) + i * (PA_ALIGN(sizeof(pa_atomic_t)) + PA_ALIGN(element_size)))
71 static void *get_cell_data(pa_atomic_t *a) {
72 return (uint8_t*) a + PA_ALIGN(sizeof(atomic_t));
75 pa_shmasyncq *pa_shmasyncq_new(unsigned n_elements, size_t element_size, void *data, int fd[2]) {
78 pa_assert(n_elements > 0);
79 pa_assert(is_power_of_two(n_elements));
80 pa_assert(element_size > 0);
84 l = pa_xnew(pa_shmasyncq, 1);
87 memset(data, 0, PA_SHMASYNCQ_SIZE(n_elements, element_size));
89 l->data->n_elements = n_elements;
90 l->data->element_size = element_size;
92 if (!(l->read_fdsem = pa_fdsem_new_shm(&d->read_fdsem_data, &fd[0]))) {
97 if (!(l->write_fdsem = pa_fdsem_new(&d->write_fdsem_data, &fd[1]))) {
98 pa_fdsem_free(l->read_fdsem);
106 void pa_shmasyncq_free(pa_shmasyncq *l, pa_free_cb_t free_cb) {
112 while ((p = pa_shmasyncq_pop(l, 0)))
116 pa_fdsem_free(l->read_fdsem);
117 pa_fdsem_free(l->write_fdsem);
121 int pa_shmasyncq_push(pa_shmasyncq*l, void *p, int wait) {
123 pa_atomic_ptr_t *cells;
128 cells = PA_SHMASYNCQ_CELLS(l);
131 idx = reduce(l, l->write_idx);
133 if (!pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p)) {
138 /* pa_log("sleeping on push"); */
141 pa_fdsem_wait(l->read_fdsem);
142 } while (!pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p));
148 pa_fdsem_post(l->write_fdsem);
153 void* pa_shmasyncq_pop(pa_shmasyncq*l, int wait) {
156 pa_atomic_ptr_t *cells;
160 cells = PA_SHMASYNCQ_CELLS(l);
163 idx = reduce(l, l->read_idx);
165 if (!(ret = pa_atomic_ptr_load(&cells[idx]))) {
170 /* pa_log("sleeping on pop"); */
173 pa_fdsem_wait(l->write_fdsem);
174 } while (!(ret = pa_atomic_ptr_load(&cells[idx])));
179 /* Guaranteed to succeed if we only have a single reader */
180 pa_assert_se(pa_atomic_ptr_cmpxchg(&cells[idx], ret, NULL));
185 pa_fdsem_post(l->read_fdsem);
190 int pa_shmasyncq_get_fd(pa_shmasyncq *q) {
193 return pa_fdsem_get(q->write_fdsem);
196 int pa_shmasyncq_before_poll(pa_shmasyncq *l) {
198 pa_atomic_ptr_t *cells;
202 cells = PA_SHMASYNCQ_CELLS(l);
205 idx = reduce(l, l->read_idx);
208 if (pa_atomic_ptr_load(&cells[idx]))
211 if (pa_fdsem_before_poll(l->write_fdsem) >= 0)
218 void pa_shmasyncq_after_poll(pa_shmasyncq *l) {
221 pa_fdsem_after_poll(l->write_fdsem);