[alsa-devel] [PATCH 1/2] pcm: Avoid lock for snd_pcm_nonblock()
snd_pcm_nonblock() is called as snd_pcm_abort(). Since snd_pcm_abort() is called often from a signal handler to clean things up (e.g. aplay does it), we may face a deadlock if the signal is raised during the locked operation.
There can be some way to check the deadlock state, but they would cost much. Since the race condition of snd_pcm_nonblock() is quite small, let's just drop the locking inside snd_pcm_nonblock() as a workaround.
Signed-off-by: Takashi Iwai tiwai@suse.de --- src/pcm/pcm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 0cf740f854a9..c136d5579320 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -759,7 +759,10 @@ int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock) int err = 0;
assert(pcm); - __snd_pcm_lock(pcm); /* forced lock due to pcm field change */ + /* FIXME: __snd_pcm_lock() call below is commented out because of the + * the possible deadlock in signal handler calling snd_pcm_abort() + */ + /* __snd_pcm_lock(pcm); */ /* forced lock due to pcm field change */ if ((err = pcm->ops->nonblock(pcm->op_arg, nonblock)) < 0) goto unlock; if (nonblock == 2) { @@ -775,7 +778,7 @@ int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock) pcm->mode &= ~SND_PCM_NONBLOCK; } unlock: - __snd_pcm_unlock(pcm); + /* __snd_pcm_unlock(pcm); */ /* FIXME: see above */ return err; }
When PCM is operated in async mode and an async handler calls some PCM functions with lock during other PCM operations, we may hit a deadlock.
Although async mode is rarely used, it's still a possible use case. Disable the locking when the stream is opened in async mode or it's set to async mode via snd_pcm_async().
Signed-off-by: Takashi Iwai tiwai@suse.de --- src/pcm/pcm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index c136d5579320..493e9039b508 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -799,6 +799,8 @@ int snd_pcm_async(snd_pcm_t *pcm, int sig, pid_t pid) sig = SIGIO; if (pid == 0) pid = getpid(); + /* async handler may lead to a deadlock; suppose no multi thread */ + pcm->lock_enabled = 0; return pcm->ops->async(pcm->op_arg, sig, pid); } #endif @@ -2597,7 +2599,10 @@ int snd_pcm_new(snd_pcm_t **pcmp, snd_pcm_type_t type, const char *name, * each plugin may suppress this in its open call */ pcm->need_lock = 1; - { + if (mode & SND_PCM_ASYNC) { + /* async handler may lead to a deadlock; suppose no MT */ + pcm->lock_enabled = 0; + } else { /* set lock_enabled field depending on $LIBASOUND_THREAD_SAFE */ static int do_lock_enable = -1; /* uninitialized */
participants (1)
-
Takashi Iwai