KiCad PCB EDA Suite
coroutine.h
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2013 CERN
5  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
6  * Copyright (C) 2016-2019 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #ifndef __COROUTINE_H
27 #define __COROUTINE_H
28 
29 #include <cassert>
30 #include <cstdlib>
31 #include <type_traits>
32 
33 #ifdef KICAD_USE_VALGRIND
34 #include <valgrind/valgrind.h>
35 #endif
36 
37 #include <libcontext.h>
38 #include <memory>
39 #include <advanced_config.h>
40 
62 template <typename ReturnType, typename ArgType>
63 class COROUTINE
64 {
65 private:
66  class CALL_CONTEXT;
67 
69  {
70  enum
71  {
72  FROM_ROOT, // a stub was called/a coroutine was resumed from the main-stack context
73  FROM_ROUTINE, // a stub was called/a coroutine was resumed from a coroutine context
74  CONTINUE_AFTER_ROOT // a function sent a request to invoke a function on the main
75  // stack context
76  } type; // invocation type
77  COROUTINE* destination; // stores the coroutine pointer for the stub OR the coroutine
78  // ptr for the coroutine to be resumed if a
79  // root(main-stack)-call-was initiated.
80  CALL_CONTEXT* context; // pointer to the call context of the current callgraph this
81  // call context holds a reference to the main stack context
82  };
83 
84  using CONTEXT_T = libcontext::fcontext_t;
86 
88  {
89  public:
91  m_mainStackContext( nullptr )
92  {
93  }
94 
95  void SetMainStack( CONTEXT_T* aStack )
96  {
97  m_mainStackContext = aStack;
98  }
99 
100  void RunMainStack( COROUTINE* aCor, std::function<void()> aFunc )
101  {
102  m_mainStackFunction = std::move( aFunc );
104 
105  libcontext::jump_fcontext( &aCor->m_callee, *m_mainStackContext,
106  reinterpret_cast<intptr_t>( &args ) );
107  }
108 
109  void Continue( INVOCATION_ARGS* args )
110  {
112  {
115  args = args->destination->doResume( args );
116  }
117  }
118 
119  private:
121  std::function<void()> m_mainStackFunction;
122  };
123 
124 public:
126  COROUTINE( nullptr )
127  {
128  }
129 
134  template <class T>
135  COROUTINE( T* object, ReturnType(T::*ptr)( ArgType ) ) :
136  COROUTINE( std::bind( ptr, object, std::placeholders::_1 ) )
137  {
138  }
139 
144  COROUTINE( std::function<ReturnType(ArgType)> aEntry ) :
145  m_func( std::move( aEntry ) ),
146  m_running( false ),
147  m_args( 0 ),
148  m_caller( nullptr ),
149  m_callContext( nullptr ),
150  m_callee( nullptr ),
151  m_retVal( 0 )
152 #ifdef KICAD_USE_VALGRIND
153  ,valgrind_stack( 0 )
154 #endif
155  {
157  }
158 
160  {
161 #ifdef KICAD_USE_VALGRIND
162  VALGRIND_STACK_DEREGISTER( valgrind_stack );
163 #endif
164  }
165 
166 public:
174  void KiYield()
175  {
176  jumpOut();
177  }
178 
185  void KiYield( ReturnType& aRetVal )
186  {
187  m_retVal = aRetVal;
188  jumpOut();
189  }
190 
199  void RunMainStack( std::function<void()> func )
200  {
201  assert( m_callContext );
202  m_callContext->RunMainStack( this, std::move( func ) );
203  }
204 
213  bool Call( ArgType aArg )
214  {
215  CALL_CONTEXT ctx;
216  INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROOT, this, &ctx };
217  ctx.Continue( doCall( &args, aArg ) );
218 
219  return Running();
220  }
221 
230  bool Call( const COROUTINE& aCor, ArgType aArg )
231  {
232  INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROUTINE, this, aCor.m_callContext };
233  doCall( &args, aArg );
234  // we will not be asked to continue
235 
236  return Running();
237  }
238 
247  bool Resume()
248  {
249  CALL_CONTEXT ctx;
250  INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROOT, this, &ctx };
251  ctx.Continue( doResume( &args ) );
252 
253  return Running();
254  }
255 
264  bool Resume( const COROUTINE& aCor )
265  {
266  INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROUTINE, this, aCor.m_callContext };
267  doResume( &args );
268  // we will not be asked to continue
269 
270  return Running();
271  }
272 
278  const ReturnType& ReturnValue() const
279  {
280  return m_retVal;
281  }
282 
288  bool Running() const
289  {
290  return m_running;
291  }
292 
293 private:
294  INVOCATION_ARGS* doCall( INVOCATION_ARGS* aInvArgs, ArgType aArgs )
295  {
296  assert( m_func );
297  assert( !m_callee );
298 
299  m_args = &aArgs;
300 
301  assert( m_stack == nullptr );
302 
303  size_t stackSize = m_stacksize;
304  void* sp = nullptr;
305 
306  #ifndef LIBCONTEXT_HAS_OWN_STACK
307  // fixme: Clean up stack stuff. Add a guard
308  m_stack.reset( new char[stackSize] );
309 
310  // align to 16 bytes
311  sp = (void*)((((ptrdiff_t) m_stack.get()) + stackSize - 0xf) & (~0x0f));
312 
313  // correct the stack size
314  stackSize -= size_t( ( (ptrdiff_t) m_stack.get() + stackSize ) - (ptrdiff_t) sp );
315 
316 #ifdef KICAD_USE_VALGRIND
317  valgrind_stack = VALGRIND_STACK_REGISTER( sp, m_stack.get() );
318 #endif
319  #endif
320 
321  m_callee = libcontext::make_fcontext( sp, stackSize, callerStub );
322  m_running = true;
323 
324  // off we go!
325  return jumpIn( aInvArgs );
326  }
327 
328  INVOCATION_ARGS* doResume( INVOCATION_ARGS* args )
329  {
330  return jumpIn( args );
331  }
332 
333  /* real entry point of the coroutine */
334  static void callerStub( intptr_t aData )
335  {
336  INVOCATION_ARGS& args = *reinterpret_cast<INVOCATION_ARGS*>( aData );
337  // get pointer to self
338  COROUTINE* cor = args.destination;
339  cor->m_callContext = args.context;
340 
341  if( args.type == INVOCATION_ARGS::FROM_ROOT )
342  cor->m_callContext->SetMainStack( &cor->m_caller );
343 
344  // call the coroutine method
345  cor->m_retVal = cor->m_func( *(cor->m_args) );
346  cor->m_running = false;
347 
348  // go back to wherever we came from.
349  cor->jumpOut();
350  }
351 
352  INVOCATION_ARGS* jumpIn( INVOCATION_ARGS* args )
353  {
354  args = reinterpret_cast<INVOCATION_ARGS*>(
355  libcontext::jump_fcontext( &m_caller, m_callee,
356  reinterpret_cast<intptr_t>( args ) )
357  );
358 
359  return args;
360  }
361 
362  void jumpOut()
363  {
364  INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROUTINE, nullptr, nullptr };
365  INVOCATION_ARGS* ret;
366  ret = reinterpret_cast<INVOCATION_ARGS*>(
367  libcontext::jump_fcontext( &m_callee, m_caller,
368  reinterpret_cast<intptr_t>( &args ) )
369  );
370 
371  m_callContext = ret->context;
372 
373  if( ret->type == INVOCATION_ARGS::FROM_ROOT )
374  {
376  }
377  }
378 
380  std::unique_ptr<char[]> m_stack;
381 
383 
384  std::function<ReturnType( ArgType )> m_func;
385 
386  bool m_running;
387 
390  typename std::remove_reference<ArgType>::type* m_args;
391 
394 
396  CALL_CONTEXT* m_callContext;
397 
400 
401  ReturnType m_retVal;
402 
403 #ifdef KICAD_USE_VALGRIND
404  uint32_t valgrind_stack;
405 #endif
406 };
407 
408 #endif
void RunMainStack(std::function< void()> func)
Function RunMainStack()
Definition: coroutine.h:199
std::function< ReturnType(ArgType)> m_func
Definition: coroutine.h:384
void KiYield(ReturnType &aRetVal)
Function KiYield()
Definition: coroutine.h:185
bool m_running
pointer to coroutine entry arguments.
Definition: coroutine.h:386
Class COROUNTINE.
Definition: coroutine.h:63
void RunMainStack(COROUTINE *aCor, std::function< void()> aFunc)
Definition: coroutine.h:100
void jumpOut()
coroutine stack
Definition: coroutine.h:362
bool Call(ArgType aArg)
Function Call()
Definition: coroutine.h:213
bool Resume(const COROUTINE &aCor)
Function Resume()
Definition: coroutine.h:264
CALL_CONTEXT * m_callContext
saved coroutine context
Definition: coroutine.h:396
CONTEXT_T * m_mainStackContext
Definition: coroutine.h:120
std::unique_ptr< char[]> m_stack
Definition: coroutine.h:380
bool Call(const COROUTINE &aCor, ArgType aArg)
Function Call()
Definition: coroutine.h:230
Template specialization to enable wxStrings for certain containers (e.g. unordered_map)
Definition: bitmap.cpp:56
T
enum T contains all this lexer's tokens.
std::function< void()> m_mainStackFunction
Definition: coroutine.h:121
int m_stacksize
Definition: coroutine.h:382
CONTEXT_T m_caller
main stack information
Definition: coroutine.h:393
INVOCATION_ARGS * doCall(INVOCATION_ARGS *aInvArgs, ArgType aArgs)
Definition: coroutine.h:294
bool Resume()
Function Resume()
Definition: coroutine.h:247
std::remove_reference< ArgType >::type * m_args
saved caller context
Definition: coroutine.h:390
CALLEE_STORAGE m_callee
Definition: coroutine.h:399
void SetMainStack(CONTEXT_T *aStack)
Definition: coroutine.h:95
const ReturnType & ReturnValue() const
Function ReturnValue()
Definition: coroutine.h:278
int m_coroutineStackSize
Set the stack size for coroutines.
ReturnType m_retVal
Definition: coroutine.h:401
INVOCATION_ARGS * doResume(INVOCATION_ARGS *args)
Definition: coroutine.h:328
~COROUTINE()
Definition: coroutine.h:159
void Continue(INVOCATION_ARGS *args)
Definition: coroutine.h:109
static void callerStub(intptr_t aData)
Definition: coroutine.h:334
INVOCATION_ARGS * jumpIn(INVOCATION_ARGS *args)
Definition: coroutine.h:352
bool Running() const
Function Running()
Definition: coroutine.h:288
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers of advanced config.
CALL_CONTEXT * context
Definition: coroutine.h:80
libcontext::fcontext_t CONTEXT_T
Definition: coroutine.h:84
enum COROUTINE::INVOCATION_ARGS::@38 type
COROUTINE(std::function< ReturnType(ArgType)> aEntry)
Constructor Creates a coroutine from a delegate object.
Definition: coroutine.h:144
void KiYield()
Function KiYield()
Definition: coroutine.h:174
COROUTINE(T *object, ReturnType(T::*ptr)(ArgType))
Constructor Creates a coroutine from a member method of an object.
Definition: coroutine.h:135