AS_IF([test "x$enable_asan" != "xno"], [
gl_COMPILER_OPTION_IF([-fsanitize=address],
- [SANITIZER_FLAGS="-fsanitize=address $SANITIZER_FLAGS"],
+ [
+ [SANITIZER_FLAGS="-fsanitize=address $SANITIZER_FLAGS"]
+ AC_CHECK_HEADERS([sanitizer/common_interface_defs.h], asan_headers=yes, asan_headers=no)
+ AS_IF([test x"$asan_headers" = "xyes" ],
+ [AC_CHECK_DECL(__sanitizer_start_switch_fiber,
+ [ AC_DEFINE([HAVE_FIBER_SANITIZER], [1], [Define if ASAN fiber annotation interface is available.]) ],
+ [ ],
+ [#include <sanitizer/common_interface_defs.h>]
+ )]
+ )
+ ],
[AC_MSG_ERROR([Cannot enable AddressSanitizer])]
)
])
unsigned int diff=d_threads[d_tid].dt.ndiff()/1000;
d_threads[d_tid].totTime+=diff;
#endif
+ notifyStackSwitchToKernel();
pdns_swapcontext(*d_waiters.find(key)->context,d_kernel); // 'A' will return here when 'key' has arrived, hands over control to kernel first
+ notifyStackSwitchDone();
#ifdef MTASKERTIMING
d_threads[d_tid].dt.start();
#endif
template<class Key, class Val>void MTasker<Key,Val>::yield()
{
d_runQueue.push(d_tid);
+ notifyStackSwitchToKernel();
pdns_swapcontext(*d_threads[d_tid].context ,d_kernel); // give control to the kernel
+ notifyStackSwitchDone();
}
//! reports that an event took place for which threads may be waiting
d_tid=waiter->tid; // set tid
d_eventkey=waiter->key; // pass waitEvent the exact key it was woken for
auto userspace=std::move(waiter->context);
- d_waiters.erase(waiter); // removes the waitpoint
+ d_waiters.erase(waiter); // removes the waitpoint
+ notifyStackSwitch(d_threads[d_tid].startOfStack, d_stacksize);
pdns_swapcontext(d_kernel,*userspace); // swaps back to the above point 'A'
+ notifyStackSwitchDone();
return 1;
}
#ifdef MTASKERTIMING
d_threads[d_tid].dt.start();
#endif
+ notifyStackSwitch(d_threads[d_tid].startOfStack, d_stacksize);
pdns_swapcontext(d_kernel, *d_threads[d_tid].context);
-
+ notifyStackSwitchDone();
+
d_runQueue.pop();
return true;
}
d_eventkey=i->key; // pass waitEvent the exact key it was woken for
auto uc = i->context;
d_tid = i->tid;
- ttdindex.erase(i++); // removes the waitpoint
+ ttdindex.erase(i++); // removes the waitpoint
+ notifyStackSwitch(d_threads[d_tid].startOfStack, d_stacksize);
pdns_swapcontext(d_kernel, *uc); // swaps back to the above point 'A'
+ notifyStackSwitchDone();
}
else if(i->ttd.tv_sec)
break;
waiters_t d_waiters;
+ void initMainStackBounds()
+ {
+#ifdef HAVE_FIBER_SANITIZER
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_getattr_np(pthread_self(), &attr);
+ pthread_attr_getstack(&attr, &t_mainStack, &t_mainStackSize);
+ pthread_attr_destroy(&attr);
+#endif /* HAVE_FIBER_SANITIZER */
+ }
+
//! Constructor
/** Constructor with a small default stacksize. If any of your threads exceeds this stack, your application will crash.
This limit applies solely to the stack, the heap is not limited in any way. If threads need to allocate a lot of data,
*/
MTasker(size_t stacksize=8192) : d_tid(0), d_maxtid(0), d_stacksize(stacksize), d_waitstatus(Error)
{
+ initMainStackBounds();
}
typedef void tfunc_t(void *); //!< type of the pointer that starts a thread
pdns_makecontext
(pdns_ucontext_t& ctx, boost::function<void(void)>& start);
+#ifdef HAVE_FIBER_SANITIZER
+#include <sanitizer/common_interface_defs.h>
+#endif /* HAVE_FIBER_SANITIZER */
+
+#ifdef HAVE_FIBER_SANITIZER
+extern __thread void* t_mainStack;
+extern __thread size_t t_mainStackSize;
+#endif /* HAVE_FIBER_SANITIZER */
+
+static inline void notifyStackSwitch(void* startOfStack, size_t stackSize)
+{
+#ifdef HAVE_FIBER_SANITIZER
+ __sanitizer_start_switch_fiber(nullptr, startOfStack, stackSize);
+#endif /* HAVE_FIBER_SANITIZER */
+}
+
+static inline void notifyStackSwitchToKernel()
+{
+#ifdef HAVE_FIBER_SANITIZER
+ notifyStackSwitch(t_mainStack, t_mainStackSize);
+#endif /* HAVE_FIBER_SANITIZER */
+}
+
+static inline void notifyStackSwitchDone()
+{
+#ifdef HAVE_FIBER_SANITIZER
+ __sanitizer_finish_switch_fiber(nullptr);
+#endif /* HAVE_FIBER_SANITIZER */
+}
+
+
#endif // MTASKER_CONTEXT_HH
#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
* 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 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);
*ptr = res.fctx;
}
#endif
+ notifyStackSwitchDone();
args = nullptr;
try {
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
args.self = &ctx;
args.work = &start;
/* jumping to threadwrapper */
+ notifyStackSwitch(&ctx.uc_stack[ctx.uc_stack.size()], ctx.uc_stack.size());
#if BOOST_VERSION < 106100
jump_fcontext (reinterpret_cast<fcontext_t*>(&args.prev_ctx),
static_cast<fcontext_t>(ctx.uc_mcontext),
/* back from threadwrapper, updating the context */
ctx.uc_mcontext = res.fctx;
#endif
+ notifyStackSwitchDone();
+
}
#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) {
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<boost::function<void()>>(fun0, fun1));
} catch (...) {
ctx->exception = std::current_exception();
}
+ notifyStackSwitchToKernel();
}
} // extern "C"