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