1 /* except-gcc.cpp -*-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 #include "except-gcc.h"
54 #include "local_state.h"
55 #include "full_frame.h"
56 #include "scheduler.h"
57 #include "frame_malloc.h"
58 #include "pedigrees.h"
63 #ifndef DEBUG_EXCEPTIONS
64 #define DEBUG_EXCEPTIONS 0
67 struct pending_exception_info
69 void make(__cxa_eh_globals
*, _Unwind_Exception
*, bool);
73 /* Active exception at time of suspend. */
74 _Unwind_Exception
*active
;
75 /* If true the most recently caught exception is to be rethrown
76 on resume. This handling is technically incorrect but allows
77 running without compiler support; the proper standards-compliant
78 method is to save the exception in the previous field. */
80 struct __cxa_eh_globals runtime_state
;
83 void pending_exception_info::check() const
86 CILK_ASSERT((int)runtime_state
.uncaughtExceptions
> 0);
89 void pending_exception_info::make(__cxa_eh_globals
*state_in
,
90 _Unwind_Exception
*exc_in
, bool rethrow_in
)
94 runtime_state
= *state_in
;
95 /* Read and clear C++ runtime state. */
96 state_in
->caughtExceptions
= 0;
97 state_in
->uncaughtExceptions
= 0;
104 pending_exception_info::empty() const
106 return !active
&& !rethrow
&& !runtime_state
.caughtExceptions
&&
107 !runtime_state
.uncaughtExceptions
;
113 decode_exceptions(char *out
, size_t len
, struct pending_exception_info
*info
)
116 cilk_snprintf_s(out
, len
, "%s", "[empty]");
117 else if (info
->rethrow
)
118 cilk_snprintf_l(out
, len
, "[rethrow %p]",
119 info
->runtime_state
.caughtExceptions
);
121 cilk_snprintf_l(out
, len
, "[throw %p]", (void *)info
->active
);
126 save_exception_info(__cilkrts_worker
*w
,
127 __cxa_eh_globals
*state
,
128 _Unwind_Exception
*exc
,
132 struct pending_exception_info
*info
=
133 (struct pending_exception_info
*)__cilkrts_frame_malloc(w
, sizeof (struct pending_exception_info
));
135 info
->make(state
, exc
, rethrow
);
140 decode_exceptions(buf
, sizeof buf
, info
);
141 fprintf(stderr
, "make exception info W%u %p %s (%s)\n",
142 w
->self
, info
, buf
, why
);
146 CILK_ASSERT(w
->l
->pending_exception
== 0);
147 w
->l
->pending_exception
= info
;
151 #include <stdio.h> /* DEBUG */
153 static void decode_flags(int flags
, char out
[9])
155 out
[0] = (flags
& CILK_FRAME_STOLEN
) ? 'S' : '_';
156 out
[1] = (flags
& CILK_FRAME_UNSYNCHED
) ? 'U' : '_';
157 out
[2] = (flags
& CILK_FRAME_DETACHED
) ? 'D' : '_';
158 out
[3] = (flags
& CILK_FRAME_EXCEPTING
) ? 'X' : '_';
163 /* __cilkrts_save_except is called from the runtime epilogue
164 when a function is returning with an exception pending.
166 If the function has a parent to which it could return normally,
167 return and have the caller call _Unwind_Resume, the same as if
168 an exception filter had not matched.
170 Otherwise save the exception in the worker.
172 If this is a return from a ordinary call that must go through
173 the runtime, the assembly epilogue must have saved the call-saved
174 register state in the parent frame. */
178 __cilkrts_return_exception(__cilkrts_stack_frame
*sf
)
180 __cilkrts_worker
*w
= sf
->worker
;
181 _Unwind_Exception
*exc
= (_Unwind_Exception
*)sf
->except_data
;
183 CILK_ASSERT(sf
->flags
& CILK_FRAME_DETACHED
);
184 sf
->flags
&= ~CILK_FRAME_DETACHED
;
187 * If we are in replay mode, and a steal occurred during the recording
188 * phase, stall till a steal actually occurs.
190 replay_wait_for_steal_if_parent_was_stolen(w
);
192 /* If this is to be an abnormal return, save the active exception. */
193 if (!__cilkrts_pop_tail(w
)) {
194 /* Write a record to the replay log for an attempt to return to a
195 stolen parent. This must be done before the exception handler
196 invokes __cilkrts_leave_frame which will bump the pedigree so
197 the replay_wait_for_steal_if_parent_was_stolen() above will match on
199 replay_record_orphaned(w
);
201 /* Now that the record/replay stuff is done, update the pedigree */
202 update_pedigree_on_leave_frame(w
, sf
);
204 /* Inline pop_frame; this may not be needed. */
205 w
->current_stack_frame
= sf
->call_parent
;
207 __cxa_eh_globals
*state
= __cxa_get_globals();
212 decode_flags(sf
->flags
, decoded
);
213 fprintf(stderr
, "__cilkrts_save_except W%u sf %p/%s exc %p [%u %p] suspend\n",
214 w
->self
, sf
, decoded
, exc
,
215 state
->uncaughtExceptions
,
216 state
->caughtExceptions
);
219 /* Like __cilkrts_save_exception_state except for setting the
221 save_exception_info(w
, state
, exc
, exc
== NULL
, "save_except");
223 full_frame
*ff
= w
->l
->frame_ff
;
224 CILK_ASSERT(NULL
== ff
->pending_exception
);
225 ff
->pending_exception
= w
->l
->pending_exception
;
226 w
->l
->pending_exception
= NULL
;
228 __cilkrts_exception_from_spawn(w
, sf
); /* does not return */
230 /* This code path is taken when the parent is attached. It is on
231 the same stack and part of the same full frame. The caller is
232 cleaning up the Cilk frame during unwind and will reraise the
235 /* Now that the record/replay stuff is done, update the pedigree */
236 update_pedigree_on_leave_frame(w
, sf
);
238 #if DEBUG_EXCEPTIONS /* DEBUG ONLY */
240 __cxa_eh_globals
*state
= __cxa_get_globals();
244 decode_flags(sf
->flags
, decoded
);
245 fprintf(stderr
, "__cilkrts_save_except W%d %p/%s %p->%p [%u %p] escape\n",
246 w
->self
, sf
, decoded
, exc
,
247 exc
? to_cxx(exc
)->nextException
: 0,
248 state
->uncaughtExceptions
,
249 state
->caughtExceptions
);
251 /* XXX This is triggering in the user thread which gets an exception
252 from somewhere but does not get the corresponding runtime exception
254 XXX There might be two or more uncaught exceptions. Test could be
255 (uncaught != 0) == (exc != 0). First, design tests to see if that
256 case is otherwise handled correctly. And what if there's an uncaught
257 exception that does not belong to this function? I.e. this is a return
258 from spawn in a destructor. */
260 CILK_ASSERT((int)state
->uncaughtExceptions
> 0);
261 /*CILK_ASSERT(state->uncaughtExceptions == (exc != 0));*/
265 /* The parent is attached so this exception can be propagated normally. */
269 /* Save the exception state into the full frame, which is exiting
272 void __cilkrts_save_exception_state(__cilkrts_worker
*w
, full_frame
*ff
)
274 save_exception_info(w
, __cxa_get_globals(), 0, false, "undo-detach");
275 CILK_ASSERT(NULL
== ff
->pending_exception
);
276 ff
->pending_exception
= w
->l
->pending_exception
;
277 w
->l
->pending_exception
= NULL
;
280 /* __cilkrts_c_sync_except is like __cilkrts_c_sync except that it
281 saves exception state. __cilkrts_c_sync never returns here and
282 always reinstalls the saved exception state.
284 This function must be used because a parent of this function may
285 be propagating an uncaught exception. The uncaught exception
286 count must be saved by the child and passed back to the parent. */
289 NORETURN
__cilkrts_c_sync_except (__cilkrts_worker
*w
, __cilkrts_stack_frame
*sf
)
291 __cxa_eh_globals
*state
= __cxa_get_globals();
292 _Unwind_Exception
*exc
= (_Unwind_Exception
*)sf
->except_data
;
294 CILK_ASSERT((sf
->flags
& (CILK_FRAME_UNSYNCHED
|CILK_FRAME_EXCEPTING
)) ==
295 (CILK_FRAME_UNSYNCHED
|CILK_FRAME_EXCEPTING
));
296 sf
->flags
&= ~CILK_FRAME_EXCEPTING
;
301 decode_flags(sf
->flags
, decoded
);
303 fprintf(stderr
, "__cilkrts_sync_except W%u %p/%s %p->%p [%u %p]\n",
304 w
->self
, sf
, decoded
, exc
,
305 to_cxx(exc
)->nextException
,
306 state
->uncaughtExceptions
,
307 state
->caughtExceptions
);
309 fprintf(stderr
, "__cilkrts_sync_except W%d %p/%s none [%u %p]\n",
310 w
->self
, sf
, decoded
,
311 state
->uncaughtExceptions
,
312 state
->caughtExceptions
);
315 /* Here the identity of an rethrown exception is always known.
316 If exc is NULL this call is only to preserve parent state. */
317 save_exception_info(w
, state
, exc
, false, "sync_except");
320 full_frame
*ff
= w
->l
->frame_ff
;
321 CILK_ASSERT(NULL
== ff
->pending_exception
);
322 ff
->pending_exception
= w
->l
->pending_exception
;
323 w
->l
->pending_exception
= NULL
;
326 CILK_ASSERT(!std::uncaught_exception());
327 __cilkrts_c_sync(w
, sf
);
331 pending_exception_info::destruct()
335 fprintf(stderr
, "destroy exception info %p %p\n", this, active
);
337 _Unwind_DeleteException(active
);
341 fprintf(stderr
, "destroy exception info %p\n", this);
344 while (runtime_state
.caughtExceptions
) {
345 __cxa_exception
*exc
= runtime_state
.caughtExceptions
;
346 runtime_state
.caughtExceptions
= exc
->nextException
;
348 fprintf(stderr
, "destroy caught exception %p\n", this);
350 _Unwind_DeleteException(&exc
->unwindHeader
);
355 * __cilkrts_merge_pending_exceptions
357 * Merge the right exception record into the left. The left is logically
360 * The active exception of E is
361 * E->active if it is non-NULL (in which case E->rethrow is false)
362 * unresolved if E->active is NULL and E->rethrow is true
363 * nil if E->active is NULL and E->rethrow is false
365 * The merged active exception is left active exception if it is not
366 * nil, otherwise the right.
368 * On entry the left state is synched and can not have an unresolved
369 * exception. The merge may result in an unresolved exception.
371 * Due to scoping rules at most one of the caught exception lists is
375 struct pending_exception_info
*
376 __cilkrts_merge_pending_exceptions (
378 struct pending_exception_info
*left
,
379 struct pending_exception_info
*right
)
381 /* If we've only got one exception, return it */
387 decode_exceptions(buf
, sizeof buf
, right
);
388 fprintf(stderr
, "__cilkrts merge W%u nil %p -> %p %s\n",
389 w
->self
, right
, right
, buf
);
399 decode_exceptions(buf
, sizeof buf
, left
);
400 fprintf(stderr
, "__cilkrts merge W%u %p nil -> %p %s\n",
401 w
->self
, left
, left
, buf
);
408 /*volatile struct pending_exception_info left_in = *left, right_in = *right;*/
415 char buf1
[40], buf2
[40];
416 decode_exceptions(buf1
, sizeof buf1
, left
);
417 decode_exceptions(buf2
, sizeof buf2
, right
);
418 fprintf(stderr
, "__cilkrts merge W%u %p %s %p %s\n",
419 w
->self
, left
, buf1
, right
, buf2
);
423 /* It should not be possible for both left and right to
424 have accumulated catch blocks.
426 The left exception record may always have a catch
427 chain it kept when its parent was stolen.
429 If they are siblings, the right sibling should not
430 have accumulated any net catches. (Catch is lexically
433 If the right frame is a parent, it should not have entered
434 a catch block without syncing first. If it spawned in a
435 catch block, the child got its catch. */
436 __cxa_exception
*caught
= left
->runtime_state
.caughtExceptions
;
438 CILK_ASSERT(!right
->runtime_state
.caughtExceptions
);
440 CILK_ASSERT(!left
->rethrow
);
441 left
->rethrow
= right
->rethrow
;
442 left
->runtime_state
.caughtExceptions
= caught
= right
->runtime_state
.caughtExceptions
;
443 right
->runtime_state
.caughtExceptions
= NULL
;
446 /* Merge the uncaught exception and count of uncaught exceptions. */
447 const unsigned int right_uncaught
= right
->runtime_state
.uncaughtExceptions
;
449 left
->active
= right
->active
; /* could be NULL */
451 left
->runtime_state
.uncaughtExceptions
+= right_uncaught
;
453 /* assert is C++ exception */
454 /*CILK_ASSERT(__cxxabiv1::__is_gxx_exception_class(left->active->exception_class))*/;
456 /* Subtract 1 if the right exception is being destructed. */
457 left
->runtime_state
.uncaughtExceptions
+= right_uncaught
- (right
->active
!= 0);
461 __cilkrts_frame_free(w
, right
, sizeof *right
);
463 /* If there is no state left, return NULL. */
466 __cilkrts_frame_free(w
, left
, sizeof *left
);
479 /* __cilkrts_c_resume_except is called from the assembly language
480 restart code when a resumed frame has a pending exception.
482 The handler count negation on rethrow was done when the throw was
485 The assembly language runtime must make the throw unwind to
486 the sync, spawn, or other location where the exception should
487 be injected. (This should not happen after a spawn but nothing
488 here depends on there being no exception on steal.)
490 This function is unused in the Intel stack based system. */
492 void __cilkrts_c_resume_except (_Unwind_Exception
*exc
)
495 fprintf(stderr
, "resume exception %p\n", exc
);
497 _Unwind_Reason_Code why
= _Unwind_RaiseException(exc
);
498 __cilkrts_bug ("Cilk runtime error: failed to reinstate suspended exception %p (%d)\n", exc
, why
);
502 /* Restore the caught exception chain. This assumes no C++ exception
503 code will run before the frame is resumed. If there is no exception
504 to be resumed free the object. */
507 void __cilkrts_setup_for_execution_sysdep(__cilkrts_worker
*w
, full_frame
*ff
)
509 // ASSERT: We own w->lock and ff->lock || P == 1
511 __cxa_eh_globals
*state
= __cxa_get_globals ();
512 struct pending_exception_info
*info
= w
->l
->pending_exception
;
517 w
->l
->pending_exception
= 0;
520 _Unwind_Exception
*exc
= info
->active
;
523 fprintf(stderr
, "__cilkrts_resume_except W%u %p->%p [%u %p]\n",
525 to_cxx(exc
)->nextException
,
526 info
->runtime_state
.uncaughtExceptions
,
527 info
->runtime_state
.caughtExceptions
);
528 /*CILK_ASSERT(info->runtime_state.uncaughtExceptions > 0);*/
532 if (state
->uncaughtExceptions
|| state
->caughtExceptions
)
533 __cilkrts_bug("W%u: resuming with non-empty prior exception state %u %p\n", state
->uncaughtExceptions
, state
->caughtExceptions
);
535 *state
= info
->runtime_state
;
536 info
->runtime_state
.caughtExceptions
= 0;
537 info
->runtime_state
.uncaughtExceptions
= 0;
540 info
->rethrow
= false;
541 /* Resuming function will rethrow. Runtime calls
542 std::terminate if there is no caught exception. */
543 ff
->call_stack
->flags
|= CILK_FRAME_EXCEPTING
;
546 ff
->call_stack
->flags
|= CILK_FRAME_EXCEPTING
;
547 ff
->call_stack
->except_data
= info
->active
;
553 __cilkrts_frame_free(w
, info
, sizeof *info
);
554 w
->l
->pending_exception
= NULL
;
558 if (ff
->call_stack
->except_data
)
559 CILK_ASSERT(std::uncaught_exception());
565 struct pending_exception_info
*__cilkrts_get_exception(__cilkrts_worker
*w
,
566 __cilkrts_stack_frame
*sf
)
568 struct pending_exception_info
*info
= w
->l
->pending_exception
;
571 sf
->flags
&= ~CILK_FRAME_EXCEPTING
;
575 w
->l
->pending_exception
= NULL
;
577 /* This exception goes into the frame. */
579 _Unwind_Exception
*exc
= info
->active
;
582 __cilkrts_frame_free(w
, info
, sizeof *info
);
584 sf
->flags
|= CILK_FRAME_EXCEPTING
;
591 void __attribute__((nonnull
)) __cilkrts_gcc_rethrow(__cilkrts_stack_frame
*sf
)
594 // Cygwin doesn't support exceptions, so _Unwind_Resume isn't available
595 // Which means we can't support exceptions either
596 __cilkrts_bug("The Cygwin implementation of the Intel Cilk Plus runtime doesn't support exceptions\n");
598 if (sf
->except_data
) {
600 CILK_ASSERT(std::uncaught_exception());
602 _Unwind_Resume ((_Unwind_Exception
*)sf
->except_data
);
609 /* End except-gcc.cpp */