#include "context_switcher/context_switcher.h" #ifdef THREAD_SANITIZER #include "context_switcher/tsan_support.h" #endif namespace context_switcher { #ifdef CS_USE_CSCONTEXT continuation switch_context(continuation &&cont) { continuation_t cont_pointer = cont.consume(); continuation_t result = cscontext::__cs_switch_context(cont_pointer); return continuation{result}; } #endif #if defined(CS_USE_FCONTEXT) and not defined(THREAD_SANITIZER) continuation switch_context(continuation &&cont) { continuation_t cont_pointer = cont.consume(); fcontext::transfer_t transfer = fcontext::jump_fcontext(cont_pointer, (void *) 1); if (transfer.data) { return continuation{transfer.continuation}; } else { return continuation{nullptr}; } } #endif #ifdef THREAD_SANITIZER std::mutex shared_cache_mtx{}; std::unordered_map shared_cached_fibers{}; thread_local std::unordered_map local_cached_fibers{}; void context_loop(fcontext::transfer_t initial_transfer) { continuation successor = continuation{initial_transfer.continuation, initial_transfer.data}; do { continuation_t cont_pointer = successor.consume(); __tsan_switch_to_fiber(successor.get_tsan_fiber(), 0); fcontext::transfer_t transfer = fcontext::jump_fcontext(cont_pointer, nullptr); auto *user_code = static_cast(transfer.data); continuation_t last_cont_pointer = transfer.continuation; successor = user_code->run(last_cont_pointer); user_code->~lambda_capture_base(); } while (successor.valid()); } continuation switch_context(continuation &&cont) { continuation_t cont_pointer = cont.consume(); void *next_fiber = cont.get_tsan_fiber(); void *last_fiber = __tsan_get_current_fiber(); __tsan_switch_to_fiber(next_fiber, 0); fcontext::transfer_t transfer = fcontext::jump_fcontext(cont_pointer, last_fiber); if (transfer.data) { return continuation{transfer.continuation, transfer.data}; } else { return continuation{nullptr, nullptr}; } } #endif }