KiCad PCB EDA Suite
COROUTINE< ReturnType, ArgType > Class Template Reference

Implement a coroutine. More...

#include <coroutine.h>

Classes

class  CALL_CONTEXT
 
struct  CONTEXT_T
 
struct  INVOCATION_ARGS
 

Public Member Functions

 COROUTINE ()
 
template<class T >
 COROUTINE (T *object, ReturnType(T::*ptr)(ArgType))
 Create a coroutine from a member method of an object. More...
 
 COROUTINE (std::function< ReturnType(ArgType)> aEntry)
 Create a coroutine from a delegate object. More...
 
 ~COROUTINE ()
 
void KiYield ()
 Stop execution of the coroutine and returns control to the caller. More...
 
void KiYield (ReturnType &aRetVal)
 KiYield with a value. More...
 
void RunMainStack (std::function< void()> func)
 Run a functor inside the application main stack context. More...
 
bool Call (ArgType aArg)
 Start execution of a coroutine, passing args as its arguments. More...
 
bool Call (const COROUTINE &aCor, ArgType aArg)
 Start execution of a coroutine, passing args as its arguments. More...
 
bool Resume ()
 Resume execution of a previously yielded coroutine. More...
 
bool Resume (const COROUTINE &aCor)
 Resume execution of a previously yielded coroutine. More...
 
const ReturnType & ReturnValue () const
 Return the yielded value (the argument KiYield() was called with). More...
 
bool Running () const
 

Private Member Functions

INVOCATION_ARGSdoCall (INVOCATION_ARGS *aInvArgs, ArgType aArgs)
 
INVOCATION_ARGSdoResume (INVOCATION_ARGS *args)
 
INVOCATION_ARGSjumpIn (INVOCATION_ARGS *args)
 
void jumpOut ()
 coroutine stack More...
 

Static Private Member Functions

static void callerStub (intptr_t aData)
 

Private Attributes

std::unique_ptr< char[]> m_stack
 
int m_stacksize
 
std::function< ReturnType(ArgType)> m_func
 
bool m_running
 pointer to coroutine entry arguments. More...
 
std::remove_reference< ArgType >::type * m_args
 saved caller context More...
 
CONTEXT_T m_caller
 main stack information More...
 
CALL_CONTEXTm_callContext
 saved coroutine context More...
 
CONTEXT_T m_callee
 
ReturnType m_retVal
 

Detailed Description

template<typename ReturnType, typename ArgType>
class COROUTINE< ReturnType, ArgType >

Implement a coroutine.

Wikipedia has a good explanation:

"Coroutines are computer program components that generalize subroutines to allow multiple entry points for suspending and resuming execution at certain locations. Coroutines are well-suited for implementing more familiar program components such as cooperative tasks, exceptions, event loop, iterators, infinite lists and pipes."

In other words, a coroutine can be considered a lightweight thread - which can be preempted only when it deliberately yields the control to the caller. This way, we avoid concurrency problems such as locking / race conditions.

Uses libcontext library to do the actual context switching.

This particular version takes a DELEGATE as an entry point, so it can invoke methods within a given object as separate coroutines.

See coroutine_example.cpp for sample code.

Definition at line 75 of file coroutine.h.

Constructor & Destructor Documentation

◆ COROUTINE() [1/3]

template<typename ReturnType , typename ArgType >
COROUTINE< ReturnType, ArgType >::COROUTINE ( )
inline

Definition at line 172 of file coroutine.h.

172 :
173 COROUTINE( nullptr )
174 {
175 }

◆ COROUTINE() [2/3]

template<typename ReturnType , typename ArgType >
template<class T >
COROUTINE< ReturnType, ArgType >::COROUTINE ( T *  object,
ReturnType(T::*)(ArgType)  ptr 
)
inline

Create a coroutine from a member method of an object.

Definition at line 181 of file coroutine.h.

181 :
182 COROUTINE( std::bind( ptr, object, std::placeholders::_1 ) )
183 {
184 }

◆ COROUTINE() [3/3]

template<typename ReturnType , typename ArgType >
COROUTINE< ReturnType, ArgType >::COROUTINE ( std::function< ReturnType(ArgType)>  aEntry)
inline

Create a coroutine from a delegate object.

