diff options
| author | Thomas Martitz <kugel@rockbox.org> | 2012-01-13 09:47:01 +0100 |
|---|---|---|
| committer | Thomas Martitz <kugel@rockbox.org> | 2012-01-21 18:39:19 +0100 |
| commit | 34b0311d0eb906bd801cc1e9a329ed211b81496f (patch) | |
| tree | b76d82b8ecb94aab048c58d2b6f3c23b57e15b7a | |
| parent | 109084d5cbaeee26373ecf1b765d9507ccbbe63e (diff) | |
| download | rockbox-34b0311d0eb906bd801cc1e9a329ed211b81496f.zip rockbox-34b0311d0eb906bd801cc1e9a329ed211b81496f.tar.gz rockbox-34b0311d0eb906bd801cc1e9a329ed211b81496f.tar.bz2 rockbox-34b0311d0eb906bd801cc1e9a329ed211b81496f.tar.xz | |
hosted/pcm/alsa: Use alternate signal stack for the async callback.
Signals are by default executed on the user stack, i.e. the stack of
the currently active thread. This has two problems:
1) The stack size of the current stack is likely insufficient (unless
using sigaltstack threads) because our stack sizes are normally
below MINSIGSTKSIZE which is needed to deliver a signal.
2) Some of our asm code does nasty tricks with the stack pointer. When a
signal comes in during this bad things can happen, e.g. random memory
being overwritten or simply a crash.
Using a well defined stack fixes this. This is comparable with the
separate irq stack on native targets.
| -rw-r--r-- | firmware/target/hosted/pcm-alsa.c | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/firmware/target/hosted/pcm-alsa.c b/firmware/target/hosted/pcm-alsa.c index 7daf485..02cb34e 100644 --- a/firmware/target/hosted/pcm-alsa.c +++ b/firmware/target/hosted/pcm-alsa.c @@ -27,6 +27,11 @@ * This driver uses the so-called unsafe async callback method and hardcoded device * names. It fails when the audio device is busy by other apps. * + * To make the async callback safer, an alternative stack is installed, since + * it's run from a signal hanlder (which otherwise uses the user stack). If + * tick tasks are run from a signal handler too, please install + * an alternative stack for it too. + * * TODO: Rewrite this to do it properly with multithreading * * Alternatively, a version using polling in a tick task is provided. While @@ -76,6 +81,7 @@ static size_t pcm_size = 0; #ifdef USE_ASYNC_CALLBACK static snd_async_handler_t *ahandler; static pthread_mutex_t pcm_mtx; +static char signal_stack[SIGSTKSZ]; #else static int recursion; #endif @@ -271,12 +277,37 @@ static int async_rw(snd_pcm_t *handle) short *samples; #ifdef USE_ASYNC_CALLBACK + /* assign alternative stack for the signal handlers */ + stack_t ss = { + .ss_sp = signal_stack, + .ss_size = sizeof(signal_stack), + .ss_flags = 0 + }; + struct sigaction sa; + + err = sigaltstack(&ss, NULL); + if (err < 0) + { + DEBUGF("Unable to install alternative signal stack: %s", strerror(err)); + return err; + } + err = snd_async_add_pcm_handler(&ahandler, handle, async_callback, NULL); if (err < 0) { DEBUGF("Unable to register async handler: %s\n", snd_strerror(err)); return err; } + + /* only modify the stack the handler runs on */ + sigaction(SIGIO, NULL, &sa); + sa.sa_flags |= SA_ONSTACK; + err = sigaction(SIGIO, &sa, NULL); + if (err < 0) + { + DEBUGF("Unable to install alternative signal stack: %s", strerror(err)); + return err; + } #endif /* fill buffer with silence to initiate playback without noisy click */ |