input/InputStreams: pass std::unique_lock<> to various methods

This commit is contained in:
Max Kellermann 2019-04-26 19:19:45 +02:00
parent 040573c636
commit 1b5c1f75a4
33 changed files with 212 additions and 156 deletions

View File

@ -72,7 +72,8 @@ public:
/* virtual methods from InputStream */ /* virtual methods from InputStream */
bool IsEOF() noexcept override; bool IsEOF() noexcept override;
size_t Read(void *ptr, size_t size) override; size_t Read(std::unique_lock<Mutex> &lock,
void *ptr, size_t size) override;
private: private:
void Open(); void Open();
@ -147,7 +148,7 @@ Bzip2InputStream::FillBuffer()
} }
size_t size_t
Bzip2InputStream::Read(void *ptr, size_t length) Bzip2InputStream::Read(std::unique_lock<Mutex> &, void *ptr, size_t length)
{ {
const ScopeUnlock unlock(mutex); const ScopeUnlock unlock(mutex);

View File

@ -157,7 +157,8 @@ public:
/* virtual methods from InputStream */ /* virtual methods from InputStream */
bool IsEOF() noexcept override; bool IsEOF() noexcept override;
size_t Read(void *ptr, size_t size) override; size_t Read(std::unique_lock<Mutex> &lock,
void *ptr, size_t size) override;
}; };
InputStreamPtr InputStreamPtr
@ -174,7 +175,8 @@ Iso9660ArchiveFile::OpenStream(const char *pathname,
} }
size_t size_t
Iso9660InputStream::Read(void *ptr, size_t read_size) Iso9660InputStream::Read(std::unique_lock<Mutex> &,
void *ptr, size_t read_size)
{ {
const ScopeUnlock unlock(mutex); const ScopeUnlock unlock(mutex);

View File

@ -111,8 +111,9 @@ public:
/* virtual methods from InputStream */ /* virtual methods from InputStream */
bool IsEOF() noexcept override; bool IsEOF() noexcept override;
size_t Read(void *ptr, size_t size) override; size_t Read(std::unique_lock<Mutex> &lock,
void Seek(offset_type offset) override; void *ptr, size_t size) override;
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
}; };
InputStreamPtr InputStreamPtr
@ -130,7 +131,7 @@ ZzipArchiveFile::OpenStream(const char *pathname,
} }
size_t size_t
ZzipInputStream::Read(void *ptr, size_t read_size) ZzipInputStream::Read(std::unique_lock<Mutex> &, void *ptr, size_t read_size)
{ {
const ScopeUnlock unlock(mutex); const ScopeUnlock unlock(mutex);
@ -149,7 +150,7 @@ ZzipInputStream::IsEOF() noexcept
} }
void void
ZzipInputStream::Seek(offset_type new_offset) ZzipInputStream::Seek(std::unique_lock<Mutex> &, offset_type new_offset)
{ {
const ScopeUnlock unlock(mutex); const ScopeUnlock unlock(mutex);

View File

@ -292,9 +292,9 @@ read_stream_art(Response &r, const char *uri, size_t offset)
size_t read_size; size_t read_size;
{ {
const std::lock_guard<Mutex> protect(mutex); std::unique_lock<Mutex> lock(mutex);
is->Seek(offset); is->Seek(lock, offset);
read_size = is->Read(&buffer, CHUNK_SIZE); read_size = is->Read(lock, &buffer, CHUNK_SIZE);
} }
r.Format("size: %" PRIoffset "\n" r.Format("size: %" PRIoffset "\n"

View File

@ -305,7 +305,7 @@ GetChromaprintCommand::Read(InputStream &is, void *buffer, size_t length)
cond.wait(lock); cond.wait(lock);
} }
return is.Read(buffer, length); return is.Read(lock, buffer, length);
} }
CommandResult CommandResult

View File

@ -403,7 +403,7 @@ try {
dc.cond.wait(lock); dc.cond.wait(lock);
} }
size_t nbytes = is.Read(buffer, length); size_t nbytes = is.Read(lock, buffer, length);
assert(nbytes > 0 || is.IsEOF()); assert(nbytes > 0 || is.IsEOF());
return nbytes; return nbytes;

View File

