Added multithread aware status for plugins

This commit is contained in:
Abramo Bagnara 2001-02-27 18:21:31 +00:00
parent 3196ef28ae
commit a02e742609
7 changed files with 197 additions and 21 deletions

View file

@ -1,13 +1,13 @@
EXTRA_LTLIBRARIES = libpcm.la EXTRA_LTLIBRARIES = libpcm.la
libpcm_la_SOURCES = mask.c interval.c \ libpcm_la_SOURCES = atomic.c mask.c interval.c \
pcm.c pcm_m4.c pcm_hw.c pcm_plugin.c pcm_copy.c pcm_linear.c \ pcm.c pcm_m4.c pcm_hw.c pcm_plugin.c pcm_copy.c pcm_linear.c \
pcm_route.c pcm_mulaw.c pcm_alaw.c pcm_adpcm.c \ pcm_route.c pcm_mulaw.c pcm_alaw.c pcm_adpcm.c \
pcm_rate.c pcm_plug.c pcm_misc.c pcm_mmap.c pcm_multi.c \ pcm_rate.c pcm_plug.c pcm_misc.c pcm_mmap.c pcm_multi.c \
pcm_shm.c pcm_file.c pcm_share.c pcm_null.c \ pcm_shm.c pcm_file.c pcm_share.c pcm_null.c \
pcm_params.c pcm_params.c
noinst_HEADERS = pcm_local.h pcm_plugin.h mask.h mask_inline.h \ noinst_HEADERS = atomic.h pcm_local.h pcm_plugin.h mask.h mask_inline.h \
interval.h interval_inline.h plugin_ops.h interval.h interval_inline.h plugin_ops.h
all: libpcm.la all: libpcm.la

43
src/pcm/atomic.c Normal file
View file

@ -0,0 +1,43 @@
/*
* Atomic read/write
* Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <stdlib.h>
#include <time.h>
#include <sched.h>
#include "atomic.h"
void snd_atomic_read_wait(snd_atomic_read_t *t)
{
volatile const snd_atomic_write_t *w = t->write;
unsigned int loops = 0;
struct timespec ts;
while (w->begin != w->end) {
if (loops < MAX_SPIN_COUNT) {
sched_yield();
loops++;
continue;
}
loops = 0;
ts.tv_sec = 0;
ts.tv_nsec = SPIN_SLEEP_DURATION;
nanosleep(&ts, NULL);
}
}

85
src/pcm/atomic.h Normal file
View file

@ -0,0 +1,85 @@
/*
* Atomic read/write
* Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <asm/system.h>
/* Max number of times we must spin on a spinlock calling sched_yield().
After MAX_SPIN_COUNT iterations, we put the calling thread to sleep. */
#ifndef MAX_SPIN_COUNT
#define MAX_SPIN_COUNT 50
#endif
/* Duration of sleep (in nanoseconds) when we can't acquire a spinlock
after MAX_SPIN_COUNT iterations of sched_yield().
This MUST BE > 2ms.
(Otherwise the kernel does busy-waiting for realtime threads,
giving other threads no chance to run.) */
#ifndef SPIN_SLEEP_DURATION
#define SPIN_SLEEP_DURATION 2000001
#endif
typedef struct {
unsigned int begin, end;
} snd_atomic_write_t;
typedef struct {
volatile const snd_atomic_write_t *write;
unsigned int end;
} snd_atomic_read_t;
void snd_atomic_read_wait(snd_atomic_read_t *t);
static inline void snd_atomic_write_init(snd_atomic_write_t *w)
{
w->begin = 0;
w->end = 0;
}
static inline void snd_atomic_write_begin(snd_atomic_write_t *w)
{
w->begin++;
wmb();
}
static inline void snd_atomic_write_end(snd_atomic_write_t *w)
{
wmb();
w->end++;
}
static inline void snd_atomic_read_init(snd_atomic_read_t *r, snd_atomic_write_t *w)
{
r->write = w;
}
static inline void snd_atomic_read_begin(snd_atomic_read_t *r)
{
r->end = r->write->end;
rmb();
}
static inline int snd_atomic_read_ok(snd_atomic_read_t *r)
{
rmb();
return r->end == r->write->begin;
}

View file

@ -214,7 +214,7 @@ static int snd_pcm_hw_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
snd_pcm_hw_t *hw = pcm->private_data; snd_pcm_hw_t *hw = pcm->private_data;
int fd = hw->fd; int fd = hw->fd;
if (ioctl(fd, SNDRV_PCM_IOCTL_DELAY, delayp) < 0) { if (ioctl(fd, SNDRV_PCM_IOCTL_DELAY, delayp) < 0) {
SYSERR("SNDRV_PCM_IOCTL_DELAY failed"); // SYSERR("SNDRV_PCM_IOCTL_DELAY failed");
return -errno; return -errno;
} }
return 0; return 0;

View file

@ -24,6 +24,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <limits.h> #include <limits.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <asm/system.h>
#define _snd_pcm_access_mask _snd_mask #define _snd_pcm_access_mask _snd_mask
#define _snd_pcm_format_mask _snd_mask #define _snd_pcm_format_mask _snd_mask
@ -486,3 +487,4 @@ int snd_pcm_hw_strategy_simple_choices(snd_pcm_hw_strategy_t *strategy, int orde
#define SND_PCM_ACCBIT_MMAP ((1 << (unsigned long) SND_PCM_ACCESS_MMAP_INTERLEAVED) | \ #define SND_PCM_ACCBIT_MMAP ((1 << (unsigned long) SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
(1 << (unsigned long) SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \ (1 << (unsigned long) SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \
(1 << (unsigned long) SND_PCM_ACCESS_MMAP_COMPLEX)) (1 << (unsigned long) SND_PCM_ACCESS_MMAP_COMPLEX))

View file

@ -70,18 +70,6 @@ int snd_pcm_plugin_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
return snd_pcm_channel_info_shm(pcm, info, plugin->shmid); return snd_pcm_channel_info_shm(pcm, info, plugin->shmid);
} }
int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
{
snd_pcm_plugin_t *plugin = pcm->private_data;
int err = snd_pcm_status(plugin->slave, status);
if (err < 0)
return err;
status->avail = snd_pcm_mmap_avail(pcm);
if (plugin->client_frames)
status->avail_max = plugin->client_frames(pcm, status->avail_max);
return 0;
}
snd_pcm_state_t snd_pcm_plugin_state(snd_pcm_t *pcm) snd_pcm_state_t snd_pcm_plugin_state(snd_pcm_t *pcm)
{ {
snd_pcm_plugin_t *plugin = pcm->private_data; snd_pcm_plugin_t *plugin = pcm->private_data;
@ -104,11 +92,16 @@ int snd_pcm_plugin_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
int snd_pcm_plugin_prepare(snd_pcm_t *pcm) int snd_pcm_plugin_prepare(snd_pcm_t *pcm)
{ {
snd_pcm_plugin_t *plugin = pcm->private_data; snd_pcm_plugin_t *plugin = pcm->private_data;
int err = snd_pcm_prepare(plugin->slave); int err;
if (err < 0) snd_atomic_write_begin(&plugin->watom);
err = snd_pcm_prepare(plugin->slave);
if (err < 0) {
snd_atomic_write_end(&plugin->watom);
return err; return err;
}
plugin->hw_ptr = 0; plugin->hw_ptr = 0;
plugin->appl_ptr = 0; plugin->appl_ptr = 0;
snd_atomic_write_end(&plugin->watom);
if (plugin->init) { if (plugin->init) {
err = plugin->init(pcm); err = plugin->init(pcm);
if (err < 0) if (err < 0)
@ -120,11 +113,16 @@ int snd_pcm_plugin_prepare(snd_pcm_t *pcm)
int snd_pcm_plugin_reset(snd_pcm_t *pcm) int snd_pcm_plugin_reset(snd_pcm_t *pcm)
{ {
snd_pcm_plugin_t *plugin = pcm->private_data; snd_pcm_plugin_t *plugin = pcm->private_data;
int err = snd_pcm_reset(plugin->slave); int err;
if (err < 0) snd_atomic_write_begin(&plugin->watom);
err = snd_pcm_reset(plugin->slave);
if (err < 0) {
snd_atomic_write_end(&plugin->watom);
return err; return err;
}
plugin->hw_ptr = 0; plugin->hw_ptr = 0;
plugin->appl_ptr = 0; plugin->appl_ptr = 0;
snd_atomic_write_end(&plugin->watom);
if (plugin->init) { if (plugin->init) {
err = plugin->init(pcm); err = plugin->init(pcm);
if (err < 0) if (err < 0)
@ -172,19 +170,24 @@ snd_pcm_sframes_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames
/* FIXME: rate plugin */ /* FIXME: rate plugin */
if (plugin->slave_frames) if (plugin->slave_frames)
frames = plugin->slave_frames(pcm, frames); frames = plugin->slave_frames(pcm, frames);
snd_atomic_write_begin(&plugin->watom);
err = snd_pcm_rewind(plugin->slave, frames); err = snd_pcm_rewind(plugin->slave, frames);
if (err < 0) { if (err < 0) {
if (n <= 0) if (n <= 0) {
snd_atomic_write_end(&plugin->watom);
return err; return err;
}
goto _end; goto _end;
} }
if (plugin->client_frames) if (plugin->client_frames)
err = plugin->client_frames(pcm, err); err = plugin->client_frames(pcm, err);
snd_pcm_mmap_hw_backward(pcm, err); snd_pcm_mmap_hw_backward(pcm, err);
n += err; n += err;
} } else
snd_atomic_write_begin(&plugin->watom);
_end: _end:
snd_pcm_mmap_appl_backward(pcm, n); snd_pcm_mmap_appl_backward(pcm, n);
snd_atomic_write_end(&plugin->watom);
return n; return n;
} }
@ -207,9 +210,11 @@ snd_pcm_uframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm,
frames = plugin->write(pcm, areas, offset, frames, frames = plugin->write(pcm, areas, offset, frames,
slave_areas, slave_offset, &slave_frames); slave_areas, slave_offset, &slave_frames);
assert(slave_frames <= snd_pcm_mmap_playback_avail(slave)); assert(slave_frames <= snd_pcm_mmap_playback_avail(slave));
snd_atomic_write_begin(&plugin->watom);
snd_pcm_mmap_appl_forward(pcm, frames); snd_pcm_mmap_appl_forward(pcm, frames);
snd_pcm_mmap_hw_forward(pcm, frames); snd_pcm_mmap_hw_forward(pcm, frames);
snd_pcm_mmap_forward(slave, slave_frames); snd_pcm_mmap_forward(slave, slave_frames);
snd_atomic_write_end(&plugin->watom);
offset += frames; offset += frames;
size -= frames; size -= frames;
if (slave_frames == slave_cont) if (slave_frames == slave_cont)
@ -239,9 +244,11 @@ snd_pcm_uframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm,
frames = plugin->read(pcm, areas, offset, frames, frames = plugin->read(pcm, areas, offset, frames,
slave_areas, slave_offset, &slave_frames); slave_areas, slave_offset, &slave_frames);
assert(slave_frames <= snd_pcm_mmap_capture_avail(slave)); assert(slave_frames <= snd_pcm_mmap_capture_avail(slave));
snd_atomic_write_begin(&plugin->watom);
snd_pcm_mmap_appl_forward(pcm, frames); snd_pcm_mmap_appl_forward(pcm, frames);
snd_pcm_mmap_hw_forward(pcm, frames); snd_pcm_mmap_hw_forward(pcm, frames);
snd_pcm_mmap_forward(slave, slave_frames); snd_pcm_mmap_forward(slave, slave_frames);
snd_atomic_write_end(&plugin->watom);
offset += frames; offset += frames;
size -= frames; size -= frames;
if (slave_frames == slave_cont) if (slave_frames == slave_cont)
@ -293,7 +300,9 @@ snd_pcm_sframes_t snd_pcm_plugin_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t
snd_pcm_uframes_t xfer, offset; snd_pcm_uframes_t xfer, offset;
snd_pcm_uframes_t slave_offset, slave_size; snd_pcm_uframes_t slave_offset, slave_size;
if (pcm->stream == SND_PCM_STREAM_CAPTURE) { if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
snd_atomic_write_begin(&plugin->watom);
snd_pcm_mmap_appl_forward(pcm, size); snd_pcm_mmap_appl_forward(pcm, size);
snd_atomic_write_end(&plugin->watom);
return size; return size;
} }
slave_size = snd_pcm_avail_update(slave); slave_size = snd_pcm_avail_update(slave);
@ -315,9 +324,11 @@ snd_pcm_sframes_t snd_pcm_plugin_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t
slave_frames = slave_cont; slave_frames = slave_cont;
frames = plugin->write(pcm, areas, offset, frames, frames = plugin->write(pcm, areas, offset, frames,
slave_areas, slave_offset, &slave_frames); slave_areas, slave_offset, &slave_frames);
snd_atomic_write_begin(&plugin->watom);
snd_pcm_mmap_appl_forward(pcm, frames); snd_pcm_mmap_appl_forward(pcm, frames);
snd_pcm_mmap_hw_forward(pcm, frames); snd_pcm_mmap_hw_forward(pcm, frames);
snd_pcm_mmap_forward(slave, slave_frames); snd_pcm_mmap_forward(slave, slave_frames);
snd_atomic_write_end(&plugin->watom);
xfer += frames; xfer += frames;
if (frames == cont) if (frames == cont)
offset = 0; offset = 0;
@ -365,8 +376,10 @@ snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
slave_frames = slave_cont; slave_frames = slave_cont;
frames = plugin->read(pcm, areas, offset, frames, frames = plugin->read(pcm, areas, offset, frames,
slave_areas, slave_offset, &slave_frames); slave_areas, slave_offset, &slave_frames);
snd_atomic_write_begin(&plugin->watom);
snd_pcm_mmap_hw_forward(pcm, frames); snd_pcm_mmap_hw_forward(pcm, frames);
snd_pcm_mmap_forward(slave, slave_frames); snd_pcm_mmap_forward(slave, slave_frames);
snd_atomic_write_end(&plugin->watom);
xfer += frames; xfer += frames;
if (frames == cont) if (frames == cont)
offset = 0; offset = 0;
@ -411,6 +424,36 @@ int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm)
return _snd_pcm_poll_descriptor(plugin->slave); return _snd_pcm_poll_descriptor(plugin->slave);
} }
int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
{
snd_pcm_plugin_t *plugin = pcm->private_data;
snd_pcm_sframes_t err;
snd_atomic_read_t ratom;
snd_atomic_read_init(&ratom, &plugin->watom);
_again:
snd_atomic_read_begin(&ratom);
err = snd_pcm_status(plugin->slave, status);
if (err < 0) {
snd_atomic_read_ok(&ratom);
return err;
}
status->appl_ptr = plugin->appl_ptr;
status->hw_ptr = plugin->hw_ptr;
err = snd_pcm_plugin_avail_update(pcm);
if (err < 0)
status->avail = pcm->buffer_size;
else
status->avail = err;
snd_pcm_plugin_delay(pcm, &status->delay);
if (!snd_atomic_read_ok(&ratom)) {
snd_atomic_read_wait(&ratom);
goto _again;
}
if (plugin->client_frames)
status->avail_max = plugin->client_frames(pcm, status->avail_max);
return 0;
}
int snd_pcm_plugin_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) int snd_pcm_plugin_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{ {
snd_pcm_plugin_t *plugin = pcm->private_data; snd_pcm_plugin_t *plugin = pcm->private_data;

View file

@ -19,6 +19,8 @@
* *
*/ */
#include "atomic.h"
typedef snd_pcm_uframes_t (*snd_pcm_slave_xfer_areas_func_t) typedef snd_pcm_uframes_t (*snd_pcm_slave_xfer_areas_func_t)
(snd_pcm_t *pcm, (snd_pcm_t *pcm,
const snd_pcm_channel_area_t *areas, const snd_pcm_channel_area_t *areas,
@ -38,6 +40,7 @@ typedef struct {
int (*init)(snd_pcm_t *pcm); int (*init)(snd_pcm_t *pcm);
int shmid; int shmid;
snd_pcm_uframes_t appl_ptr, hw_ptr; snd_pcm_uframes_t appl_ptr, hw_ptr;
snd_atomic_write_t watom;
} snd_pcm_plugin_t; } snd_pcm_plugin_t;
int snd_pcm_plugin_close(snd_pcm_t *pcm); int snd_pcm_plugin_close(snd_pcm_t *pcm);