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>
107 libcontext::fcontext_t
ctx;
109#ifdef KICAD_SANITIZE_THREADS
116#ifdef KICAD_SANITIZE_THREADS
117 ,tsan_fiber( nullptr )
118 ,own_tsan_fiber( true )
124#ifdef KICAD_SANITIZE_THREADS
127 __tsan_destroy_fiber( tsan_fiber );
157#ifdef KICAD_SANITIZE_THREADS
163 reinterpret_cast<intptr_t
>( &args ) );
191 COROUTINE( T*
object, ReturnType(T::*ptr)( ArgType ) ) :
199 COROUTINE( std::function<ReturnType( ArgType )> aEntry ) :
207#ifdef KICAD_USE_VALGRIND
208 ,m_valgrind_stack( 0 )
210#ifdef KICAD_SANITIZE_ADDRESS
211 ,asan_stack( nullptr )
219#ifdef KICAD_USE_VALGRIND
220 VALGRIND_STACK_DEREGISTER( m_valgrind_stack );
279#ifdef KICAD_SANITIZE_THREADS
281 m_caller.tsan_fiber = __tsan_get_current_fiber();
325#ifdef KICAD_SANITIZE_THREADS
327 m_caller.tsan_fiber = __tsan_get_current_fiber();
387#ifndef LIBCONTEXT_HAS_OWN_STACK
393 std::size_t pages = (
m_stacksize + systemPageSize - 1 ) / systemPageSize;
396 stackSize = ( pages + 1 ) * systemPageSize;
399 m_stack.get_deleter().SetSize( stackSize );
406 sp =
static_cast<char*
>(
m_stack.get() ) + stackSize;
408#ifdef KICAD_USE_VALGRIND
409 m_valgrind_stack = VALGRIND_STACK_REGISTER( sp,
m_stack.get() );
413#ifdef KICAD_SANITIZE_THREADS
415 m_callee.tsan_fiber = __tsan_create_fiber( 0 );
418 __tsan_set_fiber_name(
m_callee.tsan_fiber,
"Coroutine fiber" );
425 return jumpIn( aInvArgs );
428#ifndef LIBCONTEXT_HAS_OWN_STACK
434 void operator()(
void* aMem )
noexcept { ::VirtualFree( aMem, 0, MEM_RELEASE ); }
446 static std::optional<size_t> systemPageSize;
448 if( !systemPageSize.has_value() )
452 ::GetSystemInfo( &si );
453 systemPageSize =
static_cast<size_t>( si.dwPageSize );
455 int size = getpagesize();
456 systemPageSize =
static_cast<size_t>( size );
460 return systemPageSize.value();
467 void* mem = ::VirtualAlloc( 0, aAllocSize, MEM_COMMIT, PAGE_READWRITE );
470 throw std::bad_alloc();
472 void* mem = ::mmap( 0, aAllocSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 );
474 if( mem == (
void*) -1 )
475 throw std::bad_alloc();
481 static inline void GuardMemory(
void* aAddress,
size_t aGuardSize )
485 BOOL
res = ::VirtualProtect( aAddress, aGuardSize,
486 PAGE_READWRITE | PAGE_GUARD, &old_prot );
488 bool res = ( 0 == ::mprotect( aAddress, aGuardSize, PROT_NONE ) );
522#ifdef KICAD_SANITIZE_THREADS
524 __tsan_switch_to_fiber(
m_callee.tsan_fiber, 0 );
531 reinterpret_cast<intptr_t
>( args ) )
542#ifdef KICAD_SANITIZE_THREADS
544 __tsan_switch_to_fiber(
m_caller.tsan_fiber, 0 );
551 reinterpret_cast<intptr_t
>( &args ) )
562#ifndef LIBCONTEXT_HAS_OWN_STACK
564 std::unique_ptr<char[], struct STACK_DELETER>
m_stack;
569 std::function<ReturnType( ArgType )>
m_func;
574 typename std::remove_reference<ArgType>::type*
m_args;
587#ifdef KICAD_USE_VALGRIND
588 uint32_t m_valgrind_stack;
591#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
Main stack information.
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
Saved caller context.
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)
CONTEXT_T m_callee
Saved coroutine context.
INVOCATION_ARGS * jumpIn(INVOCATION_ARGS *args)
std::unique_ptr< char[], struct STACK_DELETER > m_stack
Coroutine stack.
const ReturnType & ReturnValue() const
Return the yielded value (the argument KiYield() was called with).
INVOCATION_ARGS * doResume(INVOCATION_ARGS *args)
static void * MapMemory(size_t aAllocSize)
Map a page-aligned memory region into our address space.
static size_t SystemPageSize()
The size of the mappable memory page size.
INVOCATION_ARGS * doCall(INVOCATION_ARGS *aInvArgs, ArgType aArgs)
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)
Change protection of memory page(s) to act as stack guards.
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.
std::remove_reference< ArgType >::type * m_args
Pointer to coroutine entry arguments stripped of references to avoid compiler errors.
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::@34 type
A functor that frees the stack.
void SetSize(std::size_t aSize)
void operator()(void *aMem) noexcept
wxLogTrace helper definitions.