diff options
author | Max Kellermann <max@musicpd.org> | 2017-11-13 17:08:00 +0100 |
---|---|---|
committer | Max Kellermann <max@musicpd.org> | 2017-11-13 17:13:10 +0100 |
commit | 31ab78ae8e10af948ec95496df0d2abf1ea631a4 (patch) | |
tree | 032d43d2a59eb3b443913dd4d4922d79df6b6e35 | |
parent | f82e1453e476bd6c9114e2adf4144eb643950b0e (diff) |
input/{cdio,ffmpeg,file,smbclient}: unlock the mutex during blocking I/O
InputStream::Read() and InputStream::Seek() are called with the mutex
locked. That means the implementation must not block, or unlock the
mutex before calling into blocking code.
Previously, a slow CD drive could stall the whole MPD process,
including the main thread, due to this problem.
Closes #149
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | src/input/plugins/CdioParanoiaInputPlugin.cxx | 7 | ||||
-rw-r--r-- | src/input/plugins/FfmpegInputPlugin.cxx | 15 | ||||
-rw-r--r-- | src/input/plugins/FileInputPlugin.cxx | 14 | ||||
-rw-r--r-- | src/input/plugins/SmbclientInputPlugin.cxx | 2 |
5 files changed, 35 insertions, 5 deletions
@@ -1,5 +1,7 @@ ver 0.20.12 (not yet released) * input + - cdio_paranoia, ffmpeg, file, smbclient: reduce lock contention, + fixing lots of xrun problems - curl: fix seeking * decoder - ffmpeg: fix GCC 8 warning diff --git a/src/input/plugins/CdioParanoiaInputPlugin.cxx b/src/input/plugins/CdioParanoiaInputPlugin.cxx index 39f90dcc0..e5a63a8d6 100644 --- a/src/input/plugins/CdioParanoiaInputPlugin.cxx +++ b/src/input/plugins/CdioParanoiaInputPlugin.cxx @@ -270,7 +270,10 @@ CdioParanoiaInputStream::Seek(offset_type new_offset) lsn_relofs = new_offset / CDIO_CD_FRAMESIZE_RAW; offset = new_offset; - cdio_paranoia_seek(para, lsn_from + lsn_relofs, SEEK_SET); + { + const ScopeUnlock unlock(mutex); + cdio_paranoia_seek(para, lsn_from + lsn_relofs, SEEK_SET); + } } size_t @@ -292,6 +295,8 @@ CdioParanoiaInputStream::Read(void *ptr, size_t length) //current sector was changed ? if (lsn_relofs != buffer_lsn) { + const ScopeUnlock unlock(mutex); + rbuf = cdio_paranoia_read(para, nullptr); s_err = cdda_errors(drv); diff --git a/src/input/plugins/FfmpegInputPlugin.cxx b/src/input/plugins/FfmpegInputPlugin.cxx index 4ba9b470a..9ca16aa67 100644 --- a/src/input/plugins/FfmpegInputPlugin.cxx +++ b/src/input/plugins/FfmpegInputPlugin.cxx @@ -104,7 +104,13 @@ input_ffmpeg_open(const char *uri, size_t FfmpegInputStream::Read(void *ptr, size_t read_size) { - auto result = avio_read(h, (unsigned char *)ptr, read_size); + int result; + + { + const ScopeUnlock unlock(mutex); + result = avio_read(h, (unsigned char *)ptr, read_size); + } + if (result <= 0) { if (result < 0) throw MakeFfmpegError(result, "avio_read() failed"); @@ -126,7 +132,12 @@ FfmpegInputStream::IsEOF() noexcept void FfmpegInputStream::Seek(offset_type new_offset) { - auto result = avio_seek(h, new_offset, SEEK_SET); + int64_t result; + + { + const ScopeUnlock unlock(mutex); + result = avio_seek(h, new_offset, SEEK_SET); + } if (result < 0) throw MakeFfmpegError(result, "avio_seek() failed"); diff --git a/src/input/plugins/FileInputPlugin.cxx b/src/input/plugins/FileInputPlugin.cxx index fc51715ad..2d2850c74 100644 --- a/src/input/plugins/FileInputPlugin.cxx +++ b/src/input/plugins/FileInputPlugin.cxx @@ -87,14 +87,24 @@ input_file_open(gcc_unused const char *filename, void FileInputStream::Seek(offset_type new_offset) { - reader.Seek((off_t)new_offset); + { + const ScopeUnlock unlock(mutex); + reader.Seek((off_t)new_offset); + } + offset = new_offset; } size_t FileInputStream::Read(void *ptr, size_t read_size) { - size_t nbytes = reader.Read(ptr, read_size); + size_t nbytes; + + { + const ScopeUnlock unlock(mutex); + nbytes = reader.Read(ptr, read_size); + } + offset += nbytes; return nbytes; } diff --git a/src/input/plugins/SmbclientInputPlugin.cxx b/src/input/plugins/SmbclientInputPlugin.cxx index 35bb5c5b8..80d406692 100644 --- a/src/input/plugins/SmbclientInputPlugin.cxx +++ b/src/input/plugins/SmbclientInputPlugin.cxx @@ -128,6 +128,7 @@ SmbclientInputStream::Read(void *ptr, size_t read_size) ssize_t nbytes; { + const ScopeUnlock unlock(mutex); const std::lock_guard<Mutex> lock(smbclient_mutex); nbytes = smbc_read(fd, ptr, read_size); } @@ -145,6 +146,7 @@ SmbclientInputStream::Seek(offset_type new_offset) off_t result; { + const ScopeUnlock unlock(mutex); const std::lock_guard<Mutex> lock(smbclient_mutex); result = smbc_lseek(fd, new_offset, SEEK_SET); } |