decoder/Control: convert error from Error to std::exception_ptr

Prepare full C++ exception support in the decoder thread.
This commit is contained in:
Max Kellermann 2016-09-08 17:14:11 +02:00
parent 0ce72cbf9d
commit 308010794a
4 changed files with 35 additions and 24 deletions

View File

@ -22,6 +22,7 @@
#include "DecoderError.hxx" #include "DecoderError.hxx"
#include "MusicPipe.hxx" #include "MusicPipe.hxx"
#include "DetachedSong.hxx" #include "DetachedSong.hxx"
#include "util/Error.hxx"
#include <assert.h> #include <assert.h>

View File

@ -27,7 +27,8 @@
#include "thread/Cond.hxx" #include "thread/Cond.hxx"
#include "thread/Thread.hxx" #include "thread/Thread.hxx"
#include "Chrono.hxx" #include "Chrono.hxx"
#include "util/Error.hxx"
#include <exception>
#include <utility> #include <utility>
@ -39,6 +40,7 @@
#undef ERROR #undef ERROR
#endif #endif
class Error;
class DetachedSong; class DetachedSong;
class MusicBuffer; class MusicBuffer;
class MusicPipe; class MusicPipe;
@ -97,7 +99,7 @@ struct DecoderControl {
* The object must be freed when this object transitions to * The object must be freed when this object transitions to
* any other state (usually #DecoderState::START). * any other state (usually #DecoderState::START).
*/ */
Error error; std::exception_ptr error;
bool quit; bool quit;
@ -242,29 +244,25 @@ struct DecoderControl {
} }
/** /**
* Checks whether an error has occurred, and if so, returns a * Checks whether an error has occurred, and if so, rethrows
* copy of the #Error object. * it.
* *
* Caller must lock the object. * Caller must lock the object.
*/ */
gcc_pure void CheckRethrowError() const {
Error GetError() const {
assert(command == DecoderCommand::NONE); assert(command == DecoderCommand::NONE);
assert(state != DecoderState::ERROR || error.IsDefined()); assert(state != DecoderState::ERROR || error);
Error result;
if (state == DecoderState::ERROR) if (state == DecoderState::ERROR)
result.Set(error); std::rethrow_exception(error);
return result;
} }
/** /**
* Like GetError(), but locks and unlocks the object. * Like CheckRethrowError(), but locks and unlocks the object.
*/ */
gcc_pure void LockCheckRethrowError() const {
Error LockGetError() const {
const ScopeLock protect(mutex); const ScopeLock protect(mutex);
return GetError(); CheckRethrowError();
} }
/** /**
@ -274,7 +272,7 @@ struct DecoderControl {
*/ */
void ClearError() { void ClearError() {
if (state == DecoderState::ERROR) { if (state == DecoderState::ERROR) {
error.Clear(); error = std::exception_ptr();
state = DecoderState::STOP; state = DecoderState::STOP;
} }
} }

View File

@ -34,6 +34,7 @@
#include "util/MimeType.hxx" #include "util/MimeType.hxx"
#include "util/UriUtil.hxx" #include "util/UriUtil.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "util/RuntimeError.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "thread/Name.hxx" #include "thread/Name.hxx"
#include "tag/ApeReplayGain.hxx" #include "tag/ApeReplayGain.hxx"
@ -415,7 +416,7 @@ decoder_run_song(DecoderControl &dc,
/* copy the Error from struct Decoder to /* copy the Error from struct Decoder to
DecoderControl */ DecoderControl */
dc.state = DecoderState::ERROR; dc.state = DecoderState::ERROR;
dc.error = std::move(decoder.error); dc.error = std::make_exception_ptr(std::move(decoder.error));
} else if (success) } else if (success)
dc.state = DecoderState::STOP; dc.state = DecoderState::STOP;
else { else {
@ -426,8 +427,7 @@ decoder_run_song(DecoderControl &dc,
if (!allocated.empty()) if (!allocated.empty())
error_uri = allocated.c_str(); error_uri = allocated.c_str();
dc.error.Format(decoder_domain, dc.error = std::make_exception_ptr(FormatRuntimeError("Failed to decode %s", error_uri));
"Failed to decode %s", error_uri);
} }
dc.client_cond.signal(); dc.client_cond.signal();
@ -450,9 +450,11 @@ decoder_run(DecoderControl &dc)
Path path_fs = Path::Null(); Path path_fs = Path::Null();
AllocatedPath path_buffer = AllocatedPath::Null(); AllocatedPath path_buffer = AllocatedPath::Null();
if (PathTraitsUTF8::IsAbsolute(uri_utf8)) { if (PathTraitsUTF8::IsAbsolute(uri_utf8)) {
path_buffer = AllocatedPath::FromUTF8(uri_utf8, dc.error); Error error;
path_buffer = AllocatedPath::FromUTF8(uri_utf8, error);
if (path_buffer.IsNull()) { if (path_buffer.IsNull()) {
dc.state = DecoderState::ERROR; dc.state = DecoderState::ERROR;
dc.error = std::make_exception_ptr(std::move(error));
dc.CommandFinishedLocked(); dc.CommandFinishedLocked();
return; return;
} }
@ -485,8 +487,16 @@ decoder_task(void *arg)
decoder_run(dc); decoder_run(dc);
if (dc.state == DecoderState::ERROR) if (dc.state == DecoderState::ERROR) {
LogError(dc.error); try {
std::rethrow_exception(dc.error);
} catch (const std::exception &e) {
LogError(e);
} catch (const Error &error) {
LogError(error);
} catch (...) {
}
}
break; break;

View File

@ -33,6 +33,7 @@
#include "tag/Tag.hxx" #include "tag/Tag.hxx"
#include "Idle.hxx" #include "Idle.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "util/Error.hxx"
#include "thread/Name.hxx" #include "thread/Name.hxx"
#include "Log.hxx" #include "Log.hxx"
@ -372,9 +373,10 @@ Player::StopDecoder()
bool bool
Player::ForwardDecoderError() Player::ForwardDecoderError()
{ {
Error error = dc.GetError(); try {
if (error.IsDefined()) { dc.CheckRethrowError();
pc.SetError(PlayerError::DECODER, std::move(error)); } catch (...) {
pc.SetError(PlayerError::DECODER, std::current_exception());
return false; return false;
} }