1 | //===-- lib/runtime/terminator.cpp ------------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "flang-rt/runtime/terminator.h" |
10 | #include <cstdio> |
11 | #include <cstdlib> |
12 | |
13 | namespace Fortran::runtime { |
14 | |
15 | #if !defined(RT_DEVICE_COMPILATION) |
16 | [[maybe_unused]] static void (*crashHandler)( |
17 | const char *, int, const char *, va_list &){nullptr}; |
18 | |
19 | void Terminator::RegisterCrashHandler( |
20 | void (*handler)(const char *, int, const char *, va_list &)) { |
21 | crashHandler = handler; |
22 | } |
23 | |
24 | void Terminator::InvokeCrashHandler(const char *message, ...) const { |
25 | if (crashHandler) { |
26 | va_list ap; |
27 | va_start(ap, message); |
28 | crashHandler(sourceFileName_, sourceLine_, message, ap); |
29 | va_end(ap); |
30 | } |
31 | } |
32 | |
33 | [[noreturn]] void Terminator::CrashArgs( |
34 | const char *message, va_list &ap) const { |
35 | CrashHeader(); |
36 | std::vfprintf(stderr, message, ap); |
37 | va_end(ap); |
38 | CrashFooter(); |
39 | } |
40 | #endif |
41 | |
42 | RT_OFFLOAD_API_GROUP_BEGIN |
43 | |
44 | RT_API_ATTRS void Terminator::CrashHeader() const { |
45 | #if defined(RT_DEVICE_COMPILATION) |
46 | std::printf("\nfatal Fortran runtime error" ); |
47 | if (sourceFileName_) { |
48 | std::printf("(%s" , sourceFileName_); |
49 | if (sourceLine_) { |
50 | std::printf(":%d" , sourceLine_); |
51 | } |
52 | std::printf(")" ); |
53 | } |
54 | std::printf(": " ); |
55 | #else |
56 | std::fputs("\nfatal Fortran runtime error" , stderr); |
57 | if (sourceFileName_) { |
58 | std::fprintf(stderr, "(%s" , sourceFileName_); |
59 | if (sourceLine_) { |
60 | std::fprintf(stderr, ":%d" , sourceLine_); |
61 | } |
62 | fputc(')', stderr); |
63 | } |
64 | std::fputs(": " , stderr); |
65 | #endif |
66 | } |
67 | |
68 | [[noreturn]] RT_API_ATTRS void Terminator::CrashFooter() const { |
69 | #if defined(RT_DEVICE_COMPILATION) |
70 | std::printf("\n" ); |
71 | #else |
72 | fputc('\n', stderr); |
73 | // FIXME: re-enable the flush along with the IO enabling. |
74 | io::FlushOutputOnCrash(*this); |
75 | #endif |
76 | NotifyOtherImagesOfErrorTermination(); |
77 | #if defined(RT_DEVICE_COMPILATION) |
78 | DeviceTrap(); |
79 | #else |
80 | std::abort(); |
81 | #endif |
82 | } |
83 | |
84 | [[noreturn]] RT_API_ATTRS void Terminator::CheckFailed( |
85 | const char *predicate, const char *file, int line) const { |
86 | Crash("Internal error: RUNTIME_CHECK(%s) failed at %s(%d)" , predicate, file, |
87 | line); |
88 | } |
89 | |
90 | [[noreturn]] RT_API_ATTRS void Terminator::CheckFailed( |
91 | const char *predicate) const { |
92 | Crash("Internal error: RUNTIME_CHECK(%s) failed at %s(%d)" , predicate, |
93 | sourceFileName_, sourceLine_); |
94 | } |
95 | |
96 | // TODO: These will be defined in the coarray runtime library |
97 | RT_API_ATTRS void NotifyOtherImagesOfNormalEnd() {} |
98 | RT_API_ATTRS void NotifyOtherImagesOfFailImageStatement() {} |
99 | RT_API_ATTRS void NotifyOtherImagesOfErrorTermination() {} |
100 | |
101 | RT_OFFLOAD_API_GROUP_END |
102 | |
103 | } // namespace Fortran::runtime |
104 | |