Commit 900498a3 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: pcm: Allow aborting mutex lock at OSS read/write loops

PCM OSS read/write loops keep taking the mutex lock for the whole
read/write, and this might take very long when the exceptionally high
amount of data is given.  Also, since it invokes with mutex_lock(),
the concurrent read/write becomes unbreakable.

This patch tries to address these issues by replacing mutex_lock()
with mutex_lock_interruptible(), and also splits / re-takes the lock
at each read/write period chunk, so that it can switch the context
more finely if requested.

Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 29159a4e
...@@ -1334,8 +1334,11 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha ...@@ -1334,8 +1334,11 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
return tmp; return tmp;
mutex_lock(&runtime->oss.params_lock);
while (bytes > 0) { while (bytes > 0) {
if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
tmp = -ERESTARTSYS;
break;
}
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
tmp = bytes; tmp = bytes;
if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes) if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
...@@ -1379,18 +1382,18 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha ...@@ -1379,18 +1382,18 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
xfer += tmp; xfer += tmp;
if ((substream->f_flags & O_NONBLOCK) != 0 && if ((substream->f_flags & O_NONBLOCK) != 0 &&
tmp != runtime->oss.period_bytes) tmp != runtime->oss.period_bytes)
break; tmp = -EAGAIN;
} }
err:
mutex_unlock(&runtime->oss.params_lock);
if (tmp < 0)
break;
if (signal_pending(current)) { if (signal_pending(current)) {
tmp = -ERESTARTSYS; tmp = -ERESTARTSYS;
goto err; break;
} }
tmp = 0;
} }
mutex_unlock(&runtime->oss.params_lock);
return xfer;
err:
mutex_unlock(&runtime->oss.params_lock);
return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
} }
...@@ -1438,8 +1441,11 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use ...@@ -1438,8 +1441,11 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
return tmp; return tmp;
mutex_lock(&runtime->oss.params_lock);
while (bytes > 0) { while (bytes > 0) {
if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
tmp = -ERESTARTSYS;
break;
}
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
if (runtime->oss.buffer_used == 0) { if (runtime->oss.buffer_used == 0) {
tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1); tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
...@@ -1470,16 +1476,16 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use ...@@ -1470,16 +1476,16 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
bytes -= tmp; bytes -= tmp;
xfer += tmp; xfer += tmp;
} }
err:
mutex_unlock(&runtime->oss.params_lock);
if (tmp < 0)
break;
if (signal_pending(current)) { if (signal_pending(current)) {
tmp = -ERESTARTSYS; tmp = -ERESTARTSYS;
goto err; break;
} }
tmp = 0;
} }
mutex_unlock(&runtime->oss.params_lock);
return xfer;
err:
mutex_unlock(&runtime->oss.params_lock);
return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment