xref: /petsc/src/sys/error/errtrace.c (revision a32e9c995d3c9cc14233efbb30d372fdb63ce962)
1 #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for fileno() */
2 #include <petscsys.h>                    /*I "petscsys.h" I*/
3 #include <petsc/private/petscimpl.h>
4 #include <petscconfiginfo.h>
5 #if defined(PETSC_HAVE_UNISTD_H)
6   #include <unistd.h>
7 #endif
8 #include "err.h"
9 
10 /*@C
11   PetscIgnoreErrorHandler - Deprecated, use `PetscReturnErrorHandler()`. Ignores the error, allows program to continue as if error did not occur
12 
13   Not Collective
14 
15   Input Parameters:
16 + comm - communicator over which error occurred
17 . line - the line number of the error (indicated by __LINE__)
18 . fun  - the function name
19 . file - the file in which the error was detected (indicated by __FILE__)
20 . mess - an error text string, usually just printed to the screen
21 . n    - the generic error number
22 . p    - specific error number
23 - ctx  - error handler context
24 
25   Level: developer
26 
27   Note:
28   Users do not directly call this routine
29 
30 .seealso: `PetscReturnErrorHandler()`
31  @*/
32 PetscErrorCode PetscIgnoreErrorHandler(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode n, PetscErrorType p, const char *mess, void *ctx)
33 {
34   (void)comm;
35   (void)line;
36   (void)fun;
37   (void)file;
38   (void)p;
39   (void)mess;
40   (void)ctx;
41   return n;
42 }
43 
44 /* ---------------------------------------------------------------------------------------*/
45 
46 static char      arch[128], hostname[128], username[128], pname[PETSC_MAX_PATH_LEN], date[128];
47 static PetscBool PetscErrorPrintfInitializeCalled = PETSC_FALSE;
48 static char      version[256];
49 
50 /*
51    Initializes arch, hostname, username, date so that system calls do NOT need
52    to be made during the error handler.
53 */
54 PetscErrorCode PetscErrorPrintfInitialize(void)
55 {
56   PetscBool use_stdout = PETSC_FALSE, use_none = PETSC_FALSE;
57 
58   PetscFunctionBegin;
59   PetscCall(PetscGetArchType(arch, sizeof(arch)));
60   PetscCall(PetscGetHostName(hostname, sizeof(hostname)));
61   PetscCall(PetscGetUserName(username, sizeof(username)));
62   PetscCall(PetscGetProgramName(pname, sizeof(pname)));
63   PetscCall(PetscGetDate(date, sizeof(date)));
64   PetscCall(PetscGetVersion(version, sizeof(version)));
65 
66   PetscCall(PetscOptionsGetBool(NULL, NULL, "-error_output_stdout", &use_stdout, NULL));
67   if (use_stdout) PETSC_STDERR = PETSC_STDOUT;
68   PetscCall(PetscOptionsGetBool(NULL, NULL, "-error_output_none", &use_none, NULL));
69   if (use_none) PetscErrorPrintf = PetscErrorPrintfNone;
70   PetscErrorPrintfInitializeCalled = PETSC_TRUE;
71   PetscFunctionReturn(PETSC_SUCCESS);
72 }
73 
74 PetscErrorCode PetscErrorPrintfNone(const char format[], ...)
75 {
76   return PETSC_SUCCESS;
77 }
78 
79 PetscErrorCode PetscErrorPrintfDefault(const char format[], ...)
80 {
81   va_list          Argp;
82   static PetscBool PetscErrorPrintfCalled = PETSC_FALSE;
83   PetscErrorCode   ierr;
84 
85   /*
86       This function does not call PetscFunctionBegin and PetscFunctionReturn() because
87     it may be called by PetscStackView().
88 
89       This function does not do error checking because it is called by the error handlers.
90   */
91 
92   if (!PetscErrorPrintfCalled) {
93     PetscErrorPrintfCalled = PETSC_TRUE;
94 
95     /*
96         On the SGI machines and Cray T3E, if errors are generated  "simultaneously" by
97       different processors, the messages are printed all jumbled up; to try to
98       prevent this we have each processor wait based on their rank
99     */
100 #if defined(PETSC_CAN_SLEEP_AFTER_ERROR)
101     {
102       PetscMPIInt rank = PetscGlobalRank > 8 ? 8 : PetscGlobalRank;
103       ierr             = PetscSleep((PetscReal)rank);
104       (void)ierr;
105     }
106 #endif
107   }
108 
109   ierr = PetscFPrintf(PETSC_COMM_SELF, PETSC_STDERR, "[%d]PETSC ERROR: ", PetscGlobalRank);
110   va_start(Argp, format);
111   ierr = (*PetscVFPrintf)(PETSC_STDERR, format, Argp);
112   (void)ierr;
113   va_end(Argp);
114   return PETSC_SUCCESS;
115 }
116 
117 /*
118    On some systems when the stderr is nested through several levels of shell script
119    before being passed to a file the isatty() falsely returns true resulting in
120    the screen highlight variables being passed through the test harness. Therefore
121    simply do not highlight when the PETSC_STDERR is PETSC_STDOUT.
122 */
123 static void PetscErrorPrintfHilight(void)
124 {
125 #if defined(PETSC_HAVE_UNISTD_H) && defined(PETSC_USE_ISATTY)
126   if (PetscErrorPrintf == PetscErrorPrintfDefault && PETSC_STDERR != PETSC_STDOUT) {
127     if (isatty(fileno(PETSC_STDERR))) fprintf(PETSC_STDERR, "\033[1;31m");
128   }
129 #endif
130 }
131 
132 static void PetscErrorPrintfNormal(void)
133 {
134 #if defined(PETSC_HAVE_UNISTD_H) && defined(PETSC_USE_ISATTY)
135   if (PetscErrorPrintf == PetscErrorPrintfDefault && PETSC_STDERR != PETSC_STDOUT) {
136     if (isatty(fileno(PETSC_STDERR))) fprintf(PETSC_STDERR, "\033[0;39m\033[0;49m");
137   }
138 #endif
139 }
140 
141 PETSC_EXTERN PetscErrorCode PetscOptionsViewError(void);
142 
143 /*@C
144 
145   PetscTraceBackErrorHandler - Default error handler routine that generates
146   a traceback on error detection.
147 
148   Not Collective
149 
150   Input Parameters:
151 + comm - communicator over which error occurred
152 . line - the line number of the error (indicated by __LINE__)
153 . fun  - the function name
154 . file - the file in which the error was detected (indicated by __FILE__)
155 . mess - an error text string, usually just printed to the screen
156 . n    - the generic error number
157 . p    - `PETSC_ERROR_INITIAL` if this is the first call the error handler, otherwise `PETSC_ERROR_REPEAT`
158 - ctx  - error handler context
159 
160   Options Database Keys:
161 + -error_output_stdout - output the error messages to stdout instead of the default stderr
162 - -error_output_none   - do not output the error messages
163 
164   Notes:
165   Users do not directly call this routine
166 
167   Use `PetscPushErrorHandler()` to set the desired error handler.
168 
169   Level: developer
170 
171 .seealso: `PetscError()`, `PetscPushErrorHandler()`, `PetscPopErrorHandler()`, `PetscAttachDebuggerErrorHandler()`,
172           `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`, `PetscReturnErrorHandler()`, `PetscEmacsClientErrorHandler()`
173  @*/
174 PetscErrorCode PetscTraceBackErrorHandler(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode n, PetscErrorType p, const char *mess, void *ctx)
175 {
176   PetscErrorCode ierr;
177   PetscMPIInt    rank = 0;
178 
179   (void)ctx;
180   if (comm != PETSC_COMM_SELF) MPI_Comm_rank(comm, &rank);
181 
182   if (rank == 0 && (!PetscCIEnabledPortableErrorOutput || PetscGlobalRank == 0)) {
183     static int cnt = 1;
184 
185     if (p == PETSC_ERROR_INITIAL) {
186       PetscErrorPrintfHilight();
187       ierr = (*PetscErrorPrintf)("--------------------- Error Message --------------------------------------------------------------\n");
188       PetscErrorPrintfNormal();
189       if (cnt > 1) {
190         ierr = (*PetscErrorPrintf)("  It appears a new error in the code was triggered after a previous error, possibly because:\n");
191         ierr = (*PetscErrorPrintf)("  -  The first error was not properly handled via (for example) the use of\n");
192         ierr = (*PetscErrorPrintf)("     PetscCall(TheFunctionThatErrors()); or\n");
193         ierr = (*PetscErrorPrintf)("  -  The second error was triggered while handling the first error.\n");
194         ierr = (*PetscErrorPrintf)("  Above is the traceback for the previous unhandled error, below the traceback for the next error\n");
195         ierr = (*PetscErrorPrintf)("  ALL ERRORS in the PETSc libraries are fatal, you should add the appropriate error checking to the code\n");
196         cnt  = 1;
197       }
198     }
199     if (cnt == 1) {
200       if (n == PETSC_ERR_MEM || n == PETSC_ERR_MEM_LEAK) ierr = PetscErrorMemoryMessage(n);
201       else {
202         const char *text;
203         ierr = PetscErrorMessage(n, &text, NULL);
204         if (text) ierr = (*PetscErrorPrintf)("%s\n", text);
205       }
206       if (mess) ierr = (*PetscErrorPrintf)("%s\n", mess);
207       ierr = PetscOptionsLeftError();
208       ierr = (*PetscErrorPrintf)("See https://petsc.org/release/faq/ for trouble shooting.\n");
209       if (!PetscCIEnabledPortableErrorOutput) {
210         ierr = (*PetscErrorPrintf)("%s\n", version);
211         if (PetscErrorPrintfInitializeCalled) ierr = (*PetscErrorPrintf)("%s on a %s named %s by %s %s\n", pname, arch, hostname, username, date);
212         ierr = (*PetscErrorPrintf)("Configure options %s\n", petscconfigureoptions);
213       }
214     }
215     /* print line of stack trace */
216     if (fun) ierr = (*PetscErrorPrintf)("#%d %s() at %s:%d\n", cnt++, fun, PetscCIFilename(file), PetscCILinenumber(line));
217     else if (file) ierr = (*PetscErrorPrintf)("#%d %s:%d\n", cnt++, PetscCIFilename(file), PetscCILinenumber(line));
218     if (fun) {
219       PetscBool ismain = PETSC_FALSE;
220 
221       ierr = PetscStrncmp(fun, "main", 4, &ismain);
222       if (ismain) {
223         if ((n <= PETSC_ERR_MIN_VALUE) || (n >= PETSC_ERR_MAX_VALUE)) ierr = (*PetscErrorPrintf)("Reached the main program with an out-of-range error code %d. This should never happen\n", n);
224         ierr = PetscOptionsViewError();
225         PetscErrorPrintfHilight();
226         ierr = (*PetscErrorPrintf)("----------------End of Error Message -------send entire error message to petsc-maint@mcs.anl.gov----------\n");
227         PetscErrorPrintfNormal();
228       }
229     }
230   } else {
231     /* do not print error messages since process 0 will print them, sleep before aborting so will not accidentally kill process 0*/
232     ierr = PetscSleep(10.0);
233     exit(0);
234   }
235   (void)ierr;
236   return n;
237 }
238