diff --git a/Makefile.am b/Makefile.am index a9c0c8d83..ef6523134 100644 --- a/Makefile.am +++ b/Makefile.am @@ -671,8 +671,7 @@ NFS_SOURCES = \ src/lib/nfs/Glue.cxx src/lib/nfs/Glue.hxx \ src/lib/nfs/Base.cxx src/lib/nfs/Base.hxx \ src/lib/nfs/FileReader.cxx src/lib/nfs/FileReader.hxx \ - src/lib/nfs/Blocking.cxx src/lib/nfs/Blocking.hxx \ - src/lib/nfs/Domain.cxx src/lib/nfs/Domain.hxx + src/lib/nfs/Blocking.cxx src/lib/nfs/Blocking.hxx if ENABLE_DATABASE diff --git a/src/input/plugins/NfsInputPlugin.cxx b/src/input/plugins/NfsInputPlugin.cxx index bb3eb8732..97c90b15b 100644 --- a/src/input/plugins/NfsInputPlugin.cxx +++ b/src/input/plugins/NfsInputPlugin.cxx @@ -21,7 +21,6 @@ #include "NfsInputPlugin.hxx" #include "../AsyncInputStream.hxx" #include "../InputPlugin.hxx" -#include "lib/nfs/Domain.hxx" #include "lib/nfs/Glue.hxx" #include "lib/nfs/FileReader.hxx" #include "util/StringCompare.hxx" @@ -64,7 +63,7 @@ public: } private: - bool DoRead(); + void DoRead(); protected: /* virtual methods from AsyncInputStream */ @@ -75,41 +74,34 @@ private: /* virtual methods from NfsFileReader */ void OnNfsFileOpen(uint64_t size) override; void OnNfsFileRead(const void *data, size_t size) override; - void OnNfsFileError(Error &&error) override; + void OnNfsFileError(std::exception_ptr &&e) override; }; -bool +void NfsInputStream::DoRead() { assert(NfsFileReader::IsIdle()); int64_t remaining = size - next_offset; if (remaining <= 0) - return true; + return; const size_t buffer_space = GetBufferSpace(); if (buffer_space == 0) { Pause(); - return true; + return; } size_t nbytes = std::min(std::min(remaining, 32768), buffer_space); - Error error; - bool success; - - { + try { const ScopeUnlock unlock(mutex); - success = NfsFileReader::Read(next_offset, nbytes, error); + NfsFileReader::Read(next_offset, nbytes); + } catch (...) { + postponed_exception = std::current_exception(); + cond.broadcast(); } - - if (!success) { - PostponeError(std::move(error)); - return false; - } - - return true; } void @@ -182,7 +174,7 @@ NfsInputStream::OnNfsFileRead(const void *data, size_t data_size) } void -NfsInputStream::OnNfsFileError(Error &&error) +NfsInputStream::OnNfsFileError(std::exception_ptr &&e) { const ScopeLock protect(mutex); @@ -197,7 +189,7 @@ NfsInputStream::OnNfsFileError(Error &&error) return; } - postponed_error = std::move(error); + postponed_exception = std::move(e); if (IsSeekPending()) SeekDone(); diff --git a/src/lib/nfs/Blocking.cxx b/src/lib/nfs/Blocking.cxx index 18a1b7bff..7faa0549c 100644 --- a/src/lib/nfs/Blocking.cxx +++ b/src/lib/nfs/Blocking.cxx @@ -20,12 +20,10 @@ #include "config.h" #include "Blocking.hxx" #include "Connection.hxx" -#include "Domain.hxx" #include "event/Call.hxx" -#include "util/Error.hxx" -bool -BlockingNfsOperation::Run(Error &_error) +void +BlockingNfsOperation::Run() { /* subscribe to the connection, which will invoke either OnNfsConnectionReady() or OnNfsConnectionFailed() */ @@ -33,40 +31,37 @@ BlockingNfsOperation::Run(Error &_error) [this](){ connection.AddLease(*this); }); /* wait for completion */ - if (!LockWaitFinished()) { - _error.Set(nfs_domain, 0, "Timeout"); - return false; - } + if (!LockWaitFinished()) + throw std::runtime_error("Timeout"); /* check for error */ - if (error.IsDefined()) { - _error = std::move(error); - return false; - } - - return true; + if (error) + std::rethrow_exception(std::move(error)); } void BlockingNfsOperation::OnNfsConnectionReady() { - if (!Start(error)) { + try { + Start(); + } catch (...) { + error = std::current_exception(); connection.RemoveLease(*this); LockSetFinished(); } } void -BlockingNfsOperation::OnNfsConnectionFailed(const Error &_error) +BlockingNfsOperation::OnNfsConnectionFailed(std::exception_ptr e) { - error.Set(_error); + error = std::move(e); LockSetFinished(); } void -BlockingNfsOperation::OnNfsConnectionDisconnected(const Error &_error) +BlockingNfsOperation::OnNfsConnectionDisconnected(std::exception_ptr e) { - error.Set(_error); + error = std::move(e); LockSetFinished(); } @@ -80,10 +75,10 @@ BlockingNfsOperation::OnNfsCallback(unsigned status, void *data) } void -BlockingNfsOperation::OnNfsError(Error &&_error) +BlockingNfsOperation::OnNfsError(std::exception_ptr &&e) { connection.RemoveLease(*this); - error = std::move(_error); + error = std::move(e); LockSetFinished(); } diff --git a/src/lib/nfs/Blocking.hxx b/src/lib/nfs/Blocking.hxx index a309028f0..2c23ad057 100644 --- a/src/lib/nfs/Blocking.hxx +++ b/src/lib/nfs/Blocking.hxx @@ -25,7 +25,8 @@ #include "Lease.hxx" #include "thread/Mutex.hxx" #include "thread/Cond.hxx" -#include "util/Error.hxx" + +#include class NfsConnection; @@ -42,7 +43,7 @@ class BlockingNfsOperation : protected NfsCallback, NfsLease { bool finished; - Error error; + std::exception_ptr error; protected: NfsConnection &connection; @@ -51,7 +52,10 @@ public: BlockingNfsOperation(NfsConnection &_connection) :finished(false), connection(_connection) {} - bool Run(Error &error); + /** + * Throws std::runtime_error on error. + */ + void Run(); private: bool LockWaitFinished() { @@ -75,15 +79,15 @@ private: /* virtual methods from NfsLease */ void OnNfsConnectionReady() final; - void OnNfsConnectionFailed(const Error &error) final; - void OnNfsConnectionDisconnected(const Error &error) final; + void OnNfsConnectionFailed(std::exception_ptr e) final; + void OnNfsConnectionDisconnected(std::exception_ptr e) final; /* virtual methods from NfsCallback */ void OnNfsCallback(unsigned status, void *data) final; - void OnNfsError(Error &&error) final; + void OnNfsError(std::exception_ptr &&e) final; protected: - virtual bool Start(Error &error) = 0; + virtual void Start() = 0; virtual void HandleResult(unsigned status, void *data) = 0; }; diff --git a/src/lib/nfs/Callback.hxx b/src/lib/nfs/Callback.hxx index d54610b93..5c1f44159 100644 --- a/src/lib/nfs/Callback.hxx +++ b/src/lib/nfs/Callback.hxx @@ -22,12 +22,12 @@ #include "check.h" -class Error; +#include class NfsCallback { public: virtual void OnNfsCallback(unsigned status, void *data) = 0; - virtual void OnNfsError(Error &&error) = 0; + virtual void OnNfsError(std::exception_ptr &&e) = 0; }; #endif diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx index f6d4fda2b..5f6ab4ca9 100644 --- a/src/lib/nfs/Connection.cxx +++ b/src/lib/nfs/Connection.cxx @@ -20,11 +20,10 @@ #include "config.h" #include "Connection.hxx" #include "Lease.hxx" -#include "Domain.hxx" #include "Callback.hxx" #include "event/Loop.hxx" #include "system/fd_util.h" -#include "util/Error.hxx" +#include "util/RuntimeError.hxx" extern "C" { #include @@ -36,90 +35,65 @@ extern "C" { static constexpr unsigned NFS_MOUNT_TIMEOUT = 60; -inline bool +inline void NfsConnection::CancellableCallback::Stat(nfs_context *ctx, - const char *path, - Error &error) + const char *path) { assert(connection.GetEventLoop().IsInside()); int result = nfs_stat_async(ctx, path, Callback, this); - if (result < 0) { - error.Format(nfs_domain, "nfs_stat_async() failed: %s", - nfs_get_error(ctx)); - return false; - } - - return true; + if (result < 0) + throw FormatRuntimeError("nfs_stat_async() failed: %s", + nfs_get_error(ctx)); } -inline bool +inline void NfsConnection::CancellableCallback::OpenDirectory(nfs_context *ctx, - const char *path, - Error &error) + const char *path) { assert(connection.GetEventLoop().IsInside()); int result = nfs_opendir_async(ctx, path, Callback, this); - if (result < 0) { - error.Format(nfs_domain, "nfs_opendir_async() failed: %s", - nfs_get_error(ctx)); - return false; - } - - return true; + if (result < 0) + throw FormatRuntimeError("nfs_opendir_async() failed: %s", + nfs_get_error(ctx)); } -inline bool +inline void NfsConnection::CancellableCallback::Open(nfs_context *ctx, - const char *path, int flags, - Error &error) + const char *path, int flags) { assert(connection.GetEventLoop().IsInside()); int result = nfs_open_async(ctx, path, flags, Callback, this); - if (result < 0) { - error.Format(nfs_domain, "nfs_open_async() failed: %s", - nfs_get_error(ctx)); - return false; - } - - return true; + if (result < 0) + throw FormatRuntimeError("nfs_open_async() failed: %s", + nfs_get_error(ctx)); } -inline bool +inline void NfsConnection::CancellableCallback::Stat(nfs_context *ctx, - struct nfsfh *fh, - Error &error) + struct nfsfh *fh) { assert(connection.GetEventLoop().IsInside()); int result = nfs_fstat_async(ctx, fh, Callback, this); - if (result < 0) { - error.Format(nfs_domain, "nfs_fstat_async() failed: %s", - nfs_get_error(ctx)); - return false; - } - - return true; + if (result < 0) + throw FormatRuntimeError("nfs_fstat_async() failed: %s", + nfs_get_error(ctx)); } -inline bool +inline void NfsConnection::CancellableCallback::Read(nfs_context *ctx, struct nfsfh *fh, - uint64_t offset, size_t size, - Error &error) + uint64_t offset, size_t size) { assert(connection.GetEventLoop().IsInside()); int result = nfs_pread_async(ctx, fh, offset, size, Callback, this); - if (result < 0) { - error.Format(nfs_domain, "nfs_pread_async() failed: %s", - nfs_get_error(ctx)); - return false; - } - - return true; + if (result < 0) + throw FormatRuntimeError("nfs_pread_async() failed: %s", + nfs_get_error(ctx)); } inline void @@ -160,8 +134,7 @@ NfsConnection::CancellableCallback::Callback(int err, void *data) if (err >= 0) cb.OnNfsCallback((unsigned)err, data); else - cb.OnNfsError(Error(nfs_domain, err, - (const char *)data)); + cb.OnNfsError(std::make_exception_ptr(std::runtime_error((const char *)data))); } else { if (open) { /* a nfs_open_async() call was cancelled - to @@ -234,37 +207,38 @@ NfsConnection::RemoveLease(NfsLease &lease) active_leases.remove(&lease); } -bool -NfsConnection::Stat(const char *path, NfsCallback &callback, Error &error) +void +NfsConnection::Stat(const char *path, NfsCallback &callback) { assert(GetEventLoop().IsInside()); assert(!callbacks.Contains(callback)); auto &c = callbacks.Add(callback, *this, false); - if (!c.Stat(context, path, error)) { + try { + c.Stat(context, path); + } catch (...) { callbacks.Remove(c); - return false; + throw; } ScheduleSocket(); - return true; } -bool -NfsConnection::OpenDirectory(const char *path, NfsCallback &callback, - Error &error) +void +NfsConnection::OpenDirectory(const char *path, NfsCallback &callback) { assert(GetEventLoop().IsInside()); assert(!callbacks.Contains(callback)); auto &c = callbacks.Add(callback, *this, true); - if (!c.OpenDirectory(context, path, error)) { + try { + c.OpenDirectory(context, path); + } catch (...) { callbacks.Remove(c); - return false; + throw; } ScheduleSocket(); - return true; } const struct nfsdirent * @@ -283,54 +257,56 @@ NfsConnection::CloseDirectory(struct nfsdir *dir) return nfs_closedir(context, dir); } -bool -NfsConnection::Open(const char *path, int flags, NfsCallback &callback, - Error &error) +void +NfsConnection::Open(const char *path, int flags, NfsCallback &callback) { assert(GetEventLoop().IsInside()); assert(!callbacks.Contains(callback)); auto &c = callbacks.Add(callback, *this, true); - if (!c.Open(context, path, flags, error)) { + try { + c.Open(context, path, flags); + } catch (...) { callbacks.Remove(c); - return false; + throw; } ScheduleSocket(); - return true; } -bool -NfsConnection::Stat(struct nfsfh *fh, NfsCallback &callback, Error &error) +void +NfsConnection::Stat(struct nfsfh *fh, NfsCallback &callback) { assert(GetEventLoop().IsInside()); assert(!callbacks.Contains(callback)); auto &c = callbacks.Add(callback, *this, false); - if (!c.Stat(context, fh, error)) { + try { + c.Stat(context, fh); + } catch (...) { callbacks.Remove(c); - return false; + throw; } ScheduleSocket(); - return true; } -bool +void NfsConnection::Read(struct nfsfh *fh, uint64_t offset, size_t size, - NfsCallback &callback, Error &error) + NfsCallback &callback) { assert(GetEventLoop().IsInside()); assert(!callbacks.Contains(callback)); auto &c = callbacks.Add(callback, *this, false); - if (!c.Read(context, fh, offset, size, error)) { + try { + c.Read(context, fh, offset, size); + } catch (...) { callbacks.Remove(c); - return false; + throw; } ScheduleSocket(); - return true; } void @@ -479,7 +455,7 @@ NfsConnection::OnSocketReady(unsigned flags) } if (!was_mounted && mount_finished) { - if (postponed_mount_error.IsDefined()) { + if (postponed_mount_error) { DestroyContext(); closed = true; BroadcastMountError(std::move(postponed_mount_error)); @@ -487,11 +463,10 @@ NfsConnection::OnSocketReady(unsigned flags) BroadcastMountSuccess(); } else if (result < 0) { /* the connection has failed */ - Error error; - error.Format(nfs_domain, "NFS connection has failed: %s", - nfs_get_error(context)); - BroadcastError(std::move(error)); + auto e = FormatRuntimeError("NFS connection has failed: %s", + nfs_get_error(context)); + BroadcastError(std::make_exception_ptr(e)); DestroyContext(); closed = true; @@ -499,15 +474,13 @@ NfsConnection::OnSocketReady(unsigned flags) /* this happens when rpc_reconnect_requeue() is called after the connection broke, but autoreconnect was disabled - nfs_service() returns 0 */ - Error error; + const char *msg = nfs_get_error(context); if (msg == nullptr) - error.Set(nfs_domain, "NFS socket disappeared"); - else - error.Format(nfs_domain, - "NFS socket disappeared: %s", msg); + msg = ""; + auto e = FormatRuntimeError("NFS socket disappeared: %s", msg); - BroadcastError(std::move(error)); + BroadcastError(std::make_exception_ptr(e)); DestroyContext(); closed = true; @@ -539,9 +512,9 @@ NfsConnection::MountCallback(int status, gcc_unused nfs_context *nfs, TimeoutMonitor::Cancel(); if (status < 0) { - postponed_mount_error.Format(nfs_domain, status, - "nfs_mount_async() failed: %s", - nfs_get_error(context)); + auto e = FormatRuntimeError("nfs_mount_async() failed: %s", + nfs_get_error(context)); + postponed_mount_error = std::make_exception_ptr(e); return; } } @@ -555,19 +528,17 @@ NfsConnection::MountCallback(int status, nfs_context *nfs, void *data, c->MountCallback(status, nfs, data); } -inline bool -NfsConnection::MountInternal(Error &error) +inline void +NfsConnection::MountInternal() { assert(GetEventLoop().IsInside()); assert(context == nullptr); context = nfs_init_context(); - if (context == nullptr) { - error.Set(nfs_domain, "nfs_init_context() failed"); - return false; - } + if (context == nullptr) + throw std::runtime_error("nfs_init_context() failed"); - postponed_mount_error.Clear(); + postponed_mount_error = std::exception_ptr(); mount_finished = false; TimeoutMonitor::ScheduleSeconds(NFS_MOUNT_TIMEOUT); @@ -580,16 +551,14 @@ NfsConnection::MountInternal(Error &error) if (nfs_mount_async(context, server.c_str(), export_name.c_str(), MountCallback, this) != 0) { - error.Format(nfs_domain, - "nfs_mount_async() failed: %s", - nfs_get_error(context)); + auto e = FormatRuntimeError("nfs_mount_async() failed: %s", + nfs_get_error(context)); nfs_destroy_context(context); context = nullptr; - return false; + throw e; } ScheduleSocket(); - return true; } void @@ -605,31 +574,31 @@ NfsConnection::BroadcastMountSuccess() } void -NfsConnection::BroadcastMountError(Error &&error) +NfsConnection::BroadcastMountError(std::exception_ptr &&e) { assert(GetEventLoop().IsInside()); while (!new_leases.empty()) { auto l = new_leases.front(); new_leases.pop_front(); - l->OnNfsConnectionFailed(error); + l->OnNfsConnectionFailed(e); } - OnNfsConnectionError(std::move(error)); + OnNfsConnectionError(std::move(e)); } void -NfsConnection::BroadcastError(Error &&error) +NfsConnection::BroadcastError(std::exception_ptr &&e) { assert(GetEventLoop().IsInside()); while (!active_leases.empty()) { auto l = active_leases.front(); active_leases.pop_front(); - l->OnNfsConnectionDisconnected(error); + l->OnNfsConnectionDisconnected(e); } - BroadcastMountError(std::move(error)); + BroadcastMountError(std::move(e)); } void @@ -641,7 +610,7 @@ NfsConnection::OnTimeout() mount_finished = true; DestroyContext(); - BroadcastMountError(Error(nfs_domain, "Mount timeout")); + BroadcastMountError(std::make_exception_ptr(std::runtime_error("Mount timeout"))); } void @@ -650,9 +619,10 @@ NfsConnection::RunDeferred() assert(GetEventLoop().IsInside()); if (context == nullptr) { - Error error; - if (!MountInternal(error)) { - BroadcastMountError(std::move(error)); + try { + MountInternal(); + } catch (...) { + BroadcastMountError(std::current_exception()); return; } } diff --git a/src/lib/nfs/Connection.hxx b/src/lib/nfs/Connection.hxx index 1d677e412..1e4a8ef43 100644 --- a/src/lib/nfs/Connection.hxx +++ b/src/lib/nfs/Connection.hxx @@ -24,11 +24,11 @@ #include "event/SocketMonitor.hxx" #include "event/TimeoutMonitor.hxx" #include "event/DeferredMonitor.hxx" -#include "util/Error.hxx" #include #include #include +#include struct nfs_context; struct nfsdir; @@ -65,17 +65,12 @@ class NfsConnection : SocketMonitor, TimeoutMonitor, DeferredMonitor { connection(_connection), open(_open), close_fh(nullptr) {} - bool Stat(nfs_context *context, const char *path, - Error &error); - bool OpenDirectory(nfs_context *context, const char *path, - Error &error); - bool Open(nfs_context *context, const char *path, int flags, - Error &error); - bool Stat(nfs_context *context, struct nfsfh *fh, - Error &error); - bool Read(nfs_context *context, struct nfsfh *fh, - uint64_t offset, size_t size, - Error &error); + void Stat(nfs_context *context, const char *path); + void OpenDirectory(nfs_context *context, const char *path); + void Open(nfs_context *context, const char *path, int flags); + void Stat(nfs_context *context, struct nfsfh *fh); + void Read(nfs_context *context, struct nfsfh *fh, + uint64_t offset, size_t size); /** * Cancel the operation and schedule a call to @@ -115,7 +110,7 @@ class NfsConnection : SocketMonitor, TimeoutMonitor, DeferredMonitor { */ std::forward_list deferred_close; - Error postponed_mount_error; + std::exception_ptr postponed_mount_error; #ifndef NDEBUG /** @@ -175,25 +170,32 @@ public: void AddLease(NfsLease &lease); void RemoveLease(NfsLease &lease); - bool Stat(const char *path, NfsCallback &callback, Error &error); + void Stat(const char *path, NfsCallback &callback); - bool OpenDirectory(const char *path, NfsCallback &callback, - Error &error); + void OpenDirectory(const char *path, NfsCallback &callback); const struct nfsdirent *ReadDirectory(struct nfsdir *dir); void CloseDirectory(struct nfsdir *dir); - bool Open(const char *path, int flags, NfsCallback &callback, - Error &error); - bool Stat(struct nfsfh *fh, NfsCallback &callback, Error &error); - bool Read(struct nfsfh *fh, uint64_t offset, size_t size, - NfsCallback &callback, Error &error); + /** + * Throws std::runtime_error on error. + */ + void Open(const char *path, int flags, NfsCallback &callback); + + void Stat(struct nfsfh *fh, NfsCallback &callback); + + /** + * Throws std::runtime_error on error. + */ + void Read(struct nfsfh *fh, uint64_t offset, size_t size, + NfsCallback &callback); + void Cancel(NfsCallback &callback); void Close(struct nfsfh *fh); void CancelAndClose(struct nfsfh *fh, NfsCallback &callback); protected: - virtual void OnNfsConnectionError(Error &&error) = 0; + virtual void OnNfsConnectionError(std::exception_ptr &&e) = 0; private: void DestroyContext(); @@ -208,10 +210,10 @@ private: */ void DeferClose(struct nfsfh *fh); - bool MountInternal(Error &error); + void MountInternal(); void BroadcastMountSuccess(); - void BroadcastMountError(Error &&error); - void BroadcastError(Error &&error); + void BroadcastMountError(std::exception_ptr &&e); + void BroadcastError(std::exception_ptr &&e); static void MountCallback(int status, nfs_context *nfs, void *data, void *private_data); diff --git a/src/lib/nfs/Domain.cxx b/src/lib/nfs/Domain.cxx deleted file mode 100644 index ac34e9e7a..000000000 --- a/src/lib/nfs/Domain.cxx +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2003-2016 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "Domain.hxx" -#include "util/Domain.hxx" - -const Domain nfs_domain("nfs"); diff --git a/src/lib/nfs/Domain.hxx b/src/lib/nfs/Domain.hxx deleted file mode 100644 index 9adf511f9..000000000 --- a/src/lib/nfs/Domain.hxx +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2003-2016 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPD_NFS_DOMAIN_HXX -#define MPD_NFS_DOMAIN_HXX - -class Domain; - -extern const Domain nfs_domain; - -#endif diff --git a/src/lib/nfs/FileReader.cxx b/src/lib/nfs/FileReader.cxx index 54b59e09a..5f517e22c 100644 --- a/src/lib/nfs/FileReader.cxx +++ b/src/lib/nfs/FileReader.cxx @@ -22,11 +22,9 @@ #include "Glue.hxx" #include "Base.hxx" #include "Connection.hxx" -#include "Domain.hxx" #include "event/Call.hxx" #include "IOThread.hxx" #include "util/StringCompare.hxx" -#include "util/Error.hxx" #include @@ -128,16 +126,13 @@ NfsFileReader::Open(const char *uri) DeferredMonitor::Schedule(); } -bool -NfsFileReader::Read(uint64_t offset, size_t size, Error &error) +void +NfsFileReader::Read(uint64_t offset, size_t size) { assert(state == State::IDLE); - if (!connection->Read(fh, offset, size, *this, error)) - return false; - + connection->Read(fh, offset, size, *this); state = State::READ; - return true; } void @@ -154,9 +149,10 @@ NfsFileReader::OnNfsConnectionReady() { assert(state == State::MOUNT); - Error error; - if (!connection->Open(path, O_RDONLY, *this, error)) { - OnNfsFileError(std::move(error)); + try { + connection->Open(path, O_RDONLY, *this); + } catch (...) { + OnNfsFileError(std::current_exception()); return; } @@ -164,27 +160,23 @@ NfsFileReader::OnNfsConnectionReady() } void -NfsFileReader::OnNfsConnectionFailed(const Error &error) +NfsFileReader::OnNfsConnectionFailed(std::exception_ptr e) { assert(state == State::MOUNT); state = State::INITIAL; - Error copy; - copy.Set(error); - OnNfsFileError(std::move(copy)); + OnNfsFileError(std::move(e)); } void -NfsFileReader::OnNfsConnectionDisconnected(const Error &error) +NfsFileReader::OnNfsConnectionDisconnected(std::exception_ptr e) { assert(state > State::MOUNT); CancelOrClose(); - Error copy; - copy.Set(error); - OnNfsFileError(std::move(copy)); + OnNfsFileError(std::move(e)); } inline void @@ -196,9 +188,10 @@ NfsFileReader::OpenCallback(nfsfh *_fh) fh = _fh; - Error error; - if (!connection->Stat(fh, *this, error)) { - OnNfsFileError(std::move(error)); + try { + connection->Stat(fh, *this); + } catch (...) { + OnNfsFileError(std::current_exception()); return; } @@ -214,7 +207,7 @@ NfsFileReader::StatCallback(const struct stat *st) assert(st != nullptr); if (!S_ISREG(st->st_mode)) { - OnNfsFileError(Error(nfs_domain, "Not a regular file")); + OnNfsFileError(std::make_exception_ptr(std::runtime_error("Not a regular file"))); return; } @@ -250,7 +243,7 @@ NfsFileReader::OnNfsCallback(unsigned status, void *data) } void -NfsFileReader::OnNfsError(Error &&error) +NfsFileReader::OnNfsError(std::exception_ptr &&e) { switch (state) { case State::INITIAL: @@ -276,7 +269,7 @@ NfsFileReader::OnNfsError(Error &&error) break; } - OnNfsFileError(std::move(error)); + OnNfsFileError(std::move(e)); } void diff --git a/src/lib/nfs/FileReader.hxx b/src/lib/nfs/FileReader.hxx index 177fb66f2..395d7486c 100644 --- a/src/lib/nfs/FileReader.hxx +++ b/src/lib/nfs/FileReader.hxx @@ -27,6 +27,7 @@ #include "Compiler.h" #include +#include #include #include @@ -66,7 +67,10 @@ public: */ void Open(const char *uri); - bool Read(uint64_t offset, size_t size, Error &error); + /** + * Throws std::runtime_error on error. + */ + void Read(uint64_t offset, size_t size); void CancelRead(); bool IsIdle() const { @@ -76,7 +80,7 @@ public: protected: virtual void OnNfsFileOpen(uint64_t size) = 0; virtual void OnNfsFileRead(const void *data, size_t size) = 0; - virtual void OnNfsFileError(Error &&error) = 0; + virtual void OnNfsFileError(std::exception_ptr &&e) = 0; private: /** @@ -90,12 +94,12 @@ private: /* virtual methods from NfsLease */ void OnNfsConnectionReady() final; - void OnNfsConnectionFailed(const Error &error) final; - void OnNfsConnectionDisconnected(const Error &error) final; + void OnNfsConnectionFailed(std::exception_ptr e) final; + void OnNfsConnectionDisconnected(std::exception_ptr e) final; /* virtual methods from NfsCallback */ void OnNfsCallback(unsigned status, void *data) final; - void OnNfsError(Error &&error) final; + void OnNfsError(std::exception_ptr &&e) final; /* virtual methods from DeferredMonitor */ void RunDeferred() final; diff --git a/src/lib/nfs/Lease.hxx b/src/lib/nfs/Lease.hxx index ad17e7700..37db7100c 100644 --- a/src/lib/nfs/Lease.hxx +++ b/src/lib/nfs/Lease.hxx @@ -22,6 +22,8 @@ #include "check.h" +#include + class Error; class NfsLease { @@ -36,13 +38,13 @@ public: * The #NfsConnection has failed to mount the server's export. * This is being called instead of OnNfsConnectionReady(). */ - virtual void OnNfsConnectionFailed(const Error &error) = 0; + virtual void OnNfsConnectionFailed(std::exception_ptr e) = 0; /** * The #NfsConnection has failed after OnNfsConnectionReady() * had been called already. */ - virtual void OnNfsConnectionDisconnected(const Error &error) = 0; + virtual void OnNfsConnectionDisconnected(std::exception_ptr e) = 0; }; #endif diff --git a/src/lib/nfs/Manager.cxx b/src/lib/nfs/Manager.cxx index 3eaadb4fc..6536acf54 100644 --- a/src/lib/nfs/Manager.cxx +++ b/src/lib/nfs/Manager.cxx @@ -26,9 +26,9 @@ #include void -NfsManager::ManagedConnection::OnNfsConnectionError(Error &&error) +NfsManager::ManagedConnection::OnNfsConnectionError(std::exception_ptr &&e) { - FormatError(error, "NFS error on %s:%s", GetServer(), GetExportName()); + FormatError(e, "NFS error on %s:%s", GetServer(), GetExportName()); /* defer deletion so the caller (i.e. NfsConnection::OnSocketReady()) can still use this diff --git a/src/lib/nfs/Manager.hxx b/src/lib/nfs/Manager.hxx index 3cce3dfba..a4868bfae 100644 --- a/src/lib/nfs/Manager.hxx +++ b/src/lib/nfs/Manager.hxx @@ -53,7 +53,7 @@ class NfsManager final : IdleMonitor { protected: /* virtual methods from NfsConnection */ - void OnNfsConnectionError(Error &&error) override; + void OnNfsConnectionError(std::exception_ptr &&e) override; }; struct Compare { diff --git a/src/storage/plugins/NfsStorage.cxx b/src/storage/plugins/NfsStorage.cxx index 286df71be..4e3df27ef 100644 --- a/src/storage/plugins/NfsStorage.cxx +++ b/src/storage/plugins/NfsStorage.cxx @@ -24,7 +24,6 @@ #include "storage/FileInfo.hxx" #include "storage/MemoryDirectoryReader.hxx" #include "lib/nfs/Blocking.hxx" -#include "lib/nfs/Domain.hxx" #include "lib/nfs/Base.hxx" #include "lib/nfs/Lease.hxx" #include "lib/nfs/Connection.hxx" @@ -66,7 +65,7 @@ class NfsStorage final Mutex mutex; Cond cond; State state; - Error last_error; + std::exception_ptr last_exception; public: NfsStorage(EventLoop &_loop, const char *_base, @@ -102,17 +101,17 @@ public: SetState(State::READY); } - void OnNfsConnectionFailed(gcc_unused const Error &error) final { + void OnNfsConnectionFailed(std::exception_ptr e) final { assert(state == State::CONNECTING); - SetState(State::DELAY, error); + SetState(State::DELAY, std::move(e)); TimeoutMonitor::ScheduleSeconds(60); } - void OnNfsConnectionDisconnected(gcc_unused const Error &error) final { + void OnNfsConnectionDisconnected(std::exception_ptr e) final { assert(state == State::READY); - SetState(State::DELAY, error); + SetState(State::DELAY, std::move(e)); TimeoutMonitor::ScheduleSeconds(5); } @@ -142,13 +141,12 @@ private: cond.broadcast(); } - void SetState(State _state, const Error &error) { + void SetState(State _state, std::exception_ptr &&e) { assert(GetEventLoop().IsInside()); const ScopeLock protect(mutex); state = _state; - last_error.Clear(); - last_error.Set(error); + last_exception = std::move(e); cond.broadcast(); } @@ -168,7 +166,7 @@ private: Connect(); } - bool WaitConnected(Error &error) { + void WaitConnected() { const ScopeLock protect(mutex); while (true) { @@ -184,12 +182,11 @@ private: case State::CONNECTING: case State::READY: - return true; + return; case State::DELAY: - assert(last_error.IsDefined()); - error.Set(last_error); - return false; + assert(last_exception); + std::rethrow_exception(last_exception); } } } @@ -271,8 +268,8 @@ public: :BlockingNfsOperation(_connection), path(_path), info(_info) {} protected: - bool Start(Error &_error) override { - return connection.Stat(path, *this, _error); + void Start() override { + connection.Stat(path, *this); } void HandleResult(gcc_unused unsigned status, void *data) override { @@ -288,11 +285,11 @@ NfsStorage::GetInfo(const char *uri_utf8, gcc_unused bool follow, if (path.empty()) return false; - if (!WaitConnected(error)) - return false; + WaitConnected(); NfsGetInfoOperation operation(*connection, path.c_str(), info); - return operation.Run(error); + operation.Run(); + return true; } gcc_pure @@ -342,8 +339,8 @@ public: } protected: - bool Start(Error &_error) override { - return connection.OpenDirectory(path, *this, _error); + void Start() override { + connection.OpenDirectory(path, *this); } void HandleResult(gcc_unused unsigned status, void *data) override { @@ -386,19 +383,16 @@ NfsStorage::OpenDirectory(const char *uri_utf8, Error &error) if (path.empty()) return nullptr; - if (!WaitConnected(error)) - return nullptr; + WaitConnected(); NfsListDirectoryOperation operation(*connection, path.c_str()); - if (!operation.Run(error)) - return nullptr; + operation.Run(); return operation.ToReader(); } static Storage * -CreateNfsStorageURI(EventLoop &event_loop, const char *base, - Error &error) +CreateNfsStorageURI(EventLoop &event_loop, const char *base, Error &) { if (memcmp(base, "nfs://", 6) != 0) return nullptr; @@ -406,10 +400,8 @@ CreateNfsStorageURI(EventLoop &event_loop, const char *base, const char *p = base + 6; const char *mount = strchr(p, '/'); - if (mount == nullptr) { - error.Set(nfs_domain, "Malformed nfs:// URI"); - return nullptr; - } + if (mount == nullptr) + throw std::runtime_error("Malformed nfs:// URI"); const std::string server(p, mount);