1/** 2 * \file async.c 3 * \brief Async notification helpers 4 * \author Abramo Bagnara <abramo@alsa-project.org> 5 * \date 2001 6 */ 7/* 8 * Async notification helpers 9 * Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org> 10 * 11 * This library is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License as 13 * published by the Free Software Foundation; either version 2.1 of 14 * the License, or (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU Lesser General Public License for more details. 20 * 21 * You should have received a copy of the GNU Lesser General Public 22 * License along with this library; if not, write to the Free Software 23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 24 * 25 */ 26 27#include "pcm/pcm_local.h" 28#include "control/control_local.h" 29#include <signal.h> 30 31static struct sigaction previous_action; 32#ifndef DOC_HIDDEN 33#define MAX_SIG_FUNCTION_CODE 10 /* i.e. SIG_DFL SIG_IGN SIG_HOLD et al */ 34#endif /* DOC_HIDDEN */ 35 36#ifdef SND_ASYNC_RT_SIGNAL 37/** async signal number */ 38static int snd_async_signo; 39 40void snd_async_init(void) __attribute__ ((constructor)); 41 42void snd_async_init(void) 43{ 44 snd_async_signo = __libc_allocate_rtsig(0); 45 if (snd_async_signo < 0) { 46 SNDERR("Unable to find a RT signal to use for snd_async"); 47 exit(1); 48 } 49} 50#else 51/** async signal number */ 52static const int snd_async_signo = SIGIO; 53#endif 54 55static LIST_HEAD(snd_async_handlers); 56 57static void snd_async_handler(int signo ATTRIBUTE_UNUSED, siginfo_t *siginfo, void *context ATTRIBUTE_UNUSED) 58{ 59#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) 60 /* siginfo_t does not have si_fd */ 61 struct list_head *i; 62 list_for_each(i, &snd_async_handlers) { 63 snd_async_handler_t *h = list_entry(i, snd_async_handler_t, glist); 64 if (h->callback) 65 h->callback(h); 66 } 67#else 68 int fd; 69 struct list_head *i; 70 //assert(siginfo->si_code == SI_SIGIO); 71 if (signo == SIGIO 72 && (unsigned long)(previous_action.sa_sigaction) > MAX_SIG_FUNCTION_CODE) 73 previous_action.sa_sigaction(signo, siginfo, context); 74 fd = siginfo->si_fd; 75 list_for_each(i, &snd_async_handlers) { 76 snd_async_handler_t *h = list_entry(i, snd_async_handler_t, glist); 77 if (h->fd == fd && h->callback) 78 h->callback(h); 79 } 80#endif 81} 82 83/** 84 * \brief Registers an async handler. 85 * \param handler The function puts the pointer to the new async handler 86 * object at the address specified by \p handler. 87 * \param fd The file descriptor to be associated with the callback. 88 * \param callback The async callback function. 89 * \param private_data Private data for the async callback function. 90 * \result Zero if successful, otherwise a negative error code. 91 * 92 * This function associates the callback function with the given file, 93 * and saves this association in a \c snd_async_handler_t object. 94 * 95 * Whenever the \c SIGIO signal is raised for the file \p fd, the callback 96 * function will be called with its parameter pointing to the async handler 97 * object returned by this function. 98 * 99 * The ALSA \c sigaction handler for the \c SIGIO signal automatically 100 * multiplexes the notifications to the registered async callbacks. 101 * However, the application is responsible for instructing the device driver 102 * to generate the \c SIGIO signal. 103 * 104 * The \c SIGIO signal may have been replaced with another signal, 105 * see #snd_async_handler_get_signo. 106 * 107 * When the async handler isn't needed anymore, you must delete it with 108 * #snd_async_del_handler. 109 * 110 * \see snd_async_add_pcm_handler, snd_async_add_ctl_handler 111 */ 112int snd_async_add_handler(snd_async_handler_t **handler, int fd, 113 snd_async_callback_t callback, void *private_data) 114{ 115 snd_async_handler_t *h; 116 int was_empty; 117 assert(handler); 118 h = malloc(sizeof(*h)); 119 if (!h) 120 return -ENOMEM; 121 h->fd = fd; 122 h->callback = callback; 123 h->private_data = private_data; 124 was_empty = list_empty(&snd_async_handlers); 125 list_add_tail(&h->glist, &snd_async_handlers); 126 INIT_LIST_HEAD(&h->hlist); 127 *handler = h; 128 if (was_empty) { 129 int err; 130 struct sigaction act; 131 memset(&act, 0, sizeof(act)); 132 act.sa_flags = SA_RESTART | SA_SIGINFO; 133 act.sa_sigaction = snd_async_handler; 134 sigemptyset(&act.sa_mask); 135 assert(!previous_action.sa_sigaction); 136 err = sigaction(snd_async_signo, &act, &previous_action); 137 if (err < 0) { 138 SYSERR("sigaction"); 139 return -errno; 140 } 141 } 142 return 0; 143} 144 145/** 146 * \brief Deletes an async handler. 147 * \param handler Handle of the async handler to delete. 148 * \result Zero if successful, otherwise a negative error code. 149 */ 150int snd_async_del_handler(snd_async_handler_t *handler) 151{ 152 int err = 0; 153 int was_empty = list_empty(&snd_async_handlers); 154 assert(handler); 155 list_del(&handler->glist); 156 if (!was_empty 157 && list_empty(&snd_async_handlers)) { 158 err = sigaction(snd_async_signo, &previous_action, NULL); 159 if (err < 0) { 160 SYSERR("sigaction"); 161 return -errno; 162 } 163 memset(&previous_action, 0, sizeof(previous_action)); 164 } 165 if (handler->type == SND_ASYNC_HANDLER_GENERIC) 166 goto _end; 167 if (!list_empty(&handler->hlist)) 168 list_del(&handler->hlist); 169 if (!list_empty(&handler->hlist)) 170 goto _end; 171 switch (handler->type) { 172#ifdef BUILD_PCM 173 case SND_ASYNC_HANDLER_PCM: 174 err = snd_pcm_async(handler->u.pcm, -1, 1); 175 break; 176#endif 177 case SND_ASYNC_HANDLER_CTL: 178 err = snd_ctl_async(handler->u.ctl, -1, 1); 179 break; 180 default: 181 assert(0); 182 } 183 _end: 184 free(handler); 185 return err; 186} 187 188/** 189 * \brief Returns the signal number assigned to an async handler. 190 * \param handler Handle to an async handler. 191 * \result The signal number if successful, otherwise a negative error code. 192 * 193 * The signal number for async handlers usually is \c SIGIO, 194 * but wizards can redefine it to a realtime signal 195 * when compiling the ALSA library. 196 */ 197int snd_async_handler_get_signo(snd_async_handler_t *handler) 198{ 199 assert(handler); 200 return snd_async_signo; 201} 202 203/** 204 * \brief Returns the file descriptor assigned to an async handler. 205 * \param handler Handle to an async handler. 206 * \result The file descriptor if successful, otherwise a negative error code. 207 */ 208int snd_async_handler_get_fd(snd_async_handler_t *handler) 209{ 210 assert(handler); 211 return handler->fd; 212} 213 214/** 215 * \brief Returns the private data assigned to an async handler. 216 * \param handler Handle to an async handler. 217 * \result The \c private_data value registered with the async handler. 218 */ 219void *snd_async_handler_get_callback_private(snd_async_handler_t *handler) 220{ 221 assert(handler); 222 return handler->private_data; 223} 224 225