Definition at line 189 of file coroutine.h.

189 :
190 m_func( std::move( aEntry ) ),
191 m_running( false ),
192 m_args( nullptr ),
193 m_caller(),
194 m_callContext( nullptr ),
195 m_callee(),
196 m_retVal( 0 )
197#ifdef KICAD_USE_VALGRIND
198 ,m_valgrind_stack( 0 )
199#endif
200#ifdef KICAD_SANITIZE_ADDRESS
201 ,asan_stack( nullptr )
202#endif
203 {
205 }
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
CALL_CONTEXT * m_callContext
saved coroutine context
Definition: coroutine.h:494
CONTEXT_T m_caller
main stack information
Definition: coroutine.h:491
ReturnType m_retVal
Definition: coroutine.h:499
CONTEXT_T m_callee
Definition: coroutine.h:497
bool m_running
pointer to coroutine entry arguments.
Definition: coroutine.h:484
int m_stacksize
Definition: coroutine.h:480
std::function< ReturnType(ArgType)> m_func
Definition: coroutine.h:482
std::remove_reference< ArgType >::type * m_args
saved caller context
Definition: coroutine.h:488
int m_CoroutineStackSize
Set the stack size for coroutines.

References ADVANCED_CFG::GetCfg(), ADVANCED_CFG::m_CoroutineStackSize, and COROUTINE< ReturnType, ArgType >::m_stacksize.

◆ ~COROUTINE()

template<typename ReturnType , typename ArgType >
COROUTINE< ReturnType, ArgType >::~COROUTINE ( )
inline

Definition at line 207 of file coroutine.h.

208 {
209#ifdef KICAD_USE_VALGRIND
210 VALGRIND_STACK_DEREGISTER( m_valgrind_stack );
211#endif
212
213 if( m_caller.ctx )
214 libcontext::release_fcontext( m_caller.ctx );
215
216 if( m_callee.ctx )
217 libcontext::release_fcontext( m_callee.ctx );
218 }
libcontext::fcontext_t ctx
Definition: coroutine.h:98

References COROUTINE< ReturnType, ArgType >::CONTEXT_T::ctx, COROUTINE< ReturnType, ArgType >::m_callee, and COROUTINE< ReturnType, ArgType >::m_caller.

Member Function Documentation

◆ Call() [1/2]

template<typename ReturnType , typename ArgType >
bool COROUTINE< ReturnType, ArgType >::Call ( ArgType  aArg)
inline

Start execution of a coroutine, passing args as its arguments.

Call this method from the application main stack only.

Returns
true if the coroutine has yielded and false if it has finished its execution (returned).

Definition at line 264 of file coroutine.h.

265 {
266 CALL_CONTEXT ctx;
267 INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROOT, this, &ctx };
268
269#ifdef KICAD_SANITIZE_THREADS
270 // Get the TSAN fiber for the current stack here
271 m_caller.tsan_fiber = __tsan_get_current_fiber();
272 m_caller.own_tsan_fiber = false;
273#endif
274
275 wxLogTrace( kicadTraceCoroutineStack, "COROUTINE::Call (from root)" );
276
277 ctx.Continue( doCall( &args, aArg ) );
278
279 return Running();
280 }
INVOCATION_ARGS * doCall(INVOCATION_ARGS *aInvArgs, ArgType aArgs)
Definition: coroutine.h:365
bool Running() const
Definition: coroutine.h:359
const wxChar *const kicadTraceCoroutineStack
Flag to enable tracing of the coroutine call stack.

References COROUTINE< ReturnType, ArgType >::CALL_CONTEXT::Continue(), COROUTINE< ReturnType, ArgType >::doCall(), COROUTINE< ReturnType, ArgType >::INVOCATION_ARGS::FROM_ROOT, kicadTraceCoroutineStack, COROUTINE< ReturnType, ArgType >::m_caller, and COROUTINE< ReturnType, ArgType >::Running().

Referenced by TOOL_MANAGER::dispatchInternal().

◆ Call() [2/2]

template<typename ReturnType , typename ArgType >
bool COROUTINE< ReturnType, ArgType >::Call ( const COROUTINE< ReturnType, ArgType > &  aCor,
ArgType  aArg 
)
inline

