You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

394 lines
12 KiB

12 years ago
9 years ago
12 years ago
12 years ago
12 years ago
12 years ago
  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. #ifndef __COROUTINE_H
  26. #define __COROUTINE_H
  27. #include <cassert>
  28. #include <cstdlib>
  29. #include <type_traits>
  30. #include <system/libcontext.h>
  31. #include <memory>
  32. /**
  33. * Class COROUNTINE.
  34. * Implements a coroutine. Wikipedia has a good explanation:
  35. *
  36. * "Coroutines are computer program components that generalize subroutines to
  37. * allow multiple entry points for suspending and resuming execution at certain locations.
  38. * Coroutines are well-suited for implementing more familiar program components such as cooperative
  39. * tasks, exceptions, event loop, iterators, infinite lists and pipes."
  40. *
  41. * In other words, a coroutine can be considered a lightweight thread - which can be
  42. * preempted only when it deliberately yields the control to the caller. This way,
  43. * we avoid concurrency problems such as locking / race conditions.
  44. *
  45. * Uses libcontext library to do the actual context switching.
  46. *
  47. * This particular version takes a DELEGATE as an entry point, so it can invoke
  48. * methods within a given object as separate coroutines.
  49. *
  50. * See coroutine_example.cpp for sample code.
  51. */
  52. template <typename ReturnType, typename ArgType>
  53. class COROUTINE
  54. {
  55. private:
  56. class CALL_CONTEXT;
  57. struct INVOCATION_ARGS
  58. {
  59. enum
  60. {
  61. FROM_ROOT, // a stub was called/a corutine was resumed from the main-stack context
  62. FROM_ROUTINE, // a stub was called/a coroutine was resumed fron a coroutine context
  63. CONTINUE_AFTER_ROOT // a function sent a request to invoke a function on the main
  64. // stack context
  65. } type; // invocation type
  66. COROUTINE* destination; // stores the coroutine pointer for the stub OR the coroutine
  67. // ptr for the coroutine to be resumed if a
  68. // root(main-stack)-call-was initiated.
  69. CALL_CONTEXT* context; // pointer to the call context of the current callgraph this
  70. // call context holds a reference to the main stack context
  71. };
  72. using CONTEXT_T = libcontext::fcontext_t;
  73. using CALLEE_STORAGE = CONTEXT_T;
  74. class CALL_CONTEXT
  75. {
  76. public:
  77. void SetMainStack( CONTEXT_T* aStack )
  78. {
  79. m_mainStackContext = aStack;
  80. }
  81. void RunMainStack( COROUTINE* aCor, std::function<void()> aFunc )
  82. {
  83. m_mainStackFunction = std::move( aFunc );
  84. INVOCATION_ARGS args{ INVOCATION_ARGS::CONTINUE_AFTER_ROOT, aCor, this };
  85. libcontext::jump_fcontext( &aCor->m_callee, *m_mainStackContext,
  86. reinterpret_cast<intptr_t>( &args ) );
  87. }
  88. void Continue( INVOCATION_ARGS* args )
  89. {
  90. while( args->type == INVOCATION_ARGS::CONTINUE_AFTER_ROOT )
  91. {
  92. m_mainStackFunction();
  93. args->type = INVOCATION_ARGS::FROM_ROOT;
  94. args = args->destination->doResume( args );
  95. }
  96. }
  97. private:
  98. CONTEXT_T* m_mainStackContext;
  99. std::function<void()> m_mainStackFunction;
  100. };
  101. public:
  102. COROUTINE() :
  103. COROUTINE( nullptr )
  104. {
  105. }
  106. /**
  107. * Constructor
  108. * Creates a coroutine from a member method of an object
  109. */
  110. template <class T>
  111. COROUTINE( T* object, ReturnType(T::*ptr)( ArgType ) ) :
  112. COROUTINE( std::bind( ptr, object, std::placeholders::_1 ) )
  113. {
  114. }
  115. /**
  116. * Constructor
  117. * Creates a coroutine from a delegate object
  118. */
  119. COROUTINE( std::function<ReturnType(ArgType)> aEntry ) :
  120. m_func( std::move( aEntry ) ),
  121. m_running( false ),
  122. m_args( 0 ),
  123. m_caller( nullptr ),
  124. m_callContext( nullptr ),
  125. m_callee( nullptr ),
  126. m_retVal( 0 )
  127. {
  128. }
  129. ~COROUTINE()
  130. {
  131. }
  132. public:
  133. /**
  134. * Function KiYield()
  135. *
  136. * Stops execution of the coroutine and returns control to the caller.
  137. * After a yield, Call() or Resume() methods invoked by the caller will
  138. * immediately return true, indicating that we are not done yet, just asleep.
  139. */
  140. void KiYield()
  141. {
  142. jumpOut();
  143. }
  144. /**
  145. * Function KiYield()
  146. *
  147. * KiYield with a value - passes a value of given type to the caller.
  148. * Useful for implementing generator objects.
  149. */
  150. void KiYield( ReturnType& aRetVal )
  151. {
  152. m_retVal = aRetVal;
  153. jumpOut();
  154. }
  155. /**
  156. * Function SetEntry()
  157. *
  158. * Defines the entry point for the coroutine, if not set in the constructor.
  159. */
  160. void SetEntry( std::function<ReturnType(ArgType)> aEntry )
  161. {
  162. m_func = std::move( aEntry );
  163. }
  164. /**
  165. * Function RunMainStack()
  166. *
  167. * Run a functor inside the application main stack context
  168. * Call this function for example if the operation will spawn a webkit browser instance which
  169. * will walk the stack to the upper border of the address space on mac osx systems because
  170. * its javascript needs garbage collection (for example if you paste text into an edit box).
  171. */
  172. void RunMainStack( std::function<void()> func )
  173. {
  174. assert( m_callContext );
  175. m_callContext->RunMainStack( this, std::move( func ) );
  176. }
  177. /**
  178. * Function Call()
  179. *
  180. * Starts execution of a coroutine, passing args as its arguments. Call this method
  181. * from the application main stack only.
  182. * @return true, if the coroutine has yielded and false if it has finished its
  183. * execution (returned).
  184. */
  185. bool Call( ArgType aArg )
  186. {
  187. CALL_CONTEXT ctx;
  188. INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROOT, this, &ctx };
  189. ctx.Continue( doCall( &args, aArg ) );
  190. return Running();
  191. }
  192. /**
  193. * Function Call()
  194. *
  195. * Starts execution of a coroutine, passing args as its arguments. Call this method
  196. * for a nested coroutine invocation.
  197. * @return true, if the coroutine has yielded and false if it has finished its
  198. * execution (returned).
  199. */
  200. bool Call( const COROUTINE& aCor, ArgType aArg )
  201. {
  202. INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROUTINE, this, aCor.m_callContext };
  203. doCall( &args, aArg );
  204. // we will not be asked to continue
  205. return Running();
  206. }
  207. /**
  208. * Function Resume()
  209. *
  210. * Resumes execution of a previously yielded coroutine. Call this method only
  211. * from the main application stack.
  212. * @return true, if the coroutine has yielded again and false if it has finished its
  213. * execution (returned).
  214. */
  215. bool Resume()
  216. {
  217. CALL_CONTEXT ctx;
  218. INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROOT, this, &ctx };
  219. ctx.Continue( doResume( &args ) );
  220. return Running();
  221. }
  222. /**
  223. * Function Resume()
  224. *
  225. * Resumes execution of a previously yielded coroutine. Call this method
  226. * for a nested coroutine invocation.
  227. * @return true, if the coroutine has yielded again and false if it has finished its
  228. * execution (returned).
  229. */
  230. bool Resume( const COROUTINE& aCor )
  231. {
  232. INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROUTINE, this, aCor.m_callContext };
  233. doResume( &args );
  234. // we will not be asked to continue
  235. return Running();
  236. }
  237. /**
  238. * Function ReturnValue()
  239. *
  240. * Returns the yielded value (the argument KiYield() was called with)
  241. */
  242. const ReturnType& ReturnValue() const
  243. {
  244. return m_retVal;
  245. }
  246. /**
  247. * Function Running()
  248. *
  249. * @return true, if the coroutine is active
  250. */
  251. bool Running() const
  252. {
  253. return m_running;
  254. }
  255. private:
  256. INVOCATION_ARGS* doCall( INVOCATION_ARGS* aInvArgs, ArgType aArgs )
  257. {
  258. assert( m_func );
  259. assert( !m_callee );
  260. m_args = &aArgs;
  261. assert( m_stack == nullptr );
  262. size_t stackSize = c_defaultStackSize;
  263. void* sp = nullptr;
  264. #ifndef LIBCONTEXT_HAS_OWN_STACK
  265. // fixme: Clean up stack stuff. Add a guard
  266. m_stack.reset( new char[stackSize] );
  267. // align to 16 bytes
  268. sp = (void*)((((ptrdiff_t) m_stack.get()) + stackSize - 0xf) & (~0x0f));
  269. // correct the stack size
  270. stackSize -= size_t( ( (ptrdiff_t) m_stack.get() + stackSize ) - (ptrdiff_t) sp );
  271. #endif
  272. m_callee = libcontext::make_fcontext( sp, stackSize, callerStub );
  273. m_running = true;
  274. // off we go!
  275. return jumpIn( aInvArgs );
  276. }
  277. INVOCATION_ARGS* doResume( INVOCATION_ARGS* args )
  278. {
  279. return jumpIn( args );
  280. }
  281. /* real entry point of the coroutine */
  282. static void callerStub( intptr_t aData )
  283. {
  284. INVOCATION_ARGS& args = *reinterpret_cast<INVOCATION_ARGS*>( aData );
  285. // get pointer to self
  286. COROUTINE* cor = args.destination;
  287. cor->m_callContext = args.context;
  288. if( args.type == INVOCATION_ARGS::FROM_ROOT )
  289. cor->m_callContext->SetMainStack( &cor->m_caller );
  290. // call the coroutine method
  291. cor->m_retVal = cor->m_func( *(cor->m_args) );
  292. cor->m_running = false;
  293. // go back to wherever we came from.
  294. cor->jumpOut();
  295. }
  296. INVOCATION_ARGS* jumpIn( INVOCATION_ARGS* args )
  297. {
  298. args = reinterpret_cast<INVOCATION_ARGS*>(
  299. libcontext::jump_fcontext( &m_caller, m_callee,
  300. reinterpret_cast<intptr_t>( args ) )
  301. );
  302. return args;
  303. }
  304. void jumpOut()
  305. {
  306. INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROUTINE, nullptr, nullptr };
  307. INVOCATION_ARGS* ret;
  308. ret = reinterpret_cast<INVOCATION_ARGS*>(
  309. libcontext::jump_fcontext( &m_callee, m_caller,
  310. reinterpret_cast<intptr_t>( &args ) )
  311. );
  312. m_callContext = ret->context;
  313. if( ret->type == INVOCATION_ARGS::FROM_ROOT )
  314. {
  315. m_callContext->SetMainStack( &m_caller );
  316. }
  317. }
  318. static constexpr int c_defaultStackSize = 2000000; // fixme: make configurable
  319. ///< coroutine stack
  320. std::unique_ptr<char[]> m_stack;
  321. std::function<ReturnType( ArgType )> m_func;
  322. bool m_running;
  323. ///< pointer to coroutine entry arguments. Stripped of references
  324. ///< to avoid compiler errors.
  325. typename std::remove_reference<ArgType>::type* m_args;
  326. ///< saved caller context
  327. CONTEXT_T m_caller;
  328. ///< main stack information
  329. CALL_CONTEXT* m_callContext;
  330. ///< saved coroutine context
  331. CALLEE_STORAGE m_callee;
  332. ReturnType m_retVal;
  333. };
  334. #endif