34#ifdef KICAD_USE_VALGRIND
35#include <valgrind/valgrind.h>
37#ifdef KICAD_SANITIZE_THREADS
38#include <sanitizer/tsan_interface.h>
40#ifdef KICAD_SANITIZE_ADDRESS
41#include <sanitizer/asan_interface.h>
44#include <libcontext.h>
82template <
typename ReturnType,
typename ArgType>
106 libcontext::fcontext_t
ctx;
107#ifdef KICAD_SANITIZE_THREADS
114#ifdef KICAD_SANITIZE_THREADS
115 ,tsan_fiber( nullptr )
116 ,own_tsan_fiber( true )
122#ifdef KICAD_SANITIZE_THREADS
125 __tsan_destroy_fiber( tsan_fiber );
155#ifdef KICAD_SANITIZE_THREADS
161 reinterpret_cast<intptr_t
>( &args ) );
189 COROUTINE( T*
object, ReturnType(T::*ptr)( ArgType ) ) :
197 COROUTINE( std::function<ReturnType( ArgType )> aEntry ) :
205#ifdef KICAD_USE_VALGRIND
206 ,m_valgrind_stack( 0 )
208#ifdef KICAD_SANITIZE_ADDRESS
209 ,asan_stack( nullptr )
217#ifdef KICAD_USE_VALGRIND
218 VALGRIND_STACK_DEREGISTER( m_valgrind_stack );
277#ifdef KICAD_SANITIZE_THREADS
279 m_caller.tsan_fiber = __tsan_get_current_fiber();
323#ifdef KICAD_SANITIZE_THREADS
325 m_caller.tsan_fiber = __tsan_get_current_fiber();
385#ifndef LIBCONTEXT_HAS_OWN_STACK
391 std::size_t pages = (
m_stacksize + systemPageSize - 1 ) / systemPageSize;
394 stackSize = ( pages + 1 ) * systemPageSize;
397 m_stack.get_deleter().SetSize( stackSize );
404 sp =
static_cast<char*
>(
m_stack.get() ) + stackSize;
406#ifdef KICAD_USE_VALGRIND
407 m_valgrind_stack = VALGRIND_STACK_REGISTER( sp,
m_stack.get() );
411#ifdef KICAD_SANITIZE_THREADS
413 m_callee.tsan_fiber = __tsan_create_fiber( 0 );
416 __tsan_set_fiber_name(
m_callee.tsan_fiber,
"Coroutine fiber" );
423 return jumpIn( aInvArgs );
426#ifndef LIBCONTEXT_HAS_OWN_STACK
432 void operator()(
void* aMem )
noexcept { ::VirtualFree( aMem, 0, MEM_RELEASE ); }
444 static std::optional<size_t> systemPageSize;
445 if( !systemPageSize.has_value() )
449 ::GetSystemInfo( &si );
450 systemPageSize =
static_cast<size_t>( si.dwPageSize );
452 int size = getpagesize();
453 systemPageSize =
static_cast<size_t>( size );
456 return systemPageSize.value();
463 void* mem = ::VirtualAlloc( 0, aAllocSize, MEM_COMMIT, PAGE_READWRITE );
466 throw std::bad_alloc();
468 void* mem = ::mmap( 0, aAllocSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 );
470 if( mem == (
void*) -1 )
471 throw std::bad_alloc();
477 static inline void GuardMemory(
void* aAddress,
size_t aGuardSize )
481 BOOL
res = ::VirtualProtect( aAddress, aGuardSize,
482 PAGE_READWRITE | PAGE_GUARD, &old_prot );
484 bool res = ( 0 == ::mprotect( aAddress, aGuardSize, PROT_NONE ) );
518#ifdef KICAD_SANITIZE_THREADS
520 __tsan_switch_to_fiber(
m_callee.tsan_fiber, 0 );
527 reinterpret_cast<intptr_t
>( args ) )
538#ifdef KICAD_SANITIZE_THREADS
540 __tsan_switch_to_fiber(
m_caller.tsan_fiber, 0 );
547 reinterpret_cast<intptr_t
>( &args ) )
558#ifndef LIBCONTEXT_HAS_OWN_STACK
560 std::unique_ptr<char[], struct STACK_DELETER>
m_stack;
565 std::function<ReturnType( ArgType )>
m_func;
571 typename std::remove_reference<ArgType>::type*
m_args;
584#ifdef KICAD_USE_VALGRIND
585 uint32_t m_valgrind_stack;
587#ifdef KICAD_SANITIZE_ADDRESS
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
CONTEXT_T * m_mainStackContext
void SetMainStack(CONTEXT_T *aStack)
void RunMainStack(COROUTINE *aCor, std::function< void()> aFunc)
void Continue(INVOCATION_ARGS *args)
std::function< void()> m_mainStackFunction
bool Call(ArgType aArg)
Start execution of a coroutine, passing args as its arguments.
CALL_CONTEXT * m_callContext
saved coroutine context
void KiYield(ReturnType &aRetVal)
KiYield with a value.
void KiYield()
Stop execution of the coroutine and returns control to the caller.
CONTEXT_T m_caller
main stack information
bool Resume()
Resume execution of a previously yielded coroutine.
COROUTINE(std::function< ReturnType(ArgType)> aEntry)
Create a coroutine from a delegate object.
static void callerStub(intptr_t aData)
INVOCATION_ARGS * jumpIn(INVOCATION_ARGS *args)
std::unique_ptr< char[], struct STACK_DELETER > m_stack
const ReturnType & ReturnValue() const
Return the yielded value (the argument KiYield() was called with).
INVOCATION_ARGS * doResume(INVOCATION_ARGS *args)
bool m_running
pointer to coroutine entry arguments.
static void * MapMemory(size_t aAllocSize)
Change protection of memory page(s) to act as stack guards.
static size_t SystemPageSize()
Map a page-aligned memory region into our address space.
INVOCATION_ARGS * doCall(INVOCATION_ARGS *aInvArgs, ArgType aArgs)
A functor that frees the stack.
bool Call(const COROUTINE &aCor, ArgType aArg)
Start execution of a coroutine, passing args as its arguments.
std::function< ReturnType(ArgType)> m_func
static void GuardMemory(void *aAddress, size_t aGuardSize)
bool Resume(const COROUTINE &aCor)
Resume execution of a previously yielded coroutine.
COROUTINE(T *object, ReturnType(T::*ptr)(ArgType))
Create a coroutine from a member method of an object.
void RunMainStack(std::function< void()> func)
Run a functor inside the application main stack context.
void jumpOut()
coroutine stack
std::remove_reference< ArgType >::type * m_args
saved caller context
int m_CoroutineStackSize
Configure the coroutine stack size in bytes.
const wxChar *const kicadTraceCoroutineStack
Flag to enable tracing of the coroutine call stack.
libcontext::fcontext_t ctx
enum COROUTINE::INVOCATION_ARGS::@35 type
The size of the mappable memory page size.
void SetSize(std::size_t aSize)
void operator()(void *aMem) noexcept
wxLogTrace helper definitions.