commit
900498a34a3ac9c611e9b425094c8106bdd7dc1c upstream.
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.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
return tmp;
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
return tmp;
- mutex_lock(&runtime->oss.params_lock);
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ tmp = -ERESTARTSYS;
+ break;
+ }
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
tmp = bytes;
if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
tmp = bytes;
if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
xfer += tmp;
if ((substream->f_flags & O_NONBLOCK) != 0 &&
tmp != runtime->oss.period_bytes)
xfer += tmp;
if ((substream->f_flags & O_NONBLOCK) != 0 &&
tmp != runtime->oss.period_bytes)
+ err:
+ mutex_unlock(&runtime->oss.params_lock);
+ if (tmp < 0)
+ break;
if (signal_pending(current)) {
tmp = -ERESTARTSYS;
if (signal_pending(current)) {
tmp = -ERESTARTSYS;
- 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;
}
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
return tmp;
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
return tmp;
- mutex_lock(&runtime->oss.params_lock);
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ tmp = -ERESTARTSYS;
+ break;
+ }
if (bytes < runtime->oss.period_bytes || 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);
if (bytes < runtime->oss.period_bytes || 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);
bytes -= tmp;
xfer += tmp;
}
bytes -= tmp;
xfer += tmp;
}
+ err:
+ mutex_unlock(&runtime->oss.params_lock);
+ if (tmp < 0)
+ break;
if (signal_pending(current)) {
tmp = -ERESTARTSYS;
if (signal_pending(current)) {
tmp = -ERESTARTSYS;
- 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;
}