syscall: fixes for Solaris
[official-gcc.git] / libcilkrts / runtime / except-gcc.cpp
blob7fc6e6b79b0250828575e81d18ad6c6c228bbb88
1 /* except-gcc.cpp -*-C++-*-
3 *************************************************************************
5 * Copyright (C) 2009-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:
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.
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
44 * not tracked.
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"
51 #include "except.h"
52 #include "sysdep.h"
53 #include "bug.h"
54 #include "local_state.h"
55 #include "full_frame.h"
56 #include "scheduler.h"
57 #include "frame_malloc.h"
58 #include "pedigrees.h"
60 #include <stdint.h>
61 #include <typeinfo>
63 #ifndef DEBUG_EXCEPTIONS
64 #define DEBUG_EXCEPTIONS 0
65 #endif
67 struct pending_exception_info
69 void make(__cxa_eh_globals *, _Unwind_Exception *, bool);
70 void destruct();
71 bool empty() const;
72 void check() const;
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. */
79 bool rethrow;
80 struct __cxa_eh_globals runtime_state;
83 void pending_exception_info::check() const
85 if (active)
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)
92 active = exc_in;
93 rethrow = rethrow_in;
94 runtime_state = *state_in;
95 /* Read and clear C++ runtime state. */
96 state_in->caughtExceptions = 0;
97 state_in->uncaughtExceptions = 0;
98 #if CILK_LIB_DEBUG
99 check();
100 #endif
103 bool
104 pending_exception_info::empty() const
106 return !active && !rethrow && !runtime_state.caughtExceptions &&
107 !runtime_state.uncaughtExceptions;
110 #if DEBUG_EXCEPTIONS
111 #include <stdio.h>
112 static void
113 decode_exceptions(char *out, size_t len, struct pending_exception_info *info)
115 if (info->empty())
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);
120 else
121 cilk_snprintf_l(out, len, "[throw %p]", (void *)info->active);
123 #endif
125 static void
126 save_exception_info(__cilkrts_worker *w,
127 __cxa_eh_globals *state,
128 _Unwind_Exception *exc,
129 bool rethrow,
130 const char *why)
132 struct pending_exception_info *info =
133 (struct pending_exception_info *)__cilkrts_frame_malloc(w, sizeof (struct pending_exception_info));
134 CILK_ASSERT(info);
135 info->make(state, exc, rethrow);
137 #if DEBUG_EXCEPTIONS
139 char buf[40];
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);
144 #endif
146 CILK_ASSERT(w->l->pending_exception == 0);
147 w->l->pending_exception = info;
150 #if DEBUG_EXCEPTIONS
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' : '_';
159 out[4] = '\0';
161 #endif
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. */
176 extern "C"
177 CILK_ABI_THROWS_VOID
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
198 replay */
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;
206 sf->call_parent = 0;
207 __cxa_eh_globals *state = __cxa_get_globals();
209 #if DEBUG_EXCEPTIONS
210 fflush(stdout);
211 char decoded[9];
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);
217 #endif
219 /* Like __cilkrts_save_exception_state except for setting the
220 rethrow flag. */
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
233 exception */
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();
242 fflush(stdout);
243 char decoded[9];
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
253 state.
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. */
259 if (exc)
260 CILK_ASSERT((int)state->uncaughtExceptions > 0);
261 /*CILK_ASSERT(state->uncaughtExceptions == (exc != 0));*/
263 #endif
265 /* The parent is attached so this exception can be propagated normally. */
266 return;
269 /* Save the exception state into the full frame, which is exiting
270 or suspending. */
271 extern "C"
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. */
288 extern "C"
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;
298 #if DEBUG_EXCEPTIONS
299 fflush(stdout);
300 char decoded[9];
301 decode_flags(sf->flags, decoded);
302 if (exc)
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);
308 else
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);
313 #endif
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");
318 #if 0
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;
325 #endif
326 CILK_ASSERT(!std::uncaught_exception());
327 __cilkrts_c_sync(w, sf);
330 void
331 pending_exception_info::destruct()
333 if (active) {
334 #if DEBUG_EXCEPTIONS
335 fprintf(stderr, "destroy exception info %p %p\n", this, active);
336 #endif
337 _Unwind_DeleteException(active);
338 active = 0;
339 } else {
340 #if DEBUG_EXCEPTIONS
341 fprintf(stderr, "destroy exception info %p\n", this);
342 #endif
344 while (runtime_state.caughtExceptions) {
345 __cxa_exception *exc = runtime_state.caughtExceptions;
346 runtime_state.caughtExceptions = exc->nextException;
347 #if DEBUG_EXCEPTIONS
348 fprintf(stderr, "destroy caught exception %p\n", this);
349 #endif
350 _Unwind_DeleteException(&exc->unwindHeader);
355 * __cilkrts_merge_pending_exceptions
357 * Merge the right exception record into the left. The left is logically
358 * earlier.
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
372 * non-NULL.
375 struct pending_exception_info *
376 __cilkrts_merge_pending_exceptions (
377 __cilkrts_worker *w,
378 struct pending_exception_info *left,
379 struct pending_exception_info *right)
381 /* If we've only got one exception, return it */
383 if (NULL == left) {
384 #if DEBUG_EXCEPTIONS
385 if (right) {
386 char buf[40];
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);
391 #endif
392 return right;
395 if (NULL == right) {
396 #if DEBUG_EXCEPTIONS
397 if (left) {
398 char buf[40];
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);
403 #endif
404 return left;
407 #if CILK_LIB_DEBUG
408 /*volatile struct pending_exception_info left_in = *left, right_in = *right;*/
409 left->check();
410 right->check();
411 #endif
413 #if DEBUG_EXCEPTIONS
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);
421 #endif
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
431 scoped.)
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;
437 if (caught)
438 CILK_ASSERT(!right->runtime_state.caughtExceptions);
439 else {
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;
448 if (!left->active){
449 left->active = right->active; /* could be NULL */
450 right->active = 0;
451 left->runtime_state.uncaughtExceptions += right_uncaught;
452 if (left->active)
453 /* assert is C++ exception */
454 /*CILK_ASSERT(__cxxabiv1::__is_gxx_exception_class(left->active->exception_class))*/;
455 } else {
456 /* Subtract 1 if the right exception is being destructed. */
457 left->runtime_state.uncaughtExceptions += right_uncaught - (right->active != 0);
460 right->destruct();
461 __cilkrts_frame_free(w, right, sizeof *right);
463 /* If there is no state left, return NULL. */
464 if (left->empty()) {
465 left->destruct();
466 __cilkrts_frame_free(w, left, sizeof *left);
467 left = NULL;
470 #if CILK_LIB_DEBUG
471 if (left)
472 left->check();
473 #endif
475 return left;
478 #if 0
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
483 resolved.
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. */
491 extern "C"
492 void __cilkrts_c_resume_except (_Unwind_Exception *exc)
494 #if DEBUG_EXCEPTIONS
495 fprintf(stderr, "resume exception %p\n", exc);
496 #endif
497 _Unwind_Reason_Code why = _Unwind_RaiseException(exc);
498 __cilkrts_bug ("Cilk runtime error: failed to reinstate suspended exception %p (%d)\n", exc, why);
500 #endif
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. */
506 extern "C"
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;
514 if (info == NULL)
515 return;
517 w->l->pending_exception = 0;
519 #if DEBUG_EXCEPTIONS
520 _Unwind_Exception *exc = info->active;
521 if (exc) {
522 fflush(stdout);
523 fprintf(stderr, "__cilkrts_resume_except W%u %p->%p [%u %p]\n",
524 w->self, exc,
525 to_cxx(exc)->nextException,
526 info->runtime_state.uncaughtExceptions,
527 info->runtime_state.caughtExceptions);
528 /*CILK_ASSERT(info->runtime_state.uncaughtExceptions > 0);*/
530 #endif
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;
539 if (info->rethrow) {
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;
545 if (info->active) {
546 ff->call_stack->flags |= CILK_FRAME_EXCEPTING;
547 ff->call_stack->except_data = info->active;
548 info->active = 0;
551 if (info->empty()) {
552 info->destruct();
553 __cilkrts_frame_free(w, info, sizeof *info);
554 w->l->pending_exception = NULL;
557 #if CILK_LIB_DEBUG
558 if (ff->call_stack->except_data)
559 CILK_ASSERT(std::uncaught_exception());
560 #endif
563 #if 0
564 extern "C"
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;
570 if (info == NULL) {
571 sf->flags &= ~CILK_FRAME_EXCEPTING;
572 return 0;
575 w->l->pending_exception = NULL;
577 /* This exception goes into the frame. */
579 _Unwind_Exception *exc = info->active;
580 info->active = NULL;
581 info->destruct();
582 __cilkrts_frame_free(w, info, sizeof *info);
583 info = 0;
584 sf->flags |= CILK_FRAME_EXCEPTING;
585 sf->exception = exc;
586 return 0;
588 #endif
590 extern "C"
591 void __attribute__((nonnull)) __cilkrts_gcc_rethrow(__cilkrts_stack_frame *sf)
593 #ifdef __CYGWIN__
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");
597 #else
598 if (sf->except_data) {
599 #if CILK_LIB_DEBUG
600 CILK_ASSERT(std::uncaught_exception());
601 #endif
602 _Unwind_Resume ((_Unwind_Exception *)sf->except_data);
603 } else {
604 throw;
606 #endif // __CYGWIN__
609 /* End except-gcc.cpp */