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