dep_boost_context = dependency('boost', modules: ['context'], required: true)
-# Fixed value, we no longer support SystemV
-conf.set('HAVE_BOOST_CONTEXT', true)
-summary('Context', dep_boost_context.found(), bool_yn: true, section: 'Boost')
lua_hpp.mk \
malloctrace.cc malloctrace.hh \
mkpubsuffixcc \
- mtasker_fcontext.cc mtasker_ucontext.cc \
NOTICE \
opensslsigners.hh opensslsigners.cc \
portsmplexer.cc \
PDNS_CHECK_CLOCK_GETTIME
BOOST_REQUIRE([1.54])
-
-# Boost Context was introduced in 1.51 (Aug 2012), but there was an immediate
-# API break in 1.52 (Nov 2012), so we only support that, and later.
-pdns_context_library=""
-AS_IF([test $boost_major_version -ge 152], [BOOST_CONTEXT([], [no])])
-AS_IF([test x"$boost_cv_lib_context" = "xyes"], [
- pdns_context_library="Boost Context"
-], [
- AC_CHECK_FUNCS([getcontext makecontext swapcontext], [pdns_context_library="System V ucontexts"])
-])
-AC_MSG_CHECKING([what context library to use for MTasker])
-AS_IF([test -n "$pdns_context_library"], [AC_MSG_RESULT([$pdns_context_library])], [AC_MSG_ERROR([neither boost::context nor System V ucontexts available])])
+BOOST_CONTEXT([], [yes])]
PDNS_ENABLE_UNIT_TESTS
PDNS_ENABLE_REPRODUCIBLE
[AC_MSG_NOTICE([libcurl: yes])],
[AC_MSG_NOTICE([libcurl: no])]
)
-AC_MSG_NOTICE([Context library: $pdns_context_library])
AC_MSG_NOTICE([])
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifdef HAVE_CONFIG_H
+
#include "config.h"
+#include "mtasker_context.hh"
+#include <exception>
+#include <cassert>
+#include <type_traits>
+#include <boost/version.hpp>
+#if BOOST_VERSION < 106100
+#include <boost/context/fcontext.hpp>
+using boost::context::make_fcontext;
+#else
+#include <boost/context/detail/fcontext.hpp>
+using boost::context::detail::make_fcontext;
+#endif /* BOOST_VERSION < 106100 */
+
+// __CET__ is set by the compiler if relevant, so far only relevant/tested for amd64 on OpenBSD
+#if defined(__amd64__)
+#if __CET__ & 0x1
+#define CET_ENDBR __asm("endbr64")
+#else
+#define CET_ENDBR
+#endif
+#else
+#define CET_ENDBR
+#endif
+
+#ifdef PDNS_USE_VALGRIND
+#include <valgrind/valgrind.h>
+#endif /* PDNS_USE_VALGRIND */
+
+#ifdef HAVE_FIBER_SANITIZER
+__thread void* t_mainStack{nullptr};
+__thread size_t t_mainStackSize{0};
+#endif /* HAVE_FIBER_SANITIZER */
+
+#if BOOST_VERSION < 105600
+/* Note: This typedef means functions taking fcontext_t*, like jump_fcontext(),
+ * now require a reinterpret_cast rather than a static_cast, since we're
+ * casting from pdns_context_t->uc_mcontext, which is void**, to
+ * some_opaque_struct**. In later versions fcontext_t is already void*. So if
+ * you remove this, then fix the ugly.
+ */
+using fcontext_t = boost::context::fcontext_t*;
+
+/* Emulate the >= 1.56 API for Boost 1.52 through 1.55 */
+static inline intptr_t
+jump_fcontext(fcontext_t* const ofc, fcontext_t const nfc,
+ intptr_t const arg)
+{
+ /* If the fcontext_t is preallocated then use it, otherwise allocate one
+ * on the stack ('self') and stash a pointer away in *ofc so the returning
+ * MThread can access it. This is safe because we're suspended, so the
+ * context object always outlives the jump.
+ */
+ if (*ofc) {
+ return boost::context::jump_fcontext(*ofc, nfc, arg);
+ }
+ else {
+ boost::context::fcontext_t self;
+ *ofc = &self;
+ auto ret = boost::context::jump_fcontext(*ofc, nfc, arg);
+ *ofc = nullptr;
+ return ret;
+ }
+}
+#else
+
+#if BOOST_VERSION < 106100
+using boost::context::fcontext_t;
+using boost::context::jump_fcontext;
+#else
+using boost::context::detail::fcontext_t;
+using boost::context::detail::jump_fcontext;
+using boost::context::detail::transfer_t;
+#endif /* BOOST_VERSION < 106100 */
+
+static_assert(std::is_pointer<fcontext_t>::value,
+ "Boost Context has changed the fcontext_t type again :-(");
+#endif
+
+/* Boost context only provides a means of passing a single argument across a
+ * jump. args_t simply provides a way to pass more by reference.
+ */
+struct args_t
+{
+#if BOOST_VERSION < 106100
+ fcontext_t prev_ctx = nullptr;
+#endif
+ pdns_ucontext_t* self = nullptr;
+ std::function<void(void)>* work = nullptr;
+};
+
+extern "C"
+{
+ static void
+#if BOOST_VERSION < 106100
+ threadWrapper(intptr_t const xargs)
+ {
+#else
+ threadWrapper(transfer_t const t)
+ {
+#endif
+ /* Access the args passed from pdns_makecontext, and copy them directly from
+ * the calling stack on to ours (we're now using the MThreads stack).
+ * This saves heap allocating an args object, at the cost of an extra
+ * context switch to fashion this constructor-like init phase. The work
+ * function object is still only moved after we're (re)started, so may
+ * still be set or changed after a call to pdns_makecontext. This matches
+ * the behaviour of the System V implementation, which can inherently only
+ * be passed ints and pointers.
+ */
+ notifyStackSwitchDone();
+#if BOOST_VERSION < 106100
+ auto args = reinterpret_cast<args_t*>(xargs);
+#else
+ auto args = reinterpret_cast<args_t*>(t.data);
+#endif
+ auto ctx = args->self;
+ auto work = args->work;
+ /* we switch back to pdns_makecontext() */
+ notifyStackSwitchToKernel();
+#if BOOST_VERSION < 106100
+ jump_fcontext(reinterpret_cast<fcontext_t*>(&ctx->uc_mcontext),
+ static_cast<fcontext_t>(args->prev_ctx), 0);
+#else
+ transfer_t res = jump_fcontext(t.fctx, 0);
+ CET_ENDBR;
+ /* we got switched back from pdns_swapcontext() */
+ if (res.data) {
+ /* if res.data is not a nullptr, it holds a pointer to the context
+ we just switched from, and we need to fill it to be able to
+ switch back to it later. */
+ fcontext_t* ptr = static_cast<fcontext_t*>(res.data);
+ *ptr = res.fctx;
+ }
+#endif
+ notifyStackSwitchDone();
+ args = nullptr;
+
+ try {
+ auto start = std::move(*work);
+ start();
+ }
+ catch (...) {
+ ctx->exception = std::current_exception();
+ }
+
+ notifyStackSwitchToKernel();
+ /* Emulate the System V uc_link feature. */
+ auto const next_ctx = ctx->uc_link->uc_mcontext;
+#if BOOST_VERSION < 106100
+ jump_fcontext(reinterpret_cast<fcontext_t*>(&ctx->uc_mcontext),
+ static_cast<fcontext_t>(next_ctx),
+ reinterpret_cast<intptr_t>(ctx));
+#else
+ jump_fcontext(static_cast<fcontext_t>(next_ctx), 0);
+#endif
+
+#ifdef NDEBUG
+ __builtin_unreachable();
+#endif
+ }
+}
+
+pdns_ucontext_t::pdns_ucontext_t() :
+ uc_mcontext(nullptr), uc_link(nullptr)
+{
+#ifdef PDNS_USE_VALGRIND
+ valgrind_id = 0;
+#endif /* PDNS_USE_VALGRIND */
+}
+
+pdns_ucontext_t::~pdns_ucontext_t()
+{
+ /* There's nothing to delete here since fcontext doesn't require anything
+ * to be heap allocated.
+ */
+#ifdef PDNS_USE_VALGRIND
+ if (valgrind_id != 0) {
+ VALGRIND_STACK_DEREGISTER(valgrind_id);
+ }
+#endif /* PDNS_USE_VALGRIND */
+}
+
+void pdns_swapcontext(pdns_ucontext_t& __restrict octx, pdns_ucontext_t const& __restrict ctx)
+{
+ /* we either switch back to threadwrapper() if it's the first time,
+ or we switch back to pdns_swapcontext(),
+ in both case we will be returning from a call to jump_fcontext(). */
+#if BOOST_VERSION < 106100
+ intptr_t ptr = jump_fcontext(reinterpret_cast<fcontext_t*>(&octx.uc_mcontext),
+ static_cast<fcontext_t>(ctx.uc_mcontext), 0);
+
+ auto origctx = reinterpret_cast<pdns_ucontext_t*>(ptr);
+ if (origctx && origctx->exception)
+ std::rethrow_exception(origctx->exception);
+#else
+ transfer_t res = jump_fcontext(static_cast<fcontext_t>(ctx.uc_mcontext), &octx.uc_mcontext);
+ CET_ENDBR;
+ if (res.data) {
+ /* if res.data is not a nullptr, it holds a pointer to the context
+ we just switched from, and we need to fill it to be able to
+ switch back to it later. */
+ fcontext_t* ptr = static_cast<fcontext_t*>(res.data);
+ *ptr = res.fctx;
+ }
+ if (ctx.exception) {
+ std::rethrow_exception(ctx.exception);
+ }
#endif
+}
-#if defined(HAVE_BOOST_CONTEXT)
-#include "mtasker_fcontext.cc" // NOLINT(bugprone-suspicious-include)
+void pdns_makecontext(pdns_ucontext_t& ctx, std::function<void(void)>& start)
+{
+ assert(ctx.uc_link);
+ assert(ctx.uc_stack.size() >= 8192);
+ assert(!ctx.uc_mcontext);
+ ctx.uc_mcontext = make_fcontext(&ctx.uc_stack[ctx.uc_stack.size() - 1],
+ ctx.uc_stack.size() - 1, &threadWrapper);
+ args_t args;
+ args.self = &ctx;
+ args.work = &start;
+ /* jumping to threadwrapper */
+ notifyStackSwitch(&ctx.uc_stack[ctx.uc_stack.size() - 1], ctx.uc_stack.size() - 1);
+#if BOOST_VERSION < 106100
+ jump_fcontext(reinterpret_cast<fcontext_t*>(&args.prev_ctx),
+ static_cast<fcontext_t>(ctx.uc_mcontext),
+ reinterpret_cast<intptr_t>(&args));
#else
-#include "mtasker_ucontext.cc" // NOLINT(bugprone-suspicious-include)
+ transfer_t res = jump_fcontext(static_cast<fcontext_t>(ctx.uc_mcontext),
+ &args);
+ CET_ENDBR;
+ /* back from threadwrapper, updating the context */
+ ctx.uc_mcontext = res.fctx;
#endif
+ notifyStackSwitchDone();
+}
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * 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 "mtasker_context.hh"
-#include <exception>
-#include <cassert>
-#include <type_traits>
-#include <boost/version.hpp>
-#if BOOST_VERSION < 106100
-#include <boost/context/fcontext.hpp>
-using boost::context::make_fcontext;
-#else
-#include <boost/context/detail/fcontext.hpp>
-using boost::context::detail::make_fcontext;
-#endif /* BOOST_VERSION < 106100 */
-
-// __CET__ is set by the compiler if relevant, so far only relevant/tested for amd64 on OpenBSD
-#if defined(__amd64__)
-#if __CET__ & 0x1
-#define CET_ENDBR __asm("endbr64")
-#else
-#define CET_ENDBR
-#endif
-#else
-#define CET_ENDBR
-#endif
-
-#ifdef PDNS_USE_VALGRIND
-#include <valgrind/valgrind.h>
-#endif /* PDNS_USE_VALGRIND */
-
-#ifdef HAVE_FIBER_SANITIZER
-__thread void* t_mainStack{nullptr};
-__thread size_t t_mainStackSize{0};
-#endif /* HAVE_FIBER_SANITIZER */
-
-#if BOOST_VERSION < 105600
-/* Note: This typedef means functions taking fcontext_t*, like jump_fcontext(),
- * now require a reinterpret_cast rather than a static_cast, since we're
- * casting from pdns_context_t->uc_mcontext, which is void**, to
- * some_opaque_struct**. In later versions fcontext_t is already void*. So if
- * you remove this, then fix the ugly.
- */
-using fcontext_t = boost::context::fcontext_t*;
-
-/* Emulate the >= 1.56 API for Boost 1.52 through 1.55 */
-static inline intptr_t
-jump_fcontext(fcontext_t* const ofc, fcontext_t const nfc,
- intptr_t const arg)
-{
- /* If the fcontext_t is preallocated then use it, otherwise allocate one
- * on the stack ('self') and stash a pointer away in *ofc so the returning
- * MThread can access it. This is safe because we're suspended, so the
- * context object always outlives the jump.
- */
- if (*ofc) {
- return boost::context::jump_fcontext(*ofc, nfc, arg);
- }
- else {
- boost::context::fcontext_t self;
- *ofc = &self;
- auto ret = boost::context::jump_fcontext(*ofc, nfc, arg);
- *ofc = nullptr;
- return ret;
- }
-}
-#else
-
-#if BOOST_VERSION < 106100
-using boost::context::fcontext_t;
-using boost::context::jump_fcontext;
-#else
-using boost::context::detail::fcontext_t;
-using boost::context::detail::jump_fcontext;
-using boost::context::detail::transfer_t;
-#endif /* BOOST_VERSION < 106100 */
-
-static_assert(std::is_pointer<fcontext_t>::value,
- "Boost Context has changed the fcontext_t type again :-(");
-#endif
-
-/* Boost context only provides a means of passing a single argument across a
- * jump. args_t simply provides a way to pass more by reference.
- */
-struct args_t
-{
-#if BOOST_VERSION < 106100
- fcontext_t prev_ctx = nullptr;
-#endif
- pdns_ucontext_t* self = nullptr;
- std::function<void(void)>* work = nullptr;
-};
-
-extern "C"
-{
- static void
-#if BOOST_VERSION < 106100
- threadWrapper(intptr_t const xargs)
- {
-#else
- threadWrapper(transfer_t const t)
- {
-#endif
- /* Access the args passed from pdns_makecontext, and copy them directly from
- * the calling stack on to ours (we're now using the MThreads stack).
- * This saves heap allocating an args object, at the cost of an extra
- * context switch to fashion this constructor-like init phase. The work
- * function object is still only moved after we're (re)started, so may
- * still be set or changed after a call to pdns_makecontext. This matches
- * the behaviour of the System V implementation, which can inherently only
- * be passed ints and pointers.
- */
- notifyStackSwitchDone();
-#if BOOST_VERSION < 106100
- auto args = reinterpret_cast<args_t*>(xargs);
-#else
- auto args = reinterpret_cast<args_t*>(t.data);
-#endif
- auto ctx = args->self;
- auto work = args->work;
- /* we switch back to pdns_makecontext() */
- notifyStackSwitchToKernel();
-#if BOOST_VERSION < 106100
- jump_fcontext(reinterpret_cast<fcontext_t*>(&ctx->uc_mcontext),
- static_cast<fcontext_t>(args->prev_ctx), 0);
-#else
- transfer_t res = jump_fcontext(t.fctx, 0);
- CET_ENDBR;
- /* we got switched back from pdns_swapcontext() */
- if (res.data) {
- /* if res.data is not a nullptr, it holds a pointer to the context
- we just switched from, and we need to fill it to be able to
- switch back to it later. */
- fcontext_t* ptr = static_cast<fcontext_t*>(res.data);
- *ptr = res.fctx;
- }
-#endif
- notifyStackSwitchDone();
- args = nullptr;
-
- try {
- auto start = std::move(*work);
- start();
- }
- catch (...) {
- ctx->exception = std::current_exception();
- }
-
- notifyStackSwitchToKernel();
- /* Emulate the System V uc_link feature. */
- auto const next_ctx = ctx->uc_link->uc_mcontext;
-#if BOOST_VERSION < 106100
- jump_fcontext(reinterpret_cast<fcontext_t*>(&ctx->uc_mcontext),
- static_cast<fcontext_t>(next_ctx),
- reinterpret_cast<intptr_t>(ctx));
-#else
- jump_fcontext(static_cast<fcontext_t>(next_ctx), 0);
-#endif
-
-#ifdef NDEBUG
- __builtin_unreachable();
-#endif
- }
-}
-
-pdns_ucontext_t::pdns_ucontext_t() :
- uc_mcontext(nullptr), uc_link(nullptr)
-{
-#ifdef PDNS_USE_VALGRIND
- valgrind_id = 0;
-#endif /* PDNS_USE_VALGRIND */
-}
-
-pdns_ucontext_t::~pdns_ucontext_t()
-{
- /* There's nothing to delete here since fcontext doesn't require anything
- * to be heap allocated.
- */
-#ifdef PDNS_USE_VALGRIND
- if (valgrind_id != 0) {
- VALGRIND_STACK_DEREGISTER(valgrind_id);
- }
-#endif /* PDNS_USE_VALGRIND */
-}
-
-void pdns_swapcontext(pdns_ucontext_t& __restrict octx, pdns_ucontext_t const& __restrict ctx)
-{
- /* we either switch back to threadwrapper() if it's the first time,
- or we switch back to pdns_swapcontext(),
- in both case we will be returning from a call to jump_fcontext(). */
-#if BOOST_VERSION < 106100
- intptr_t ptr = jump_fcontext(reinterpret_cast<fcontext_t*>(&octx.uc_mcontext),
- static_cast<fcontext_t>(ctx.uc_mcontext), 0);
-
- auto origctx = reinterpret_cast<pdns_ucontext_t*>(ptr);
- if (origctx && origctx->exception)
- std::rethrow_exception(origctx->exception);
-#else
- transfer_t res = jump_fcontext(static_cast<fcontext_t>(ctx.uc_mcontext), &octx.uc_mcontext);
- CET_ENDBR;
- if (res.data) {
- /* if res.data is not a nullptr, it holds a pointer to the context
- we just switched from, and we need to fill it to be able to
- switch back to it later. */
- fcontext_t* ptr = static_cast<fcontext_t*>(res.data);
- *ptr = res.fctx;
- }
- if (ctx.exception) {
- std::rethrow_exception(ctx.exception);
- }
-#endif
-}
-
-void pdns_makecontext(pdns_ucontext_t& ctx, std::function<void(void)>& start)
-{
- assert(ctx.uc_link);
- assert(ctx.uc_stack.size() >= 8192);
- assert(!ctx.uc_mcontext);
- ctx.uc_mcontext = make_fcontext(&ctx.uc_stack[ctx.uc_stack.size() - 1],
- ctx.uc_stack.size() - 1, &threadWrapper);
- args_t args;
- args.self = &ctx;
- args.work = &start;
- /* jumping to threadwrapper */
- notifyStackSwitch(&ctx.uc_stack[ctx.uc_stack.size() - 1], ctx.uc_stack.size() - 1);
-#if BOOST_VERSION < 106100
- jump_fcontext(reinterpret_cast<fcontext_t*>(&args.prev_ctx),
- static_cast<fcontext_t>(ctx.uc_mcontext),
- reinterpret_cast<intptr_t>(&args));
-#else
- transfer_t res = jump_fcontext(static_cast<fcontext_t>(ctx.uc_mcontext),
- &args);
- CET_ENDBR;
- /* back from threadwrapper, updating the context */
- ctx.uc_mcontext = res.fctx;
-#endif
- notifyStackSwitchDone();
-}
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * 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 "mtasker_context.hh"
-#include <system_error>
-#include <exception>
-#include <cstring>
-#include <cassert>
-#include <csignal>
-#include <cstdint>
-#include <ucontext.h>
-
-#ifdef PDNS_USE_VALGRIND
-#include <valgrind/valgrind.h>
-#endif /* PDNS_USE_VALGRIND */
-
-#ifdef HAVE_FIBER_SANITIZER
-__thread void* t_mainStack{nullptr};
-__thread size_t t_mainStackSize{0};
-#endif /* HAVE_FIBER_SANITIZER */
-
-template <typename Message>
-static __attribute__((noinline, cold, noreturn)) void
-throw_errno(Message&& msg)
-{
- throw std::system_error(errno, std::system_category(), std::forward<Message>(msg));
-}
-
-static inline std::pair<int, int>
-splitPointer(void* const ptr) noexcept
-{
- static_assert(sizeof(int) == 4, "splitPointer() requires an 4 byte 'int'");
- // In theory, we need this assertion. In practice, it prevents compilation
- // on EL6 i386. Without the assertion, everything works.
- // If you ever run into trouble with this code, please heed the warnings at
- // http://man7.org/linux/man-pages/man3/makecontext.3.html#NOTES
- // static_assert (sizeof(uintptr_t) == 8,
- // "splitPointer() requires an 8 byte 'uintptr_t'");
- std::pair<int, int> words;
- auto rep = reinterpret_cast<uintptr_t>(ptr);
- uint32_t const hw = rep >> 32;
- auto const lw = static_cast<uint32_t>(rep);
- std::memcpy(&words.first, &hw, 4);
- std::memcpy(&words.second, &lw, 4);
- return words;
-}
-
-template <typename T>
-static inline T*
-joinPtr(int const first, int const second) noexcept
-{
- static_assert(sizeof(int) == 4, "joinPtr() requires an 4 byte 'int'");
- // See above.
- // static_assert (sizeof(uintptr_t) == 8,
- // "joinPtr() requires an 8 byte 'uintptr_t'");
- uint32_t hw;
- uint32_t lw;
- std::memcpy(&hw, &first, 4);
- std::memcpy(&lw, &second, 4);
- return reinterpret_cast<T*>((static_cast<uintptr_t>(hw) << 32) | lw);
-}
-
-extern "C"
-{
- static void
- threadWrapper(int const ctx0, int const ctx1, int const fun0, int const fun1)
- {
- notifyStackSwitchDone();
- auto ctx = joinPtr<pdns_ucontext_t>(ctx0, ctx1);
- try {
- auto start = std::move(*joinPtr<std::function<void()>>(fun0, fun1));
- start();
- }
- catch (...) {
- ctx->exception = std::current_exception();
- }
- notifyStackSwitchToKernel();
- }
-} // extern "C"
-
-pdns_ucontext_t::pdns_ucontext_t()
-{
- uc_mcontext = new ::ucontext_t();
- uc_link = nullptr;
-#ifdef PDNS_USE_VALGRIND
- valgrind_id = 0;
-#endif /* PDNS_USE_VALGRIND */
-}
-
-pdns_ucontext_t::~pdns_ucontext_t()
-{
- delete static_cast<ucontext_t*>(uc_mcontext);
-#ifdef PDNS_USE_VALGRIND
- if (valgrind_id != 0) {
- VALGRIND_STACK_DEREGISTER(valgrind_id);
- }
-#endif /* PDNS_USE_VALGRIND */
-}
-
-void pdns_swapcontext(pdns_ucontext_t& __restrict octx, pdns_ucontext_t const& __restrict ctx)
-{
- if (::swapcontext(static_cast<ucontext_t*>(octx.uc_mcontext),
- static_cast<ucontext_t*>(ctx.uc_mcontext))) {
- throw_errno("swapcontext() failed");
- }
- if (ctx.exception) {
- std::rethrow_exception(ctx.exception);
- }
-}
-
-void pdns_makecontext(pdns_ucontext_t& ctx, std::function<void(void)>& start)
-{
- assert(ctx.uc_link);
- assert(ctx.uc_stack.size());
-
- auto const mcp = static_cast<ucontext_t*>(ctx.uc_mcontext);
- auto const next = static_cast<ucontext_t*>(ctx.uc_link->uc_mcontext);
- if (::getcontext(mcp)) {
- throw_errno("getcontext() failed");
- }
- mcp->uc_link = next;
- mcp->uc_stack.ss_sp = ctx.uc_stack.data();
- mcp->uc_stack.ss_size = ctx.uc_stack.size() - 1;
- mcp->uc_stack.ss_flags = 0;
-
- auto ctxarg = splitPointer(&ctx);
- auto funarg = splitPointer(&start);
- return ::makecontext(mcp, reinterpret_cast<void (*)(void)>(&threadWrapper),
- 4, ctxarg.first, ctxarg.second,
- funarg.first, funarg.second);
-}
#ifdef HAVE_LIBDECAF
<< " decaf"
#endif
-#ifdef HAVE_BOOST_CONTEXT
- << " fcontext"
-#endif
#ifdef HAVE_LIBCRYPTO_ECDSA
<< " libcrypto-ecdsa"
#endif