input/thread: use C++ exceptions instead of class Error

This commit is contained in:
Max Kellermann 2016-09-16 17:20:55 +02:00
parent 3cd07d0b54
commit 597e59f10d
3 changed files with 38 additions and 37 deletions

View File

@ -64,7 +64,10 @@ ThreadInputStream::ThreadFunc()
const ScopeLock lock(mutex); const ScopeLock lock(mutex);
if (!Open(postponed_error)) { try {
Open();
} catch (...) {
postponed_exception = std::current_exception();
cond.broadcast(); cond.broadcast();
return; return;
} }
@ -73,25 +76,27 @@ ThreadInputStream::ThreadFunc()
SetReady(); SetReady();
while (!close) { while (!close) {
assert(!postponed_error.IsDefined()); assert(!postponed_exception);
auto w = buffer->Write(); auto w = buffer->Write();
if (w.IsEmpty()) { if (w.IsEmpty()) {
wake_cond.wait(mutex); wake_cond.wait(mutex);
} else { } else {
Error error;
size_t nbytes; size_t nbytes;
{ try {
const ScopeUnlock unlock(mutex); const ScopeUnlock unlock(mutex);
nbytes = ThreadRead(w.data, w.size, error); nbytes = ThreadRead(w.data, w.size);
} catch (...) {
postponed_exception = std::current_exception();
cond.broadcast();
break;
} }
cond.broadcast(); cond.broadcast();
if (nbytes == 0) { if (nbytes == 0) {
eof = true; eof = true;
postponed_error = std::move(error);
break; break;
} }
@ -110,14 +115,12 @@ ThreadInputStream::ThreadFunc(void *ctx)
} }
bool bool
ThreadInputStream::Check(Error &error) ThreadInputStream::Check(Error &)
{ {
assert(!thread.IsInside()); assert(!thread.IsInside());
if (postponed_error.IsDefined()) { if (postponed_exception)
error = std::move(postponed_error); std::rethrow_exception(postponed_exception);
return false;
}
return true; return true;
} }
@ -127,19 +130,17 @@ ThreadInputStream::IsAvailable()
{ {
assert(!thread.IsInside()); assert(!thread.IsInside());
return !buffer->IsEmpty() || eof || postponed_error.IsDefined(); return !buffer->IsEmpty() || eof || postponed_exception;
} }
inline size_t inline size_t
ThreadInputStream::Read(void *ptr, size_t read_size, Error &error) ThreadInputStream::Read(void *ptr, size_t read_size, Error &)
{ {
assert(!thread.IsInside()); assert(!thread.IsInside());
while (true) { while (true) {
if (postponed_error.IsDefined()) { if (postponed_exception)
error = std::move(postponed_error); std::rethrow_exception(postponed_exception);
return 0;
}
auto r = buffer->Read(); auto r = buffer->Read();
if (!r.IsEmpty()) { if (!r.IsEmpty()) {

View File

@ -24,7 +24,8 @@
#include "InputStream.hxx" #include "InputStream.hxx"
#include "thread/Thread.hxx" #include "thread/Thread.hxx"
#include "thread/Cond.hxx" #include "thread/Cond.hxx"
#include "util/Error.hxx"
#include <exception>
#include <stdint.h> #include <stdint.h>
@ -51,7 +52,7 @@ class ThreadInputStream : public InputStream {
*/ */
Cond wake_cond; Cond wake_cond;
Error postponed_error; std::exception_ptr postponed_exception;
const size_t buffer_size; const size_t buffer_size;
CircularBuffer<uint8_t> *buffer = nullptr; CircularBuffer<uint8_t> *buffer = nullptr;
@ -103,9 +104,10 @@ protected:
* *
* The #InputStream is locked. Unlock/relock it if you do a * The #InputStream is locked. Unlock/relock it if you do a
* blocking operation. * blocking operation.
*
* Throws std::runtime_error on error.
*/ */
virtual bool Open(gcc_unused Error &error) { virtual void Open() {
return true;
} }
/** /**
@ -113,9 +115,11 @@ protected:
* *
* The #InputStream is not locked. * The #InputStream is not locked.
* *
* @return 0 on end-of-file or on error * Throws std::runtime_error on error.
*
* @return 0 on end-of-file
*/ */
virtual size_t ThreadRead(void *ptr, size_t size, Error &error) = 0; virtual size_t ThreadRead(void *ptr, size_t size) = 0;
/** /**
* Optional deinitialization before leaving the thread. * Optional deinitialization before leaving the thread.

View File

@ -21,12 +21,13 @@
#include "MmsInputPlugin.hxx" #include "MmsInputPlugin.hxx"
#include "input/ThreadInputStream.hxx" #include "input/ThreadInputStream.hxx"
#include "input/InputPlugin.hxx" #include "input/InputPlugin.hxx"
#include "system/Error.hxx"
#include "util/StringCompare.hxx" #include "util/StringCompare.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include <libmms/mmsx.h> #include <libmms/mmsx.h>
#include <stdexcept>
static constexpr size_t MMS_BUFFER_SIZE = 256 * 1024; static constexpr size_t MMS_BUFFER_SIZE = 256 * 1024;
class MmsInputStream final : public ThreadInputStream { class MmsInputStream final : public ThreadInputStream {
@ -39,27 +40,23 @@ public:
} }
protected: protected:
virtual bool Open(gcc_unused Error &error) override; virtual void Open() override;
virtual size_t ThreadRead(void *ptr, size_t size, virtual size_t ThreadRead(void *ptr, size_t size) override;
Error &error) override;
void Close() override { void Close() override {
mmsx_close(mms); mmsx_close(mms);
} }
}; };
static constexpr Domain mms_domain("mms"); void
MmsInputStream::Open()
bool
MmsInputStream::Open(Error &error)
{ {
Unlock(); Unlock();
mms = mmsx_connect(nullptr, nullptr, GetURI(), 128 * 1024); mms = mmsx_connect(nullptr, nullptr, GetURI(), 128 * 1024);
if (mms == nullptr) { if (mms == nullptr) {
Lock(); Lock();
error.Set(mms_domain, "mmsx_connect() failed"); throw std::runtime_error("mmsx_connect() failed");
return false;
} }
Lock(); Lock();
@ -67,7 +64,6 @@ MmsInputStream::Open(Error &error)
/* TODO: is this correct? at least this selects the ffmpeg /* TODO: is this correct? at least this selects the ffmpeg
decoder, which seems to work fine */ decoder, which seems to work fine */
SetMimeType("audio/x-ms-wma"); SetMimeType("audio/x-ms-wma");
return true;
} }
static InputStream * static InputStream *
@ -86,7 +82,7 @@ input_mms_open(const char *url,
} }
size_t size_t
MmsInputStream::ThreadRead(void *ptr, size_t read_size, Error &error) MmsInputStream::ThreadRead(void *ptr, size_t read_size)
{ {
/* unfortunately, mmsx_read() blocks until the whole buffer /* unfortunately, mmsx_read() blocks until the whole buffer
has been filled; to avoid big latencies, limit the size of has been filled; to avoid big latencies, limit the size of
@ -98,7 +94,7 @@ MmsInputStream::ThreadRead(void *ptr, size_t read_size, Error &error)
int nbytes = mmsx_read(nullptr, mms, (char *)ptr, read_size); int nbytes = mmsx_read(nullptr, mms, (char *)ptr, read_size);
if (nbytes <= 0) { if (nbytes <= 0) {
if (nbytes < 0) if (nbytes < 0)
error.SetErrno("mmsx_read() failed"); throw MakeErrno("mmsx_read() failed");
return 0; return 0;
} }