@ -55,7 +55,8 @@ static constexpr Domain decoder_thread_domain("decoder_thread");
static bool static bool
decoder_stream_decode(const DecoderPlugin &plugin, decoder_stream_decode(const DecoderPlugin &plugin,
DecoderBridge &bridge, DecoderBridge &bridge,
InputStream &input_stream) InputStream &input_stream,
std::unique_lock<Mutex> &lock)
{ {
assert(plugin.stream_decode != nullptr); assert(plugin.stream_decode != nullptr);
assert(bridge.stream_tag == nullptr); assert(bridge.stream_tag == nullptr);
@ -70,7 +71,7 @@ decoder_stream_decode(const DecoderPlugin &plugin,
/* rewind the stream, so each plugin gets a fresh start */ /* rewind the stream, so each plugin gets a fresh start */
try { try {
input_stream.Rewind(); input_stream.Rewind(lock);
} catch (...) { } catch (...) {
} }
@ -161,6 +162,7 @@ decoder_check_plugin(const DecoderPlugin &plugin, const InputStream &is,
static bool static bool
decoder_run_stream_plugin(DecoderBridge &bridge, InputStream &is, decoder_run_stream_plugin(DecoderBridge &bridge, InputStream &is,
std::unique_lock<Mutex> &lock,
const char *suffix, const char *suffix,
const DecoderPlugin &plugin, const DecoderPlugin &plugin,
bool &tried_r) bool &tried_r)
@ -171,11 +173,12 @@ decoder_run_stream_plugin(DecoderBridge &bridge, InputStream &is,
bridge.Reset(); bridge.Reset();
tried_r = true; tried_r = true;
return decoder_stream_decode(plugin, bridge, is); return decoder_stream_decode(plugin, bridge, is, lock);
} }
static bool static bool
decoder_run_stream_locked(DecoderBridge &bridge, InputStream &is, decoder_run_stream_locked(DecoderBridge &bridge, InputStream &is,
std::unique_lock<Mutex> &lock,
const char *uri, bool &tried_r) const char *uri, bool &tried_r)
{ {
UriSuffixBuffer suffix_buffer; UriSuffixBuffer suffix_buffer;
@ -183,7 +186,8 @@ decoder_run_stream_locked(DecoderBridge &bridge, InputStream &is,
using namespace std::placeholders; using namespace std::placeholders;
const auto f = std::bind(decoder_run_stream_plugin, const auto f = std::bind(decoder_run_stream_plugin,
std::ref(bridge), std::ref(is), suffix, std::ref(bridge), std::ref(is), std::ref(lock),
suffix,
_1, std::ref(tried_r)); _1, std::ref(tried_r));
return decoder_plugins_try(f); return decoder_plugins_try(f);
} }
@ -192,7 +196,8 @@ decoder_run_stream_locked(DecoderBridge &bridge, InputStream &is,
* Try decoding a stream, using the fallback plugin. * Try decoding a stream, using the fallback plugin.
*/ */
static bool static bool
decoder_run_stream_fallback(DecoderBridge &bridge, InputStream &is) decoder_run_stream_fallback(DecoderBridge &bridge, InputStream &is,
std::unique_lock<Mutex> &lock)
{ {
const struct DecoderPlugin *plugin; const struct DecoderPlugin *plugin;
@ -202,7 +207,7 @@ decoder_run_stream_fallback(DecoderBridge &bridge, InputStream &is)
plugin = decoder_plugin_from_name("mad"); plugin = decoder_plugin_from_name("mad");
#endif #endif
return plugin != nullptr && plugin->stream_decode != nullptr && return plugin != nullptr && plugin->stream_decode != nullptr &&
decoder_stream_decode(*plugin, bridge, is); decoder_stream_decode(*plugin, bridge, is, lock);
} }
/** /**
@ -249,16 +254,16 @@ decoder_run_stream(DecoderBridge &bridge, const char *uri)
MaybeLoadReplayGain(bridge, *input_stream); MaybeLoadReplayGain(bridge, *input_stream);
const std::lock_guard<Mutex> protect(dc.mutex); std::unique_lock<Mutex> lock(dc.mutex);
bool tried = false; bool tried = false;
return dc.command == DecoderCommand::STOP || return dc.command == DecoderCommand::STOP ||
decoder_run_stream_locked(bridge, *input_stream, uri, decoder_run_stream_locked(bridge, *input_stream, lock, uri,
tried) || tried) ||
/* fallback to mp3: this is needed for bastard streams /* fallback to mp3: this is needed for bastard streams
that don't have a suffix or set the mimeType */ that don't have a suffix or set the mimeType */
(!tried && (!tried &&
decoder_run_stream_fallback(bridge, *input_stream)); decoder_run_stream_fallback(bridge, *input_stream, lock));
} }
/** /**
@ -282,8 +287,9 @@ TryDecoderFile(DecoderBridge &bridge, Path path_fs, const char *suffix,
const std::lock_guard<Mutex> protect(dc.mutex); const std::lock_guard<Mutex> protect(dc.mutex);
return decoder_file_decode(plugin, bridge, path_fs); return decoder_file_decode(plugin, bridge, path_fs);
} else if (plugin.stream_decode != nullptr) { } else if (plugin.stream_decode != nullptr) {
const std::lock_guard<Mutex> protect(dc.mutex); std::unique_lock<Mutex> lock(dc.mutex);
return decoder_stream_decode(plugin, bridge, input_stream); return decoder_stream_decode(plugin, bridge, input_stream,
lock);
} else } else
return false; return false;
} }

View File

@ -95,7 +95,8 @@ AsyncInputStream::IsEOF() noexcept
} }
void void
AsyncInputStream::Seek(offset_type new_offset) AsyncInputStream::Seek(std::unique_lock<Mutex> &lock,
offset_type new_offset)
{ {
assert(IsReady()); assert(IsReady());
assert(seek_state == SeekState::NONE); assert(seek_state == SeekState::NONE);
@ -136,7 +137,7 @@ AsyncInputStream::Seek(offset_type new_offset)
CondInputStreamHandler cond_handler; CondInputStreamHandler cond_handler;
const ScopeExchangeInputStreamHandler h(*this, &cond_handler); const ScopeExchangeInputStreamHandler h(*this, &cond_handler);
while (seek_state != SeekState::NONE) while (seek_state != SeekState::NONE)
cond_handler.cond.wait(mutex); cond_handler.cond.wait(lock);
Check(); Check();
} }
@ -171,7 +172,8 @@ AsyncInputStream::IsAvailable() noexcept
} }
size_t size_t
AsyncInputStream::Read(void *ptr, size_t read_size) AsyncInputStream::Read(std::unique_lock<Mutex> &lock,
void *ptr, size_t read_size)
{ {
assert(!GetEventLoop().IsInside()); assert(!GetEventLoop().IsInside());
@ -187,7 +189,7 @@ AsyncInputStream::Read(void *ptr, size_t read_size)
break; break;
const ScopeExchangeInputStreamHandler h(*this, &cond_handler); const ScopeExchangeInputStreamHandler h(*this, &cond_handler);
cond_handler.cond.wait(mutex); cond_handler.cond.wait(lock);
} }
const size_t nbytes = std::min(read_size, r.size); const size_t nbytes = std::min(read_size, r.size);

View File

@ -83,10 +83,12 @@ public:
/* virtual methods from InputStream */ /* virtual methods from InputStream */
void Check() final; void Check() final;
bool IsEOF() noexcept final; bool IsEOF() noexcept final;
void Seek(offset_type new_offset) final; void Seek(std::unique_lock<Mutex> &lock,
offset_type new_offset) final;
std::unique_ptr<Tag> ReadTag() noexcept final; std::unique_ptr<Tag> ReadTag() noexcept final;
bool IsAvailable() noexcept final; bool IsAvailable() noexcept final;
size_t Read(void *ptr, size_t read_size) final; size_t Read(std::unique_lock<Mutex> &lock,
void *ptr, size_t read_size) final;
protected: protected:
/** /**

View File

@ -64,7 +64,8 @@ BufferedInputStream::Check()
} }
void void
BufferedInputStream::Seek(offset_type new_offset) BufferedInputStream::Seek(std::unique_lock<Mutex> &lock,
offset_type new_offset)
{ {
if (new_offset >= size) { if (new_offset >= size) {
offset = size; offset = size;
@ -84,7 +85,7 @@ BufferedInputStream::Seek(offset_type new_offset)
wake_cond.notify_one(); wake_cond.notify_one();
while (seek) while (seek)
client_cond.wait(mutex); client_cond.wait(lock);
if (seek_error) if (seek_error)
std::rethrow_exception(std::exchange(seek_error, {})); std::rethrow_exception(std::exchange(seek_error, {}));
@ -105,7 +106,8 @@ BufferedInputStream::IsAvailable() noexcept
} }
size_t size_t
BufferedInputStream::Read(void *ptr, size_t s) BufferedInputStream::Read(std::unique_lock<Mutex> &lock,
void *ptr, size_t s)
{ {
if (offset >= size) if (offset >= size)
return 0; return 0;
@ -140,7 +142,7 @@ BufferedInputStream::Read(void *ptr, size_t s)
wake_cond.notify_one(); wake_cond.notify_one();
} }
client_cond.wait(mutex); client_cond.wait(lock);
} }
} }
@ -156,7 +158,7 @@ BufferedInputStream::RunThread() noexcept
if (seek) { if (seek) {
try { try {
input->Seek(seek_offset); input->Seek(lock, seek_offset);
} catch (...) { } catch (...) {
seek_error = std::current_exception(); seek_error = std::current_exception();
} }
@ -183,7 +185,7 @@ BufferedInputStream::RunThread() noexcept
offset to prepare filling offset to prepare filling
the buffer from there */ the buffer from there */
try { try {
input->Seek(offset); input->Seek(lock, offset);
} catch (...) { } catch (...) {
read_error = std::current_exception(); read_error = std::current_exception();
client_cond.notify_one(); client_cond.notify_one();
@ -195,7 +197,8 @@ BufferedInputStream::RunThread() noexcept
} }
try { try {
size_t nbytes = input->Read(w.data, w.size); size_t nbytes = input->Read(lock,
w.data, w.size);
buffer.Commit(read_offset, buffer.Commit(read_offset,
read_offset + nbytes); read_offset + nbytes);
} catch (...) { } catch (...) {

View File

@ -85,12 +85,13 @@ public:
/* we don't need to implement Update() because all attributes /* we don't need to implement Update() because all attributes
have been copied already in our constructor */ have been copied already in our constructor */
//void Update() noexcept; //void Update() noexcept;
void Seek(offset_type offset) override; void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
bool IsEOF() noexcept override; bool IsEOF() noexcept override;
/* we don't support tags */ /* we don't support tags */
// std::unique_ptr<Tag> ReadTag() override; // std::unique_ptr<Tag> ReadTag() override;
bool IsAvailable() noexcept override; bool IsAvailable() noexcept override;
size_t Read(void *ptr, size_t size) override; size_t Read(std::unique_lock<Mutex> &lock,
void *ptr, size_t size) override;
/* virtual methods from class InputStreamHandler */ /* virtual methods from class InputStreamHandler */
void OnInputStreamReady() noexcept override { void OnInputStreamReady() noexcept override {

View File

@ -45,7 +45,7 @@ public:
std::rethrow_exception(error); std::rethrow_exception(error);
} }
void Seek(offset_type) override { void Seek(std::unique_lock<Mutex> &, offset_type) override {
std::rethrow_exception(error); std::rethrow_exception(error);
} }
@ -53,7 +53,7 @@ public:
return false; return false;
} }
size_t Read(void *, size_t) override { size_t Read(std::unique_lock<Mutex> &, void *, size_t) override {
std::rethrow_exception(error); std::rethrow_exception(error);
} }
}; };

View File

@ -80,13 +80,14 @@ IcyInputStream::ReadTag() noexcept
} }
size_t size_t
IcyInputStream::Read(void *ptr, size_t read_size) IcyInputStream::Read(std::unique_lock<Mutex> &lock,
void *ptr, size_t read_size)
{ {
if (!IsEnabled()) if (!IsEnabled())
return ProxyInputStream::Read(ptr, read_size); return ProxyInputStream::Read(lock, ptr, read_size);
while (true) { while (true) {
size_t nbytes = ProxyInputStream::Read(ptr, read_size); size_t nbytes = ProxyInputStream::Read(lock, ptr, read_size);
if (nbytes == 0) if (nbytes == 0)
return 0; return 0;

View File

@ -66,7 +66,8 @@ public:
/* virtual methods from InputStream */ /* virtual methods from InputStream */
void Update() noexcept override; void Update() noexcept override;
std::unique_ptr<Tag> ReadTag() noexcept override; std::unique_ptr<Tag> ReadTag() noexcept override;
size_t Read(void *ptr, size_t size) override; size_t Read(std::unique_lock<Mutex> &lock,
void *ptr, size_t size) override;
}; };
#endif #endif

View File

@ -72,7 +72,7 @@ InputStream::CheapSeeking() const noexcept
} }
void void
InputStream::Seek(gcc_unused offset_type new_offset) InputStream::Seek(std::unique_lock<Mutex> &, gcc_unused offset_type new_offset)
{ {
throw std::runtime_error("Seeking is not implemented"); throw std::runtime_error("Seeking is not implemented");
} }
@ -80,15 +80,15 @@ InputStream::Seek(gcc_unused offset_type new_offset)
void void
InputStream::LockSeek(offset_type _offset) InputStream::LockSeek(offset_type _offset)
{ {
const std::lock_guard<Mutex> protect(mutex); std::unique_lock<Mutex> lock(mutex);
Seek(_offset); Seek(lock, _offset);
} }
void void
InputStream::LockSkip(offset_type _offset) InputStream::LockSkip(offset_type _offset)
{ {
const std::lock_guard<Mutex> protect(mutex); std::unique_lock<Mutex> lock(mutex);
Skip(_offset); Skip(lock, _offset);
} }
std::unique_ptr<Tag> std::unique_ptr<Tag>
@ -119,18 +119,18 @@ InputStream::LockRead(void *ptr, size_t _size)
#endif #endif
assert(_size > 0); assert(_size > 0);
const std::lock_guard<Mutex> protect(mutex); std::unique_lock<Mutex> lock(mutex);
return Read(ptr, _size); return Read(lock, ptr, _size);
} }
void void
InputStream::ReadFull(void *_ptr, size_t _size) InputStream::ReadFull(std::unique_lock<Mutex> &lock, void *_ptr, size_t _size)
{ {
uint8_t *ptr = (uint8_t *)_ptr; uint8_t *ptr = (uint8_t *)_ptr;
size_t nbytes_total = 0; size_t nbytes_total = 0;
while (_size > 0) { while (_size > 0) {
size_t nbytes = Read(ptr + nbytes_total, _size); size_t nbytes = Read(lock, ptr + nbytes_total, _size);
if (nbytes == 0) if (nbytes == 0)
throw std::runtime_error("Unexpected end of file"); throw std::runtime_error("Unexpected end of file");
@ -148,8 +148,8 @@ InputStream::LockReadFull(void *ptr, size_t _size)
#endif #endif
assert(_size > 0); assert(_size > 0);
const std::lock_guard<Mutex> protect(mutex); std::unique_lock<Mutex> lock(mutex);
ReadFull(ptr, _size); ReadFull(lock, ptr, _size);
} }
bool bool

View File

@ -271,9 +271,11 @@ public:
* *
* Throws std::runtime_error on error. * Throws std::runtime_error on error.
* *
* @param lock the locked mutex; may be used to wait on
* condition variables
* @param offset the relative offset * @param offset the relative offset
*/ */
virtual void Seek(offset_type offset); virtual void Seek(std::unique_lock<Mutex> &lock, offset_type offset);
/** /**
* Wrapper for Seek() which locks and unlocks the mutex; the * Wrapper for Seek() which locks and unlocks the mutex; the
@ -285,8 +287,8 @@ public:
* Rewind to the beginning of the stream. This is a wrapper * Rewind to the beginning of the stream. This is a wrapper
* for Seek(0, error). * for Seek(0, error).
*/ */
void Rewind() { void Rewind(std::unique_lock<Mutex> &lock) {
Seek(0); Seek(lock, 0);
} }
void LockRewind() { void LockRewind() {
@ -296,8 +298,9 @@ public:
/** /**
* Skip input bytes. * Skip input bytes.
*/ */
void Skip(offset_type _offset) { void Skip(std::unique_lock<Mutex> &lock,
Seek(GetOffset() + _offset); offset_type _offset) {
Seek(lock, GetOffset() + _offset);
} }
void LockSkip(offset_type _offset); void LockSkip(offset_type _offset);
@ -351,12 +354,15 @@ public:
* *
* Throws std::runtime_error on error. * Throws std::runtime_error on error.
* *
* @param lock the locked mutex; may be used to wait on
* condition variables
* @param ptr the buffer to read into * @param ptr the buffer to read into
* @param size the maximum number of bytes to read * @param size the maximum number of bytes to read
* @return the number of bytes read * @return the number of bytes read
*/ */
gcc_nonnull_all gcc_nonnull_all
virtual size_t Read(void *ptr, size_t size) = 0; virtual size_t Read(std::unique_lock<Mutex> &lock,
void *ptr, size_t size) = 0;
/** /**
* Wrapper for Read() which locks and unlocks the mutex; * Wrapper for Read() which locks and unlocks the mutex;
@ -379,7 +385,7 @@ public:
* @return true if the whole data was read, false otherwise. * @return true if the whole data was read, false otherwise.
*/ */
gcc_nonnull_all gcc_nonnull_all
void ReadFull(void *ptr, size_t size); void ReadFull(std::unique_lock<Mutex> &lock, void *ptr, size_t size);
/** /**
* Wrapper for ReadFull() which locks and unlocks the mutex; * Wrapper for ReadFull() which locks and unlocks the mutex;

View File

@ -89,12 +89,13 @@ ProxyInputStream::Update() noexcept
} }
void void
ProxyInputStream::Seek(offset_type new_offset) ProxyInputStream::Seek(std::unique_lock<Mutex> &lock,
offset_type new_offset)
{ {
while (!input) while (!input)
set_input_cond.wait(mutex); set_input_cond.wait(lock);
input->Seek(new_offset); input->Seek(lock, new_offset);
CopyAttributes(); CopyAttributes();
} }
@ -120,12 +121,13 @@ ProxyInputStream::IsAvailable() noexcept
} }
size_t size_t
ProxyInputStream::Read(void *ptr, size_t read_size) ProxyInputStream::Read(std::unique_lock<Mutex> &lock,
void *ptr, size_t read_size)
{ {
while (!input) while (!input)
set_input_cond.wait(mutex); set_input_cond.wait(lock);
size_t nbytes = input->Read(ptr, read_size); size_t nbytes = input->Read(lock, ptr, read_size);
CopyAttributes(); CopyAttributes();
return nbytes; return nbytes;
} }

View File

@ -60,11 +60,13 @@ public:
/* virtual methods from InputStream */ /* virtual methods from InputStream */
void Check() override; void Check() override;
void Update() noexcept override; void Update() noexcept override;
void Seek(offset_type new_offset) override; void Seek(std::unique_lock<Mutex> &lock,
offset_type new_offset) override;
bool IsEOF() noexcept override; bool IsEOF() noexcept override;
std::unique_ptr<Tag> ReadTag() noexcept override; std::unique_ptr<Tag> ReadTag() noexcept override;
bool IsAvailable() noexcept override; bool IsAvailable() noexcept override;
size_t Read(void *ptr, size_t read_size) override; size_t Read(std::unique_lock<Mutex> &lock,
void *ptr, size_t read_size) override;
protected: protected:
/** /**

View File

@ -60,8 +60,9 @@ public:
return !ReadingFromBuffer() && ProxyInputStream::IsEOF(); return !ReadingFromBuffer() && ProxyInputStream::IsEOF();
} }
size_t Read(void *ptr, size_t size) override; size_t Read(std::unique_lock<Mutex> &lock,
void Seek(offset_type offset) override; void *ptr, size_t size) override;
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
private: private:
/** /**
@ -74,7 +75,8 @@ private:
}; };
size_t size_t
RewindInputStream::Read(void *ptr, size_t read_size) RewindInputStream::Read(std::unique_lock<Mutex> &lock,
void *ptr, size_t read_size)
{ {
if (ReadingFromBuffer()) { if (ReadingFromBuffer()) {
/* buffered read */ /* buffered read */
@ -93,7 +95,7 @@ RewindInputStream::Read(void *ptr, size_t read_size)
} else { } else {
/* pass method call to underlying stream */ /* pass method call to underlying stream */
size_t nbytes = input->Read(ptr, read_size); size_t nbytes = input->Read(lock, ptr, read_size);
if (input->GetOffset() > (offset_type)sizeof(buffer)) if (input->GetOffset() > (offset_type)sizeof(buffer))
/* disable buffering */ /* disable buffering */
@ -114,7 +116,7 @@ RewindInputStream::Read(void *ptr, size_t read_size)
} }
void void
RewindInputStream::Seek(offset_type new_offset) RewindInputStream::Seek(std::unique_lock<Mutex> &lock, offset_type new_offset)
{ {
assert(IsReady()); assert(IsReady());
@ -132,7 +134,7 @@ RewindInputStream::Seek(offset_type new_offset)
buffered range now */ buffered range now */
tail = 0; tail = 0;
ProxyInputStream::Seek(new_offset); ProxyInputStream::Seek(lock, new_offset);
} }
} }

