terror_handling.cc - pism - [fork] customized build of PISM, the parallel ice sheet model (tillflux branch)
HTML git clone git://src.adamsgaard.dk/pism
DIR Log
DIR Files
DIR Refs
DIR LICENSE
---
terror_handling.cc (6291B)
---
1 /* Copyright (C) 2014, 2015, 2016, 2017 PISM Authors
2 *
3 * This file is part of PISM.
4 *
5 * PISM is free software; you can redistribute it and/or modify it under the
6 * terms of the GNU General Public License as published by the Free Software
7 * Foundation; either version 3 of the License, or (at your option) any later
8 * version.
9 *
10 * PISM is distributed in the hope that it will be useful, but WITHOUT ANY
11 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 * details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with PISM; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include "error_handling.hh"
21 #include <petsc.h>
22
23 #include <stdexcept>
24 #include <stdarg.h>
25
26 namespace pism {
27
28 ErrorLocation::ErrorLocation()
29 : filename(NULL), line_number(0) {
30 // empty
31 }
32
33 ErrorLocation::ErrorLocation(const char *name, int line)
34 : filename(name), line_number(line) {
35 // empty
36 }
37
38 RuntimeError::Hook RuntimeError::sm_hook = NULL;
39
40 RuntimeError::RuntimeError(const ErrorLocation &location, const std::string &message)
41 : std::runtime_error(message), m_location(location) {
42 if (sm_hook != NULL) {
43 sm_hook(this);
44 }
45 }
46
47 RuntimeError RuntimeError::formatted(const ErrorLocation &location, const char format[], ...) {
48 char buffer[8192];
49 va_list argp;
50
51 va_start(argp, format);
52 vsnprintf(buffer, sizeof(buffer), format, argp);
53 va_end(argp);
54
55 return RuntimeError(location, buffer);
56 }
57
58 void RuntimeError::set_hook(Hook new_hook) {
59 sm_hook = new_hook;
60 }
61
62 RuntimeError::~RuntimeError() throw() {
63 // empty
64 }
65
66 void RuntimeError::add_context(const std::string &message) {
67 m_context.push_back(message);
68 }
69
70 void RuntimeError::add_context(const char format[], ...) {
71 char buffer[8192];
72 va_list argp;
73
74 va_start(argp, format);
75 vsnprintf(buffer, sizeof(buffer), format, argp);
76 va_end(argp);
77
78 // convert to std::string to avoid recursion
79 this->add_context(std::string(buffer));
80 }
81
82 void RuntimeError::print(MPI_Comm com) {
83 PetscErrorCode ierr = 0;
84 std::string error = "PISM ERROR: ",
85 message = this->what();
86
87 std::string padding = std::string(error.size(), ' ');
88
89 // replace newlines with newlines plus padding
90 size_t k = message.find("\n", 0);
91 while (k != std::string::npos) {
92 message.insert(k+1, padding);
93 k = message.find("\n", k+1);
94 }
95
96 // print the error message with "PISM ERROR:" in front:
97 ierr = PetscPrintf(com,
98 "%s%s\n", error.c_str(), message.c_str()); CHKERRCONTINUE(ierr);
99
100 // compute how much padding we need to align things:
101 std::string while_str = std::string(error.size(), ' ') + "while ";
102 padding = std::string(while_str.size() + 1, ' '); // 1 extra space
103
104 // loop over "context" messages
105 for (auto j : m_context) {
106 message = j;
107
108 // replace newlines with newlines plus padding
109 k = message.find("\n", 0);
110 while (k != std::string::npos) {
111 message.insert(k+1, padding);
112 k = message.find("\n", k+1);
113 }
114
115 // print a "context" message
116 ierr = PetscPrintf(com,
117 "%s%s\n", while_str.c_str(), message.c_str()); CHKERRCONTINUE(ierr);
118 }
119
120 if (m_location.filename != NULL) {
121 padding = std::string(error.size(), ' ');
122 ierr = PetscPrintf(com,
123 "%sError location: %s, line %d\n",
124 padding.c_str(), m_location.filename, m_location.line_number); CHKERRCONTINUE(ierr);
125 }
126 }
127
128 /** Handle fatal PISM errors by printing an informative error message.
129 *
130 * (Since these are fatal there is nothing else that can be done.)
131 *
132 * Should be called from a catch(...) block *only*.
133 */
134 void handle_fatal_errors(MPI_Comm com) {
135 PetscErrorCode ierr;
136 try {
137 throw; // re-throw the current exception
138 }
139 catch (RuntimeError &e) {
140 e.print(com);
141 }
142 catch (std::exception &e) {
143 ierr = PetscPrintf(PETSC_COMM_SELF,
144 "\n"
145 "PISM ERROR: Caught a C++ standard library exception: \"%s\".\n"
146 " This is probably a bug in PISM.\n"
147 " Please send a report to uaf-pism@alaska.edu\n"
148 "\n",
149 e.what()); CHKERRCONTINUE(ierr);
150 } catch (...) {
151 ierr = PetscPrintf(PETSC_COMM_SELF,
152 "\n"
153 "PISM ERROR: Caught an unexpected exception.\n"
154 " This is probably a bug in PISM.\n"
155 " Please send a report to uaf-pism@alaska.edu\n"
156 "\n");
157 CHKERRCONTINUE(ierr);
158 }
159 }
160
161 void check_c_call(int errcode, int success,
162 const char* function_name, const char *file, int line) {
163 if (errcode != success) {
164 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "External library function %s failed at %s:%d",
165 function_name, file, line);
166 }
167 }
168
169 void check_petsc_call(int errcode,
170 const char* function_name, const char *file, int line) {
171 // tell PETSc to print the error message
172 CHKERRCONTINUE(errcode);
173 check_c_call(errcode, 0, function_name, file, line);
174 }
175
176 ParallelSection::ParallelSection(MPI_Comm com)
177 : m_failed(false), m_com(com) {
178 // empty
179 }
180
181 ParallelSection::~ParallelSection() {
182 // empty
183 }
184
185 //! @brief Indicates a failure of a parallel section.
186 /*!
187 * This should be called from a `catch (...) { ... }` block **only**.
188 */
189 void ParallelSection::failed() {
190 int rank = 0;
191 MPI_Comm_rank(m_com, &rank);
192
193 PetscFPrintf(MPI_COMM_SELF, stderr,
194 "PISM ERROR: Rank %d failed with the following message.\n", rank);
195
196 handle_fatal_errors(MPI_COMM_SELF);
197
198 m_failed = true;
199 }
200
201 void ParallelSection::reset() {
202 m_failed = false;
203 }
204
205 void ParallelSection::check() {
206 int success_flag = m_failed ? 0 : 1;
207 int success_flag_global = 0;
208
209 MPI_Allreduce(&success_flag, &success_flag_global, 1, MPI_INT, MPI_LAND, m_com);
210
211 if (success_flag_global == 0) {
212 throw RuntimeError(PISM_ERROR_LOCATION, "Failure in a parallel section. See error messages above for more.");
213 }
214 }
215
216 } // end of namespace pism