Hi, thanks for quick response!

On 03/04/07, malc <[EMAIL PROTECTED]> wrote:
On Tue, 3 Apr 2007, andrzej zaborowski wrote:

> Hi,
> with QEMU_AUDIO_DRV set to "sdl" and booting from CD-ROM with AIO on
> a Linux host and with SDL 1.2.11, qemu locks up in sigwait() (the main
> thread) and SDL_SemWait() (the audio thread) as soon as music is
> playing and CD-ROM is being read at the same time. It appears that
> audio/sdlaudio.c:sdl_callback is called by SDL when it shouldn't be
> called, and block-raw.c is trying to flush the AIO operations, so it
> would seem that the SIGUSR2 which is intended to wake up the sigwait
> is instead captured by SDL and SDL tries to be smart and calls
> sdl_callback. sdl_callback has a sanity check but this check is
> *after* SDL_SemWait() so it is not triggered. The strange thing is
> that using a different signal (tried SIGUSR1 and SIGPOLL) for AIO
> doesn't help. Does SDL catch all signals?
> I could be totally wrong because I don't know SDLAudio at all.

If my reading of SDLs sources are correct then it shouldn't be trying
to catch any signals when explicitly instructed not to do so (which is
done in sdl.c (SDL_INIT_NOPARACHUTE flag)).

>
> Any ideas about the exact reason why this is happening and how to fix it?
>

Given the semantics of signal delivery in POSIX what you describe
might happen, what is a little surprising is that SDL (btw. which
backend SDL uses?) doesn't complain.

It should be using ALSA.


Here's my theory: signal will be delivered to the arbitrary thread
that happens to not block it, for whatever reason, the thread SDL
created to do audio processing is picked up, which leads to some
system call being interrupted(eventually) and -1 (errno == EINTR), SDL
happily continues calling stuff.

Yes, reading the PTHREAD_SIGNAL(3) note, this sounds very likely.


One solution would be to explicitly block everything upon entering
sdl_callback for the first time. This is ugly and can have any
consequences one cares to imagine, but that's SDL for you (any
particular reason why you are using it?)

Not really - just had only OSS and SDL compiled into qemu at this moment.

Yes, the suggested solution works. Unfortunately it's neither pretty
nor correct, because at the time sdl_callback runs, the signal which
was supposed to wake up sigwait() is already lost and I can't find any
way to prevent that - we can add a kill(0, SIGUSR2) but this is even
uglier and again we don't know when sdl_callback is called as a result
of this signal and when legally. (That's also why I didn't put a
"return" after pthread_sigmask().)

diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index f2a6896..efeb3c0 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -46,6 +46,7 @@ struct SDLAudioState {
    SDL_mutex *mutex;
    SDL_sem *sem;
    int initialized;
+    int threadstart;
} glob_sdl;
typedef struct SDLAudioState SDLAudioState;

@@ -197,13 +198,25 @@ static void sdl_close (SDLAudioState *s)
    }
}

+#ifdef __sun__
+#define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+#include <signal.h>
+
static void sdl_callback (void *opaque, Uint8 *buf, int len)
{
    SDLVoiceOut *sdl = opaque;
    SDLAudioState *s = &glob_sdl;
    HWVoiceOut *hw = &sdl->hw;
    int samples = len >> hw->info.shift;
+    sigset_t set;

+    if (s->threadstart) {
+        /* QEMU uses sigwait() so all threads should block signals.  */
+        s->threadstart = 0;
+        sigfillset(&set);
+        pthread_sigmask(SIG_BLOCK, &set, 0);
+    }
    if (s->exit) {
        return;
    }
@@ -313,6 +326,8 @@ static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as)
    audfmt_e effective_fmt;
    audsettings_t obt_as;

+    s->threadstart = 1;
+
    shift <<= as->nchannels == 2;

    req.freq = as->freq;

What POSIX needs is a way to set the default signal mask for new threads :-/
Regards,
Andrzej


Reply via email to