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