cilk_fiber.h 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  1. /* cilk_fiber.h -*-C++-*-
  2. *
  3. *************************************************************************
  4. *
  5. * @copyright
  6. * Copyright (C) 2012-2013, Intel Corporation
  7. * All rights reserved.
  8. *
  9. * @copyright
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. *
  14. * * Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * * Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in
  18. * the documentation and/or other materials provided with the
  19. * distribution.
  20. * * Neither the name of Intel Corporation nor the names of its
  21. * contributors may be used to endorse or promote products derived
  22. * from this software without specific prior written permission.
  23. *
  24. * @copyright
  25. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  26. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  27. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  28. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  29. * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  30. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  31. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  32. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  33. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
  35. * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. **************************************************************************/
  38. /**
  39. * @file cilk_fiber.h
  40. *
  41. * @brief Abstraction of a "fiber": A coprocess-like stack and auxiliary data
  42. */
  43. #ifndef INCLUDED_CILK_FIBER_DOT_H
  44. #define INCLUDED_CILK_FIBER_DOT_H
  45. #include <cilk/common.h>
  46. #ifdef __cplusplus
  47. # include <cstddef>
  48. #else
  49. # include <stddef.h>
  50. #endif
  51. #include "bug.h"
  52. #include "cilk-tbb-interop.h"
  53. #include "spin_mutex.h"
  54. #include "internal/abi.h" // Define __cilkrts_stack_frame
  55. /**
  56. * @brief Debugging level for Cilk fiber code.
  57. *
  58. * A value of 0 means no debugging.
  59. * Higher values generate more debugging output.
  60. */
  61. #define FIBER_DEBUG 0
  62. /**
  63. * @brief Flag for validating reference counts.
  64. *
  65. * Set to 1 to assert that fiber reference counts are reasonable.
  66. */
  67. #define FIBER_CHECK_REF_COUNTS 1
  68. /**
  69. * @brief Flag to determine whether fibers support reference counting.
  70. * We require reference counting only on Windows, for exception
  71. * processing. Unix does not need reference counting.
  72. */
  73. #if defined(_WIN32)
  74. # define NEED_FIBER_REF_COUNTS 1
  75. #endif
  76. /**
  77. * @brief Flag to enable support for the
  78. * cilk_fiber_get_current_fiber() method.
  79. *
  80. * I'd like this flag to be 0. However, the cilk_fiber test depends
  81. * on being able to call this method.
  82. */
  83. #if !defined(SUPPORT_GET_CURRENT_FIBER)
  84. # define SUPPORT_GET_CURRENT_FIBER 0
  85. #endif
  86. /**
  87. * @brief Switch for enabling "fast path" check for fibers, which
  88. * doesn't go to the heap or OS until checking the ancestors first.
  89. *
  90. * Doing this check seems to make the stress test in
  91. * cilk_fiber_pool.t.cpp run faster. But it doesn't seem to make much
  92. * difference in other benchmarks, so it is disabled by default.
  93. */
  94. #define USE_FIBER_TRY_ALLOCATE_FROM_POOL 0
  95. __CILKRTS_BEGIN_EXTERN_C
  96. /// @brief Forward reference to fiber pool.
  97. typedef struct cilk_fiber_pool cilk_fiber_pool;
  98. /** @brief Opaque data structure representing a fiber */
  99. typedef struct cilk_fiber cilk_fiber;
  100. /** @brief Function pointer type for use as a fiber's "main" procedure */
  101. typedef void (*cilk_fiber_proc)(cilk_fiber*);
  102. /** @brief Data structure associated with each fiber. */
  103. typedef struct cilk_fiber_data
  104. {
  105. __STDNS size_t stack_size; /**< Size of stack for fiber */
  106. __cilkrts_worker* owner; /**< Worker using this fiber */
  107. __cilkrts_stack_frame* resume_sf; /**< Stack frame to resume */
  108. __cilk_tbb_pfn_stack_op stack_op_routine; /**< Cilk/TBB interop callback */
  109. void* stack_op_data; /**< Data for Cilk/TBB callback */
  110. void* client_data; /**< Data managed by client */
  111. #ifdef _WIN32
  112. char *initial_sp; /**< Initalized in fiber_stub */
  113. # ifdef _WIN64
  114. char *steal_frame_sp; /**< RSP for frame stealing work */
  115. // Needed for exception handling so we can
  116. // identify when about to unwind off stack
  117. # endif
  118. #endif
  119. } cilk_fiber_data;
  120. /** @brief Pool of cilk_fiber for fiber reuse
  121. *
  122. * Pools form a hierarchy, with each pool pointing to its parent. When the
  123. * pool undeflows, it gets a fiber from its parent. When a pool overflows,
  124. * it returns some fibers to its parent. If the root pool underflows, it
  125. * allocates and initializes a new fiber from the heap but only if the total
  126. * is less than max_size; otherwise, fiber creation fails.
  127. */
  128. struct cilk_fiber_pool
  129. {
  130. spin_mutex* lock; ///< Mutual exclusion for pool operations
  131. __STDNS size_t stack_size; ///< Size of stacks for fibers in this pool.
  132. cilk_fiber_pool* parent; ///< @brief Parent pool.
  133. ///< If this pool is empty, get from parent
  134. // Describes inactive fibers stored in the pool.
  135. cilk_fiber** fibers; ///< Array of max_size fiber pointers
  136. unsigned max_size; ///< Limit on number of fibers in pool
  137. unsigned size; ///< Number of fibers currently in the pool
  138. // Statistics on active fibers that were allocated from this pool,
  139. // but no longer in the pool.
  140. int total; ///< @brief Fibers allocated - fiber deallocated from pool
  141. ///< total may be negative for non-root pools.
  142. int high_water; ///< High water mark of total fibers
  143. int alloc_max; ///< Limit on number of fibers allocated from the heap/OS
  144. };
  145. /** @brief Initializes a cilk_fiber_pool structure
  146. *
  147. * @param pool - The address of the pool that is to be initialized
  148. * @param parent - The address of this pool's parent, or NULL for root pool
  149. * @param stack_size - Size of stacks for fibers allocated from this pool.
  150. * @param buffer_size - The maximum number of fibers that may be pooled.
  151. * @param alloc_max - Limit on # of fibers this pool can allocate from the heap.
  152. * @param is_shared - True if accessing this pool needs a lock, false otherwise.
  153. */
  154. void cilk_fiber_pool_init(cilk_fiber_pool* pool,
  155. cilk_fiber_pool* parent,
  156. size_t stack_size,
  157. unsigned buffer_size,
  158. int alloc_max,
  159. int is_shared);
  160. /** @brief Sets the maximum number of fibers to allocate from a root pool.
  161. *
  162. * @param root_pool - A root fiber pool
  163. * @param max_fibers_to_allocate - The limit on # of fibers to allocate.
  164. *
  165. * Sets the maximum number of fibers that can be allocated from this
  166. * pool and all its descendants. This pool must be a root pool.
  167. */
  168. void cilk_fiber_pool_set_fiber_limit(cilk_fiber_pool* root_pool,
  169. unsigned max_fibers_to_allocate);
  170. /** @brief De-initalizes a cilk_fiber_pool
  171. *
  172. * @param pool - The address of the pool that is to be destroyed
  173. */
  174. void cilk_fiber_pool_destroy(cilk_fiber_pool* pool);
  175. /** @brief Allocates a new cilk_fiber.
  176. *
  177. * If the specified pool is empty, this method may choose to either
  178. * allocate a fiber from the heap (if pool->total < pool->alloc_max),
  179. * or retrieve a fiber from the parent pool.
  180. *
  181. * @note If a non-null fiber is returned, @c cilk_fiber_reset_state
  182. * should be called on this fiber before using it.
  183. *
  184. * An allocated fiber begins with a reference count of 1.
  185. * This method may lock @c pool or one of its ancestors.
  186. *
  187. * @pre pool should not be NULL.
  188. *
  189. * @param pool The fiber pool from which to retrieve a fiber.
  190. * @return An allocated fiber, or NULL if failed to allocate.
  191. */
  192. cilk_fiber* cilk_fiber_allocate(cilk_fiber_pool* pool);
  193. /** @brief Allocate and initialize a new cilk_fiber using memory from
  194. * the heap and/or OS.
  195. *
  196. * The allocated fiber begins with a reference count of 1.
  197. *
  198. * @param stack_size The size (in bytes) to be allocated for the fiber's
  199. * stack.
  200. * @return An initialized fiber. This method should not return NULL
  201. * unless some exceptional condition has occurred.
  202. */
  203. cilk_fiber* cilk_fiber_allocate_from_heap(size_t stack_size);
  204. /** @brief Resets an fiber object just allocated from a pool with the
  205. * specified proc.
  206. *
  207. * After this call, cilk_fiber_data object associated with this fiber
  208. * is filled with zeros.
  209. *
  210. * This function can be called only on a fiber that has been allocated
  211. * from a pool, but never used.
  212. *
  213. * @param fiber The fiber to reset and initialize.
  214. * @param start_proc The function to run when switching to the fiber. If
  215. * null, the fiber can be used with cilk_fiber_run_proc()
  216. * but not with cilk_fiber_resume().
  217. */
  218. void cilk_fiber_reset_state(cilk_fiber* fiber,
  219. cilk_fiber_proc start_proc);
  220. /** @brief Remove a reference from this fiber, possibly deallocating it.
  221. *
  222. * This fiber is deallocated only when there are no other references
  223. * to it. Deallocation happens either by returning the fiber to the
  224. * specified pool, or returning it to the heap.
  225. *
  226. * A fiber that is currently executing should not remove the last
  227. * reference to itself.
  228. *
  229. * When a fiber is deallocated, destructors are not called for the
  230. * objects (if any) still on its stack. The fiber's stack and fiber
  231. * data is returned to the stack pool but the client fiber data is not
  232. * deallocated.
  233. *
  234. * If the pool overflows because of a deallocation, then some fibers
  235. * will be returned to the parent pool. If the root pool overflows,
  236. * then the fiber is returned to the heap.
  237. *
  238. * @param fiber The Cilk fiber to remove a reference to.
  239. * @param pool The fiber pool to which the fiber should be returned. The
  240. * caller is assumed to have exclusive access to the pool
  241. * either because there is no contention for it or because
  242. * its lock has been acquired. If pool is NULL, any
  243. * deallocated fiber is destroyed and returned to the
  244. * heap.
  245. *
  246. * @return Final reference count. If the count is 0, the fiber was
  247. * returned to a pool or the heap.
  248. */
  249. int cilk_fiber_remove_reference(cilk_fiber *fiber, cilk_fiber_pool *pool);
  250. /** @brief Allocates and intializes this thread's main fiber
  251. *
  252. * Each thread has an "implicit" main fiber that control's the
  253. * thread's initial stack. This function makes this fiber visible to
  254. * the client and allocates the Cilk-specific aspects of the implicit
  255. * fiber. A call to this function must be paired with a call to
  256. * cilk_fiber_deallocate_fiber_from_thread()
  257. * or a memory leak (or worse) will result.
  258. *
  259. * A fiber allocated from a thread begins with a reference count of 2.
  260. * One is for being allocated, and one is for being active.
  261. * (A fiber created from a thread is automatically currently executing.)
  262. * The matching calls above each decrement the reference count by 1.
  263. *
  264. * @return A fiber for the currently executing thread.
  265. */
  266. cilk_fiber* cilk_fiber_allocate_from_thread(void);
  267. /** @brief Remove a fiber created from a thread,
  268. * possibly deallocating it.
  269. *
  270. * Same as cilk_fiber_remove_reference, except that it works on fibers
  271. * created via cilk_fiber_allocate_from_thread().
  272. *
  273. * Fibers created from a thread are never returned to a pool.
  274. *
  275. * @param fiber The Cilk fiber to remove a reference from.
  276. * @return Final reference count. If the count is 0, the fiber was
  277. * returned to the heap.
  278. */
  279. int cilk_fiber_remove_reference_from_thread(cilk_fiber *fiber);
  280. /** @brief Deallocate a fiber created from a thread,
  281. * possibly destroying it.
  282. *
  283. * This method decrements the reference count of the fiber by 2, and
  284. * destroys the fiber struct if the reference count is 0.
  285. *
  286. * OS-specific cleanup for the fiber executes unconditionally with
  287. * this method. The destruction of the actual object, however, does
  288. * not occur unless the reference count is 0.
  289. *
  290. * @param fiber The cilk_fiber to deallocate from a thread.
  291. * @return Final reference count. If the count is 0, the fiber was
  292. * returned to the heap.
  293. */
  294. int cilk_fiber_deallocate_from_thread(cilk_fiber *fiber);
  295. /** @brief Returns true if this fiber is allocated from a thread.
  296. */
  297. int cilk_fiber_is_allocated_from_thread(cilk_fiber *fiber);
  298. /** @brief Suspend execution on current fiber resumes other fiber.
  299. *
  300. * Suspends the current fiber and transfers control to a new fiber. Execution
  301. * on the new fiber resumes from the point at which fiber suspended itself to
  302. * run a different fiber. If fiber was freshly allocated, then runs the
  303. * start_proc function specified at allocation. This function returns when
  304. * another fiber resumes the self fiber. Note that the state of the
  305. * floating-point control register (i.e., the register that controls rounding
  306. * mode, etc.) is valid but indeterminate on return -- different
  307. * implementations will have different results.
  308. *
  309. * When the @c self fiber is resumed, execution proceeds as though
  310. * this function call returns.
  311. *
  312. * This operation increments the reference count of @p other.
  313. * This operation decrements the reference count of @p self.
  314. *
  315. * @param self Fiber to switch from. Must equal current fiber.
  316. * @param other Fiber to switch to.
  317. */
  318. void cilk_fiber_suspend_self_and_resume_other(cilk_fiber* self,
  319. cilk_fiber* other);
  320. /** @brief Removes a reference from the currently executing fiber and
  321. * resumes other fiber.
  322. *
  323. * Removes a reference from @p self and transfer control to @p other
  324. * fiber. Execution on @p other resumes from the point at which @p
  325. * other suspended itself to run a different fiber. If @p other fiber
  326. * was freshly allocated, then runs the function specified at
  327. * creation.
  328. *
  329. *
  330. * This operation increments the reference count of @p other.
  331. *
  332. * This operation conceptually decrements the reference count of
  333. * @p self twice, once to suspend it, and once to remove a reference to
  334. * it. Then, if the count is 0, it is returned to the specified pool
  335. * or destroyed.
  336. *
  337. * @pre @p self is the currently executing fiber.
  338. *
  339. * @param self Fiber to remove reference switch from.
  340. * @param self_pool Pool to which the current fiber should be returned
  341. * @param other Fiber to switch to.
  342. */
  343. NORETURN
  344. cilk_fiber_remove_reference_from_self_and_resume_other(cilk_fiber* self,
  345. cilk_fiber_pool* self_pool,
  346. cilk_fiber* other);
  347. /** @brief Set the proc method to execute immediately after a switch
  348. * to this fiber.
  349. *
  350. * The @c post_switch_proc method executes immediately after switching
  351. * away form @p self fiber to some other fiber, but before @c self
  352. * gets cleaned up.
  353. *
  354. * @note A fiber can have only one post_switch_proc method at a time.
  355. * If this method is called multiple times before switching to the
  356. * fiber, only the last proc method will execute.
  357. *
  358. * @param self Fiber.
  359. * @param post_switch_proc Proc method to execute immediately after switching to this fiber.
  360. */
  361. void cilk_fiber_set_post_switch_proc(cilk_fiber* self, cilk_fiber_proc post_switch_proc);
  362. /** @brief Invoke TBB stack op for this fiber.
  363. *
  364. * @param fiber Fiber to invoke stack op for.
  365. * @param op The stack op to invoke
  366. */
  367. void cilk_fiber_invoke_tbb_stack_op(cilk_fiber* fiber, __cilk_tbb_stack_op op);
  368. /** @brief Returns the fiber data associated with the specified fiber.
  369. *
  370. * The returned struct is owned by the fiber and is deallocated automatically
  371. * when the fiber is destroyed. However, the client_data field is owned by
  372. * the client and must be deallocated separately. When called for a
  373. * newly-allocated fiber, the returned data is zero-filled.
  374. *
  375. * @param fiber The fiber for which data is being requested.
  376. * @return The fiber data for the specified fiber
  377. */
  378. cilk_fiber_data* cilk_fiber_get_data(cilk_fiber* fiber);
  379. /** @brief Retrieve the owner field from the fiber.
  380. *
  381. * This method is provided for convenience. One can also get the
  382. * fiber data, and then get the owner field.
  383. */
  384. __CILKRTS_INLINE
  385. __cilkrts_worker* cilk_fiber_get_owner(cilk_fiber* fiber)
  386. {
  387. // TBD: We really want a static assert here, that this cast is
  388. // doing the right thing.
  389. cilk_fiber_data* fdata = (cilk_fiber_data*)fiber;
  390. return fdata->owner;
  391. }
  392. /** @brief Sets the owner field of a fiber.
  393. *
  394. * This method is provided for convenience. One can also get the
  395. * fiber data, and then get the owner field.
  396. */
  397. __CILKRTS_INLINE
  398. void cilk_fiber_set_owner(cilk_fiber* fiber, __cilkrts_worker* owner)
  399. {
  400. // TBD: We really want a static assert here, that this cast is
  401. // doing the right thing.
  402. cilk_fiber_data* fdata = (cilk_fiber_data*)fiber;
  403. fdata->owner = owner;
  404. }
  405. /** @brief Returns true if this fiber is resumable.
  406. *
  407. * A fiber is considered resumable when it is not currently being
  408. * executed.
  409. *
  410. * This function is used by Windows exception code.
  411. * @param fiber The fiber to check.
  412. * @return Nonzero value if fiber is resumable.
  413. */
  414. int cilk_fiber_is_resumable(cilk_fiber* fiber);
  415. /**
  416. * @brief Returns the base of this fiber's stack.
  417. *
  418. * On some platforms (e.g., Windows), the fiber must have started
  419. * running before we can get this information.
  420. *
  421. * @param fiber The fiber to get the stack pointer from.
  422. * @return The base of the stack, or NULL if this
  423. * information is not available yet.
  424. */
  425. char* cilk_fiber_get_stack_base(cilk_fiber* fiber);
  426. /****************************************************************************
  427. * TBB interop functions
  428. * **************************************************************************/
  429. /**
  430. * @brief Set the TBB callback information for a stack
  431. *
  432. * @param fiber The fiber to set the TBB callback information for
  433. * @param o The TBB callback thunk. Specifies the callback address and
  434. * context value.
  435. */
  436. void cilk_fiber_set_stack_op(cilk_fiber *fiber,
  437. __cilk_tbb_stack_op_thunk o);
  438. /**
  439. * @brief Save the TBB callback address and context value in
  440. * thread-local storage.
  441. *
  442. * We'll use it later when the thread binds to a worker.
  443. *
  444. * @param o The TBB callback thunk which is to be saved.
  445. */
  446. void cilk_fiber_tbb_interop_save_stack_op_info(__cilk_tbb_stack_op_thunk o);
  447. /**
  448. * @brief Move TBB stack-op info from thread-local storage and store
  449. * it into the fiber.
  450. *
  451. * Called when we bind a thread to the runtime. If there is any TBB
  452. * interop information in thread-local storage, bind it to the stack
  453. * now.
  454. *
  455. * @pre \c fiber should not be NULL.
  456. * @param fiber The fiber that should take over the TBB interop information.
  457. */
  458. void cilk_fiber_tbb_interop_use_saved_stack_op_info(cilk_fiber *fiber);
  459. /**
  460. * @brief Free any TBB interop information saved in thread-local storage
  461. */
  462. void cilk_fiber_tbb_interop_free_stack_op_info(void);
  463. /**
  464. * @brief Migrate any TBB interop information from a cilk_fiber to
  465. * thread-local storage.
  466. *
  467. * Returns immediately if no TBB interop information has been
  468. * associated with the stack.
  469. *
  470. * @param fiber The cilk_fiber who's TBB interop information should be
  471. * saved in thread-local storage.
  472. */
  473. void cilk_fiber_tbb_interop_save_info_from_stack(cilk_fiber* fiber);
  474. #if SUPPORT_GET_CURRENT_FIBER
  475. /** @brief Returns the fiber associated with the currently executing thread
  476. *
  477. * @note This function is currently used only for testing the Cilk
  478. * runtime.
  479. *
  480. * @return Fiber associated with the currently executing thread or NULL if no
  481. * fiber was associated with this thread.
  482. */
  483. cilk_fiber* cilk_fiber_get_current_fiber(void);
  484. #endif
  485. #if NEED_FIBER_REF_COUNTS
  486. /** @brief Returns true if this fiber has reference count > 0.
  487. *
  488. * @param fiber The fiber to check for references.
  489. * @return Nonzero value if the fiber has references.
  490. */
  491. int cilk_fiber_has_references(cilk_fiber *fiber);
  492. /** @brief Returns the value of the reference count.
  493. *
  494. * @param fiber The fiber to check for references.
  495. * @return The value of the reference count of fiber.
  496. */
  497. int cilk_fiber_get_ref_count(cilk_fiber *fiber);
  498. /** @brief Adds a reference to this fiber.
  499. *
  500. * Increments the reference count of a current fiber. Fibers with
  501. * nonzero reference count will not be freed or returned to a fiber
  502. * pool.
  503. *
  504. * @param fiber The fiber to add a reference to.
  505. */
  506. void cilk_fiber_add_reference(cilk_fiber *fiber);
  507. #endif // NEED_FIBER_REF_COUNTS
  508. __CILKRTS_END_EXTERN_C
  509. #ifdef __cplusplus
  510. // Some C++ implementation details
  511. /// Opaque declaration of a cilk_fiber_sysdep object.
  512. struct cilk_fiber_sysdep;
  513. /**
  514. * cilk_fiber is a base-class for system-dependent fiber implementations.
  515. */
  516. struct cilk_fiber : protected cilk_fiber_data
  517. {
  518. protected:
  519. // This is a rare acceptable use of protected inheritence and protected
  520. // variable access: when the base class and derived class collaborate
  521. // tightly to comprise a single component.
  522. /// For overloading constructor of cilk_fiber.
  523. enum from_thread_t { from_thread = 1 };
  524. // Boolean flags capturing the status of the fiber.
  525. // Each one can be set independently.
  526. // A default fiber is constructed with a flag value of 0.
  527. static const int RESUMABLE = 0x01; ///< True if the fiber is in a suspended state and can be resumed.
  528. static const int ALLOCATED_FROM_THREAD = 0x02; ///< True if fiber was allocated from a thread.
  529. cilk_fiber_proc m_start_proc; ///< Function to run on start up/reset
  530. cilk_fiber_proc m_post_switch_proc; ///< Function that executes when we first switch to a new fiber from a different one.
  531. cilk_fiber* m_pending_remove_ref;///< Fiber to possibly delete on start up or resume
  532. cilk_fiber_pool* m_pending_pool; ///< Pool where m_pending_remove_ref should go if it is deleted.
  533. unsigned m_flags; ///< Captures the status of this fiber.
  534. #if NEED_FIBER_REF_COUNTS
  535. volatile long m_outstanding_references; ///< Counts references to this fiber.
  536. #endif
  537. /// Creates a fiber with NULL data.
  538. cilk_fiber();
  539. /**
  540. * @brief Creates a fiber with user-specified arguments.
  541. *
  542. * @param stack_size Size of stack to use for this fiber.
  543. */
  544. cilk_fiber(std::size_t stack_size);
  545. /// Empty destructor.
  546. ~cilk_fiber();
  547. /**
  548. * @brief Performs any actions that happen after switching from
  549. * one fiber to another.
  550. *
  551. * These actions are:
  552. * 1. Execute m_post_switch_proc on a fiber.
  553. * 2. Do any pending deallocations from the previous fiber.
  554. */
  555. void do_post_switch_actions();
  556. /**
  557. *@brief Helper method that converts a @c cilk_fiber object into a
  558. * @c cilk_fiber_sysdep object.
  559. *
  560. * The @c cilk_fiber_sysdep object contains the system-dependent parts
  561. * of the implementation of a @\c cilk_fiber.
  562. *
  563. * We could have @c cilk_fiber_sysdep inherit from @c cilk_fiber and
  564. * then use virtual functions. But since a given platform only uses
  565. * one definition of @c cilk_fiber_sysdep at a time, we statically
  566. * cast between them.
  567. */
  568. inline cilk_fiber_sysdep* sysdep();
  569. /**
  570. * @brief Set resumable flag to specified state.
  571. */
  572. inline void set_resumable(bool state) {
  573. m_flags = state ? (m_flags | RESUMABLE) : (m_flags & (~RESUMABLE));
  574. }
  575. /**
  576. *@brief Set the allocated_from_thread flag.
  577. */
  578. inline void set_allocated_from_thread(bool state) {
  579. m_flags = state ? (m_flags | ALLOCATED_FROM_THREAD) : (m_flags & (~ALLOCATED_FROM_THREAD));
  580. }
  581. public:
  582. /**
  583. * @brief Allocates and initializes a new cilk_fiber, either from
  584. * the specified pool or from the heap.
  585. *
  586. * @pre pool should not be NULL.
  587. */
  588. static cilk_fiber* allocate(cilk_fiber_pool* pool);
  589. /**
  590. * @brief Allocates a fiber from the heap.
  591. */
  592. static cilk_fiber* allocate_from_heap(size_t stack_size);
  593. /**
  594. * @brief Return a fiber to the heap.
  595. */
  596. void deallocate_to_heap();
  597. /**
  598. * @brief Reset the state of a fiber just allocated from a pool.
  599. */
  600. void reset_state(cilk_fiber_proc start_proc);
  601. /**
  602. * @brief Remove a reference from this fiber, possibly
  603. * deallocating it if the reference count becomes 0.
  604. *
  605. * @param pool The fiber pool to which this fiber should be returned.
  606. * @return The final reference count.
  607. */
  608. int remove_reference(cilk_fiber_pool* pool);
  609. /**
  610. * @brief Deallocate the fiber by returning it to the pool.
  611. * @pre This method should only be called if the reference count
  612. * is 0.
  613. *
  614. * @param pool The fiber pool to return this fiber to. If NULL,
  615. * fiber is returned to the heap.
  616. */
  617. void deallocate_self(cilk_fiber_pool *pool);
  618. /** @brief Allocates and intializes this thread's main fiber. */
  619. static cilk_fiber* allocate_from_thread();
  620. /** @brief Deallocate a fiber created from a thread,
  621. * possibly destroying it.
  622. *
  623. * This method decrements the reference count of this fiber by 2,
  624. * and destroys the fiber if the reference count is 0.
  625. *
  626. * OS-specific cleanup for the fiber executes unconditionally with for
  627. * this method. The destruction of the actual object, however, does
  628. * not occur unless the reference count is 0.
  629. *
  630. * @return Final reference count. If the count is 0, the fiber was
  631. * returned to the heap.
  632. */
  633. int deallocate_from_thread();
  634. /** @brief Removes a reference from this fiber.
  635. *
  636. * This method deallocates this fiber if the reference count
  637. * becomes 0.
  638. *
  639. * @pre This fiber must be allocated from a thread.
  640. * @return The final reference count of this fiber.
  641. */
  642. int remove_reference_from_thread();
  643. #if SUPPORT_GET_CURRENT_FIBER
  644. /** @brief Get the current fiber from TLS.
  645. *
  646. * @note This function is only used for testing the runtime.
  647. */
  648. static cilk_fiber* get_current_fiber();
  649. #endif
  650. /** @brief Suspend execution on current fiber resumes other fiber.
  651. *
  652. * Control returns after resuming execution of the self fiber.
  653. */
  654. void suspend_self_and_resume_other(cilk_fiber* other);
  655. /** @brief Removes a reference from the currently executing fiber
  656. * and resumes other fiber.
  657. *
  658. * This fiber may be returned to a pool or deallocated.
  659. */
  660. NORETURN remove_reference_from_self_and_resume_other(cilk_fiber_pool* self_pool,
  661. cilk_fiber* other);
  662. /** @brief Set the proc method to execute immediately after a switch
  663. * to this fiber.
  664. *
  665. * @param post_switch_proc Proc method to execute immediately
  666. * after switching to this fiber.
  667. */
  668. inline void set_post_switch_proc(cilk_fiber_proc post_switch_proc) {
  669. m_post_switch_proc = post_switch_proc;
  670. }
  671. /** @brief Returns true if this fiber is resumable.
  672. *
  673. * A fiber is considered resumable when it is not currently being
  674. * executed.
  675. */
  676. inline bool is_resumable(void) {
  677. return (m_flags & RESUMABLE);
  678. }
  679. /** @brief Returns true if fiber was allocated from a thread. */
  680. inline bool is_allocated_from_thread(void) {
  681. return (m_flags & ALLOCATED_FROM_THREAD);
  682. }
  683. /**
  684. *@brief Get the address at the base of the stack for this fiber.
  685. */
  686. inline char* get_stack_base();
  687. /** @brief Return the data for this fiber. */
  688. cilk_fiber_data* get_data() { return this; }
  689. /** @brief Return the data for this fiber. */
  690. cilk_fiber_data const* get_data() const { return this; }
  691. #if NEED_FIBER_REF_COUNTS
  692. /** @brief Verifies that this fiber's reference count equals v. */
  693. inline void assert_ref_count_equals(long v) {
  694. #if FIBER_CHECK_REF_COUNTS
  695. CILK_ASSERT(m_outstanding_references >= v);
  696. #endif
  697. }
  698. /** @brief Verifies that this fiber's reference count is at least v. */
  699. inline void assert_ref_count_at_least(long v) {
  700. #if FIBER_CHECK_REF_COUNTS
  701. CILK_ASSERT(m_outstanding_references >= v);
  702. #endif
  703. }
  704. /** @brief Get reference count. */
  705. inline long get_ref_count() { return m_outstanding_references; }
  706. /** @brief Initialize reference count.
  707. * Operation is not atomic.
  708. */
  709. inline void init_ref_count(long v) { m_outstanding_references = v; }
  710. // For Windows, updates to the fiber reference count need to be
  711. // atomic, because exceptions can live on a stack that we are not
  712. // currently executing on. Thus, we can update the reference
  713. // count of a fiber we are not currently executing on.
  714. /** @brief Increment reference count for this fiber [Windows]. */
  715. inline void inc_ref_count() { atomic_inc_ref_count(); }
  716. /** @brief Decrement reference count for this fiber [Windows]. */
  717. inline long dec_ref_count() { return atomic_dec_ref_count(); }
  718. /** @brief Subtract v from the reference count for this fiber [Windows]. */
  719. inline long sub_from_ref_count(long v) { return atomic_sub_from_ref_count(v); }
  720. #else // NEED_FIBER_REF_COUNTS
  721. // Without reference counting, we have placeholder methods.
  722. inline void init_ref_count(long v) { }
  723. inline void inc_ref_count() { }
  724. // With no reference counting, dec_ref_count always return 0.
  725. // Thus, anyone checking is always the "last" one.
  726. inline long dec_ref_count() { return 0; }
  727. inline long sub_from_ref_count(long v) { return 0; }
  728. // The assert methods do nothing.
  729. inline void assert_ref_count_equals(long v) { }
  730. inline void assert_ref_count_at_least(long v) { }
  731. #endif
  732. /**
  733. * @brief Call TBB to tell it about an "interesting" event.
  734. *
  735. * @param op Value specifying the event to track.
  736. */
  737. void invoke_tbb_stack_op(__cilk_tbb_stack_op op);
  738. private:
  739. /**
  740. * @brief Helper method: try to allocate a fiber from this pool or
  741. * its ancestors without going to the OS / heap.
  742. *
  743. * Returns allocated pool, or NULL if no pool is found.
  744. *
  745. * If pool contains a suitable fiber. Return it. Otherwise, try to
  746. * recursively grab a fiber from the parent pool, if there is one.
  747. *
  748. * This method will not allocate a fiber from the heap.
  749. */
  750. static cilk_fiber* try_allocate_from_pool_recursive(cilk_fiber_pool* pool);
  751. #if NEED_FIBER_REF_COUNTS
  752. /**
  753. * @brief Atomic increment of reference count.
  754. */
  755. void atomic_inc_ref_count();
  756. /**
  757. * @brief Atomic decrement of reference count.
  758. */
  759. long atomic_dec_ref_count();
  760. /**
  761. * @brief Atomic subtract of v from reference count.
  762. * @param v Value to subtract.
  763. */
  764. long atomic_sub_from_ref_count(long v);
  765. #endif // NEED_FIBER_REF_COUNTS
  766. };
  767. #endif // __cplusplus
  768. #endif // ! defined(INCLUDED_CILK_FIBER_DOT_H)