Home | History | Annotate | Download | only in src
      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