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 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 <cstdlib>
30 
31 #include <type_traits>
32 
33 #include <system/libcontext.h>
34 #include <memory>
35 
57 template <typename ReturnType, typename ArgType>
58 class COROUTINE
59 {
60 private:
61  class CALL_CONTEXT;
62 
64  {
65  enum
66  {
67  FROM_ROOT, // a stub was called/a corutine was resumed from the main-stack context
68  FROM_ROUTINE, // a stub was called/a coroutine was resumed fron a coroutine context
69  CONTINUE_AFTER_ROOT // a function sent a request to invoke a function on the main
70  // stack context
71  } type; // invocation type
72  COROUTINE* destination; // stores the coroutine pointer for the stub OR the coroutine
73  // ptr for the coroutine to be resumed if a
74  // root(main-stack)-call-was initiated.
75  CALL_CONTEXT* context; // pointer to the call context of the current callgraph this
76  // call context holds a reference to the main stack context
77  };
78 
81 
83  {
84  public:
85  void SetMainStack( CONTEXT_T* aStack )
86  {
87  m_mainStackContext = aStack;
88  }
89 
90  void RunMainStack( COROUTINE* aCor, std::function<void()> aFunc )
91  {
92  m_mainStackFunction = std::move( aFunc );
94 
95  libcontext::jump_fcontext( &aCor->m_callee, *m_mainStackContext,
96  reinterpret_cast<intptr_t>( &args ) );
97  }
98 
99  void Continue( INVOCATION_ARGS* args )
100  {
102  {
103  m_mainStackFunction();
105  args = args->destination->doResume( args );
106  }
107  }
108 
109  private:
111  std::function<void()> m_mainStackFunction;
112  };
113 
114 public:
116  COROUTINE( nullptr )
117  {
118  }
119 
124  template <class T>
125  COROUTINE( T* object, ReturnType(T::*ptr)( ArgType ) ) :
126  COROUTINE( std::bind( ptr, object, std::placeholders::_1 ) )
127  {
128  }
129 
134  COROUTINE( std::function<ReturnType(ArgType)> aEntry ) :
135  m_func( std::move( aEntry ) ),
136  m_running( false ),
137  m_args( 0 ),
138  m_callContext( nullptr ),
139  m_callee( nullptr ),
140  m_retVal( 0 )
141  {
142  }
143 
145  {
146  }
147 
148 public:
156  void KiYield()
157  {
158  jumpOut();
159  }
160 
167  void KiYield( ReturnType& aRetVal )
168  {
169  m_retVal = aRetVal;
170  jumpOut();
171  }
172 
178  void SetEntry( std::function<ReturnType(ArgType)> aEntry )
179  {
180  m_func = std::move( aEntry );
181  }
182 
191  void RunMainStack( std::function<void()> func )
192  {
193  assert( m_callContext );
194  m_callContext->RunMainStack( this, std::move( func ) );
195  }
196 
205  bool Call( ArgType aArg )
206  {
207  CALL_CONTEXT ctx;
208  INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROOT, this, &ctx };
209  ctx.Continue( doCall( &args, aArg ) );
210 
211  return Running();
212  }
213 
222  bool Call( const COROUTINE& aCor, ArgType aArg )
223  {
224  INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROUTINE, this, aCor.m_callContext };
225  doCall( &args, aArg );
226  // we will not be asked to continue
227 
228  return Running();
229  }
230 
239  bool Resume()
240  {
241  CALL_CONTEXT ctx;
242  INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROOT, this, &ctx };
243  ctx.Continue( doResume( &args ) );
244 
245  return Running();
246  }
247 
256  bool Resume( const COROUTINE& aCor )
257  {
258  INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROUTINE, this, aCor.m_callContext };
259  doResume( &args );
260  // we will not be asked to continue
261 
262  return Running();
263  }
264 
270  const ReturnType& ReturnValue() const
271  {
272  return m_retVal;
273  }
274 
280  bool Running() const
281  {
282  return m_running;
283  }
284 
285 private:
286  INVOCATION_ARGS* doCall( INVOCATION_ARGS* aInvArgs, ArgType aArgs )
287  {
288  assert( m_func );
289  assert( !m_callee );
290 
291  m_args = &aArgs;
292 
293  assert( m_stack == nullptr );
294 
295  // fixme: Clean up stack stuff. Add a guard
296  size_t stackSize = c_defaultStackSize;
297  m_stack.reset( new char[stackSize] );
298 
299  // align to 16 bytes
300  void* sp = (void*)((((ptrdiff_t) m_stack.get()) + stackSize - 0xf) & (~0x0f));
301 
302  // correct the stack size
303  stackSize -= size_t( ( (ptrdiff_t) m_stack.get() + stackSize ) - (ptrdiff_t) sp );
304 
305  m_callee = libcontext::make_fcontext( sp, stackSize, callerStub );
306  m_running = true;
307 
308  // off we go!
309  return jumpIn( aInvArgs );
310  }
311 
312  INVOCATION_ARGS* doResume( INVOCATION_ARGS* args )
313  {
314  return jumpIn( args );
315  }
316 
317  /* real entry point of the coroutine */
318  static void callerStub( intptr_t aData )
319  {
320  INVOCATION_ARGS& args = *reinterpret_cast<INVOCATION_ARGS*>( aData );
321  // get pointer to self
322  COROUTINE* cor = args.destination;
323  cor->m_callContext = args.context;
324 
325  if( args.type == INVOCATION_ARGS::FROM_ROOT )
326  cor->m_callContext->SetMainStack( &cor->m_caller );
327 
328  // call the coroutine method
329  cor->m_retVal = cor->m_func( *(cor->m_args) );
330  cor->m_running = false;
331 
332  // go back to wherever we came from.
333  cor->jumpOut();
334  }
335 
336  INVOCATION_ARGS* jumpIn( INVOCATION_ARGS* args )
337  {
338  args = reinterpret_cast<INVOCATION_ARGS*>(
340  reinterpret_cast<intptr_t>( args ) )
341  );
342 
343  return args;
344  }
345 
346  void jumpOut()
347  {
348  INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROUTINE, nullptr, nullptr };
349  INVOCATION_ARGS* ret;
350  ret = reinterpret_cast<INVOCATION_ARGS*>(
352  reinterpret_cast<intptr_t>( &args ) )
353  );
354 
355  m_callContext = ret->context;
356 
357  if( ret->type == INVOCATION_ARGS::FROM_ROOT )
358  {
360  }
361  }
362 
363  static constexpr int c_defaultStackSize = 2000000; // fixme: make configurable
364 
366  std::unique_ptr<char[]> m_stack;
367 
368  std::function<ReturnType( ArgType )> m_func;
369 
370  bool m_running;
371 
374  typename std::remove_reference<ArgType>::type* m_args;
375 
378 
380  CALL_CONTEXT* m_callContext;
381 
384 
385  ReturnType m_retVal;
386 };
387 
388 #endif
void RunMainStack(std::function< void()> func)
Function RunMainStack()
Definition: coroutine.h:191
std::function< ReturnType(ArgType)> m_func
Definition: coroutine.h:368
void KiYield(ReturnType &aRetVal)
Function KiYield()
Definition: coroutine.h:167
intptr_t LIBCONTEXT_CALL_CONVENTION jump_fcontext(fcontext_t *ofc, fcontext_t nfc, intptr_t vp, bool preserve_fpu=true)
bool m_running
pointer to coroutine entry arguments.
Definition: coroutine.h:370
Class COROUNTINE.
Definition: coroutine.h:58
void RunMainStack(COROUTINE *aCor, std::function< void()> aFunc)
Definition: coroutine.h:90
void jumpOut()
Definition: coroutine.h:346
bool Call(ArgType aArg)
Function Call()
Definition: coroutine.h:205
void * fcontext_t
Definition: libcontext.h:75
bool Resume(const COROUTINE &aCor)
Function Resume()
Definition: coroutine.h:256
CALL_CONTEXT * m_callContext
saved coroutine context
Definition: coroutine.h:380
CONTEXT_T * m_mainStackContext
Definition: coroutine.h:110
std::unique_ptr< char[]> m_stack
< coroutine stack
Definition: coroutine.h:366
bool Call(const COROUTINE &aCor, ArgType aArg)
Function Call()
Definition: coroutine.h:222
Template specialization to enable wxStrings for certain containers (e.g. unordered_map) ...
Definition: bitmap.cpp:54
std::function< void()> m_mainStackFunction
Definition: coroutine.h:111
static constexpr int c_defaultStackSize
Definition: coroutine.h:363
const ReturnType & ReturnValue() const
Function ReturnValue()
Definition: coroutine.h:270
CONTEXT_T m_caller
main stack information
Definition: coroutine.h:377
INVOCATION_ARGS * doCall(INVOCATION_ARGS *aInvArgs, ArgType aArgs)
Definition: coroutine.h:286
bool Resume()
Function Resume()
Definition: coroutine.h:239
std::remove_reference< ArgType >::type * m_args
saved caller context
Definition: coroutine.h:374
CALLEE_STORAGE m_callee
Definition: coroutine.h:383
void SetMainStack(CONTEXT_T *aStack)
Definition: coroutine.h:85
ReturnType m_retVal
Definition: coroutine.h:385
INVOCATION_ARGS * doResume(INVOCATION_ARGS *args)
Definition: coroutine.h:312
CONTEXT_T CALLEE_STORAGE
Definition: coroutine.h:80
~COROUTINE()
Definition: coroutine.h:144
void Continue(INVOCATION_ARGS *args)
Definition: coroutine.h:99
static void callerStub(intptr_t aData)
Definition: coroutine.h:318
fcontext_t LIBCONTEXT_CALL_CONVENTION make_fcontext(void *sp, size_t size, void(*fn)(intptr_t))
INVOCATION_ARGS * jumpIn(INVOCATION_ARGS *args)
Definition: coroutine.h:336
void SetEntry(std::function< ReturnType(ArgType)> aEntry)
Function SetEntry()
Definition: coroutine.h:178
CALL_CONTEXT * context
Definition: coroutine.h:75
libcontext::fcontext_t CONTEXT_T
Definition: coroutine.h:79
enum COROUTINE::INVOCATION_ARGS::@59 type
bool Running() const
Function Running()
Definition: coroutine.h:280
COROUTINE(std::function< ReturnType(ArgType)> aEntry)
Constructor Creates a coroutine from a delegate object.
Definition: coroutine.h:134
void KiYield()
Function KiYield()
Definition: coroutine.h:156
COROUTINE(T *object, ReturnType(T::*ptr)(ArgType))
Constructor Creates a coroutine from a member method of an object.
Definition: coroutine.h:125