cilk-abi.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. /* Cilk_abi.c -*-C++-*-
  2. *
  3. *************************************************************************
  4. *
  5. * @copyright
  6. * Copyright (C) 2010-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. /**
  40. * @file cilk-abi.c
  41. *
  42. * @brief cilk-abi.c implements all of the entrypoints to the Intel Cilk
  43. * Plus runtime.
  44. */
  45. /*
  46. * Define this macro so that compiliation of this file generates the
  47. * non-inlined versions of certain functions in cilk_api.h.
  48. */
  49. #include "internal/abi.h"
  50. #include "cilk/cilk_api.h"
  51. #include "cilk/cilk_undocumented.h"
  52. #include "cilktools/cilkscreen.h"
  53. #include "global_state.h"
  54. #include "os.h"
  55. #include "os_mutex.h"
  56. #include "bug.h"
  57. #include "local_state.h"
  58. #include "full_frame.h"
  59. #include "pedigrees.h"
  60. #include "scheduler.h"
  61. #include "sysdep.h"
  62. #include "except.h"
  63. #include "cilk_malloc.h"
  64. #include "record-replay.h"
  65. #include <errno.h>
  66. #include <string.h>
  67. #include <stdlib.h>
  68. #ifdef _MSC_VER
  69. /* Some versions of icc don't support limits.h on Linux if
  70. gcc 4.3 or newer is installed. */
  71. #include <limits.h>
  72. /* Declare _ReturnAddress compiler intrinsic */
  73. void * _ReturnAddress(void);
  74. #pragma intrinsic(_ReturnAddress)
  75. #include "sysdep-win.h" // Needed for sysdep_init_module()
  76. #endif /* _WIN32 */
  77. #include "metacall_impl.h"
  78. #include "reducer_impl.h"
  79. #include "cilk-ittnotify.h"
  80. #include "cilk-tbb-interop.h"
  81. #define TBB_INTEROP_DATA_DELAYED_UNTIL_BIND (void *)-1
  82. /**
  83. * __cilkrts_bind_thread is a versioned entrypoint. The runtime should be
  84. * exporting copies of __cilkrts_bind_version for the current and all previous
  85. * versions of the ABI.
  86. *
  87. * This macro should always be set to generate a version to match the current
  88. * version; __CILKRTS_ABI_VERSION.
  89. */
  90. #define BIND_THREAD_RTN __cilkrts_bind_thread_1
  91. static inline
  92. void enter_frame_internal(__cilkrts_stack_frame *sf, uint32_t version)
  93. {
  94. __cilkrts_worker *w = __cilkrts_get_tls_worker();
  95. if (w == 0) { /* slow path */
  96. w = BIND_THREAD_RTN();
  97. sf->flags = CILK_FRAME_LAST | (version << 24);
  98. CILK_ASSERT((sf->flags & CILK_FRAME_FLAGS_MASK) == CILK_FRAME_LAST);
  99. } else {
  100. sf->flags = (version << 24);
  101. CILK_ASSERT((sf->flags & CILK_FRAME_FLAGS_MASK) == 0);
  102. }
  103. sf->call_parent = w->current_stack_frame;
  104. sf->worker = w;
  105. w->current_stack_frame = sf;
  106. }
  107. CILK_ABI_VOID __cilkrts_enter_frame(__cilkrts_stack_frame *sf)
  108. {
  109. enter_frame_internal(sf, 0);
  110. }
  111. CILK_ABI_VOID __cilkrts_enter_frame_1(__cilkrts_stack_frame *sf)
  112. {
  113. enter_frame_internal(sf, 1);
  114. sf->reserved = 0;
  115. }
  116. static inline
  117. void enter_frame_fast_internal(__cilkrts_stack_frame *sf, uint32_t version)
  118. {
  119. __cilkrts_worker *w = __cilkrts_get_tls_worker_fast();
  120. sf->flags = version << 24;
  121. sf->call_parent = w->current_stack_frame;
  122. sf->worker = w;
  123. w->current_stack_frame = sf;
  124. }
  125. CILK_ABI_VOID __cilkrts_enter_frame_fast(__cilkrts_stack_frame *sf)
  126. {
  127. enter_frame_fast_internal(sf, 0);
  128. }
  129. CILK_ABI_VOID __cilkrts_enter_frame_fast_1(__cilkrts_stack_frame *sf)
  130. {
  131. enter_frame_fast_internal(sf, 1);
  132. sf->reserved = 0;
  133. }
  134. /**
  135. * A component of the THE protocol. __cilkrts_undo_detach checks whether
  136. * this frame's parent has been stolen. If it hasn't, the frame can return
  137. * normally. If the parent has been stolen, of if we suspect it might be,
  138. * then __cilkrts_leave_frame() needs to call into the runtime.
  139. *
  140. * @note __cilkrts_undo_detach() is comparing the exception pointer against
  141. * the tail pointer. The exception pointer is modified when another worker
  142. * is considering whether it can steal a frame. The head pointer is updated
  143. * to match when the worker lock is taken out and the thief is sure that
  144. * it can complete the steal. If the steal cannot be completed, the thief
  145. * will restore the exception pointer.
  146. *
  147. * @return true if undo-detach failed.
  148. */
  149. static int __cilkrts_undo_detach(__cilkrts_stack_frame *sf)
  150. {
  151. __cilkrts_worker *w = sf->worker;
  152. __cilkrts_stack_frame *volatile *t = w->tail;
  153. /* DBGPRINTF("%d - __cilkrts_undo_detach - sf %p\n", w->self, sf); */
  154. --t;
  155. w->tail = t;
  156. /* On x86 the __sync_fetch_and_<op> family includes a
  157. full memory barrier. In theory the sequence in the
  158. second branch of the #if should be faster, but on
  159. most x86 it is not. */
  160. #if defined __i386__ || defined __x86_64__
  161. __sync_fetch_and_and(&sf->flags, ~CILK_FRAME_DETACHED);
  162. #else
  163. __cilkrts_fence(); /* membar #StoreLoad */
  164. sf->flags &= ~CILK_FRAME_DETACHED;
  165. #endif
  166. return __builtin_expect(t < w->exc, 0);
  167. }
  168. CILK_ABI_VOID __cilkrts_leave_frame(__cilkrts_stack_frame *sf)
  169. {
  170. __cilkrts_worker *w = sf->worker;
  171. /* DBGPRINTF("%d-%p __cilkrts_leave_frame - sf %p, flags: %x\n", w->self, GetWorkerFiber(w), sf, sf->flags); */
  172. #ifdef _WIN32
  173. /* if leave frame was called from our unwind handler, leave_frame should
  174. proceed no further. */
  175. if (sf->flags & CILK_FRAME_UNWINDING)
  176. {
  177. /* DBGPRINTF("%d - __cilkrts_leave_frame - aborting due to UNWINDING flag\n", w->self); */
  178. // If this is the frame of a spawn helper (indicated by the
  179. // CILK_FRAME_DETACHED flag) we must update the pedigree. The pedigree
  180. // points to nodes allocated on the stack. Failing to update it will
  181. // result in a accvio/segfault if the pedigree is walked. This must happen
  182. // for all spawn helper frames, even if we're processing an exception
  183. if ((sf->flags & CILK_FRAME_DETACHED))
  184. {
  185. update_pedigree_on_leave_frame(w, sf);
  186. }
  187. return;
  188. }
  189. #endif
  190. #if CILK_LIB_DEBUG
  191. /* ensure the caller popped itself */
  192. CILK_ASSERT(w->current_stack_frame != sf);
  193. #endif
  194. /* The exiting function should have checked for zero flags,
  195. so there is no check for flags == 0 here. */
  196. #if CILK_LIB_DEBUG
  197. if (__builtin_expect(sf->flags & (CILK_FRAME_EXITING|CILK_FRAME_UNSYNCHED), 0))
  198. __cilkrts_bug("W%u: function exiting with invalid flags %02x\n",
  199. w->self, sf->flags);
  200. #endif
  201. /* Must return normally if (1) the active function was called
  202. and not spawned, or (2) the parent has never been stolen. */
  203. if ((sf->flags & CILK_FRAME_DETACHED)) {
  204. /* DBGPRINTF("%d - __cilkrts_leave_frame - CILK_FRAME_DETACHED\n", w->self); */
  205. #ifndef _WIN32
  206. if (__builtin_expect(sf->flags & CILK_FRAME_EXCEPTING, 0)) {
  207. // Pedigree will be updated in __cilkrts_leave_frame. We need the
  208. // pedigree before the update for record/replay
  209. // update_pedigree_on_leave_frame(w, sf);
  210. __cilkrts_return_exception(sf);
  211. /* If return_exception returns the caller is attached.
  212. leave_frame is called from a cleanup (destructor)
  213. for the frame object. The caller will reraise the
  214. exception. */
  215. return;
  216. }
  217. #endif
  218. // During replay, check whether w was the last worker to continue
  219. replay_wait_for_steal_if_parent_was_stolen(w);
  220. // Attempt to undo the detach
  221. if (__builtin_expect(__cilkrts_undo_detach(sf), 0)) {
  222. // The update of pedigree for leaving the frame occurs
  223. // inside this call if it does not return.
  224. __cilkrts_c_THE_exception_check(w, sf);
  225. }
  226. update_pedigree_on_leave_frame(w, sf);
  227. /* This path is taken when undo-detach wins the race with stealing.
  228. Otherwise this strand terminates and the caller will be resumed
  229. via setjmp at sync. */
  230. if (__builtin_expect(sf->flags & CILK_FRAME_FLAGS_MASK, 0))
  231. __cilkrts_bug("W%u: frame won undo-detach race with flags %02x\n",
  232. w->self, sf->flags);
  233. return;
  234. }
  235. #if CILK_LIB_DEBUG
  236. sf->flags |= CILK_FRAME_EXITING;
  237. #endif
  238. if (__builtin_expect(sf->flags & CILK_FRAME_LAST, 0))
  239. __cilkrts_c_return_from_initial(w); /* does return */
  240. else if (sf->flags & CILK_FRAME_STOLEN)
  241. __cilkrts_return(w); /* does return */
  242. /* DBGPRINTF("%d-%p __cilkrts_leave_frame - returning, StackBase: %p\n", w->self, GetWorkerFiber(w)); */
  243. }
  244. /* Caller must have called setjmp. */
  245. CILK_ABI_VOID __cilkrts_sync(__cilkrts_stack_frame *sf)
  246. {
  247. __cilkrts_worker *w = sf->worker;
  248. /* DBGPRINTF("%d-%p __cilkrts_sync - sf %p\n", w->self, GetWorkerFiber(w), sf); */
  249. if (__builtin_expect(!(sf->flags & CILK_FRAME_UNSYNCHED), 0))
  250. __cilkrts_bug("W%u: double sync %p\n", w->self, sf);
  251. #ifndef _WIN32
  252. if (__builtin_expect(sf->flags & CILK_FRAME_EXCEPTING, 0)) {
  253. __cilkrts_c_sync_except(w, sf);
  254. }
  255. #endif
  256. __cilkrts_c_sync(w, sf);
  257. }
  258. /*
  259. * __cilkrts_get_sf
  260. *
  261. * Debugging aid to provide access to the current __cilkrts_stack_frame.
  262. *
  263. * Not documented!
  264. */
  265. CILK_API_VOID_PTR
  266. __cilkrts_get_sf(void)
  267. {
  268. __cilkrts_worker *w = __cilkrts_get_tls_worker();
  269. if (0 == w)
  270. return NULL;
  271. return w->current_stack_frame;
  272. }
  273. /* Call with global lock held */
  274. static __cilkrts_worker *find_free_worker(global_state_t *g)
  275. {
  276. __cilkrts_worker *w = 0;
  277. int i;
  278. // Scan the non-system workers looking for one which is free so we can
  279. // use it.
  280. for (i = g->P - 1; i < g->total_workers; ++i) {
  281. w = g->workers[i];
  282. CILK_ASSERT(WORKER_SYSTEM != w->l->type);
  283. if (w->l->type == WORKER_FREE) {
  284. w->l->type = WORKER_USER;
  285. w->l->team = w;
  286. return w;
  287. }
  288. }
  289. // If we ran out of workers, create a new one. It doesn't actually belong
  290. // to the Cilk global state so nobody will ever try to steal from it.
  291. w = (__cilkrts_worker *)__cilkrts_malloc(sizeof(*w));
  292. __cilkrts_cilkscreen_ignore_block(w, w+1);
  293. make_worker(g, -1, w);
  294. w->l->type = WORKER_USER;
  295. w->l->team = w;
  296. return w;
  297. }
  298. /*
  299. * __cilkrts_bind_thread
  300. *
  301. * Exported function to bind a thread to the runtime.
  302. *
  303. * This function name should always have a trailing suffix for the latest ABI
  304. * version. This means that code built with a new compiler will not load
  305. * against an old copy of the runtime.
  306. *
  307. * Symbols for the function called by code compiled with old versions of the
  308. * compiler are created in an OS-specific manner:
  309. * - On Windows the old symbols are defined in the cilk-exports.def linker
  310. * definitions file as aliases of BIND_THREAD_RTN
  311. * - On Linux aliased symbols are created for BIND_THREAD_RTN in this file
  312. * - On MacOS the alternate entrypoints are implemented and simply call
  313. * BIND_THREAD_RTN.
  314. */
  315. CILK_ABI_WORKER_PTR BIND_THREAD_RTN(void)
  316. {
  317. __cilkrts_worker *w;
  318. int start_cilkscreen = 0;
  319. #ifdef USE_ITTNOTIFY
  320. static int unique_obj;
  321. #endif
  322. // Cannot set this pointer until after __cilkrts_init_internal() call:
  323. global_state_t* g;
  324. ITT_SYNC_CREATE (&unique_obj, "Initialization");
  325. ITT_SYNC_PREPARE(&unique_obj);
  326. ITT_SYNC_ACQUIRED(&unique_obj);
  327. /* 1: Initialize and start the Cilk runtime */
  328. __cilkrts_init_internal(1);
  329. /*
  330. * 2: Choose a worker for this thread (fail if none left). The table of
  331. * user workers is protected by the global OS mutex lock.
  332. */
  333. g = cilkg_get_global_state();
  334. global_os_mutex_lock();
  335. if (__builtin_expect(g->work_done, 0))
  336. __cilkrts_bug("Attempt to enter Cilk while Cilk is shutting down");
  337. w = find_free_worker(g);
  338. CILK_ASSERT(w);
  339. __cilkrts_set_tls_worker(w);
  340. __cilkrts_cilkscreen_establish_worker(w);
  341. {
  342. full_frame *ff = __cilkrts_make_full_frame(w, 0);
  343. ff->fiber_self = cilk_fiber_allocate_from_thread();
  344. CILK_ASSERT(ff->fiber_self);
  345. cilk_fiber_set_owner(ff->fiber_self, w);
  346. cilk_fiber_tbb_interop_use_saved_stack_op_info(ff->fiber_self);
  347. CILK_ASSERT(ff->join_counter == 0);
  348. ff->join_counter = 1;
  349. w->l->frame_ff = ff;
  350. w->reducer_map = __cilkrts_make_reducer_map(w);
  351. __cilkrts_set_leftmost_reducer_map(w->reducer_map, 1);
  352. load_pedigree_leaf_into_user_worker(w);
  353. }
  354. // Make sure that the head and tail are reset, and saved_protected_tail
  355. // allows all frames to be stolen.
  356. //
  357. // Note that we must NOT check w->exc, since workers that are trying to
  358. // steal from it will be updating w->exc and we don't own the worker lock.
  359. // It's not worth taking out the lock just for an assertion.
  360. CILK_ASSERT(w->head == w->l->ltq);
  361. CILK_ASSERT(w->tail == w->l->ltq);
  362. CILK_ASSERT(w->protected_tail == w->ltq_limit);
  363. // There may have been an old pending exception which was freed when the
  364. // exception was caught outside of Cilk
  365. w->l->pending_exception = NULL;
  366. w->reserved = NULL;
  367. // If we've already created a scheduling fiber for this worker, we'll just
  368. // reuse it. If w->self < 0, it means that this is an ad-hoc user worker
  369. // not known to the global state. Thus, we need to create a scheduling
  370. // stack only if we don't already have one and w->self >= 0.
  371. if (NULL == w->l->scheduling_fiber && w->self >= 0)
  372. {
  373. START_INTERVAL(w, INTERVAL_FIBER_ALLOCATE) {
  374. // Create a scheduling fiber for this worker.
  375. w->l->scheduling_fiber =
  376. cilk_fiber_allocate_from_heap(CILK_SCHEDULING_STACK_SIZE);
  377. cilk_fiber_reset_state(w->l->scheduling_fiber,
  378. scheduler_fiber_proc_for_user_worker);
  379. cilk_fiber_set_owner(w->l->scheduling_fiber, w);
  380. } STOP_INTERVAL(w, INTERVAL_FIBER_ALLOCATE);
  381. }
  382. // If the scheduling fiber is NULL, we've either exceeded our quota for
  383. // fibers or workers or we're out of memory, so we should lose parallelism
  384. // by disallowing stealing.
  385. if (NULL == w->l->scheduling_fiber)
  386. __cilkrts_disallow_stealing(w, NULL);
  387. start_cilkscreen = (0 == w->g->Q);
  388. if (w->self != -1) {
  389. // w->self != -1, means that w is a normal user worker and must be
  390. // accounted for by the global state since other workers can steal from
  391. // it.
  392. // w->self == -1, means that w is an overflow worker and was created on
  393. // demand. I.e., it does not need to be accounted for by the global
  394. // state.
  395. __cilkrts_enter_cilk(w->g);
  396. }
  397. global_os_mutex_unlock();
  398. /* If there's only 1 worker, the counts will be started in
  399. * __cilkrts_scheduler */
  400. if (g->P > 1)
  401. {
  402. START_INTERVAL(w, INTERVAL_IN_SCHEDULER);
  403. START_INTERVAL(w, INTERVAL_WORKING);
  404. }
  405. ITT_SYNC_RELEASING(&unique_obj);
  406. /* Turn on Cilkscreen if this is the first worker. This needs to be done
  407. * when we are NOT holding the os mutex. */
  408. if (start_cilkscreen)
  409. __cilkrts_cilkscreen_enable_instrumentation();
  410. return w;
  411. }
  412. #ifndef _MSC_VER
  413. /*
  414. * Define old version-specific symbols for binding threads (since they exist in
  415. * all Cilk code). These aliases prohibit newly compiled code from loading an
  416. * old version of the runtime. We can handle old code with a new runtime, but
  417. * new code with an old runtime is verboten!
  418. *
  419. * For Windows, the aliased symbol is exported in cilk-exports.def.
  420. */
  421. #if defined(_DARWIN_C_SOURCE) || defined(__APPLE__)
  422. /**
  423. * Mac OS X: Unfortunately, Darwin doesn't allow aliasing, so we just make a
  424. * call and hope the optimizer does the right thing.
  425. */
  426. CILK_ABI_WORKER_PTR __cilkrts_bind_thread (void) {
  427. return BIND_THREAD_RTN();
  428. }
  429. #else
  430. /**
  431. * Macro to convert a parameter to a string. Used on Linux or BSD.
  432. */
  433. #define STRINGIFY(x) #x
  434. /**
  435. * Macro to generate an __attribute__ for an aliased name
  436. */
  437. #define ALIASED_NAME(x) __attribute__ ((alias (STRINGIFY(x))))
  438. /**
  439. * Linux or BSD: Use the alias attribute to make the labels for the versioned
  440. * functions point to the same place in the code as the original. Using
  441. * the two macros is annoying but required.
  442. */
  443. CILK_ABI_WORKER_PTR __cilkrts_bind_thread(void)
  444. ALIASED_NAME(BIND_THREAD_RTN);
  445. #endif // defined _DARWIN_C_SOURCE || defined __APPLE__
  446. #endif // !defined _MSC_VER
  447. CILK_API_SIZET
  448. __cilkrts_get_stack_size(void) {
  449. return cilkg_get_stack_size();
  450. }
  451. // Method for debugging.
  452. CILK_API_VOID __cilkrts_dump_stats(void)
  453. {
  454. // While the stats aren't protected by the global OS mutex, the table
  455. // of workers is, so take out the global OS mutex while we're doing this
  456. global_os_mutex_lock();
  457. if (cilkg_is_published()) {
  458. global_state_t *g = cilkg_get_global_state();
  459. __cilkrts_dump_stats_to_stderr(g);
  460. }
  461. else {
  462. __cilkrts_bug("Attempting to report Cilk stats before the runtime has started\n");
  463. }
  464. global_os_mutex_unlock();
  465. }
  466. #ifndef _WIN32
  467. CILK_ABI_THROWS_VOID __cilkrts_rethrow(__cilkrts_stack_frame *sf)
  468. {
  469. __cilkrts_gcc_rethrow(sf);
  470. }
  471. #endif
  472. /*
  473. * __cilkrts_unwatch_stack
  474. *
  475. * Callback for TBB to tell us they don't want to watch the stack anymore
  476. */
  477. static __cilk_tbb_retcode __cilkrts_unwatch_stack(void *data)
  478. {
  479. __cilk_tbb_stack_op_thunk o;
  480. // If the cilk_fiber wasn't available fetch it now
  481. if (TBB_INTEROP_DATA_DELAYED_UNTIL_BIND == data)
  482. {
  483. full_frame *ff;
  484. __cilkrts_worker *w = __cilkrts_get_tls_worker();
  485. if (NULL == w)
  486. {
  487. // Free any saved stack op information
  488. cilk_fiber_tbb_interop_free_stack_op_info();
  489. return 0; /* Success! */
  490. }
  491. __cilkrts_worker_lock(w);
  492. ff = w->l->frame_ff;
  493. __cilkrts_frame_lock(w,ff);
  494. data = ff->fiber_self;
  495. __cilkrts_frame_unlock(w,ff);
  496. __cilkrts_worker_unlock(w);
  497. }
  498. #if CILK_LIB_DEBUG /* Debug code */
  499. /* Get current stack */
  500. full_frame *ff;
  501. __cilkrts_worker *w = __cilkrts_get_tls_worker();
  502. __cilkrts_worker_lock(w);
  503. ff = w->l->frame_ff;
  504. __cilkrts_frame_lock(w,ff);
  505. CILK_ASSERT (data == ff->fiber_self);
  506. __cilkrts_frame_unlock(w,ff);
  507. __cilkrts_worker_unlock(w);
  508. #endif
  509. /* Clear the callback information */
  510. o.data = NULL;
  511. o.routine = NULL;
  512. cilk_fiber_set_stack_op((cilk_fiber*)data, o);
  513. // Note. Do *NOT* free any saved stack information here. If they want to
  514. // free the saved stack op information, they'll do it when the thread is
  515. // unbound
  516. return 0; /* Success! */
  517. }
  518. /*
  519. * __cilkrts_watch_stack
  520. *
  521. * Called by TBB, defined by Cilk.
  522. *
  523. * Requests that Cilk invoke the stack op routine when it orphans a stack.
  524. * Cilk sets *u to a thunk that TBB should call when it is no longer interested
  525. * in watching the stack.
  526. */
  527. CILK_API_TBB_RETCODE
  528. __cilkrts_watch_stack(__cilk_tbb_unwatch_thunk *u,
  529. __cilk_tbb_stack_op_thunk o)
  530. {
  531. cilk_fiber* current_fiber;
  532. __cilkrts_worker *w;
  533. #ifdef _MSC_VER
  534. // This may be called by TBB *before* the OS has given us our
  535. // initialization call. Make sure the module is initialized.
  536. sysdep_init_module();
  537. #endif
  538. // Fetch the __cilkrts_worker bound to this thread
  539. w = __cilkrts_get_tls_worker();
  540. if (NULL == w)
  541. {
  542. // Save data for later. We'll deal with it when/if this thread binds
  543. // to the runtime
  544. cilk_fiber_tbb_interop_save_stack_op_info(o);
  545. u->routine = __cilkrts_unwatch_stack;
  546. u->data = TBB_INTEROP_DATA_DELAYED_UNTIL_BIND;
  547. return 0;
  548. }
  549. /* Get current stack */
  550. __cilkrts_worker_lock(w);
  551. current_fiber = w->l->frame_ff->fiber_self;
  552. __cilkrts_worker_unlock(w);
  553. /* CILK_ASSERT( !sd->stack_op_data ); */
  554. /* CILK_ASSERT( !sd->stack_op_routine ); */
  555. /* Give TBB our callback */
  556. u->routine = __cilkrts_unwatch_stack;
  557. u->data = current_fiber;
  558. /* Save the callback information */
  559. cilk_fiber_set_stack_op(current_fiber, o);
  560. return 0; /* Success! */
  561. }
  562. // This function must be called only within a continuation, within the stack
  563. // frame of the continuation itself.
  564. CILK_API_INT __cilkrts_synched(void)
  565. {
  566. __cilkrts_worker *w = __cilkrts_get_tls_worker();
  567. // If we don't have a worker, then we're synched by definition :o)
  568. if (NULL == w)
  569. return 1;
  570. // Check to see if we are in a stolen continuation. If not, then
  571. // we are synched.
  572. uint32_t flags = w->current_stack_frame->flags;
  573. if (0 == (flags & CILK_FRAME_UNSYNCHED))
  574. return 1;
  575. // We are in a stolen continutation, but the join counter might have been
  576. // decremented to one, making us synched again. Get the full frame so
  577. // that we can check the join counter. ASSUME: frame_ff is stable (can be
  578. // read without a lock) in a stolen continuation -- it can't be stolen
  579. // while it's currently executing.
  580. full_frame *ff = w->l->frame_ff;
  581. // Make sure we have a full frame
  582. // TBD: Don't think that we should ever not have a full frame here.
  583. // CILK_ASSERT(NULL != ff); ?
  584. if (NULL == ff)
  585. return 1;
  586. // We're synched if there are no outstanding children at this instant in
  587. // time. Note that this is a known race, but it's ok since we're only
  588. // reading. We can get false negatives, but not false positives. (I.e.,
  589. // we can read a non-one join_counter just before it goes to one, but the
  590. // join_counter cannot go from one to greater than one while we're
  591. // reading.)
  592. return 1 == ff->join_counter;
  593. }
  594. CILK_API_INT
  595. __cilkrts_bump_loop_rank_internal(__cilkrts_worker* w)
  596. {
  597. // If we don't have a worker, then the runtime is not bound to this
  598. // thread and there is no rank to increment
  599. if (NULL == w)
  600. return -1;
  601. // We're at the start of the loop body. Advance the cilk_for loop
  602. // body pedigree by following the parent link and updating its
  603. // rank.
  604. // Normally, we'd just write "w->pedigree.parent->rank++"
  605. // But we need to cast away the "const".
  606. ((__cilkrts_pedigree*) w->pedigree.parent)->rank++;
  607. // Zero the worker's pedigree rank since this is the start of a new
  608. // pedigree domain.
  609. w->pedigree.rank = 0;
  610. return 0;
  611. }
  612. CILK_ABI_VOID
  613. __cilkrts_save_fp_ctrl_state(__cilkrts_stack_frame *sf)
  614. {
  615. // Pass call onto OS/architecture dependent function
  616. sysdep_save_fp_ctrl_state(sf);
  617. }
  618. /* end cilk-abi.c */