Start execution of a coroutine, passing args as its arguments.

Call this method for a nested coroutine invocation.

Returns
true if the coroutine has yielded and false if it has finished its execution (returned).

Definition at line 290 of file coroutine.h.

291 {
292 INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROUTINE, this, aCor.m_callContext };
293
294 wxLogTrace( kicadTraceCoroutineStack, wxT( "COROUTINE::Call (from routine)" ) );
295
296 doCall( &args, aArg );
297 // we will not be asked to continue
298
299 return Running();
300 }

References COROUTINE< ReturnType, ArgType >::doCall(), COROUTINE< ReturnType, ArgType >::INVOCATION_ARGS::FROM_ROUTINE, kicadTraceCoroutineStack, COROUTINE< ReturnType, ArgType >::m_callContext, and COROUTINE< ReturnType, ArgType >::Running().

◆ callerStub()

template<typename ReturnType , typename ArgType >
static void COROUTINE< ReturnType, ArgType >::callerStub ( intptr_t  aData)
inlinestaticprivate

◆ doCall()

template<typename ReturnType , typename ArgType >
INVOCATION_ARGS * COROUTINE< ReturnType, ArgType >::doCall ( INVOCATION_ARGS aInvArgs,
ArgType  aArgs 
)
inlineprivate

Definition at line 365 of file coroutine.h.

366 {
367 assert( m_func );
368 assert( !( m_callee.ctx ) );
369
370 m_args = &aArgs;
371
372 assert( m_stack == nullptr );
373
374 size_t stackSize = m_stacksize;
375 void* sp = nullptr;
376
377#ifndef LIBCONTEXT_HAS_OWN_STACK
378
379 // fixme: Clean up stack stuff. Add a guard
380 m_stack.reset( new char[stackSize] );
381
382 // align to 16 bytes
383 sp = (void*)((((ptrdiff_t) m_stack.get()) + stackSize - 0xf) & (~0x0f));
384
385 // correct the stack size
386 stackSize -= size_t( ( (ptrdiff_t) m_stack.get() + stackSize ) - (ptrdiff_t) sp );
387
388#ifdef KICAD_USE_VALGRIND
389 m_valgrind_stack = VALGRIND_STACK_REGISTER( sp, m_stack.get() );
390#endif
391#endif
392
393#ifdef KICAD_SANITIZE_THREADS
394 // Create a new fiber to go with the new context
395 m_callee.tsan_fiber = __tsan_create_fiber( 0 );
396 m_callee.own_tsan_fiber = true;
397
398 __tsan_set_fiber_name( m_callee.tsan_fiber, "Coroutine fiber" );
399#endif
400
401 wxLogTrace( kicadTraceCoroutineStack, wxT( "COROUTINE::doCall" ) );
402
403 m_callee.ctx = libcontext::make_fcontext( sp, stackSize, callerStub );
404 m_running = true;
405
406 // off we go!
407 return jumpIn( aInvArgs );
408 }
std::unique_ptr< char[]> m_stack
Definition: coroutine.h:478
static void callerStub(intptr_t aData)
Definition: coroutine.h:416
INVOCATION_ARGS * jumpIn(INVOCATION_ARGS *args)
Definition: coroutine.h:435

References COROUTINE< ReturnType, ArgType >::callerStub(), COROUTINE< ReturnType, ArgType >::CONTEXT_T::ctx, COROUTINE< ReturnType, ArgType >::jumpIn(), kicadTraceCoroutineStack, COROUTINE< ReturnType, ArgType >::m_args, COROUTINE< ReturnType, ArgType >::m_callee, COROUTINE< ReturnType, ArgType >::m_func, COROUTINE< ReturnType, ArgType >::m_running, COROUTINE< ReturnType, ArgType >::m_stack, and COROUTINE< ReturnType, ArgType >::m_stacksize.

Referenced by COROUTINE< ReturnType, ArgType >::Call().

◆ doResume()

template<typename ReturnType , typename ArgType >
INVOCATION_ARGS * COROUTINE< ReturnType, ArgType >::doResume ( INVOCATION_ARGS args)
inlineprivate

◆ jumpIn()

template<typename ReturnType , typename ArgType >
INVOCATION_ARGS * COROUTINE< ReturnType, ArgType >::jumpIn ( INVOCATION_ARGS args)
inlineprivate

