int pa_asyncmsgq_send(pa_asyncmsgq *a, pa_msgobject *object, int code, const void *userdata, int64_t offset, const pa_memchunk *chunk) { struct asyncmsgq_item i; pa_assert(PA_REFCNT_VALUE(a) > 0); i.code = code; i.object = object; i.userdata = (void*) userdata; i.free_cb = NULL; i.ret = -1; i.offset = offset; if (chunk) { pa_assert(chunk->memblock); i.memchunk = *chunk; } else pa_memchunk_reset(&i.memchunk); if (!(i.semaphore = pa_flist_pop(PA_STATIC_FLIST_GET(semaphores)))) i.semaphore = pa_semaphore_new(0); /* This mutex makes the queue multiple-writer safe. This lock is only used on the writing side */ pa_mutex_lock(a->mutex); pa_assert_se(pa_asyncq_push(a->asyncq, &i, true) == 0); pa_mutex_unlock(a->mutex); pa_semaphore_wait(i.semaphore); if (pa_flist_push(PA_STATIC_FLIST_GET(semaphores), i.semaphore) < 0) pa_semaphore_free(i.semaphore); return i.ret; }
/* Self locked */ static void memblock_wait(pa_memblock *b) { pa_assert(b); if (pa_atomic_load(&b->n_acquired) > 0) { /* We need to wait until all threads gave up access to the * memory block before we can go on. Unfortunately this means * that we have to lock and wait here. Sniff! */ pa_atomic_inc(&b->please_signal); while (pa_atomic_load(&b->n_acquired) > 0) pa_semaphore_wait(b->pool->semaphore); pa_atomic_dec(&b->please_signal); } }
unsigned pa_aupdate_write_swap(pa_aupdate *a) { unsigned n; pa_assert(a); for (;;) { n = (unsigned) pa_atomic_load(&a->read_lock); /* If the read counter is > 0 wait; if it is 0 try to swap the lists */ if (COUNTER(n) > 0) pa_semaphore_wait(a->semaphore); else if (pa_atomic_cmpxchg(&a->read_lock, (int) n, (int) (n ^ MSB))) break; } a->swapped = true; return WHICH(n); }