Let's yank all the System-V ucontext switching out of MTasker, massaging it
in to a an implementation neutral, hopefully trivial, pdns_* API.
Stack management and context chaining (similar to ucontexts 'uc_link') are
left exposed, but the implementation is type-erased (void*'d), to force a
clean break. This currently introduces an extra allocation, which hopefully
won't matter once an alternative backend is in place, but means all the
threadWrapper guff can be hidden away.
At the same time, all manual memory management has been removed, with
MThread stacks now being allocated via std::vector with a "lazy_allocator"
which eliminates needless zero-initialization. (Which, compared to a context
switch, is actually quite expensive: diddling 8192 bytes takes ~500ns over
~15 GB/s of memory bandwidth).
pdns_makecontext now takes a std::function object by reference, which must
live until the MThread is started with pdns_swapcontext, at which point it is
std::move'd on to the MThreads stack and can go away. This means a task can
never be started twice (because std::function be empty and throw). I think using
std::function could simplify recursor code, but atm the MTasker makeThread() API
has been left as-is. In MTasker, the MThread start routine is stashed in
ThreadInfo, which also owns the context jointly (via std::shared_ptr) with
any waiters. std::function shouldn't introduce any allocations when used with
trivial function pointers.
In addition, exceptions can hopefully now propagate safely from MThreads
back up to, and through, schedule(), thanks to C++11s exception_ptr.
splitPointer/joinPtr, required to deal with SysVss hairy API, has also been
reimplemented, because master currently still passes one pointer, which only
works on 64-bit thanks to a GNU extension. The new implementation, despite
using memcpy and looking verbose, still compiles down to 2-4 CPU instructions
on each side under GCC -O2, and doesn't depend on any undefined behaviour.