Definition at line 435 of file coroutine.h.

436 {
437#ifdef KICAD_SANITIZE_THREADS
438 // Tell TSAN we are changing fibers to the callee
439 __tsan_switch_to_fiber( m_callee.tsan_fiber, 0 );
440#endif
441
442 wxLogTrace( kicadTraceCoroutineStack, wxT( "COROUTINE::jumpIn" ) );
443
444 args = reinterpret_cast<INVOCATION_ARGS*>(
445 libcontext::jump_fcontext( &( m_caller.ctx ), m_callee.ctx,
446 reinterpret_cast<intptr_t>( args ) )
447 );
448
449 return args;
450 }

References COROUTINE< ReturnType, ArgType >::CONTEXT_T::ctx, kicadTraceCoroutineStack, COROUTINE< ReturnType, ArgType >::m_callee, and COROUTINE< ReturnType, ArgType >::m_caller.

Referenced by COROUTINE< ReturnType, ArgType >::doCall(), and COROUTINE< ReturnType, ArgType >::doResume().

◆ jumpOut()

◆ KiYield() [1/2]

template<typename ReturnType , typename ArgType >
void COROUTINE< ReturnType, ArgType >::KiYield ( )
inline

Stop execution of the coroutine and returns control to the caller.

After a yield, Call() or Resume() methods invoked by the caller will immediately return true, indicating that we are not done yet, just asleep.

Definition at line 227 of file coroutine.h.

228 {
229 jumpOut();
230 }

References COROUTINE< ReturnType, ArgType >::jumpOut().

Referenced by TOOL_MANAGER::ScheduleWait().

◆ KiYield() [2/2]

template<typename ReturnType , typename ArgType >
void COROUTINE< ReturnType, ArgType >::KiYield ( ReturnType &  aRetVal)
inline

KiYield with a value.

Passe a value of given type to the caller. Useful for implementing generator objects.

Definition at line 237 of file coroutine.h.

238 {
239 m_retVal = aRetVal;
240 jumpOut();
241 }

References COROUTINE< ReturnType, ArgType >::jumpOut(), and COROUTINE< ReturnType, ArgType >::m_retVal.

◆ Resume() [1/2]

template<typename ReturnType , typename ArgType >
bool COROUTINE< ReturnType, ArgType >::Resume ( )
inline

Resume execution of a previously yielded coroutine.

Call this method only from the main application stack.

Returns
true if the coroutine has yielded again and false if it has finished its execution (returned).

Definition at line 310 of file coroutine.h.

311 {
312 CALL_CONTEXT ctx;
313 INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROOT, this, &ctx };
314
315#ifdef KICAD_SANITIZE_THREADS
316 // Get the TSAN fiber for the current stack here
317 m_caller.tsan_fiber = __tsan_get_current_fiber();
318 m_caller.own_tsan_fiber = false;
319#endif
320
321 wxLogTrace( kicadTraceCoroutineStack, wxT( "COROUTINE::Resume (from root)" ) );
322
323 ctx.Continue( doResume( &args ) );
324
325 return Running();
326 }
INVOCATION_ARGS * doResume(INVOCATION_ARGS *args)
Definition: coroutine.h:410

References COROUTINE< ReturnType, ArgType >::CALL_CONTEXT::Continue(), COROUTINE< ReturnType, ArgType >::doResume(), COROUTINE< ReturnType, ArgType >::INVOCATION_ARGS::FROM_ROOT, kicadTraceCoroutineStack, COROUTINE< ReturnType, ArgType >::m_caller, and COROUTINE< ReturnType, ArgType >::Running().

Referenced by TOOL_MANAGER::dispatchInternal(), and TOOL_MANAGER::ShutdownTool().

◆ Resume() [2/2]

template<typename ReturnType , typename ArgType >
bool COROUTINE< ReturnType, ArgType >::Resume ( const COROUTINE< ReturnType, ArgType > &  aCor)
inline

Resume execution of a previously yielded coroutine.

Call this method for a nested coroutine invocation.

Returns
true if the coroutine has yielded again and false if it has finished its execution (returned).

Definition at line 336 of file coroutine.h.

