URI:
       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