View File

@ -130,7 +130,8 @@ ThreadInputStream::IsAvailable() noexcept
} }
inline size_t inline size_t
ThreadInputStream::Read(void *ptr, size_t read_size) ThreadInputStream::Read(std::unique_lock<Mutex> &lock,
void *ptr, size_t read_size)
{ {
assert(!thread.IsInside()); assert(!thread.IsInside());
@ -154,7 +155,7 @@ ThreadInputStream::Read(void *ptr, size_t read_size)
return 0; return 0;
const ScopeExchangeInputStreamHandler h(*this, &cond_handler); const ScopeExchangeInputStreamHandler h(*this, &cond_handler);
cond_handler.cond.wait(mutex); cond_handler.cond.wait(lock);
} }
} }

View File

@ -94,7 +94,8 @@ public:
void Check() override final; void Check() override final;
bool IsEOF() noexcept final; bool IsEOF() noexcept final;
bool IsAvailable() noexcept final; bool IsAvailable() noexcept final;
size_t Read(void *ptr, size_t size) override final; size_t Read(std::unique_lock<Mutex> &lock,
void *ptr, size_t size) override final;
protected: protected:
/** /**

View File

@ -91,8 +91,9 @@ class CdioParanoiaInputStream final : public InputStream {
/* virtual methods from InputStream */ /* virtual methods from InputStream */
bool IsEOF() noexcept override; bool IsEOF() noexcept override;
size_t Read(void *ptr, size_t size) override; size_t Read(std::unique_lock<Mutex> &lock,
void Seek(offset_type offset) override; void *ptr, size_t size) override;
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
}; };
static constexpr Domain cdio_domain("cdio"); static constexpr Domain cdio_domain("cdio");
@ -255,7 +256,8 @@ input_cdio_open(const char *uri,
} }
void void
CdioParanoiaInputStream::Seek(offset_type new_offset) CdioParanoiaInputStream::Seek(std::unique_lock<Mutex> &,
offset_type new_offset)
{ {
if (new_offset > size) if (new_offset > size)
throw FormatRuntimeError("Invalid offset to seek %ld (%ld)", throw FormatRuntimeError("Invalid offset to seek %ld (%ld)",
@ -276,7 +278,8 @@ CdioParanoiaInputStream::Seek(offset_type new_offset)
} }
size_t size_t
CdioParanoiaInputStream::Read(void *ptr, size_t length) CdioParanoiaInputStream::Read(std::unique_lock<Mutex> &,
void *ptr, size_t length)
{ {
size_t nbytes = 0; size_t nbytes = 0;
char *wptr = (char *) ptr; char *wptr = (char *) ptr;

View File

@ -49,8 +49,10 @@ public:
/* virtual methods from InputStream */ /* virtual methods from InputStream */
bool IsEOF() noexcept override; bool IsEOF() noexcept override;
size_t Read(void *ptr, size_t size) override; size_t Read(std::unique_lock<Mutex> &lock,
void Seek(offset_type offset) override; void *ptr, size_t size) override;
void Seek(std::unique_lock<Mutex> &lock,
offset_type offset) override;
}; };
gcc_const gcc_const
@ -79,7 +81,8 @@ input_ffmpeg_open(const char *uri,
} }
size_t size_t
FfmpegInputStream::Read(void *ptr, size_t read_size) FfmpegInputStream::Read(std::unique_lock<Mutex> &,
void *ptr, size_t read_size)
{ {
size_t result; size_t result;
@ -99,7 +102,7 @@ FfmpegInputStream::IsEOF() noexcept
} }
void void
FfmpegInputStream::Seek(offset_type new_offset) FfmpegInputStream::Seek(std::unique_lock<Mutex> &, offset_type new_offset)
{ {
uint64_t result; uint64_t result;

View File

@ -48,8 +48,10 @@ public:
return GetOffset() >= GetSize(); return GetOffset() >= GetSize();
} }
size_t Read(void *ptr, size_t size) override; size_t Read(std::unique_lock<Mutex> &lock,
void Seek(offset_type offset) override; void *ptr, size_t size) override;
void Seek(std::unique_lock<Mutex> &lock,
offset_type offset) override;
}; };
InputStreamPtr InputStreamPtr
@ -74,7 +76,8 @@ OpenFileInputStream(Path path, Mutex &mutex)
} }
void void
FileInputStream::Seek(offset_type new_offset) FileInputStream::Seek(std::unique_lock<Mutex> &,
offset_type new_offset)
{ {
{ {
const ScopeUnlock unlock(mutex); const ScopeUnlock unlock(mutex);
@ -85,7 +88,8 @@ FileInputStream::Seek(offset_type new_offset)
} }
size_t size_t
FileInputStream::Read(void *ptr, size_t read_size) FileInputStream::Read(std::unique_lock<Mutex> &,
void *ptr, size_t read_size)
{ {
size_t nbytes; size_t nbytes;

View File

@ -56,8 +56,9 @@ public:
return offset >= size; return offset >= size;
} }
size_t Read(void *ptr, size_t size) override; size_t Read(std::unique_lock<Mutex> &lock,
void Seek(offset_type offset) override; void *ptr, size_t size) override;
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
}; };
/* /*
@ -118,7 +119,8 @@ input_smbclient_open(const char *uri,
} }
size_t size_t
SmbclientInputStream::Read(void *ptr, size_t read_size) SmbclientInputStream::Read(std::unique_lock<Mutex> &,
void *ptr, size_t read_size)
{ {
ssize_t nbytes; ssize_t nbytes;
@ -136,7 +138,8 @@ SmbclientInputStream::Read(void *ptr, size_t read_size)
} }
void void
SmbclientInputStream::Seek(offset_type new_offset) SmbclientInputStream::Seek(std::unique_lock<Mutex> &,
offset_type new_offset)
{ {
off_t result; off_t result;

View File

@ -39,14 +39,14 @@ struct aiff_chunk_header {
}; };
size_t size_t
aiff_seek_id3(InputStream &is) aiff_seek_id3(InputStream &is, std::unique_lock<Mutex> &lock)
{ {
/* seek to the beginning and read the AIFF header */ /* seek to the beginning and read the AIFF header */
is.Rewind(); is.Rewind(lock);
aiff_header header; aiff_header header;
is.ReadFull(&header, sizeof(header)); is.ReadFull(lock, &header, sizeof(header));
if (memcmp(header.id, "FORM", 4) != 0 || if (memcmp(header.id, "FORM", 4) != 0 ||
(is.KnownSize() && FromBE32(header.size) > is.GetSize()) || (is.KnownSize() && FromBE32(header.size) > is.GetSize()) ||
(memcmp(header.format, "AIFF", 4) != 0 && (memcmp(header.format, "AIFF", 4) != 0 &&
@ -57,7 +57,7 @@ aiff_seek_id3(InputStream &is)
/* read the chunk header */ /* read the chunk header */
aiff_chunk_header chunk; aiff_chunk_header chunk;
is.ReadFull(&chunk, sizeof(chunk)); is.ReadFull(lock, &chunk, sizeof(chunk));
size_t size = FromBE32(chunk.size); size_t size = FromBE32(chunk.size);
if (size > size_t(std::numeric_limits<int>::max())) if (size > size_t(std::numeric_limits<int>::max()))
@ -73,6 +73,6 @@ aiff_seek_id3(InputStream &is)
/* pad byte */ /* pad byte */
++size; ++size;
is.Skip(size); is.Skip(lock, size);
} }
} }

View File

@ -25,9 +25,12 @@
#ifndef MPD_AIFF_HXX #ifndef MPD_AIFF_HXX
#define MPD_AIFF_HXX #define MPD_AIFF_HXX
#include <mutex>
#include <stddef.h> #include <stddef.h>
class InputStream; class InputStream;
class Mutex;
/** /**
* Seeks the AIFF file to the ID3 chunk. * Seeks the AIFF file to the ID3 chunk.
@ -38,6 +41,6 @@ class InputStream;
* @return the size of the ID3 chunk * @return the size of the ID3 chunk
*/ */
size_t size_t
aiff_seek_id3(InputStream &is); aiff_seek_id3(InputStream &is, std::unique_lock<Mutex> &lock);
#endif #endif

View File

@ -40,15 +40,15 @@ struct ApeFooter {
bool bool
tag_ape_scan(InputStream &is, ApeTagCallback callback) tag_ape_scan(InputStream &is, ApeTagCallback callback)
try { try {
const std::lock_guard<Mutex> protect(is.mutex); std::unique_lock<Mutex> lock(is.mutex);
if (!is.KnownSize() || !is.CheapSeeking()) if (!is.KnownSize() || !is.CheapSeeking())
return false; return false;
/* determine if file has an apeV2 tag */ /* determine if file has an apeV2 tag */
ApeFooter footer; ApeFooter footer;
is.Seek(is.GetSize() - sizeof(footer)); is.Seek(lock, is.GetSize() - sizeof(footer));
is.ReadFull(&footer, sizeof(footer)); is.ReadFull(lock, &footer, sizeof(footer));
if (memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0 || if (memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0 ||
FromLE32(footer.version) != 2000) FromLE32(footer.version) != 2000)
@ -61,14 +61,14 @@ try {
remaining > 1024 * 1024) remaining > 1024 * 1024)
return false; return false;
is.Seek(is.GetSize() - remaining); is.Seek(lock, is.GetSize() - remaining);
/* read tag into buffer */ /* read tag into buffer */
remaining -= sizeof(footer); remaining -= sizeof(footer);
assert(remaining > 10); assert(remaining > 10);
std::unique_ptr<char[]> buffer(new char[remaining]); std::unique_ptr<char[]> buffer(new char[remaining]);
is.ReadFull(buffer.get(), remaining); is.ReadFull(lock, buffer.get(), remaining);
/* read tags */ /* read tags */
unsigned n = FromLE32(footer.count); unsigned n = FromLE32(footer.count);

View File

@ -37,11 +37,12 @@ tag_is_id3v1(struct id3_tag *tag) noexcept
} }
static long static long
get_id3v2_footer_size(InputStream &is, offset_type offset) get_id3v2_footer_size(InputStream &is, std::unique_lock<Mutex> &lock,
offset_type offset)
try { try {
id3_byte_t buf[ID3_TAG_QUERYSIZE]; id3_byte_t buf[ID3_TAG_QUERYSIZE];
is.Seek(offset); is.Seek(lock, offset);
is.ReadFull(buf, sizeof(buf)); is.ReadFull(lock, buf, sizeof(buf));
return id3_tag_query(buf, sizeof(buf)); return id3_tag_query(buf, sizeof(buf));
} catch (...) { } catch (...) {
@ -49,10 +50,10 @@ try {
} }
static UniqueId3Tag static UniqueId3Tag
ReadId3Tag(InputStream &is) ReadId3Tag(InputStream &is, std::unique_lock<Mutex> &lock)
try { try {
id3_byte_t query_buffer[ID3_TAG_QUERYSIZE]; id3_byte_t query_buffer[ID3_TAG_QUERYSIZE];
is.ReadFull(query_buffer, sizeof(query_buffer)); is.ReadFull(lock, query_buffer, sizeof(query_buffer));
/* Look for a tag header */ /* Look for a tag header */
long tag_size = id3_tag_query(query_buffer, sizeof(query_buffer)); long tag_size = id3_tag_query(query_buffer, sizeof(query_buffer));
@ -72,7 +73,7 @@ try {
/* now read the remaining bytes */ /* now read the remaining bytes */
const size_t remaining = tag_size - sizeof(query_buffer); const size_t remaining = tag_size - sizeof(query_buffer);
is.ReadFull(end, remaining); is.ReadFull(lock, end, remaining);
return UniqueId3Tag(id3_tag_parse(tag_buffer.get(), tag_size)); return UniqueId3Tag(id3_tag_parse(tag_buffer.get(), tag_size));
} catch (...) { } catch (...) {
@ -80,20 +81,20 @@ try {
} }
static UniqueId3Tag static UniqueId3Tag
ReadId3Tag(InputStream &is, offset_type offset) ReadId3Tag(InputStream &is, std::unique_lock<Mutex> &lock, offset_type offset)
try { try {
is.Seek(offset); is.Seek(lock, offset);
return ReadId3Tag(is); return ReadId3Tag(is, lock);
} catch (...) { } catch (...) {
return nullptr; return nullptr;
} }
static UniqueId3Tag static UniqueId3Tag
ReadId3v1Tag(InputStream &is) ReadId3v1Tag(InputStream &is, std::unique_lock<Mutex> &lock)
try { try {
id3_byte_t buffer[ID3V1_SIZE]; id3_byte_t buffer[ID3V1_SIZE];
is.ReadFull(buffer, ID3V1_SIZE); is.ReadFull(lock, buffer, ID3V1_SIZE);
return UniqueId3Tag(id3_tag_parse(buffer, ID3V1_SIZE)); return UniqueId3Tag(id3_tag_parse(buffer, ID3V1_SIZE));
} catch (...) { } catch (...) {
@ -101,18 +102,19 @@ try {
} }
static UniqueId3Tag static UniqueId3Tag
ReadId3v1Tag(InputStream &is, offset_type offset) ReadId3v1Tag(InputStream &is, std::unique_lock<Mutex> &lock,
offset_type offset)
try { try {
is.Seek(offset); is.Seek(lock, offset);
return ReadId3v1Tag(is); return ReadId3v1Tag(is, lock);
} catch (...) { } catch (...) {
return nullptr; return nullptr;
} }
static UniqueId3Tag static UniqueId3Tag
tag_id3_find_from_beginning(InputStream &is) tag_id3_find_from_beginning(InputStream &is, std::unique_lock<Mutex> &lock)
try { try {
auto tag = ReadId3Tag(is); auto tag = ReadId3Tag(is, lock);
if (!tag) { if (!tag) {
return nullptr; return nullptr;
} else if (tag_is_id3v1(tag.get())) { } else if (tag_is_id3v1(tag.get())) {
@ -129,7 +131,7 @@ try {
break; break;
/* Get the tag specified by the SEEK frame */ /* Get the tag specified by the SEEK frame */
auto seektag = ReadId3Tag(is, is.GetOffset() + seek); auto seektag = ReadId3Tag(is, lock, is.GetOffset() + seek);
if (!seektag || tag_is_id3v1(seektag.get())) if (!seektag || tag_is_id3v1(seektag.get()))
break; break;
@ -143,7 +145,7 @@ try {
} }
static UniqueId3Tag static UniqueId3Tag
tag_id3_find_from_end(InputStream &is) tag_id3_find_from_end(InputStream &is, std::unique_lock<Mutex> &lock)
try { try {
if (!is.KnownSize() || !is.CheapSeeking()) if (!is.KnownSize() || !is.CheapSeeking())
return nullptr; return nullptr;
@ -155,7 +157,7 @@ try {
offset_type offset = size - ID3V1_SIZE; offset_type offset = size - ID3V1_SIZE;
/* Get an id3v1 tag from the end of file for later use */ /* Get an id3v1 tag from the end of file for later use */
auto v1tag = ReadId3v1Tag(is, offset); auto v1tag = ReadId3v1Tag(is, lock, offset);
if (!v1tag) if (!v1tag)
offset = size; offset = size;
@ -164,7 +166,7 @@ try {
return v1tag; return v1tag;
long tag_offset = long tag_offset =
get_id3v2_footer_size(is, offset - ID3_TAG_QUERYSIZE); get_id3v2_footer_size(is, lock, offset - ID3_TAG_QUERYSIZE);
if (tag_offset >= 0) if (tag_offset >= 0)
return v1tag; return v1tag;
@ -173,7 +175,7 @@ try {
return v1tag; return v1tag;
/* Get the tag which the footer belongs to */ /* Get the tag which the footer belongs to */
auto tag = ReadId3Tag(is, offset - tag_size); auto tag = ReadId3Tag(is, lock, offset - tag_size);
if (!tag) if (!tag)
return v1tag; return v1tag;
@ -184,13 +186,13 @@ try {
} }
static UniqueId3Tag static UniqueId3Tag
tag_id3_riff_aiff_load(InputStream &is) tag_id3_riff_aiff_load(InputStream &is, std::unique_lock<Mutex> &lock)
try { try {
size_t size; size_t size;
try { try {
size = riff_seek_id3(is); size = riff_seek_id3(is, lock);
} catch (...) { } catch (...) {
size = aiff_seek_id3(is); size = aiff_seek_id3(is, lock);
} }
if (size > 4 * 1024 * 1024) if (size > 4 * 1024 * 1024)
@ -198,7 +200,7 @@ try {
return nullptr; return nullptr;
std::unique_ptr<id3_byte_t[]> buffer(new id3_byte_t[size]); std::unique_ptr<id3_byte_t[]> buffer(new id3_byte_t[size]);
is.ReadFull(buffer.get(), size); is.ReadFull(lock, buffer.get(), size);
return UniqueId3Tag(id3_tag_parse(buffer.get(), size)); return UniqueId3Tag(id3_tag_parse(buffer.get(), size));
} catch (...) { } catch (...) {
@ -208,13 +210,13 @@ try {
UniqueId3Tag UniqueId3Tag
tag_id3_load(InputStream &is) tag_id3_load(InputStream &is)
try { try {
const std::lock_guard<Mutex> protect(is.mutex); std::unique_lock<Mutex> lock(is.mutex);
auto tag = tag_id3_find_from_beginning(is); auto tag = tag_id3_find_from_beginning(is, lock);
if (tag == nullptr && is.CheapSeeking()) { if (tag == nullptr && is.CheapSeeking()) {
tag = tag_id3_riff_aiff_load(is); tag = tag_id3_riff_aiff_load(is, lock);
if (tag == nullptr) if (tag == nullptr)
tag = tag_id3_find_from_end(is); tag = tag_id3_find_from_end(is, lock);
} }
return tag; return tag;

View File

@ -39,14 +39,14 @@ struct riff_chunk_header {
}; };
size_t size_t
riff_seek_id3(InputStream &is) riff_seek_id3(InputStream &is, std::unique_lock<Mutex> &lock)
{ {
/* seek to the beginning and read the RIFF header */ /* seek to the beginning and read the RIFF header */
is.Rewind(); is.Rewind(lock);
riff_header header; riff_header header;
is.ReadFull(&header, sizeof(header)); is.ReadFull(lock, &header, sizeof(header));
if (memcmp(header.id, "RIFF", 4) != 0 || if (memcmp(header.id, "RIFF", 4) != 0 ||
(is.KnownSize() && FromLE32(header.size) > is.GetSize())) (is.KnownSize() && FromLE32(header.size) > is.GetSize()))
throw std::runtime_error("Not a RIFF file"); throw std::runtime_error("Not a RIFF file");
@ -55,7 +55,7 @@ riff_seek_id3(InputStream &is)
/* read the chunk header */ /* read the chunk header */
riff_chunk_header chunk; riff_chunk_header chunk;
is.ReadFull(&chunk, sizeof(chunk)); is.ReadFull(lock, &chunk, sizeof(chunk));
size_t size = FromLE32(chunk.size); size_t size = FromLE32(chunk.size);
if (size > size_t(std::numeric_limits<int>::max())) if (size > size_t(std::numeric_limits<int>::max()))
@ -72,6 +72,6 @@ riff_seek_id3(InputStream &is)
/* pad byte */ /* pad byte */
++size; ++size;
is.Skip(size); is.Skip(lock, size);
} }
} }

View File

@ -25,8 +25,11 @@
#ifndef MPD_RIFF_HXX #ifndef MPD_RIFF_HXX
#define MPD_RIFF_HXX #define MPD_RIFF_HXX
#include <mutex>
#include <stddef.h> #include <stddef.h>
class Mutex;
class InputStream; class InputStream;
/** /**
@ -38,6 +41,6 @@ class InputStream;
* @return the size of the ID3 chunk * @return the size of the ID3 chunk
*/ */
size_t size_t
riff_seek_id3(InputStream &is); riff_seek_id3(InputStream &is, std::unique_lock<Mutex> &lock);
#endif #endif

View File

@ -28,7 +28,8 @@ public:
return remaining == 0; return remaining == 0;
} }
size_t Read(void *ptr, size_t read_size) override { size_t Read(std::unique_lock<Mutex> &,
void *ptr, size_t read_size) override {
size_t nbytes = std::min(remaining, read_size); size_t nbytes = std::min(remaining, read_size);
memcpy(ptr, data, nbytes); memcpy(ptr, data, nbytes);
data += nbytes; data += nbytes;
@ -51,7 +52,7 @@ TEST(RewindInputStream, Basic)
EXPECT_TRUE(ris.get() != sis); EXPECT_TRUE(ris.get() != sis);
EXPECT_TRUE(ris != nullptr); EXPECT_TRUE(ris != nullptr);
const std::lock_guard<Mutex> protect(mutex); std::unique_lock<Mutex> lock(mutex);
ris->Update(); ris->Update();
EXPECT_TRUE(ris->IsReady()); EXPECT_TRUE(ris->IsReady());
@ -59,50 +60,50 @@ TEST(RewindInputStream, Basic)
EXPECT_EQ(offset_type(0), ris->GetOffset()); EXPECT_EQ(offset_type(0), ris->GetOffset());
char buffer[16]; char buffer[16];
size_t nbytes = ris->Read(buffer, 2); size_t nbytes = ris->Read(lock, buffer, 2);
EXPECT_EQ(size_t(2), nbytes); EXPECT_EQ(size_t(2), nbytes);
EXPECT_EQ('f', buffer[0]); EXPECT_EQ('f', buffer[0]);
EXPECT_EQ('o', buffer[1]); EXPECT_EQ('o', buffer[1]);
EXPECT_EQ(offset_type(2), ris->GetOffset()); EXPECT_EQ(offset_type(2), ris->GetOffset());
EXPECT_FALSE(ris->IsEOF()); EXPECT_FALSE(ris->IsEOF());
nbytes = ris->Read(buffer, 2); nbytes = ris->Read(lock, buffer, 2);
EXPECT_EQ(size_t(2), nbytes); EXPECT_EQ(size_t(2), nbytes);
EXPECT_EQ('o', buffer[0]); EXPECT_EQ('o', buffer[0]);
EXPECT_EQ(' ', buffer[1]); EXPECT_EQ(' ', buffer[1]);
EXPECT_EQ(offset_type(4), ris->GetOffset()); EXPECT_EQ(offset_type(4), ris->GetOffset());
EXPECT_FALSE(ris->IsEOF()); EXPECT_FALSE(ris->IsEOF());
ris->Seek(1); ris->Seek(lock, 1);
EXPECT_EQ(offset_type(1), ris->GetOffset()); EXPECT_EQ(offset_type(1), ris->GetOffset());
EXPECT_FALSE(ris->IsEOF()); EXPECT_FALSE(ris->IsEOF());
nbytes = ris->Read(buffer, 2); nbytes = ris->Read(lock, buffer, 2);
EXPECT_EQ(size_t(2), nbytes); EXPECT_EQ(size_t(2), nbytes);
EXPECT_EQ('o', buffer[0]); EXPECT_EQ('o', buffer[0]);
EXPECT_EQ('o', buffer[1]); EXPECT_EQ('o', buffer[1]);
EXPECT_EQ(offset_type(3), ris->GetOffset()); EXPECT_EQ(offset_type(3), ris->GetOffset());
EXPECT_FALSE(ris->IsEOF()); EXPECT_FALSE(ris->IsEOF());
ris->Seek(0); ris->Seek(lock, 0);
EXPECT_EQ(offset_type(0), ris->GetOffset()); EXPECT_EQ(offset_type(0), ris->GetOffset());
EXPECT_FALSE(ris->IsEOF()); EXPECT_FALSE(ris->IsEOF());
nbytes = ris->Read(buffer, 2); nbytes = ris->Read(lock, buffer, 2);
EXPECT_EQ(size_t(2), nbytes); EXPECT_EQ(size_t(2), nbytes);
EXPECT_EQ('f', buffer[0]); EXPECT_EQ('f', buffer[0]);
EXPECT_EQ('o', buffer[1]); EXPECT_EQ('o', buffer[1]);
EXPECT_EQ(offset_type(2), ris->GetOffset()); EXPECT_EQ(offset_type(2), ris->GetOffset());
EXPECT_FALSE(ris->IsEOF()); EXPECT_FALSE(ris->IsEOF());
nbytes = ris->Read(buffer, sizeof(buffer)); nbytes = ris->Read(lock, buffer, sizeof(buffer));
EXPECT_EQ(size_t(2), nbytes); EXPECT_EQ(size_t(2), nbytes);
EXPECT_EQ('o', buffer[0]); EXPECT_EQ('o', buffer[0]);
EXPECT_EQ(' ', buffer[1]); EXPECT_EQ(' ', buffer[1]);
EXPECT_EQ(offset_type(4), ris->GetOffset()); EXPECT_EQ(offset_type(4), ris->GetOffset());
EXPECT_FALSE(ris->IsEOF()); EXPECT_FALSE(ris->IsEOF());
nbytes = ris->Read(buffer, sizeof(buffer)); nbytes = ris->Read(lock, buffer, sizeof(buffer));
EXPECT_EQ(size_t(3), nbytes); EXPECT_EQ(size_t(3), nbytes);
EXPECT_EQ('b', buffer[0]); EXPECT_EQ('b', buffer[0]);
EXPECT_EQ('a', buffer[1]); EXPECT_EQ('a', buffer[1]);
@ -110,11 +111,11 @@ TEST(RewindInputStream, Basic)
EXPECT_EQ(offset_type(7), ris->GetOffset()); EXPECT_EQ(offset_type(7), ris->GetOffset());
EXPECT_TRUE(ris->IsEOF()); EXPECT_TRUE(ris->IsEOF());
ris->Seek(3); ris->Seek(lock, 3);
EXPECT_EQ(offset_type(3), ris->GetOffset()); EXPECT_EQ(offset_type(3), ris->GetOffset());
EXPECT_FALSE(ris->IsEOF()); EXPECT_FALSE(ris->IsEOF());
nbytes = ris->Read(buffer, sizeof(buffer)); nbytes = ris->Read(lock, buffer, sizeof(buffer));
EXPECT_EQ(size_t(4), nbytes); EXPECT_EQ(size_t(4), nbytes);
EXPECT_EQ(' ', buffer[0]); EXPECT_EQ(' ', buffer[0]);
EXPECT_EQ('b', buffer[1]); EXPECT_EQ('b', buffer[1]);

View File

@ -131,7 +131,7 @@ tag_save(FILE *file, const Tag &tag)
static int static int
dump_input_stream(InputStream *is) dump_input_stream(InputStream *is)
{ {
const std::lock_guard<Mutex> protect(is->mutex); std::unique_lock<Mutex> lock(is->mutex);
/* print meta data */ /* print meta data */
@ -150,7 +150,7 @@ dump_input_stream(InputStream *is)
} }
char buffer[4096]; char buffer[4096];
size_t num_read = is->Read(buffer, sizeof(buffer)); size_t num_read = is->Read(lock, buffer, sizeof(buffer));
if (num_read == 0) if (num_read == 0)
break; break;