1 /** 2 * \file async.c 3 * \brief Async notification helpers 4 * \author Abramo Bagnara <abramo (at) alsa-project.org> 5 * \date 2001 6 */ 7 /* 8 * Async notification helpers 9 * Copyright (c) 2001 by Abramo Bagnara <abramo (at) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 24 * 25 */ 26 27 #include "pcm/pcm_local.h" 28 #include "control/control_local.h" 29 #include <signal.h> 30 31 #ifdef SND_ASYNC_RT_SIGNAL 32 /** async signal number */ 33 static int snd_async_signo; 34 35 void snd_async_init(void) __attribute__ ((constructor)); 36 37 void snd_async_init(void) 38 { 39 snd_async_signo = __libc_allocate_rtsig(0); 40 if (snd_async_signo < 0) { 41 SNDERR("Unable to find a RT signal to use for snd_async"); 42 exit(1); 43 } 44 } 45 #else 46 /** async signal number */ 47 static const int snd_async_signo = SIGIO; 48 #endif 49 50 static LIST_HEAD(snd_async_handlers); 51 52 static void snd_async_handler(int signo ATTRIBUTE_UNUSED, siginfo_t *siginfo, void *context ATTRIBUTE_UNUSED) 53 { 54 int fd; 55 struct list_head *i; 56 //assert(siginfo->si_code == SI_SIGIO); 57 fd = siginfo->si_fd; 58 list_for_each(i, &snd_async_handlers) { 59 snd_async_handler_t *h = list_entry(i, snd_async_handler_t, glist); 60 if (h->fd == fd && h->callback) 61 h->callback(h); 62 } 63 } 64 65 /** 66 * \brief Registers an async handler. 67 * \param handler The function puts the pointer to the new async handler 68 * object at the address specified by \p handler. 69 * \param fd The file descriptor to be associated with the callback. 70 * \param callback The async callback function. 71 * \param private_data Private data for the async callback function. 72 * \result Zero if successful, otherwise a negative error code. 73 * 74 * This function associates the callback function with the given file, 75 * and saves this association in a \c snd_async_handler_t object. 76 * 77 * Whenever the \c SIGIO signal is raised for the file \p fd, the callback 78 * function will be called with its parameter pointing to the async handler 79 * object returned by this function. 80 * 81 * The ALSA \c sigaction handler for the \c SIGIO signal automatically 82 * multiplexes the notifications to the registered async callbacks. 83 * However, the application is responsible for instructing the device driver 84 * to generate the \c SIGIO signal. 85 * 86 * The \c SIGIO signal may have been replaced with another signal, 87 * see #snd_async_handler_get_signo. 88 * 89 * When the async handler isn't needed anymore, you must delete it with 90 * #snd_async_del_handler. 91 * 92 * \see snd_async_add_pcm_handler, snd_async_add_ctl_handler 93 */ 94 int snd_async_add_handler(snd_async_handler_t **handler, int fd, 95 snd_async_callback_t callback, void *private_data) 96 { 97 snd_async_handler_t *h; 98 int was_empty; 99 assert(handler); 100 h = malloc(sizeof(*h)); 101 if (!h) 102 return -ENOMEM; 103 h->fd = fd; 104 h->callback = callback; 105 h->private_data = private_data; 106 was_empty = list_empty(&snd_async_handlers); 107 list_add_tail(&h->glist, &snd_async_handlers); 108 INIT_LIST_HEAD(&h->hlist); 109 *handler = h; 110 if (was_empty) { 111 int err; 112 struct sigaction act; 113 memset(&act, 0, sizeof(act)); 114 act.sa_flags = SA_RESTART | SA_SIGINFO; 115 act.sa_sigaction = snd_async_handler; 116 sigemptyset(&act.sa_mask); 117 err = sigaction(snd_async_signo, &act, NULL); 118 if (err < 0) { 119 SYSERR("sigaction"); 120 return -errno; 121 } 122 } 123 return 0; 124 } 125 126 /** 127 * \brief Deletes an async handler. 128 * \param handler Handle of the async handler to delete. 129 * \result Zero if successful, otherwise a negative error code. 130 */ 131 int snd_async_del_handler(snd_async_handler_t *handler) 132 { 133 int err = 0; 134 assert(handler); 135 list_del(&handler->glist); 136 if (list_empty(&snd_async_handlers)) { 137 struct sigaction act; 138 memset(&act, 0, sizeof(act)); 139 act.sa_flags = 0; 140 act.sa_handler = SIG_DFL; 141 err = sigaction(snd_async_signo, &act, NULL); 142 if (err < 0) { 143 SYSERR("sigaction"); 144 return -errno; 145 } 146 } 147 if (handler->type == SND_ASYNC_HANDLER_GENERIC) 148 goto _end; 149 if (!list_empty(&handler->hlist)) 150 list_del(&handler->hlist); 151 if (!list_empty(&handler->hlist)) 152 goto _end; 153 switch (handler->type) { 154 #ifdef BUILD_PCM 155 case SND_ASYNC_HANDLER_PCM: 156 err = snd_pcm_async(handler->u.pcm, -1, 1); 157 break; 158 #endif 159 case SND_ASYNC_HANDLER_CTL: 160 err = snd_ctl_async(handler->u.ctl, -1, 1); 161 break; 162 default: 163 assert(0); 164 } 165 _end: 166 free(handler); 167 return err; 168 } 169 170 /** 171 * \brief Returns the signal number assigned to an async handler. 172 * \param handler Handle to an async handler. 173 * \result The signal number if successful, otherwise a negative error code. 174 * 175 * The signal number for async handlers usually is \c SIGIO, 176 * but wizards can redefine it to a realtime signal 177 * when compiling the ALSA library. 178 */ 179 int snd_async_handler_get_signo(snd_async_handler_t *handler) 180 { 181 assert(handler); 182 return snd_async_signo; 183 } 184 185 /** 186 * \brief Returns the file descriptor assigned to an async handler. 187 * \param handler Handle to an async handler. 188 * \result The file descriptor if successful, otherwise a negative error code. 189 */ 190 int snd_async_handler_get_fd(snd_async_handler_t *handler) 191 { 192 assert(handler); 193 return handler->fd; 194 } 195 196 /** 197 * \brief Returns the private data assigned to an async handler. 198 * \param handler Handle to an async handler. 199 * \result The \c private_data value registered with the async handler. 200 */ 201 void *snd_async_handler_get_callback_private(snd_async_handler_t *handler) 202 { 203 assert(handler); 204 return handler->private_data; 205 } 206 207