1 #include "moab/ErrorHandler.hpp"
2 #include "ErrorOutput.hpp"
3 #ifdef MOAB_HAVE_MPI
4 #include "moab_mpi.h"
5 #endif
6 
7 #include <stdlib.h>
8 #include <assert.h>
9 
10 #ifdef _WIN32
11 #include <io.h>
12 #include <windows.h>
13 namespace
14 {
sleep(int sec)15   void sleep(int sec)
16   {
17 	  Sleep(sec*1000);
18   }
19 }
20 #else
21 #include <unistd.h>
22 #endif
23 
24 namespace moab {
25 
26 static ErrorOutput* errorOutput = NULL;
27 static std::string lastError = "No error";
28 
MBErrorHandler_Init()29 void MBErrorHandler_Init()
30 {
31   if (NULL == errorOutput) {
32     errorOutput = new (std::nothrow) ErrorOutput(stderr);
33     assert(NULL != errorOutput);
34     errorOutput->use_world_rank();
35   }
36 }
37 
MBErrorHandler_Finalize()38 void MBErrorHandler_Finalize()
39 {
40   if (NULL != errorOutput) {
41     delete errorOutput;
42     errorOutput = NULL;
43   }
44 }
45 
MBErrorHandler_Initialized()46 bool MBErrorHandler_Initialized()
47 {
48   return (NULL != errorOutput);
49 }
50 
MBErrorHandler_GetLastError(std::string & error)51 void MBErrorHandler_GetLastError(std::string& error)
52 {
53   error = lastError;
54 }
55 
MBTraceBackErrorHandler(int line,const char * func,const char * file,const char * dir,const char * err_msg,ErrorType err_type)56 void MBTraceBackErrorHandler(int line, const char* func, const char* file, const char* dir, const char* err_msg, ErrorType err_type)
57 {
58   if (NULL == errorOutput)
59     return;
60 
61   // For a globally fatal error, get world rank of current processor, so that it is only printed from processor 0
62   // For a per-processor relevant error, set rank of current processor to 0, so that it is always printed
63   int rank = 0;
64   if (MB_ERROR_TYPE_NEW_GLOBAL == err_type && errorOutput->have_rank())
65     rank = errorOutput->get_rank();
66 
67   if (0 == rank) {
68     // Print the error message for a new error
69     if (MB_ERROR_TYPE_EXISTING != err_type && NULL != err_msg) {
70       errorOutput->print("--------------------- Error Message ------------------------------------\n");
71       errorOutput->printf("%s!\n", err_msg);
72       lastError = err_msg;
73     }
74 
75     // Print a line of stack trace for a new error, or an existing one
76     errorOutput->printf("%s() line %d in %s%s\n", func, line, dir, file);
77   }
78   else {
79     // Do not print the error message or stack trace, since processor 0 will print them
80     // Sleep 10 seconds before aborting so it will not accidently kill process 0
81     sleep(10);
82     abort();
83   }
84 }
85 
MBError(int line,const char * func,const char * file,const char * dir,ErrorCode err_code,const char * err_msg,ErrorType err_type)86 ErrorCode MBError(int line, const char* func, const char* file, const char* dir, ErrorCode err_code, const char* err_msg, ErrorType err_type)
87 {
88   // When this routine is called to handle an existing error (instead of creating a new one),
89   // we need to check if the returned non-success result from a function might be a non-error
90   // condition. If no last error message was ever set, just return the given error code.
91   if (MB_ERROR_TYPE_EXISTING == err_type && "No error" == lastError)
92     return err_code;
93 
94   MBTraceBackErrorHandler(line, func, file, dir, err_msg, err_type);
95 
96 #ifdef MOAB_HAVE_MPI
97   // If this is called from the main() routine we call MPI_Abort() to allow
98   // the parallel program to be properly shutdown
99   if (strncmp(func, "main", 4) == 0)
100     MPI_Abort(MPI_COMM_WORLD, err_code);
101 #endif
102 
103   return err_code;
104 }
105 
106 } // namespace moab
107