1 /* except-gcc.cpp -*-C++-*-
3 *************************************************************************
6 * Copyright (C) 2009-2013, Intel Corporation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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
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.
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 **************************************************************************/
39 #include "except-gcc.h"
43 #include "local_state.h"
44 #include "full_frame.h"
45 #include "scheduler.h"
46 #include "frame_malloc.h"
47 #include "pedigrees.h"
52 #define DEBUG_EXCEPTIONS 0
54 struct pending_exception_info
56 void make(__cxa_eh_globals
*, _Unwind_Exception
*, bool);
60 /* Active exception at time of suspend. */
61 _Unwind_Exception
*active
;
62 /* If true the most recently caught exception is to be rethrown
63 on resume. This handling is technically incorrect but allows
64 running without compiler support; the proper standards-compliant
65 method is to save the exception in the previous field. */
67 struct __cxa_eh_globals runtime_state
;
70 void pending_exception_info::check() const
73 CILK_ASSERT((int)runtime_state
.uncaughtExceptions
> 0);
76 void pending_exception_info::make(__cxa_eh_globals
*state_in
,
77 _Unwind_Exception
*exc_in
, bool rethrow_in
)
81 runtime_state
= *state_in
;
82 /* Read and clear C++ runtime state. */
83 state_in
->caughtExceptions
= 0;
84 state_in
->uncaughtExceptions
= 0;
91 pending_exception_info::empty() const
93 return !active
&& !rethrow
&& !runtime_state
.caughtExceptions
&&
94 !runtime_state
.uncaughtExceptions
;
100 decode_exceptions(char *out
, size_t len
, struct pending_exception_info
*info
)
103 snprintf(out
, len
, "[empty]");
104 else if (info
->rethrow
)
105 snprintf(out
, len
, "[rethrow %p]",
106 info
->runtime_state
.caughtExceptions
);
108 snprintf(out
, len
, "[throw %p]", (void *)info
->active
);
113 save_exception_info(__cilkrts_worker
*w
,
114 __cxa_eh_globals
*state
,
115 _Unwind_Exception
*exc
,
119 struct pending_exception_info
*info
=
120 (struct pending_exception_info
*)__cilkrts_frame_malloc(w
, sizeof (struct pending_exception_info
));
122 info
->make(state
, exc
, rethrow
);
127 decode_exceptions(buf
, sizeof buf
, info
);
128 fprintf(stderr
, "make exception info W%u %p %s (%s)\n",
129 w
->self
, info
, buf
, why
);
133 CILK_ASSERT(w
->l
->pending_exception
== 0);
134 w
->l
->pending_exception
= info
;
138 #include <stdio.h> /* DEBUG */
140 static void decode_flags(int flags
, char out
[9])
142 out
[0] = (flags
& CILK_FRAME_STOLEN
) ? 'S' : '_';
143 out
[1] = (flags
& CILK_FRAME_UNSYNCHED
) ? 'U' : '_';
144 out
[2] = (flags
& CILK_FRAME_DETACHED
) ? 'D' : '_';
145 out
[3] = (flags
& CILK_FRAME_EXCEPTING
) ? 'X' : '_';
150 /* __cilkrts_save_except is called from the runtime epilogue
151 when a function is returning with an exception pending.
153 If the function has a parent to which it could return normally,
154 return and have the caller call _Unwind_Resume, the same as if
155 an exception filter had not matched.
157 Otherwise save the exception in the worker.
159 If this is a return from a ordinary call that must go through
160 the runtime, the assembly epilogue must have saved the call-saved
161 register state in the parent frame. */
165 __cilkrts_return_exception(__cilkrts_stack_frame
*sf
)
167 __cilkrts_worker
*w
= sf
->worker
;
168 _Unwind_Exception
*exc
= (_Unwind_Exception
*)sf
->except_data
;
170 CILK_ASSERT(sf
->flags
& CILK_FRAME_DETACHED
);
171 sf
->flags
&= ~CILK_FRAME_DETACHED
;
174 * If we are in replay mode, and a steal occurred during the recording
175 * phase, stall till a steal actually occurs.
177 replay_wait_for_steal_if_parent_was_stolen(w
);
179 /* If this is to be an abnormal return, save the active exception. */
180 if (!__cilkrts_pop_tail(w
)) {
181 /* Write a record to the replay log for an attempt to return to a
182 stolen parent. This must be done before the exception handler
183 invokes __cilkrts_leave_frame which will bump the pedigree so
184 the replay_wait_for_steal_if_parent_was_stolen() above will match on
186 replay_record_orphaned(w
);
188 /* Now that the record/replay stuff is done, update the pedigree */
189 update_pedigree_on_leave_frame(w
, sf
);
191 /* Inline pop_frame; this may not be needed. */
192 w
->current_stack_frame
= sf
->call_parent
;
194 __cxa_eh_globals
*state
= __cxa_get_globals();
199 decode_flags(sf
->flags
, decoded
);
200 fprintf(stderr
, "__cilkrts_save_except W%u sf %p/%s exc %p [%u %p] suspend\n",
201 w
->self
, sf
, decoded
, exc
,
202 state
->uncaughtExceptions
,
203 state
->caughtExceptions
);
206 /* Like __cilkrts_save_exception_state except for setting the
208 save_exception_info(w
, state
, exc
, exc
== NULL
, "save_except");
210 full_frame
*ff
= w
->l
->frame_ff
;
211 CILK_ASSERT(NULL
== ff
->pending_exception
);
212 ff
->pending_exception
= w
->l
->pending_exception
;
213 w
->l
->pending_exception
= NULL
;
215 __cilkrts_exception_from_spawn(w
, sf
); /* does not return */
217 /* This code path is taken when the parent is attached. It is on
218 the same stack and part of the same full frame. The caller is
219 cleaning up the Cilk frame during unwind and will reraise the
222 /* Now that the record/replay stuff is done, update the pedigree */
223 update_pedigree_on_leave_frame(w
, sf
);
225 #if DEBUG_EXCEPTIONS /* DEBUG ONLY */
227 __cxa_eh_globals
*state
= __cxa_get_globals();
231 decode_flags(sf
->flags
, decoded
);
232 fprintf(stderr
, "__cilkrts_save_except W%d %p/%s %p->%p [%u %p] escape\n",
233 w
->self
, sf
, decoded
, exc
,
234 exc
? to_cxx(exc
)->nextException
: 0,
235 state
->uncaughtExceptions
,
236 state
->caughtExceptions
);
238 /* XXX This is triggering in the user thread which gets an exception
239 from somewhere but does not get the corresponding runtime exception
241 XXX There might be two or more uncaught exceptions. Test could be
242 (uncaught != 0) == (exc != 0). First, design tests to see if that
243 case is otherwise handled correctly. And what if there's an uncaught
244 exception that does not belong to this function? I.e. this is a return
245 from spawn in a destructor. */
247 CILK_ASSERT((int)state
->uncaughtExceptions
> 0);
248 /*CILK_ASSERT(state->uncaughtExceptions == (exc != 0));*/
252 /* The parent is attached so this exception can be propagated normally. */
256 /* Save the exception state into the full frame, which is exiting
259 void __cilkrts_save_exception_state(__cilkrts_worker
*w
, full_frame
*ff
)
261 save_exception_info(w
, __cxa_get_globals(), 0, false, "undo-detach");
262 CILK_ASSERT(NULL
== ff
->pending_exception
);
263 ff
->pending_exception
= w
->l
->pending_exception
;
264 w
->l
->pending_exception
= NULL
;
267 /* __cilkrts_c_sync_except is like __cilkrts_c_sync except that it
268 saves exception state. __cilkrts_c_sync never returns here and
269 always reinstalls the saved exception state.
271 This function must be used because a parent of this function may
272 be propagating an uncaught exception. The uncaught exception
273 count must be saved by the child and passed back to the parent. */
276 NORETURN
__cilkrts_c_sync_except (__cilkrts_worker
*w
, __cilkrts_stack_frame
*sf
)
278 __cxa_eh_globals
*state
= __cxa_get_globals();
279 _Unwind_Exception
*exc
= (_Unwind_Exception
*)sf
->except_data
;
281 CILK_ASSERT((sf
->flags
& (CILK_FRAME_UNSYNCHED
|CILK_FRAME_EXCEPTING
)) ==
282 (CILK_FRAME_UNSYNCHED
|CILK_FRAME_EXCEPTING
));
283 sf
->flags
&= ~CILK_FRAME_EXCEPTING
;
288 decode_flags(sf
->flags
, decoded
);
290 fprintf(stderr
, "__cilkrts_sync_except W%u %p/%s %p->%p [%u %p]\n",
291 w
->self
, sf
, decoded
, exc
,
292 to_cxx(exc
)->nextException
,
293 state
->uncaughtExceptions
,
294 state
->caughtExceptions
);
296 fprintf(stderr
, "__cilkrts_sync_except W%d %p/%s none [%u %p]\n",
297 w
->self
, sf
, decoded
,
298 state
->uncaughtExceptions
,
299 state
->caughtExceptions
);
302 /* Here the identity of an rethrown exception is always known.
303 If exc is NULL this call is only to preserve parent state. */
304 save_exception_info(w
, state
, exc
, false, "sync_except");
307 full_frame
*ff
= w
->l
->frame_ff
;
308 CILK_ASSERT(NULL
== ff
->pending_exception
);
309 ff
->pending_exception
= w
->l
->pending_exception
;
310 w
->l
->pending_exception
= NULL
;
313 CILK_ASSERT(!std::uncaught_exception());
314 __cilkrts_c_sync(w
, sf
);
318 pending_exception_info::destruct()
322 fprintf(stderr
, "destroy exception info %p %p\n", this, active
);
324 _Unwind_DeleteException(active
);
328 fprintf(stderr
, "destroy exception info %p\n", this);
331 while (runtime_state
.caughtExceptions
) {
332 __cxa_exception
*exc
= runtime_state
.caughtExceptions
;
333 runtime_state
.caughtExceptions
= exc
->nextException
;
335 fprintf(stderr
, "destroy caught exception %p\n", this);
337 _Unwind_DeleteException(&exc
->unwindHeader
);
342 * __cilkrts_merge_pending_exceptions
344 * Merge the right exception record into the left. The left is logically
347 * The active exception of E is
348 * E->active if it is non-NULL (in which case E->rethrow is false)
349 * unresolved if E->active is NULL and E->rethrow is true
350 * nil if E->active is NULL and E->rethrow is false
352 * The merged active exception is left active exception if it is not
353 * nil, otherwise the right.
355 * On entry the left state is synched and can not have an unresolved
356 * exception. The merge may result in an unresolved exception.
358 * Due to scoping rules at most one of the caught exception lists is
362 struct pending_exception_info
*
363 __cilkrts_merge_pending_exceptions (
365 struct pending_exception_info
*left
,
366 struct pending_exception_info
*right
)
368 /* If we've only got one exception, return it */
374 decode_exceptions(buf
, sizeof buf
, right
);
375 fprintf(stderr
, "__cilkrts merge W%u nil %p -> %p %s\n",
376 w
->self
, right
, right
, buf
);
386 decode_exceptions(buf
, sizeof buf
, left
);
387 fprintf(stderr
, "__cilkrts merge W%u %p nil -> %p %s\n",
388 w
->self
, left
, left
, buf
);
395 /*volatile struct pending_exception_info left_in = *left, right_in = *right;*/
402 char buf1
[40], buf2
[40];
403 decode_exceptions(buf1
, sizeof buf1
, left
);
404 decode_exceptions(buf2
, sizeof buf2
, right
);
405 fprintf(stderr
, "__cilkrts merge W%u %p %s %p %s\n",
406 w
->self
, left
, buf1
, right
, buf2
);
410 /* It should not be possible for both left and right to
411 have accumulated catch blocks.
413 The left exception record may always have a catch
414 chain it kept when its parent was stolen.
416 If they are siblings, the right sibling should not
417 have accumulated any net catches. (Catch is lexically
420 If the right frame is a parent, it should not have entered
421 a catch block without syncing first. If it spawned in a
422 catch block, the child got its catch. */
423 __cxa_exception
*caught
= left
->runtime_state
.caughtExceptions
;
425 CILK_ASSERT(!right
->runtime_state
.caughtExceptions
);
427 CILK_ASSERT(!left
->rethrow
);
428 left
->rethrow
= right
->rethrow
;
429 left
->runtime_state
.caughtExceptions
= caught
= right
->runtime_state
.caughtExceptions
;
430 right
->runtime_state
.caughtExceptions
= NULL
;
433 /* Merge the uncaught exception and count of uncaught exceptions. */
434 const unsigned int right_uncaught
= right
->runtime_state
.uncaughtExceptions
;
436 left
->active
= right
->active
; /* could be NULL */
438 left
->runtime_state
.uncaughtExceptions
+= right_uncaught
;
440 /* assert is C++ exception */
441 /*CILK_ASSERT(__cxxabiv1::__is_gxx_exception_class(left->active->exception_class))*/;
443 /* Subtract 1 if the right exception is being destructed. */
444 left
->runtime_state
.uncaughtExceptions
+= right_uncaught
- (right
->active
!= 0);
448 __cilkrts_frame_free(w
, right
, sizeof *right
);
450 /* If there is no state left, return NULL. */
453 __cilkrts_frame_free(w
, left
, sizeof *left
);
466 /* __cilkrts_c_resume_except is called from the assembly language
467 restart code when a resumed frame has a pending exception.
469 The handler count negation on rethrow was done when the throw was
472 The assembly language runtime must make the throw unwind to
473 the sync, spawn, or other location where the exception should
474 be injected. (This should not happen after a spawn but nothing
475 here depends on there being no exception on steal.)
477 This function is unused in the Intel stack based system. */
479 void __cilkrts_c_resume_except (_Unwind_Exception
*exc
)
482 fprintf(stderr
, "resume exception %p\n", exc
);
484 _Unwind_Reason_Code why
= _Unwind_RaiseException(exc
);
485 __cilkrts_bug ("Cilk runtime error: failed to reinstate suspended exception %p (%d)\n", exc
, why
);
489 /* Restore the caught exception chain. This assumes no C++ exception
490 code will run before the frame is resumed. If there is no exception
491 to be resumed free the object. */
494 void __cilkrts_setup_for_execution_sysdep(__cilkrts_worker
*w
, full_frame
*ff
)
496 // ASSERT: We own w->lock and ff->lock || P == 1
498 __cxa_eh_globals
*state
= __cxa_get_globals ();
499 struct pending_exception_info
*info
= w
->l
->pending_exception
;
504 w
->l
->pending_exception
= 0;
507 _Unwind_Exception
*exc
= info
->active
;
510 fprintf(stderr
, "__cilkrts_resume_except W%u %p->%p [%u %p]\n",
512 to_cxx(exc
)->nextException
,
513 info
->runtime_state
.uncaughtExceptions
,
514 info
->runtime_state
.caughtExceptions
);
515 /*CILK_ASSERT(info->runtime_state.uncaughtExceptions > 0);*/
519 if (state
->uncaughtExceptions
|| state
->caughtExceptions
)
520 __cilkrts_bug("W%u: resuming with non-empty prior exception state %u %p\n", state
->uncaughtExceptions
, state
->caughtExceptions
);
522 *state
= info
->runtime_state
;
523 info
->runtime_state
.caughtExceptions
= 0;
524 info
->runtime_state
.uncaughtExceptions
= 0;
527 info
->rethrow
= false;
528 /* Resuming function will rethrow. Runtime calls
529 std::terminate if there is no caught exception. */
530 ff
->call_stack
->flags
|= CILK_FRAME_EXCEPTING
;
533 ff
->call_stack
->flags
|= CILK_FRAME_EXCEPTING
;
534 ff
->call_stack
->except_data
= info
->active
;
540 __cilkrts_frame_free(w
, info
, sizeof *info
);
541 w
->l
->pending_exception
= NULL
;
545 if (ff
->call_stack
->except_data
)
546 CILK_ASSERT(std::uncaught_exception());
552 struct pending_exception_info
*__cilkrts_get_exception(__cilkrts_worker
*w
,
553 __cilkrts_stack_frame
*sf
)
555 struct pending_exception_info
*info
= w
->l
->pending_exception
;
558 sf
->flags
&= ~CILK_FRAME_EXCEPTING
;
562 w
->l
->pending_exception
= NULL
;
564 /* This exception goes into the frame. */
566 _Unwind_Exception
*exc
= info
->active
;
569 __cilkrts_frame_free(w
, info
, sizeof *info
);
571 sf
->flags
|= CILK_FRAME_EXCEPTING
;
578 void __attribute__((nonnull
)) __cilkrts_gcc_rethrow(__cilkrts_stack_frame
*sf
)
581 // Cygwin doesn't support exceptions, so _Unwind_Resume isn't available
582 // Which means we can't support exceptions either
583 __cilkrts_bug("The Cygwin implementation of the Intel Cilk Plus runtime doesn't support exceptions\n");
585 if (sf
->except_data
) {
587 CILK_ASSERT(std::uncaught_exception());
589 _Unwind_Resume ((_Unwind_Exception
*)sf
->except_data
);
596 /* End except-gcc.cpp */