1481bde2ee6efba78ff33e4d9a8851e5fc02c954
[alexxy/gromacs.git] / src / gromacs / gmxlib / gmx_fatal.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #include <ctype.h>
42 #include <errno.h>
43 #include <stdarg.h>
44 #include <string.h>
45
46 #include "main.h"
47 #include "network.h"
48 #include "gmx_fatal.h"
49 #include "copyrite.h"
50 #include "macros.h"
51 #include "string2.h"
52 #include "smalloc.h"
53
54 #include "gromacs/fileio/futil.h"
55 #include "gromacs/fileio/gmxfio.h"
56 #include "gromacs/utility/gmxmpi.h"
57
58 #include "gromacs/legacyheaders/thread_mpi/threads.h"
59
60 static gmx_bool            bDebug         = FALSE;
61 static char               *fatal_tmp_file = NULL;
62 static FILE               *log_file       = NULL;
63
64 static tMPI_Thread_mutex_t debug_mutex     = TMPI_THREAD_MUTEX_INITIALIZER;
65 static tMPI_Thread_mutex_t where_mutex     = TMPI_THREAD_MUTEX_INITIALIZER;
66 static tMPI_Thread_mutex_t fatal_tmp_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
67
68
69 gmx_bool bDebugMode(void)
70 {
71     gmx_bool ret;
72 #if 0
73     tMPI_Thread_mutex_lock(&debug_mutex);
74 #endif
75     ret = bDebug;
76 #if 0
77     tMPI_Thread_mutex_unlock(&debug_mutex);
78 #endif
79     return bDebug;
80 }
81
82 void gmx_fatal_set_log_file(FILE *fp)
83 {
84     log_file = fp;
85 }
86
87 void _where(const char *file, int line)
88 {
89     static gmx_bool bFirst = TRUE;
90     static int      nskip  = -1;
91     static int      nwhere =  0;
92     FILE           *fp;
93     char           *temp;
94
95     if (bFirst)
96     {
97         tMPI_Thread_mutex_lock(&where_mutex);
98         if (bFirst) /* we repeat the check in the locked section because things
99                        might have changed */
100         {
101             if ((temp = getenv("WHERE")) != NULL)
102             {
103                 nskip = strtol(temp, NULL, 10);
104             }
105             bFirst = FALSE;
106         }
107         tMPI_Thread_mutex_unlock(&where_mutex);
108     }
109
110     if (nskip >= 0)
111     {
112         /* Skip the first n occasions, this allows to see where it goes wrong */
113         if (nwhere >= nskip)
114         {
115             if (log_file)
116             {
117                 fp = log_file;
118             }
119             else
120             {
121                 fp = stderr;
122             }
123             fprintf(fp, "WHERE %d, file %s - line %d\n", nwhere, file, line);
124         }
125         nwhere++;
126     }
127 }
128
129 static int fatal_errno = 0;
130
131 static void quit_gmx(const char *msg)
132 {
133     tMPI_Thread_mutex_lock(&debug_mutex);
134     if (fatal_errno == 0)
135     {
136         if (log_file)
137         {
138             fprintf(log_file, "%s\n", msg);
139         }
140         fprintf(stderr, "%s\n", msg);
141         /* we set it to no-zero because if this function is called, something
142            has gone wrong */
143         fatal_errno = 255;
144     }
145     else
146     {
147         if (fatal_errno != -1)
148         {
149             errno = fatal_errno;
150         }
151         perror(msg);
152     }
153
154 #ifdef GMX_LIB_MPI
155     if (gmx_mpi_initialized())
156     {
157         int  nnodes;
158         int  noderank;
159
160         nnodes   = gmx_node_num();
161         noderank = gmx_node_rank();
162
163         if (nnodes > 1)
164         {
165             fprintf(stderr, "Error on node %d, will try to stop all the nodes\n",
166                     noderank);
167         }
168         gmx_abort(noderank, nnodes, -1);
169     }
170 #endif
171
172     if (debug)
173     {
174         fflush(debug);
175     }
176     if (bDebugMode())
177     {
178         fprintf(stderr, "dump core (y/n):");
179         fflush(stderr);
180         if (toupper(getc(stdin)) != 'N')
181         {
182             (void) abort();
183         }
184     }
185
186     exit(fatal_errno);
187     tMPI_Thread_mutex_unlock(&debug_mutex);
188 }
189
190 /* The function below should be identical to quit_gmx,
191  * except that is does not actually quit and call gmx_abort.
192  */
193 static void quit_gmx_noquit(const char *msg)
194 {
195     tMPI_Thread_mutex_lock(&debug_mutex);
196     if (!fatal_errno)
197     {
198         if (log_file)
199         {
200             fprintf(log_file, "%s\n", msg);
201         }
202         fprintf(stderr, "%s\n", msg);
203         /* we set it to no-zero because if this function is called, something
204            has gone wrong */
205         fatal_errno = 255;
206     }
207     else
208     {
209         if (fatal_errno != -1)
210         {
211             errno = fatal_errno;
212         }
213         perror(msg);
214     }
215
216 #ifndef GMX_LIB_MPI
217     if (debug)
218     {
219         fflush(debug);
220     }
221     if (bDebugMode())
222     {
223         fprintf(stderr, "dump core (y/n):");
224         fflush(stderr);
225         if (toupper(getc(stdin)) != 'N')
226         {
227             (void) abort();
228         }
229     }
230 #endif
231
232     tMPI_Thread_mutex_unlock(&debug_mutex);
233 }
234
235 void _set_fatal_tmp_file(const char *fn, const char *file, int line)
236 {
237     tMPI_Thread_mutex_lock(&fatal_tmp_mutex);
238     if (fatal_tmp_file == NULL)
239     {
240         fatal_tmp_file = strdup(fn);
241     }
242     else
243     {
244         fprintf(stderr, "BUGWARNING: fatal_tmp_file already set at %s:%d",
245                 file, line);
246     }
247     tMPI_Thread_mutex_unlock(&fatal_tmp_mutex);
248 }
249
250 void _unset_fatal_tmp_file(const char *fn, const char *file, int line)
251 {
252     tMPI_Thread_mutex_lock(&fatal_tmp_mutex);
253     if (strcmp(fn, fatal_tmp_file) == 0)
254     {
255         sfree(fatal_tmp_file);
256         fatal_tmp_file = NULL;
257     }
258     else
259     {
260         fprintf(stderr, "BUGWARNING: file %s not set as fatal_tmp_file at %s:%d",
261                 fn, file, line);
262     }
263     tMPI_Thread_mutex_unlock(&fatal_tmp_mutex);
264 }
265
266 static void clean_fatal_tmp_file()
267 {
268     tMPI_Thread_mutex_lock(&fatal_tmp_mutex);
269     if (fatal_tmp_file)
270     {
271         fprintf(stderr, "Cleaning up temporary file %s\n", fatal_tmp_file);
272         remove(fatal_tmp_file);
273         sfree(fatal_tmp_file);
274         fatal_tmp_file = NULL;
275     }
276     tMPI_Thread_mutex_unlock(&fatal_tmp_mutex);
277 }
278
279 void gmx_fatal(int f_errno, const char *file, int line, const char *fmt, ...)
280 {
281     va_list ap;
282     char    msg[STRLEN];
283
284     clean_fatal_tmp_file();
285
286     va_start(ap, fmt);
287     vsprintf(msg, fmt, ap);
288     va_end(ap);
289
290     tMPI_Thread_mutex_lock(&debug_mutex);
291     fatal_errno = f_errno;
292     tMPI_Thread_mutex_unlock(&debug_mutex);
293
294     _gmx_error("fatal", msg, file, line);
295 }
296
297 void gmx_fatal_collective(int f_errno, const char *file, int line,
298                           const t_commrec *cr, gmx_domdec_t *dd,
299                           const char *fmt, ...)
300 {
301     gmx_bool    bFinalize;
302     va_list     ap;
303     char        msg[STRLEN];
304 #ifdef GMX_MPI
305     int         result;
306 #endif
307
308     bFinalize = TRUE;
309
310 #ifdef GMX_MPI
311     /* Check if we are calling on all processes in MPI_COMM_WORLD */
312     if (cr != NULL)
313     {
314         MPI_Comm_compare(cr->mpi_comm_mysim, MPI_COMM_WORLD, &result);
315     }
316     else
317     {
318         MPI_Comm_compare(dd->mpi_comm_all, MPI_COMM_WORLD, &result);
319     }
320     /* Any result except MPI_UNEQUAL allows us to call MPI_Finalize */
321     bFinalize = (result != MPI_UNEQUAL);
322 #endif
323
324     if ((cr != NULL && MASTER(cr)  ) ||
325         (dd != NULL && DDMASTER(dd)))
326     {
327         clean_fatal_tmp_file();
328
329         va_start(ap, fmt);
330         vsprintf(msg, fmt, ap);
331         va_end(ap);
332
333         tMPI_Thread_mutex_lock(&debug_mutex);
334         fatal_errno = f_errno;
335         tMPI_Thread_mutex_unlock(&debug_mutex);
336
337         if (bFinalize)
338         {
339             /* Use an error handler that does not quit */
340             set_gmx_error_handler(quit_gmx_noquit);
341         }
342
343         _gmx_error("fatal", msg, file, line);
344     }
345
346 #ifdef GMX_MPI
347     if (bFinalize)
348     {
349         /* Broadcast the fatal error number possibly modified
350          * on the master process, in case the user would like
351          * to use the return status on a non-master process.
352          * The master process in cr and dd always has global rank 0.
353          */
354         MPI_Bcast(&fatal_errno, sizeof(fatal_errno), MPI_BYTE,
355                   0, MPI_COMM_WORLD);
356
357         /* Finalize nicely instead of aborting */
358         MPI_Finalize();
359     }
360     else
361     {
362         /* Let all other processes wait till the master has printed
363          * the error message and issued MPI_Abort.
364          */
365         MPI_Barrier(MPI_COMM_WORLD);
366     }
367 #endif
368
369     exit(fatal_errno);
370 }
371
372 void _invalid_case(const char *fn, int line)
373 {
374     gmx_fatal(FARGS, "Invalid case in switch statement, file %s, line %d",
375               fn, line);
376 }
377
378 void _unexpected_eof(const char *fn, int line, const char *srcfn, int srcline)
379 {
380     gmx_fatal(FARGS, "Unexpected end of file in file %s at line %d\n"
381               "(Source file %s, line %d)", fn, line, srcfn, srcline);
382 }
383
384 /*
385  * These files are global variables in the gromacs preprocessor
386  * Every routine in a file that includes gmx_fatal.h can write to these
387  * debug channels. Depending on the debuglevel used
388  * 0 to 3 of these filed are redirected to /dev/null
389  *
390  */
391 FILE    *debug           = NULL;
392 gmx_bool gmx_debug_at    = FALSE;
393
394 void init_debug(const int dbglevel, const char *dbgfile)
395 {
396     tMPI_Thread_mutex_lock(&debug_mutex);
397     if (!bDebug) /* another thread hasn't already run this*/
398     {
399         no_buffers();
400         debug  = gmx_fio_fopen(dbgfile, "w+");
401         bDebug = TRUE;
402         if (dbglevel >= 2)
403         {
404             gmx_debug_at = TRUE;
405         }
406     }
407     tMPI_Thread_mutex_unlock(&debug_mutex);
408 }
409
410 #if (defined __sgi && defined USE_SGI_FPE)
411 static void user_routine(unsigned us[5], int ii[2])
412 {
413     fprintf(stderr, "User routine us=(%u,%u,%u,%u,%u) ii=(%d,%d)\n",
414             us[0], us[1], us[2], us[3], us[4], ii[0], ii[1]);
415     fprintf(stderr, "Exception encountered! Dumping core\n");
416     abort();
417 }
418
419 static void abort_routine(unsigned int **ii)
420 {
421     fprintf(stderr, "Abort routine\n");
422     abort();
423 }
424
425 static void handle_signals(int n)
426 {
427     fprintf(stderr, "Handle signals: n = %d\n", n);
428     fprintf(stderr, "Dumping core\n");
429     abort();
430 }
431
432 void doexceptions(void)
433 {
434 #include <sigfpe.h>
435 #include <signal.h>
436     int hs[] = { SIGILL, SIGFPE, SIGTRAP, SIGEMT, SIGSYS };
437
438     int onoff, en_mask, abort_action, i;
439
440     tMPI_Thread_mutex_lock(&debug_mutex);
441     onoff   = _DEBUG;
442     en_mask = _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO |
443         _EN_INVALID | _EN_INT_OVERFL;
444     abort_action = _ABORT_ON_ERROR;
445     handle_sigfpes(onoff, en_mask, user_routine, abort_action, abort_routine);
446
447     for (i = 0; (i < asize(hs)); i++)
448     {
449         signal(hs[i], handle_signals);
450     }
451     tMPI_Thread_mutex_unlock(&debug_mutex);
452 }
453 #endif /* __sgi and FPE */
454
455 static const char *gmxuser = "Please report this to the mailing list (gmx-users@gromacs.org)";
456
457 static void        (*gmx_error_handler)(const char *msg) = quit_gmx;
458
459 void set_gmx_error_handler(void (*func)(const char *msg))
460 {
461     tMPI_Thread_mutex_lock(&debug_mutex);
462     gmx_error_handler = func;
463     tMPI_Thread_mutex_unlock(&debug_mutex);
464 }
465
466 char *gmx_strerror(const char *key)
467 {
468     typedef struct {
469         const char *key, *msg;
470     } error_msg_t;
471     error_msg_t msg[] = {
472         { "bug",    "Possible bug" },
473         { "call",   "Routine should not have been called" },
474         { "comm",   "Communication (parallel processing) problem" },
475         { "fatal",  "Fatal error" },
476         { "cmd",    "Invalid command line argument" },
477         { "file",   "File input/output error" },
478         { "impl",   "Implementation restriction" },
479         { "incons", "Software inconsistency error" },
480         { "input",  "Input error or input inconsistency" },
481         { "mem",    "Memory allocation/freeing error" },
482         { "open",   "Can not open file" },
483         { "range",  "Range checking error" }
484     };
485 #define NMSG asize(msg)
486     char        buf[1024];
487     size_t      i;
488
489     if (key == NULL)
490     {
491         return strdup("Empty message");
492     }
493     else
494     {
495         for (i = 0; (i < NMSG); i++)
496         {
497             if (strcmp(key, msg[i].key) == 0)
498             {
499                 break;
500             }
501         }
502         if (i == NMSG)
503         {
504             sprintf(buf, "No error message associated with key %s\n%s", key, gmxuser);
505             return strdup(buf);
506         }
507         else
508         {
509             return strdup(msg[i].msg);
510         }
511     }
512 }
513
514
515 void _gmx_error(const char *key, const char *msg, const char *file, int line)
516 {
517     char        buf[10240], errerrbuf[1024];
518     const char *llines = "-------------------------------------------------------";
519     char       *strerr;
520
521     /* protect the audience from suggestive discussions */
522
523     if (msg == NULL)
524     {
525         sprintf(errerrbuf, "Empty fatal_error message. %s", gmxuser);
526     }
527
528     strerr = gmx_strerror(key);
529     sprintf(buf, "\n%s\nProgram %s, %s\n"
530             "Source code file: %s, line: %d\n\n"
531             "%s:\n%s\nFor more information and tips for troubleshooting, please check the GROMACS\n"
532             "website at http://www.gromacs.org/Documentation/Errors\n%s\n",
533             llines, ShortProgram(), GromacsVersion(), file, line,
534             strerr, msg ? msg : errerrbuf, llines);
535     free(strerr);
536
537     gmx_error_handler(buf);
538 }
539
540 void _range_check(int n, int n_min, int n_max, const char *warn_str,
541                   const char *var, const char *file, int line)
542 {
543     char buf[1024];
544
545     if ((n < n_min) || (n >= n_max))
546     {
547         if (warn_str != NULL)
548         {
549             strcpy(buf, warn_str);
550             strcat(buf, "\n");
551         }
552         else
553         {
554             buf[0] = '\0';
555         }
556
557         sprintf(buf+strlen(buf), "Variable %s has value %d. It should have been "
558                 "within [ %d .. %d ]\n", var, n, n_min, n_max);
559
560         _gmx_error("range", buf, file, line);
561     }
562 }
563
564 void gmx_warning(const char *fmt, ...)
565 {
566     va_list ap;
567     char    msg[STRLEN];
568
569     va_start(ap, fmt);
570     vsprintf(msg, fmt, ap);
571     va_end(ap);
572
573     fprintf(stderr, "\nWARNING: %s\n\n", msg);
574 }