337 {
338 INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROUTINE, this, aCor.m_callContext };
339
340 wxLogTrace( kicadTraceCoroutineStack, wxT( "COROUTINE::Resume (from routine)" ) );
341
342 doResume( &args );
343 // we will not be asked to continue
344
345 return Running();
346 }

References COROUTINE< ReturnType, ArgType >::doResume(), COROUTINE< ReturnType, ArgType >::INVOCATION_ARGS::FROM_ROUTINE, kicadTraceCoroutineStack, COROUTINE< ReturnType, ArgType >::m_callContext, and COROUTINE< ReturnType, ArgType >::Running().

◆ ReturnValue()

template<typename ReturnType , typename ArgType >
const ReturnType & COROUTINE< ReturnType, ArgType >::ReturnValue ( ) const
inline

Return the yielded value (the argument KiYield() was called with).

Definition at line 351 of file coroutine.h.

352 {
353 return m_retVal;
354 }

References COROUTINE< ReturnType, ArgType >::m_retVal.

◆ RunMainStack()

template<typename ReturnType , typename ArgType >
void COROUTINE< ReturnType, ArgType >::RunMainStack ( std::function< void()>  func)
inline

Run a functor inside the application main stack context.

Call this function for example if the operation will spawn a webkit browser instance which will walk the stack to the upper border of the address space on mac osx systems because its javascript needs garbage collection (for example if you paste text into an edit box).

Definition at line 250 of file coroutine.h.

251 {
252 assert( m_callContext );
253 m_callContext->RunMainStack( this, std::move( func ) );
254 }
void RunMainStack(COROUTINE *aCor, std::function< void()> aFunc)
Definition: coroutine.h:142

References COROUTINE< ReturnType, ArgType >::m_callContext, and COROUTINE< ReturnType, ArgType >::CALL_CONTEXT::RunMainStack().

Referenced by TOOL_MANAGER::RunMainStack().

◆ Running()

template<typename ReturnType , typename ArgType >
bool COROUTINE< ReturnType, ArgType >::Running ( ) const
inline
Returns
true if the coroutine is active.

Definition at line 359 of file coroutine.h.

360 {
361 return m_running;
362 }

References COROUTINE< ReturnType, ArgType >::m_running.

Referenced by COROUTINE< ReturnType, ArgType >::Call(), TOOL_MANAGER::dispatchInternal(), and COROUTINE< ReturnType, ArgType >::Resume().

Member Data Documentation

◆ m_args

template<typename ReturnType , typename ArgType >
std::remove_reference<ArgType>::type* COROUTINE< ReturnType, ArgType >::m_args
private

saved caller context

Definition at line 488 of file coroutine.h.

Referenced by COROUTINE< ReturnType, ArgType >::callerStub(), and COROUTINE< ReturnType, ArgType >::doCall().

◆ m_callContext

template<typename ReturnType , typename ArgType >
CALL_CONTEXT* COROUTINE< ReturnType, ArgType >::m_callContext
private

◆ m_callee

◆ m_caller

◆ m_func

template<typename ReturnType , typename ArgType >
std::function<ReturnType( ArgType )> COROUTINE< ReturnType, ArgType >::m_func
private

◆ m_retVal

template<typename ReturnType , typename ArgType >
ReturnType COROUTINE< ReturnType, ArgType >::m_retVal
private

◆ m_running

template<typename ReturnType , typename ArgType >
bool COROUTINE< ReturnType, ArgType >::m_running
private

pointer to coroutine entry arguments.

Stripped of references to avoid compiler errors.

Definition at line 484 of file coroutine.h.

Referenced by COROUTINE< ReturnType, ArgType >::callerStub(), COROUTINE< ReturnType, ArgType >::doCall(), and COROUTINE< ReturnType, ArgType >::Running().

◆ m_stack

template<typename ReturnType , typename ArgType >
std::unique_ptr<char[]> COROUTINE< ReturnType, ArgType >::m_stack
private

Definition at line 478 of file coroutine.h.

Referenced by COROUTINE< ReturnType, ArgType >::doCall().

◆ m_stacksize

template<typename ReturnType , typename ArgType >
int COROUTINE< ReturnType, ArgType >::m_stacksize
private

The documentation for this class was generated from the following file: