Hi,
the patch below adds a framework to support async on ioplug. Now an external ioplug plugin can implement appropriate async methods if possible.
The async callback is just a copy of snd_pcm_async(). When sig >= 0, activate the async, and with a negative value, deactivate async.
The test patch to alsa-plugins will follow.
Takashi
--- diff -r 8b22022a861d include/local.h --- a/include/local.h Fri May 09 16:02:02 2008 +0200 +++ b/include/local.h Tue May 20 09:02:35 2008 +0200 @@ -149,7 +149,13 @@ void *private_data; struct list_head glist; struct list_head hlist; + int no_signal; }; + +int _snd_async_add_handler(snd_async_handler_t **handler, int fd, + snd_async_callback_t callback, + void *private_data, int no_signal); +void _snd_async_call_handlers(int fd);
typedef enum _snd_set_mode { SND_CHANGE, diff -r 8b22022a861d include/pcm_ioplug.h --- a/include/pcm_ioplug.h Fri May 09 16:02:02 2008 +0200 +++ b/include/pcm_ioplug.h Tue May 20 09:02:35 2008 +0200 @@ -66,7 +66,7 @@ */ #define SND_PCM_IOPLUG_VERSION_MAJOR 1 /**< Protocol major version */ #define SND_PCM_IOPLUG_VERSION_MINOR 0 /**< Protocol minor version */ -#define SND_PCM_IOPLUG_VERSION_TINY 1 /**< Protocol tiny version */ +#define SND_PCM_IOPLUG_VERSION_TINY 2 /**< Protocol tiny version */ /** * IO-plugin protocol version */ @@ -114,6 +114,10 @@ unsigned int rate; /**< rate; filled after hw_params is called */ snd_pcm_uframes_t period_size; /**< period size; filled after hw_params is called */ snd_pcm_uframes_t buffer_size; /**< buffer size; filled after hw_params is called */ + /** + * fields added by version 1.0.2 + */ + unsigned int no_signal_async; /**< async support without signal */ };
/** Callback table of ioplug */ @@ -189,6 +193,10 @@ * get the delay for the running PCM; optional */ int (*delay)(snd_pcm_ioplug_t *io, snd_pcm_sframes_t *delayp); + /** + * set up async handler; optional; added in version 1.0.2 + */ + int (*async)(snd_pcm_ioplug_t *io, int sig, pid_t pid); };
@@ -212,6 +220,9 @@ /* change PCM status */ int snd_pcm_ioplug_set_state(snd_pcm_ioplug_t *ioplug, snd_pcm_state_t state);
+/* call async handlers */ +void snd_pcm_ioplug_call_async_handlers(snd_pcm_ioplug_t *ioplug); + /** } */
#endif /* __ALSA_PCM_IOPLUG_H */ diff -r 8b22022a861d src/async.c --- a/src/async.c Fri May 09 16:02:02 2008 +0200 +++ b/src/async.c Tue May 20 09:02:35 2008 +0200 @@ -48,19 +48,48 @@ #endif
static LIST_HEAD(snd_async_handlers); +static int sig_count;
-static void snd_async_handler(int signo ATTRIBUTE_UNUSED, siginfo_t *siginfo, void *context ATTRIBUTE_UNUSED) +#ifndef DOC_HIDDEN +void _snd_async_call_handlers(int fd) { - int fd; struct list_head *i; - //assert(siginfo->si_code == SI_SIGIO); - fd = siginfo->si_fd; list_for_each(i, &snd_async_handlers) { snd_async_handler_t *h = list_entry(i, snd_async_handler_t, glist); if (h->fd == fd && h->callback) h->callback(h); } } +#endif + +static void snd_async_handler(int signo ATTRIBUTE_UNUSED, siginfo_t *siginfo, void *context ATTRIBUTE_UNUSED) +{ + int fd; + //assert(siginfo->si_code == SI_SIGIO); + fd = siginfo->si_fd; + _snd_async_call_handlers(fd); +} + +#ifndef DOC_HIDDEN +int _snd_async_add_handler(snd_async_handler_t **handler, int fd, + snd_async_callback_t callback, + void *private_data, int no_signal) +{ + snd_async_handler_t *h; + assert(handler); + h = malloc(sizeof(*h)); + if (!h) + return -ENOMEM; + h->fd = fd; + h->callback = callback; + h->private_data = private_data; + list_add_tail(&h->glist, &snd_async_handlers); + INIT_LIST_HEAD(&h->hlist); + h->no_signal = no_signal; + *handler = h; + return 0; +} +#endif
/** * \brief Registers an async handler. @@ -94,20 +123,13 @@ int snd_async_add_handler(snd_async_handler_t **handler, int fd, snd_async_callback_t callback, void *private_data) { - snd_async_handler_t *h; - int was_empty; - assert(handler); - h = malloc(sizeof(*h)); - if (!h) - return -ENOMEM; - h->fd = fd; - h->callback = callback; - h->private_data = private_data; - was_empty = list_empty(&snd_async_handlers); - list_add_tail(&h->glist, &snd_async_handlers); - INIT_LIST_HEAD(&h->hlist); - *handler = h; - if (was_empty) { + int err; + + err = _snd_async_add_handler(handler, fd, callback, private_data, 0); + if (err < 0) + return err; + + if (!sig_count) { int err; struct sigaction act; memset(&act, 0, sizeof(act)); @@ -116,10 +138,15 @@ sigemptyset(&act.sa_mask); err = sigaction(snd_async_signo, &act, NULL); if (err < 0) { + err = -errno; SYSERR("sigaction"); - return -errno; + list_del(&(*handler)->glist); + free(*handler); + *handler = NULL; + return err; } } + sig_count++; return 0; }
@@ -133,15 +160,18 @@ int err = 0; assert(handler); list_del(&handler->glist); - if (list_empty(&snd_async_handlers)) { - struct sigaction act; - memset(&act, 0, sizeof(act)); - act.sa_flags = 0; - act.sa_handler = SIG_DFL; - err = sigaction(snd_async_signo, &act, NULL); - if (err < 0) { - SYSERR("sigaction"); - return -errno; + if (!handler->no_signal) { + sig_count--; + if (!sig_count) { + struct sigaction act; + memset(&act, 0, sizeof(act)); + act.sa_flags = 0; + act.sa_handler = SIG_DFL; + err = sigaction(snd_async_signo, &act, NULL); + if (err < 0) { + SYSERR("sigaction"); + /* return -errno; */ + } } } if (handler->type == SND_ASYNC_HANDLER_GENERIC) diff -r 8b22022a861d src/pcm/pcm.c --- a/src/pcm/pcm.c Fri May 09 16:02:02 2008 +0200 +++ b/src/pcm/pcm.c Tue May 20 09:02:36 2008 +0200 @@ -1984,8 +1984,10 @@ int err; int was_empty; snd_async_handler_t *h; - err = snd_async_add_handler(&h, _snd_pcm_async_descriptor(pcm), - callback, private_data); + + err = _snd_async_add_handler(&h, _snd_pcm_async_descriptor(pcm), + callback, private_data, + pcm->no_signal_async); if (err < 0) return err; h->type = SND_ASYNC_HANDLER_PCM; diff -r 8b22022a861d src/pcm/pcm_ioplug.c --- a/src/pcm/pcm_ioplug.c Fri May 09 16:02:02 2008 +0200 +++ b/src/pcm/pcm_ioplug.c Tue May 20 09:02:36 2008 +0200 @@ -698,11 +698,15 @@ return 0; }
-static int snd_pcm_ioplug_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED, - int sig ATTRIBUTE_UNUSED, - pid_t pid ATTRIBUTE_UNUSED) +static int snd_pcm_ioplug_async(snd_pcm_t *pcm, int sig, pid_t pid) { - return -ENOSYS; + ioplug_priv_t *io = pcm->private_data; + + if (io->data->version >= 0x010002 && + io->data->callback->async) + return io->data->callback->async(io->data, sig, pid); + else + return -ENOSYS; }
static int snd_pcm_ioplug_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) @@ -1037,6 +1041,9 @@ ioplug->pcm->poll_events = ioplug->poll_events; ioplug->pcm->monotonic = (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC) != 0; ioplug->pcm->mmap_rw = ioplug->mmap_rw; + if (ioplug->version >= 0x010002) + ioplug->pcm->no_signal_async = ioplug->no_signal_async; + return 0; }
@@ -1070,3 +1077,16 @@ ioplug->state = state; return 0; } + +/** + * \brief Call the associated async handlers + * \param ioplug the ioplug handle + * + * Call the async handlers associated with the given ioplug. + * This function is usually called from the plugin's async handling + * routine appropriately. + */ +void snd_pcm_ioplug_call_async_handlers(snd_pcm_ioplug_t *ioplug) +{ + _snd_async_call_handlers(ioplug->poll_fd); +} diff -r 8b22022a861d src/pcm/pcm_local.h --- a/src/pcm/pcm_local.h Fri May 09 16:02:02 2008 +0200 +++ b/src/pcm/pcm_local.h Tue May 20 09:02:36 2008 +0200 @@ -220,6 +220,7 @@ * use the mmaped buffer of the slave */ unsigned int donot_close: 1; /* don't close this PCM */ + unsigned int no_signal_async :1; /* async without signal */ snd_pcm_channel_info_t *mmap_channels; snd_pcm_channel_area_t *running_areas; snd_pcm_channel_area_t *stopped_areas;