aboutsummaryrefslogtreecommitdiff
path: root/flang-rt/lib/runtime/terminator.cpp
blob: e8d64223919e4c8777e1a5e94b47d2dbb8762bca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//===-- lib/runtime/terminator.cpp ------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "flang-rt/runtime/terminator.h"
#include <cstdio>
#include <cstdlib>

namespace Fortran::runtime {

#if !defined(RT_DEVICE_COMPILATION)
[[maybe_unused]] static void (*crashHandler)(
    const char *, int, const char *, va_list &){nullptr};

void Terminator::RegisterCrashHandler(
    void (*handler)(const char *, int, const char *, va_list &)) {
  crashHandler = handler;
}

void Terminator::InvokeCrashHandler(const char *message, ...) const {
  if (crashHandler) {
    va_list ap;
    va_start(ap, message);
    crashHandler(sourceFileName_, sourceLine_, message, ap);
    va_end(ap);
  }
}

[[noreturn]] void Terminator::CrashArgs(
    const char *message, va_list &ap) const {
  CrashHeader();
  std::vfprintf(stderr, message, ap);
  va_end(ap);
  CrashFooter();
}
#endif

RT_OFFLOAD_API_GROUP_BEGIN

RT_API_ATTRS void Terminator::CrashHeader() const {
#if defined(RT_DEVICE_COMPILATION)
  std::printf("\nfatal Fortran runtime error");
  if (sourceFileName_) {
    std::printf("(%s", sourceFileName_);
    if (sourceLine_) {
      std::printf(":%d", sourceLine_);
    }
    std::printf(")");
  }
  std::printf(": ");
#else
  std::fputs("\nfatal Fortran runtime error", stderr);
  if (sourceFileName_) {
    std::fprintf(stderr, "(%s", sourceFileName_);
    if (sourceLine_) {
      std::fprintf(stderr, ":%d", sourceLine_);
    }
    fputc(')', stderr);
  }
  std::fputs(": ", stderr);
#endif
}

[[noreturn]] RT_API_ATTRS void Terminator::CrashFooter() const {
#if defined(RT_DEVICE_COMPILATION)
  std::printf("\n");
#else
  fputc('\n', stderr);
  // FIXME: re-enable the flush along with the IO enabling.
  io::FlushOutputOnCrash(*this);
#endif
  NotifyOtherImagesOfErrorTermination(EXIT_FAILURE);
#if defined(RT_DEVICE_COMPILATION)
  DeviceTrap();
#else
  std::abort();
#endif
}

[[noreturn]] RT_API_ATTRS void Terminator::CheckFailed(
    const char *predicate, const char *file, int line) const {
  Crash("Internal error: RUNTIME_CHECK(%s) failed at %s(%d)", predicate, file,
      line);
}

[[noreturn]] RT_API_ATTRS void Terminator::CheckFailed(
    const char *predicate) const {
  Crash("Internal error: RUNTIME_CHECK(%s) failed at %s(%d)", predicate,
      sourceFileName_, sourceLine_);
}

static RT_VAR_ATTRS void (*normalEndCallback)(int) = nullptr;
static RT_VAR_ATTRS void (*failImageCallback)(void) = nullptr;
static RT_VAR_ATTRS void (*errorCallback)(int) = nullptr;

void SetNormalEndCallback(void (*callback)(int)) {
  normalEndCallback = callback;
}

void SetFailImageCallback(void (*callback)(void)) {
  failImageCallback = callback;
}

void SetErrorCallback(void (*callback)(int)) { errorCallback = callback; }

[[noreturn]]
void NormalExit(int exitCode) {
  SynchronizeImagesOfNormalEnd(exitCode); // might never return

  std::exit(exitCode);
}

[[noreturn]]
void ErrorExit(int exitCode) {
  NotifyOtherImagesOfErrorTermination(exitCode); // might never return

  std::exit(exitCode);
}

RT_API_ATTRS void SynchronizeImagesOfNormalEnd(int code) {
  if (normalEndCallback)
    (*normalEndCallback)(code);
}

RT_API_ATTRS void NotifyOtherImagesOfFailImageStatement() {
  if (failImageCallback)
    (*failImageCallback)();
}

RT_API_ATTRS void NotifyOtherImagesOfErrorTermination(int code) {
  if (errorCallback)
    (*errorCallback)(code);
}
RT_OFFLOAD_API_GROUP_END

} // namespace Fortran::runtime