2018-02-04 03:22:01 +01:00
|
|
|
// Matrix Construct
|
|
|
|
//
|
|
|
|
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
|
|
|
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
|
|
|
//
|
|
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
|
|
// copyright notice and this permission notice is present in all copies. The
|
|
|
|
// full license for this software is available in the LICENSE file.
|
2016-07-26 04:06:31 +02:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
#define HAVE_IRCD_EXCEPTION_H
|
|
|
|
|
2018-03-08 17:34:55 +01:00
|
|
|
/// Forward declarations for boost::system because it is not included here.
|
|
|
|
namespace boost::system
|
|
|
|
{
|
|
|
|
struct error_code;
|
2018-11-09 06:04:07 +01:00
|
|
|
struct error_category;
|
2018-03-08 17:34:55 +01:00
|
|
|
struct system_error;
|
|
|
|
namespace errc {}
|
|
|
|
}
|
|
|
|
|
2017-08-28 23:51:22 +02:00
|
|
|
namespace ircd
|
|
|
|
{
|
2018-11-05 02:18:00 +01:00
|
|
|
struct exception; // Root exception
|
2018-01-11 06:32:32 +01:00
|
|
|
|
|
|
|
// util
|
2018-11-09 09:29:31 +01:00
|
|
|
bool system_category(const std::error_category &) noexcept;
|
|
|
|
bool system_category(const std::error_code &) noexcept;
|
2019-04-04 02:47:59 +02:00
|
|
|
bool system_category(const boost::system::error_code &) noexcept;
|
2018-11-09 09:29:31 +01:00
|
|
|
bool is(const std::error_code &, const std::errc &) noexcept;
|
2019-04-04 02:47:59 +02:00
|
|
|
bool is(const boost::system::error_code &, const std::errc &) noexcept;
|
2019-08-06 01:15:56 +02:00
|
|
|
std::error_code make_error_code(const int &code = errno) noexcept;
|
|
|
|
std::error_code make_error_code(const std::error_code &) noexcept;
|
|
|
|
std::error_code make_error_code(const std::system_error &) noexcept;
|
|
|
|
std::error_code make_error_code(const boost::system::error_code &) noexcept;
|
|
|
|
std::error_code make_error_code(const boost::system::system_error &) noexcept;
|
2018-03-08 18:21:16 +01:00
|
|
|
std::system_error make_system_error(const int &code = errno);
|
2018-11-09 03:07:22 +01:00
|
|
|
std::system_error make_system_error(const std::errc &);
|
|
|
|
std::system_error make_system_error(const std::error_code &);
|
2018-03-08 18:21:16 +01:00
|
|
|
std::system_error make_system_error(const boost::system::error_code &);
|
|
|
|
std::system_error make_system_error(const boost::system::system_error &);
|
2022-07-08 20:37:12 +02:00
|
|
|
[[noreturn]] void throw_system_error();
|
2018-03-08 18:21:16 +01:00
|
|
|
template<class... args> std::exception_ptr make_system_eptr(args&&...);
|
|
|
|
template<class... args> [[noreturn]] void throw_system_error(args&&...);
|
2019-03-16 23:01:46 +01:00
|
|
|
template<class E, class... args> std::exception_ptr make_exception_ptr(args&&...);
|
2018-03-08 18:21:16 +01:00
|
|
|
|
|
|
|
string_view string(const mutable_buffer &, const std::error_code &);
|
|
|
|
string_view string(const mutable_buffer &, const std::system_error &);
|
2018-03-08 17:34:55 +01:00
|
|
|
string_view string(const mutable_buffer &, const boost::system::error_code &);
|
|
|
|
string_view string(const mutable_buffer &, const boost::system::system_error &);
|
2018-03-08 18:21:16 +01:00
|
|
|
std::string string(const std::error_code &);
|
|
|
|
std::string string(const std::system_error &);
|
2018-03-08 17:34:55 +01:00
|
|
|
std::string string(const boost::system::error_code &);
|
|
|
|
std::string string(const boost::system::system_error &);
|
2017-08-28 23:51:22 +02:00
|
|
|
}
|
2016-07-26 04:06:31 +02:00
|
|
|
|
2017-09-12 18:37:44 +02:00
|
|
|
/// The root exception type.
|
|
|
|
///
|
2018-09-05 06:09:12 +02:00
|
|
|
/// All exceptions in the project inherit from this type. We generally don't
|
|
|
|
/// have catch blocks on this type. Instead we use `ircd::error` to catch
|
|
|
|
/// project-specific exceptions. This gives us just a little more indirection
|
|
|
|
/// to play with before inheriting from std::exception.
|
2017-09-12 18:37:44 +02:00
|
|
|
///
|
2018-09-05 06:09:12 +02:00
|
|
|
/// Not all exceptions are from project developer's code, such as
|
|
|
|
/// `std::out_of_range`, etc. It's not necessarily bad to just catch
|
|
|
|
/// `std::exception` and we do it often enough, but be considerate.
|
2017-09-12 18:37:44 +02:00
|
|
|
///
|
2018-09-05 06:09:12 +02:00
|
|
|
/// Remember: Not all exceptions have to inherit from `std::exception` either.
|
|
|
|
/// We have only one example of this: ctx::terminated. To be sure nothing can
|
|
|
|
/// possibly get through you can `catch(...)` but with extreme care that you
|
|
|
|
/// are not discarding a termination which will hang the `ircd::ctx` you're on.
|
2017-09-12 18:37:44 +02:00
|
|
|
///
|
2018-09-05 06:09:12 +02:00
|
|
|
/// !!!
|
|
|
|
/// NOTE: CONTEXT SWITCHES CANNOT OCCUR INSIDE CATCH BLOCKS UNLESS YOU USE THE
|
|
|
|
/// MITIGATION TOOLS PROVIDED IN `ircd::ctx` WHICH RESULT IN THE LOSS OF THE
|
|
|
|
/// ABILITY TO RETHROW THE EXCEPTION (i.e `throw` statement). BEST PRACTICE
|
|
|
|
/// IS TO RETURN CONTROL FROM THE CATCH BLOCK BEFORE CONTEXT SWITCHING.
|
|
|
|
/// !!!
|
2017-08-28 23:51:22 +02:00
|
|
|
struct ircd::exception
|
2019-03-16 23:39:21 +01:00
|
|
|
:virtual std::exception
|
2016-07-26 04:06:31 +02:00
|
|
|
{
|
2022-06-29 01:19:18 +02:00
|
|
|
static constexpr const size_t BUFSIZE
|
2018-08-16 09:20:27 +02:00
|
|
|
{
|
|
|
|
512UL
|
|
|
|
};
|
|
|
|
|
2016-10-17 21:15:26 +02:00
|
|
|
IRCD_OVERLOAD(generate_skip)
|
2019-08-26 20:00:14 +02:00
|
|
|
IRCD_OVERLOAD(hide_name)
|
2016-10-17 21:15:26 +02:00
|
|
|
|
2019-08-26 20:00:14 +02:00
|
|
|
protected:
|
2016-08-15 04:03:25 +02:00
|
|
|
char buf[BUFSIZE];
|
2016-07-26 04:06:31 +02:00
|
|
|
|
2018-12-10 22:08:35 +01:00
|
|
|
ssize_t generate(const char *const &name, const string_view &fmt, const va_rtti &ap) noexcept;
|
|
|
|
ssize_t generate(const string_view &fmt, const va_rtti &ap) noexcept;
|
2016-07-26 04:06:31 +02:00
|
|
|
|
2016-08-15 04:03:25 +02:00
|
|
|
public:
|
2019-05-27 11:55:32 +02:00
|
|
|
const char *what() const noexcept override;
|
2016-07-26 04:06:31 +02:00
|
|
|
|
2020-08-06 04:48:43 +02:00
|
|
|
exception(generate_skip_t = {}) noexcept;
|
2019-03-16 23:39:21 +01:00
|
|
|
exception(exception &&) = delete;
|
|
|
|
exception(const exception &) = delete;
|
|
|
|
exception &operator=(exception &&) = delete;
|
|
|
|
exception &operator=(const exception &) = delete;
|
2022-06-13 23:20:07 +02:00
|
|
|
~exception() noexcept override;
|
2016-08-15 04:03:25 +02:00
|
|
|
};
|
2016-07-26 04:06:31 +02:00
|
|
|
|
2017-09-12 18:37:44 +02:00
|
|
|
/// Exception generator convenience macro
|
|
|
|
///
|
|
|
|
/// If you want to create your own exception type, you have found the right
|
|
|
|
/// place! This macro allows creating an exception in the the hierarchy.
|
|
|
|
///
|
|
|
|
/// To create an exception, invoke this macro in your header. Examples:
|
|
|
|
///
|
|
|
|
/// IRCD_EXCEPTION(ircd::exception, my_exception)
|
|
|
|
/// IRCD_EXCEPTION(my_exception, my_specific_exception)
|
|
|
|
///
|
|
|
|
/// Then your catch sequence can look like the following:
|
|
|
|
///
|
|
|
|
/// catch(const my_specific_exception &e)
|
|
|
|
/// {
|
|
|
|
/// log("something specifically bad happened: %s", e.what());
|
|
|
|
/// }
|
|
|
|
/// catch(const my_exception &e)
|
|
|
|
/// {
|
|
|
|
/// log("something generically bad happened: %s", e.what());
|
|
|
|
/// }
|
|
|
|
/// catch(const ircd::exception &e)
|
|
|
|
/// {
|
|
|
|
/// log("unrelated bad happened: %s", e.what());
|
|
|
|
/// }
|
|
|
|
/// catch(const std::exception &e)
|
|
|
|
/// {
|
|
|
|
/// log("unhandled bad happened: %s", e.what());
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// Remember: the order of the catch blocks is important.
|
|
|
|
///
|
2016-08-15 04:03:25 +02:00
|
|
|
#define IRCD_EXCEPTION(parent, name) \
|
2022-06-14 23:15:53 +02:00
|
|
|
struct [[gnu::visibility("protected")]] name \
|
2016-08-15 04:03:25 +02:00
|
|
|
:parent \
|
|
|
|
{ \
|
2017-03-18 01:37:40 +01:00
|
|
|
template<class... args> \
|
2020-08-06 04:48:43 +02:00
|
|
|
[[gnu::noinline]] \
|
2019-08-26 20:00:14 +02:00
|
|
|
name(hide_name_t, const string_view &fmt, args&&... ap) noexcept \
|
|
|
|
:parent{generate_skip} \
|
|
|
|
{ \
|
|
|
|
generate(fmt, ircd::va_rtti{std::forward<args>(ap)...}); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
template<class... args> \
|
2020-08-06 04:48:43 +02:00
|
|
|
[[gnu::noinline]] \
|
2019-08-26 20:00:14 +02:00
|
|
|
name(hide_name_t, const string_view &fmt = " ") noexcept \
|
|
|
|
:parent{generate_skip} \
|
|
|
|
{ \
|
|
|
|
generate(fmt, ircd::va_rtti{}); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
template<class... args> \
|
2020-08-06 04:48:43 +02:00
|
|
|
[[gnu::noinline]] \
|
2019-06-21 12:17:20 +02:00
|
|
|
name(const string_view &fmt, args&&... ap) noexcept \
|
2016-10-17 21:15:26 +02:00
|
|
|
:parent{generate_skip} \
|
2016-08-15 04:03:25 +02:00
|
|
|
{ \
|
2018-02-03 03:56:30 +01:00
|
|
|
generate(#name, fmt, ircd::va_rtti{std::forward<args>(ap)...}); \
|
2016-08-15 04:03:25 +02:00
|
|
|
} \
|
2016-10-17 21:15:26 +02:00
|
|
|
\
|
2019-06-21 12:17:20 +02:00
|
|
|
template<class... args> \
|
2020-08-06 04:48:43 +02:00
|
|
|
[[gnu::noinline]] \
|
2019-06-21 12:17:20 +02:00
|
|
|
name(const string_view &fmt = " ") noexcept \
|
|
|
|
:parent{generate_skip} \
|
|
|
|
{ \
|
|
|
|
generate(#name, fmt, ircd::va_rtti{}); \
|
|
|
|
} \
|
|
|
|
\
|
2020-08-06 04:48:43 +02:00
|
|
|
[[using gnu: flatten, always_inline]] \
|
2017-03-31 00:46:40 +02:00
|
|
|
name(generate_skip_t) noexcept \
|
2016-10-17 21:15:26 +02:00
|
|
|
:parent{generate_skip} \
|
|
|
|
{ \
|
|
|
|
} \
|
2019-06-21 12:17:20 +02:00
|
|
|
};
|
2016-07-26 04:06:31 +02:00
|
|
|
|
2017-09-12 18:37:44 +02:00
|
|
|
/// Hides the name of the exception when generating a string
|
2016-08-15 04:03:25 +02:00
|
|
|
#define IRCD_EXCEPTION_HIDENAME(parent, name) \
|
2022-06-14 23:15:53 +02:00
|
|
|
struct [[gnu::visibility("protected")]] name \
|
2016-08-15 04:03:25 +02:00
|
|
|
:parent \
|
|
|
|
{ \
|
2017-03-18 01:37:40 +01:00
|
|
|
template<class... args> \
|
2020-08-06 04:48:43 +02:00
|
|
|
[[gnu::noinline]] \
|
2019-06-21 12:17:20 +02:00
|
|
|
name(const string_view &fmt, args&&... ap) noexcept \
|
2017-03-31 00:46:40 +02:00
|
|
|
:parent{generate_skip} \
|
2016-08-15 04:03:25 +02:00
|
|
|
{ \
|
2018-02-03 03:56:30 +01:00
|
|
|
generate(fmt, ircd::va_rtti{std::forward<args>(ap)...}); \
|
2016-10-17 21:15:26 +02:00
|
|
|
} \
|
|
|
|
\
|
2019-06-21 12:17:20 +02:00
|
|
|
template<class... args> \
|
2020-08-06 04:48:43 +02:00
|
|
|
[[gnu::noinline]] \
|
2019-06-21 12:17:20 +02:00
|
|
|
name(const string_view &fmt = " ") noexcept \
|
|
|
|
:parent{generate_skip} \
|
|
|
|
{ \
|
|
|
|
generate(fmt, ircd::va_rtti{}); \
|
|
|
|
} \
|
|
|
|
\
|
2020-08-06 04:48:43 +02:00
|
|
|
[[using gnu: flatten, always_inline]] \
|
2017-03-31 00:46:40 +02:00
|
|
|
name(generate_skip_t = {}) noexcept \
|
2016-10-17 21:15:26 +02:00
|
|
|
:parent{generate_skip} \
|
|
|
|
{ \
|
2016-08-15 04:03:25 +02:00
|
|
|
} \
|
|
|
|
};
|
2016-07-26 04:06:31 +02:00
|
|
|
|
2017-08-28 23:51:22 +02:00
|
|
|
namespace ircd
|
|
|
|
{
|
2017-10-05 03:10:00 +02:00
|
|
|
/// Root error exception type. Inherit from this.
|
|
|
|
/// List your own exception somewhere else (unless you're overhauling libircd).
|
|
|
|
/// example, in your namespace:
|
|
|
|
///
|
|
|
|
/// IRCD_EXCEPTION(ircd::error, error)
|
|
|
|
///
|
2018-01-08 22:26:29 +01:00
|
|
|
IRCD_EXCEPTION(exception, error) // throw ircd::error("something bad")
|
2017-08-28 23:51:22 +02:00
|
|
|
IRCD_EXCEPTION(error, user_error) // throw ircd::user_error("something silly")
|
|
|
|
}
|
2018-03-08 18:21:16 +01:00
|
|
|
|
2019-03-16 23:01:46 +01:00
|
|
|
template<class E,
|
|
|
|
class... args>
|
2022-05-26 21:28:28 +02:00
|
|
|
inline std::exception_ptr
|
2019-03-16 23:01:46 +01:00
|
|
|
ircd::make_exception_ptr(args&&... a)
|
|
|
|
try
|
|
|
|
{
|
|
|
|
throw E{std::forward<args>(a)...};
|
|
|
|
}
|
|
|
|
catch(const E &)
|
|
|
|
{
|
|
|
|
return std::current_exception();
|
|
|
|
};
|
|
|
|
|
2018-03-08 18:21:16 +01:00
|
|
|
template<class... args>
|
2022-05-26 21:28:28 +02:00
|
|
|
inline void
|
2018-03-08 18:21:16 +01:00
|
|
|
ircd::throw_system_error(args&&... a)
|
|
|
|
{
|
2019-04-04 02:47:59 +02:00
|
|
|
throw make_system_error(std::forward<args>(a)...);
|
2018-03-08 18:21:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template<class... args>
|
2022-05-26 21:28:28 +02:00
|
|
|
inline std::exception_ptr
|
2018-03-08 18:21:16 +01:00
|
|
|
ircd::make_system_eptr(args&&... a)
|
|
|
|
{
|
|
|
|
return std::make_exception_ptr(make_system_error(std::forward<args>(a)...));
|
|
|
|
}
|
2020-08-06 04:48:43 +02:00
|
|
|
|
|
|
|
[[gnu::always_inline]]
|
|
|
|
inline
|
|
|
|
ircd::exception::exception(generate_skip_t)
|
|
|
|
noexcept
|
|
|
|
{
|
|
|
|
buf[0] = '\0';
|
|
|
|
}
|