1 /* full_frame.h -*-C++-*-
3 *************************************************************************
5 * Copyright (C) 2009-2016, Intel Corporation
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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.
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.
35 * *********************************************************************
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
46 * We welcome your contributions to this open source project. Thank you
47 * for your assistance in helping us improve Cilk Plus.
48 **************************************************************************/
50 #ifndef INCLUDED_FULL_FRAME_DOT_H
51 #define INCLUDED_FULL_FRAME_DOT_H
54 #include "rts-common.h"
55 #include "worker_mutex.h"
57 #include <cilk/common.h>
58 #include <internal/abi.h>
60 #include "cilk_fiber.h"
62 __CILKRTS_BEGIN_EXTERN_C
64 /** Magic numbers for full_frame, used for debugging */
65 typedef unsigned long long ff_magic_t
;
67 /* COMMON_SYSDEP */ struct pending_exception_info
; /* opaque */
69 /*************************************************************
71 *************************************************************/
75 * @brief A full frame includes additional information such as a join
76 * counter and parent frame.
77 * @defgroup FullFrames Full Frames
78 * A full frame includes additional information such as a join
79 * counter and parent frame.
84 * Convenience typedef so we don't have to specify "struct full_frame"
85 * all over the code. Putting it before the structure definition allows
86 * us to use the typedef within the structure itself
88 typedef struct full_frame full_frame
;
91 * @brief A full frame includes additional information such as a join
92 * counter and parent frame.
94 * The frame at the top of a worker's stack is promoted into a "full"
95 * frame, which carries additional information, such as join counter
96 * and parent frame. Full frames can be suspended at a sync, in which
97 * case they lie somewhere in memory and do not belong to any
100 * Full frames are in contrast to the entries in the worker's deque which
101 * are only represented by a pointer to their __cilkrts_stack_frame.
103 * At any instant, we say that a full frame ff is either "suspended",
104 * or "owned" by some worker w.
106 * More precisely, we say that a worker w owns a frame ff under one of
107 * the following conditions:
109 * 1. Creation: Worker w has just created ff, but not yet linked ff
110 * into the tree of full frames. This situation can occur when a
111 * worker is unrolling a call stack to promote a
112 * __cilkrts_stack_frame to a full_frame.
113 * 2. Executing frame: We have w->l->frame_ff == ff, i.e,. ff is the
114 * currently executing frame for w.
115 * 3. Next frame: We have w->l->next_frame_ff == ff, i.e,. ff is the
116 * next frame that w is about to execute.
117 * 4. Resume execution: Worker w has popped ff from
118 * w->l->next_frame_ff, and is about to resume execution of ff.
119 * 5. Dying leaf: Worker w has finished executing a frame ff
120 * that is a leaf the tree of full frames, and is in the process
121 * of unlinking "ff" from the tree.
123 * Otherwise, the frame ff is suspended, and has no owner.
124 * Note that work-stealing changes the owner of a full frame from the
125 * victim to the thief.
127 * Using this notion of ownership, we classify the fields of a full
128 * frame into one of several categories:
131 * These fields are accessed only by the owner of the full frame.
132 * Because a frame can have only one owner at a time, these fields
133 * can be modified without any (additional) locking or
134 * synchronization, assuming the correct synchronization for
135 * changing the ownership of full frame (e.g., on a successful
136 * steal) is already in place.
138 * 2. Constant (i.e., read-only):
139 * This field is constant for the lifetime of the full frame.
140 * No locks are needed to access this field.
141 * Technically, a field could be read-only and local, but we assume
145 * To access this field in the frame ff, a worker should acquire
147 * A self-locked field is conceptually "shared" between the worker
148 * that owns frame ff (which is a child) and the worker that
149 * owns the frame ff->parent (which is the parent of ff).
152 * To access this field in the frame ff, a worker should
153 * acquire the lock on ff->parent.
154 * A parent-locked field is conceptually "shared" between the worker
155 * that owns frame ff, and a worker that is either owns the
156 * parent frame (ff->parent) or owns a sibling frame of ff (i.e.,
157 * any child of ff->parent).
160 * A field used explicitly for synchronization (i.e., locks).
163 /* COMMON_PORTABLE */
167 * Value to detect writes off the beginning of a full_frame.
169 # define FULL_FRAME_MAGIC_0 ((ff_magic_t)0x361e710b9597d553ULL)
172 * Field to detect writes off the beginning of a full_frame. Must be
173 * FULL_FRAME_MAGIC_0.
176 ff_magic_t full_frame_magic_0
;
179 * Used to serialize access to this full_frame
185 * Count of outstanding children running in parallel
191 * If TRUE: frame was called by the parent.
192 * If FALSE: frame was spawned by parent.
198 * TRUE if this frame is the loot of a simulated steal.
200 * This situation never happens in normal execution. However,
201 * when running under cilkscreen, a worker may promote frames and
202 * then immediately suspend them, in order to simulate an
203 * execution on an infinite number of processors where all spawns
204 * are stolen. In this case, the frame is marked as the loot of a fake
208 int simulated_stolen
;
211 * Caller of this full_frame
217 * Doubly-linked list of children. The serial execution order is
218 * by definition from left to right. Because of how we do work
219 * stealing, the parent is always to the right of all its
222 * For a frame ff, we lock the ff->parent to follow the sibling
227 full_frame
*left_sibling
;
230 * @copydoc left_sibling
232 full_frame
*right_sibling
;
235 * Pointer to rightmost child
239 full_frame
*rightmost_child
;
242 * Call stack associated with this frame.
243 * Set and reset in make_unrunnable and make_runnable
247 __cilkrts_stack_frame
*call_stack
;
250 * Accumulated reducers of children
254 struct cilkred_map
*children_reducer_map
;
257 * Accumulated reducers of right siblings that have already
262 struct cilkred_map
*right_reducer_map
;
265 * Exception that needs to be pass to our parent
269 * TBD: verify that the exception code satisfies this requirement.
271 struct pending_exception_info
*pending_exception
;
274 * Exception from one of our children
278 struct pending_exception_info
*child_pending_exception
;
281 * Exception from any right siblings
285 struct pending_exception_info
*right_pending_exception
;
288 * Stack pointer to restore on sync.
295 * Stack pointer to restore on exception.
301 * Exception trylevel at steal
304 * TBD: this field is set but not read?
306 unsigned long trylevel
;
309 * Exception registration head pointer to restore on sync.
312 unsigned long registration
;
316 * Size of frame to match sync sp
318 * TBD: obsolete field only used in debugging?
320 ptrdiff_t frame_size
;
323 * Allocated fibers that need to be freed. The fibers work
324 * like a reducer. The leftmost frame may have @c fiber_self
325 * null and owner non-null.
328 * TBD: verify exception code satisfies this requirement.
330 cilk_fiber
*fiber_self
;
333 * Allocated fibers that need to be freed. The fibers work
334 * like a reducer. The leftmost frame may have @c fiber_self
335 * null and owner non-null.
339 cilk_fiber
*fiber_child
;
342 * If the sync_master is set, this function can only be sync'd by the team
343 * leader, who first entered Cilk. This is set by the first worker to steal
344 * from the user worker.
348 __cilkrts_worker
*sync_master
;
351 * Value to detect writes off the end of a full_frame.
353 # define FULL_FRAME_MAGIC_1 ((ff_magic_t)0x189986dcc7aee1caULL)
356 * Field to detect writes off the end of a full_frame. Must be
357 * FULL_FRAME_MAGIC_1.
361 ff_magic_t full_frame_magic_1
;
364 /* The functions __cilkrts_put_stack and __cilkrts_take_stack keep track of
365 * changes in the stack's depth between when the point at which a frame is
366 * stolen and when it is resumed at a sync. A stolen frame typically goes
367 * through the following phase changes:
369 * 1. Suspend frame while stealing it.
370 * 2. Resume stolen frame at begining of continuation
371 * 3. Suspend stolen frame at a sync
372 * 4. Resume frame (no longer marked stolen) after the sync
374 * When the frame is suspended (steps 1 and 3), __cilkrts_put_stack is called to
375 * establish the stack pointer for the sync. When the frame is resumed (steps
376 * 2 and 4), __cilkrts_take_stack is called to indicate the stack pointer
377 * (which may be on a different stack) at
378 * the point of resume. If the stack pointer changes between steps 2 and 3,
379 * e.g., as a result of pushing 4 bytes onto the stack,
380 * the offset is reflected in the value of ff->sync_sp after step 3 relative to
381 * its value after step 1 (e.g., the value of ff->sync_sp after step 3 would be
382 * 4 less than its value after step 1, for a down-growing stack).
384 * Imp detail: The actual call chains for each of these phase-change events is:
386 * 1. unroll_call_stack -> make_unrunnable -> __cilkrts_put_stack
387 * 2. do_work -> __cilkrts_resume -> __cilkrts_take_stack
388 * 3. do_sync -> disown -> make_runnable -> __cilkrts_put_stack
389 * 4. __cilkrts_resume -> __cilkrts_take_stack
391 * (The above is a changeable implementation detail. The resume, sequence, in
392 * particular, is more complex on some operating systems.)
396 * @brief Records the stack pointer within the @c sf stack frame as the
397 * current stack pointer at the point of suspending full frame @c ff.
399 * @pre @c ff->sync_sp must be either null or contain the result of a prior call to
400 * @c __cilkrts_take_stack().
401 * @pre If @c ff->sync_sp is not null, then @c SP(sf) must refer to the same stack as
402 * the @c sp argument to the prior call to @c __cilkrts_take_stack().
405 * @post If @c ff->sync_sp was null before the call, then @c
406 * ff->sync_sp will be set to @c SP(sf).
407 * @post Otherwise, @c ff->sync_sp will be restored to the value it had just prior
408 * to the last call to @c __cilkrts_take_stack(), except offset by any change
409 * in the stack pointer between the call to @c __cilkrts_take_stack() and
410 * this call to @c __cilkrts_put_stack().
412 * @param ff The full frame that is being suspended.
413 * @param sf The @c __cilkrts_stack_frame that is being suspended. The stack
414 * pointer will be taken from the jmpbuf contained within this
415 * @c __cilkrts_stack_frame.
417 COMMON_PORTABLE
void __cilkrts_put_stack(full_frame
*ff
,
418 __cilkrts_stack_frame
*sf
);
421 * @brief Records the stack pointer @c sp as the stack pointer at the point of
422 * resuming execution on full frame @c ff.
424 * The value of @c sp may be on a different stack than the original
425 * value recorded for the stack pointer using __cilkrts_put_stack().
427 * @pre @c ff->sync_sp must contain a value set by @c __cilkrts_put_stack().
429 * @post @c ff->sync_sp contains an *integer* value used to compute a change in the
430 * stack pointer upon the next call to @c __cilkrts_take_stack().
431 * @post If @c sp equals @c ff->sync_sp, then @c ff->sync_sp is set to null.
433 * @param ff The full frame that is being resumed.
434 * @param sp The stack pointer for the stack the function is being resumed on.
436 COMMON_PORTABLE
void __cilkrts_take_stack(full_frame
*ff
, void *sp
);
439 * @brief Adjust the stack for to deallocate a Variable Length Array
441 * @param ff The full frame that is being adjusted.
442 * @param size The size of the array being deallocated from the stack
444 COMMON_PORTABLE
void __cilkrts_adjust_stack(full_frame
*ff
, size_t size
);
447 * @brief Allocates and initailizes a full_frame.
449 * @param w The memory for the full_frame will be allocated out of the
451 * @param sf The @c __cilkrts_stack_frame which will be saved as the call_stack
452 * for this full_frame.
454 * @return The newly allocated and initialized full_frame.
457 full_frame
*__cilkrts_make_full_frame(__cilkrts_worker
*w
,
458 __cilkrts_stack_frame
*sf
);
461 * @brief Deallocates a full_frame.
463 * @param w The memory for the full_frame will be returned to the worker's pool.
464 * @param ff The full_frame to be deallocated.
467 void __cilkrts_destroy_full_frame(__cilkrts_worker
*w
, full_frame
*ff
);
470 * @brief Performs sanity checks to check the integrity of a full_frame.
472 * @param ff The full_frame to be validated.
474 COMMON_PORTABLE
void validate_full_frame(full_frame
*ff
);
477 * @brief Locks the mutex contained in a full_frame.
479 * The full_frame is validated before the runtime attempts to lock it.
481 * @post @c ff->lock will be owned by @c w.
483 * @param w The worker that will own the full_frame. If the runtime is
484 * collecting stats, the intervals will be attributed to the worker.
485 * @param ff The full_frame containing the mutex to be locked.
487 COMMON_PORTABLE
void __cilkrts_frame_lock(__cilkrts_worker
*w
,
491 * @brief Unlocks the mutex contained in a full_frame.
493 * @pre @c ff->lock must must be owned by @c w.
495 * @param w The worker that currently owns the full_frame.
496 * @param ff The full_frame containing the mutex to be unlocked.
498 COMMON_PORTABLE
void __cilkrts_frame_unlock(__cilkrts_worker
*w
,
502 __CILKRTS_END_EXTERN_C
504 #endif // ! defined(INCLUDED_FULL_FRAME_DOT_H)