From 308010794a032669313bf989dd8421b9f1a8cba3 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 8 Sep 2016 17:14:11 +0200 Subject: [PATCH] decoder/Control: convert error from Error to std::exception_ptr Prepare full C++ exception support in the decoder thread. --- src/decoder/DecoderControl.cxx | 1 + src/decoder/DecoderControl.hxx | 28 +++++++++++++--------------- src/decoder/DecoderThread.cxx | 22 ++++++++++++++++------ src/player/Thread.cxx | 8 +++++--- 4 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/decoder/DecoderControl.cxx b/src/decoder/DecoderControl.cxx index e32a3cad8..c4250be0e 100644 --- a/src/decoder/DecoderControl.cxx +++ b/src/decoder/DecoderControl.cxx @@ -22,6 +22,7 @@ #include "DecoderError.hxx" #include "MusicPipe.hxx" #include "DetachedSong.hxx" +#include "util/Error.hxx" #include diff --git a/src/decoder/DecoderControl.hxx b/src/decoder/DecoderControl.hxx index d1d385d43..e3ef63192 100644 --- a/src/decoder/DecoderControl.hxx +++ b/src/decoder/DecoderControl.hxx @@ -27,7 +27,8 @@ #include "thread/Cond.hxx" #include "thread/Thread.hxx" #include "Chrono.hxx" -#include "util/Error.hxx" + +#include #include @@ -39,6 +40,7 @@ #undef ERROR #endif +class Error; class DetachedSong; class MusicBuffer; class MusicPipe; @@ -97,7 +99,7 @@ struct DecoderControl { * The object must be freed when this object transitions to * any other state (usually #DecoderState::START). */ - Error error; + std::exception_ptr error; bool quit; @@ -242,29 +244,25 @@ struct DecoderControl { } /** - * Checks whether an error has occurred, and if so, returns a - * copy of the #Error object. + * Checks whether an error has occurred, and if so, rethrows + * it. * * Caller must lock the object. */ - gcc_pure - Error GetError() const { + void CheckRethrowError() const { assert(command == DecoderCommand::NONE); - assert(state != DecoderState::ERROR || error.IsDefined()); + assert(state != DecoderState::ERROR || error); - Error result; if (state == DecoderState::ERROR) - result.Set(error); - return result; + std::rethrow_exception(error); } /** - * Like GetError(), but locks and unlocks the object. + * Like CheckRethrowError(), but locks and unlocks the object. */ - gcc_pure - Error LockGetError() const { + void LockCheckRethrowError() const { const ScopeLock protect(mutex); - return GetError(); + CheckRethrowError(); } /** @@ -274,7 +272,7 @@ struct DecoderControl { */ void ClearError() { if (state == DecoderState::ERROR) { - error.Clear(); + error = std::exception_ptr(); state = DecoderState::STOP; } } diff --git a/src/decoder/DecoderThread.cxx b/src/decoder/DecoderThread.cxx index 49b5fd1c4..694c95e66 100644 --- a/src/decoder/DecoderThread.cxx +++ b/src/decoder/DecoderThread.cxx @@ -34,6 +34,7 @@ #include "util/MimeType.hxx" #include "util/UriUtil.hxx" #include "util/Error.hxx" +#include "util/RuntimeError.hxx" #include "util/Domain.hxx" #include "thread/Name.hxx" #include "tag/ApeReplayGain.hxx" @@ -415,7 +416,7 @@ decoder_run_song(DecoderControl &dc, /* copy the Error from struct Decoder to DecoderControl */ dc.state = DecoderState::ERROR; - dc.error = std::move(decoder.error); + dc.error = std::make_exception_ptr(std::move(decoder.error)); } else if (success) dc.state = DecoderState::STOP; else { @@ -426,8 +427,7 @@ decoder_run_song(DecoderControl &dc, if (!allocated.empty()) error_uri = allocated.c_str(); - dc.error.Format(decoder_domain, - "Failed to decode %s", error_uri); + dc.error = std::make_exception_ptr(FormatRuntimeError("Failed to decode %s", error_uri)); } dc.client_cond.signal(); @@ -450,9 +450,11 @@ decoder_run(DecoderControl &dc) Path path_fs = Path::Null(); AllocatedPath path_buffer = AllocatedPath::Null(); 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()) { dc.state = DecoderState::ERROR; + dc.error = std::make_exception_ptr(std::move(error)); dc.CommandFinishedLocked(); return; } @@ -485,8 +487,16 @@ decoder_task(void *arg) decoder_run(dc); - if (dc.state == DecoderState::ERROR) - LogError(dc.error); + if (dc.state == DecoderState::ERROR) { + try { + std::rethrow_exception(dc.error); + } catch (const std::exception &e) { + LogError(e); + } catch (const Error &error) { + LogError(error); + } catch (...) { + } + } break; diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx index 4458ba671..1e4a3cc7d 100644 --- a/src/player/Thread.cxx +++ b/src/player/Thread.cxx @@ -33,6 +33,7 @@ #include "tag/Tag.hxx" #include "Idle.hxx" #include "util/Domain.hxx" +#include "util/Error.hxx" #include "thread/Name.hxx" #include "Log.hxx" @@ -372,9 +373,10 @@ Player::StopDecoder() bool Player::ForwardDecoderError() { - Error error = dc.GetError(); - if (error.IsDefined()) { - pc.SetError(PlayerError::DECODER, std::move(error)); + try { + dc.CheckRethrowError(); + } catch (...) { + pc.SetError(PlayerError::DECODER, std::current_exception()); return false; }