2b82bdc7dc58dcab3dcfbf8bb806a75dae756b52
[alexxy/gromacs.git] / src / gromacs / gmxlib / gmx_fatal.c
1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
2  *
3  *
4  *                This source code is part of
5  *
6  *                 G   R   O   M   A   C   S
7  *
8  *          GROningen MAchine for Chemical Simulations
9  *
10  *                        VERSION 3.2.0
11  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13  * Copyright (c) 2001-2004, The GROMACS development team,
14  * check out http://www.gromacs.org for more information.
15
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  *
21  * If you want to redistribute modifications, please consider that
22  * scientific software is very special. Version control is crucial -
23  * bugs must be traceable. We will be happy to consider code for
24  * inclusion in the official distribution, but derived work must not
25  * be called official GROMACS. Details are found in the README & COPYING
26  * files - if they are missing, get the official version at www.gromacs.org.
27  *
28  * To help us fund GROMACS development, we humbly ask that you cite
29  * the papers on the package - you can find them in the top README file.
30  *
31  * For more info, check our website at http://www.gromacs.org
32  *
33  * And Hey:
34  * GROningen Mixture of Alchemy and Childrens' Stories
35  */
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include <sysstuff.h>
41 #include <ctype.h>
42 #include <errno.h>
43 #include <stdarg.h>
44 #include <string.h>
45 #include "gromacs/fileio/futil.h"
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 #include "gromacs/fileio/gmxfio.h"
54
55 #include "gromacs/utility/gmxmpi.h"
56
57 #include "gromacs/legacyheaders/thread_mpi/threads.h"
58
59 static gmx_bool bDebug         = FALSE;
60 static char    *fatal_tmp_file = NULL;
61 static FILE    *log_file       = NULL;
62
63 static tMPI_Thread_mutex_t debug_mutex     = TMPI_THREAD_MUTEX_INITIALIZER;
64 static tMPI_Thread_mutex_t where_mutex     = TMPI_THREAD_MUTEX_INITIALIZER;
65 static tMPI_Thread_mutex_t fatal_tmp_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
66
67
68 gmx_bool bDebugMode(void)
69 {
70     gmx_bool ret;
71 #if 0
72     tMPI_Thread_mutex_lock(&debug_mutex);
73 #endif
74     ret = bDebug;
75 #if 0
76     tMPI_Thread_mutex_unlock(&debug_mutex);
77 #endif
78     return bDebug;
79 }
80
81 void gmx_fatal_set_log_file(FILE *fp)
82 {
83     log_file = fp;
84 }
85
86 void _where(const char *file, int line)
87 {
88     static gmx_bool bFirst = TRUE;
89     static int      nskip  = -1;
90     static int      nwhere =  0;
91     FILE           *fp;
92     char           *temp;
93
94     if (bFirst)
95     {
96         tMPI_Thread_mutex_lock(&where_mutex);
97         if (bFirst) /* we repeat the check in the locked section because things
98                        might have changed */
99         {
100             if ((temp = getenv("WHERE")) != NULL)
101             {
102                 nskip = strtol(temp, NULL, 10);
103             }
104             bFirst = FALSE;
105         }
106         tMPI_Thread_mutex_unlock(&where_mutex);
107     }
108
109     if (nskip >= 0)
110     {
111         /* Skip the first n occasions, this allows to see where it goes wrong */
112         if (nwhere >= nskip)
113         {
114             if (log_file)
115             {
116                 fp = log_file;
117             }
118             else
119             {
120                 fp = stderr;
121             }
122             fprintf(fp, "WHERE %d, file %s - line %d\n", nwhere, file, line);
123         }
124         nwhere++;
125     }
126 }
127
128 static void bputc(char *msg, int *len, char ch)
129 {
130     msg[(*len)++] = ch;
131 }
132
133 static void bputs(char *msg, int *len, const char *s, int fld)
134 {
135     for (fld -= (int)strlen(s); fld > 0; fld--)
136     {
137         bputc(msg, len, ' ');
138     }
139     while (*s)
140     {
141         bputc(msg, len, *(s++));
142     }
143 }
144
145 static void bputd(char *msg, int *len, int d)
146 {
147     if (d < 10)
148     {
149         bputc(msg, len, d+'0');
150     }
151     else
152     {
153         bputc(msg, len, d-10+'a');
154     }
155 }
156
157 static void bputi(char *msg, int *len, int val, int radix, int fld, gmx_bool bNeg)
158 {
159     int fmax = 0;
160
161     if (bNeg)
162     {
163         fmax = 1;
164     }
165
166     if (val < radix)
167     {
168         for (fld--; fld > fmax; fld--)
169         {
170             bputc(msg, len, ' ');
171         }
172         if (bNeg)
173         {
174             bputc(msg, len, '-');
175         }
176         bputd(msg, len, val);
177     }
178     else
179     {
180         if (bNeg)
181         {
182             bputc(msg, len, '-');
183         }
184         bputi(msg, len, val/radix, radix, fld-1, FALSE);
185         bputd(msg, len, val%radix);
186     }
187 }
188
189 static int getfld(const char **p)
190 {
191     int fld;
192
193     fld = 0;
194     while (isdigit(**p))
195     {
196         fld = (fld*10)+((*((*p)++))-'0');
197     }
198     return fld;
199 }
200
201 /*static void _halt(char *file,int line,char *reason)
202    {
203    fprintf(stderr,"\nHALT in file %s line %d because:\n\t%s\n",
204       file,line,reason);
205    exit(1);
206    }
207  */
208
209 static int fatal_errno = 0;
210
211 static void quit_gmx(const char *msg)
212 {
213     tMPI_Thread_mutex_lock(&debug_mutex);
214     if (fatal_errno == 0)
215     {
216         if (log_file)
217         {
218             fprintf(log_file, "%s\n", msg);
219         }
220         fprintf(stderr, "%s\n", msg);
221         /* we set it to no-zero because if this function is called, something
222            has gone wrong */
223         fatal_errno = 255;
224     }
225     else
226     {
227         if (fatal_errno != -1)
228         {
229             errno = fatal_errno;
230         }
231         perror(msg);
232     }
233
234 #ifdef GMX_LIB_MPI
235     if (gmx_mpi_initialized())
236     {
237         int  nnodes;
238         int  noderank;
239
240         nnodes   = gmx_node_num();
241         noderank = gmx_node_rank();
242
243         if (nnodes > 1)
244         {
245             fprintf(stderr, "Error on node %d, will try to stop all the nodes\n",
246                     noderank);
247         }
248         gmx_abort(noderank, nnodes, -1);
249     }
250 #endif
251
252     if (debug)
253     {
254         fflush(debug);
255     }
256     if (bDebugMode())
257     {
258         fprintf(stderr, "dump core (y/n):");
259         fflush(stderr);
260         if (toupper(getc(stdin)) != 'N')
261         {
262             (void) abort();
263         }
264     }
265
266     exit(fatal_errno);
267     tMPI_Thread_mutex_unlock(&debug_mutex);
268 }
269
270 /* The function below should be identical to quit_gmx,
271  * except that is does not actually quit and call gmx_abort.
272  */
273 static void quit_gmx_noquit(const char *msg)
274 {
275     tMPI_Thread_mutex_lock(&debug_mutex);
276     if (!fatal_errno)
277     {
278         if (log_file)
279         {
280             fprintf(log_file, "%s\n", msg);
281         }
282         fprintf(stderr, "%s\n", msg);
283         /* we set it to no-zero because if this function is called, something
284            has gone wrong */
285         fatal_errno = 255;
286     }
287     else
288     {
289         if (fatal_errno != -1)
290         {
291             errno = fatal_errno;
292         }
293         perror(msg);
294     }
295
296 #ifndef GMX_LIB_MPI
297     if (debug)
298     {
299         fflush(debug);
300     }
301     if (bDebugMode())
302     {
303         fprintf(stderr, "dump core (y/n):");
304         fflush(stderr);
305         if (toupper(getc(stdin)) != 'N')
306         {
307             (void) abort();
308         }
309     }
310 #endif
311
312     tMPI_Thread_mutex_unlock(&debug_mutex);
313 }
314
315 void _set_fatal_tmp_file(const char *fn, const char *file, int line)
316 {
317     tMPI_Thread_mutex_lock(&fatal_tmp_mutex);
318     if (fatal_tmp_file == NULL)
319     {
320         fatal_tmp_file = strdup(fn);
321     }
322     else
323     {
324         fprintf(stderr, "BUGWARNING: fatal_tmp_file already set at %s:%d",
325                 file, line);
326     }
327     tMPI_Thread_mutex_unlock(&fatal_tmp_mutex);
328 }
329
330 void _unset_fatal_tmp_file(const char *fn, const char *file, int line)
331 {
332     tMPI_Thread_mutex_lock(&fatal_tmp_mutex);
333     if (strcmp(fn, fatal_tmp_file) == 0)
334     {
335         sfree(fatal_tmp_file);
336         fatal_tmp_file = NULL;
337     }
338     else
339     {
340         fprintf(stderr, "BUGWARNING: file %s not set as fatal_tmp_file at %s:%d",
341                 fn, file, line);
342     }
343     tMPI_Thread_mutex_unlock(&fatal_tmp_mutex);
344 }
345
346 static void clean_fatal_tmp_file()
347 {
348     tMPI_Thread_mutex_lock(&fatal_tmp_mutex);
349     if (fatal_tmp_file)
350     {
351         fprintf(stderr, "Cleaning up temporary file %s\n", fatal_tmp_file);
352         remove(fatal_tmp_file);
353         sfree(fatal_tmp_file);
354         fatal_tmp_file = NULL;
355     }
356     tMPI_Thread_mutex_unlock(&fatal_tmp_mutex);
357 }
358
359 static void parse_printf_args(const char *fmt, va_list *ap, char *msg)
360 {
361     int     len;
362     const char *p;
363     char    cval, *sval;
364     char    ibuf[64], ifmt[64];
365     int     index, ival, fld;
366     double  dval;
367
368     len = 0;
369     for (p = fmt; *p; p++)
370     {
371         if (*p != '%')
372         {
373             bputc(msg, &len, *p);
374         }
375         else
376         {
377             p++;
378             fld = getfld(&p);
379             switch (*p)
380             {
381                 case 'x':
382                     ival = va_arg(*ap, int);
383                     sprintf(ifmt, "0x%%%dx", fld);
384                     sprintf(ibuf, ifmt, (unsigned int)ival);
385                     for (index = 0; (index < (int)strlen(ibuf)); index++)
386                     {
387                         bputc(msg, &len, ibuf[index]);
388                     }
389                     break;
390                 case 'd':
391                     ival = va_arg(*ap, int);
392                     sprintf(ifmt, "%%%dd", fld);
393                     sprintf(ibuf, ifmt, ival);
394                     for (index = 0; (index < (int)strlen(ibuf)); index++)
395                     {
396                         bputc(msg, &len, ibuf[index]);
397                     }
398                     break;
399                 case 'u':
400                     ival = va_arg(*ap, unsigned);
401                     sprintf(ifmt, "%%%du", fld);
402                     sprintf(ibuf, ifmt, ival);
403                     for (index = 0; (index < (int)strlen(ibuf)); index++)
404                     {
405                         bputc(msg, &len, ibuf[index]);
406                     }
407                     break;
408                 case 'f':
409                     dval = va_arg(*ap, double);
410                     sprintf(ifmt, "%%%df", fld);
411                     sprintf(ibuf, ifmt, dval);
412                     for (index = 0; (index < (int)strlen(ibuf)); index++)
413                     {
414                         bputc(msg, &len, ibuf[index]);
415                     }
416                     break;
417                 case 'g':
418                     dval = va_arg(*ap, double);
419                     sprintf(ifmt, "%%%dg", fld);
420                     sprintf(ibuf, ifmt, dval);
421                     for (index = 0; (index < (int)strlen(ibuf)); index++)
422                     {
423                         bputc(msg, &len, ibuf[index]);
424                     }
425                     break;
426                 case 'c':
427                     cval = (char) va_arg(*ap, int); /* char is promoted to int */
428                     bputc(msg, &len, cval);
429                     break;
430                 case 's':
431                     sval = va_arg(*ap, char *);
432                     if (sval == NULL)
433                     {
434                         sval = strdup("(null)");
435                     }
436                     bputs(msg, &len, sval, fld);
437                     break;
438                 case '%':
439                     bputc(msg, &len, *p);
440                     break;
441                 default:
442                     break;
443             }
444         }
445     }
446
447     bputc(msg, &len, '\0');
448 }
449
450 void gmx_fatal(int f_errno, const char *file, int line, const char *fmt, ...)
451 {
452     va_list ap;
453     char    msg[STRLEN];
454
455     va_start(ap, fmt);
456
457     clean_fatal_tmp_file();
458
459     parse_printf_args(fmt, &ap, msg);
460
461     va_end(ap);
462
463     tMPI_Thread_mutex_lock(&debug_mutex);
464     fatal_errno = f_errno;
465     tMPI_Thread_mutex_unlock(&debug_mutex);
466
467     _gmx_error("fatal", msg, file, line);
468 }
469
470 void gmx_fatal_collective(int f_errno, const char *file, int line,
471                           const t_commrec *cr, gmx_domdec_t *dd,
472                           const char *fmt, ...)
473 {
474     gmx_bool    bFinalize;
475     va_list ap;
476     char    msg[STRLEN];
477 #ifdef GMX_MPI
478     int     result;
479 #endif
480
481     bFinalize = TRUE;
482
483 #ifdef GMX_MPI
484     /* Check if we are calling on all processes in MPI_COMM_WORLD */
485     if (cr != NULL)
486     {
487         MPI_Comm_compare(cr->mpi_comm_mysim, MPI_COMM_WORLD, &result);
488     }
489     else
490     {
491         MPI_Comm_compare(dd->mpi_comm_all, MPI_COMM_WORLD, &result);
492     }
493     /* Any result except MPI_UNEQUAL allows us to call MPI_Finalize */
494     bFinalize = (result != MPI_UNEQUAL);
495 #endif
496
497     if ((cr != NULL && MASTER(cr)  ) ||
498         (dd != NULL && DDMASTER(dd)))
499     {
500         va_start(ap, fmt);
501
502         clean_fatal_tmp_file();
503
504         parse_printf_args(fmt, &ap, msg);
505
506         va_end(ap);
507
508         tMPI_Thread_mutex_lock(&debug_mutex);
509         fatal_errno = f_errno;
510         tMPI_Thread_mutex_unlock(&debug_mutex);
511
512         if (bFinalize)
513         {
514             /* Use an error handler that does not quit */
515             set_gmx_error_handler(quit_gmx_noquit);
516         }
517
518         _gmx_error("fatal", msg, file, line);
519     }
520
521 #ifdef GMX_MPI
522     if (bFinalize)
523     {
524         /* Broadcast the fatal error number possibly modified
525          * on the master process, in case the user would like
526          * to use the return status on a non-master process.
527          * The master process in cr and dd always has global rank 0.
528          */
529         MPI_Bcast(&fatal_errno, sizeof(fatal_errno), MPI_BYTE,
530                   0, MPI_COMM_WORLD);
531
532         /* Finalize nicely instead of aborting */
533         MPI_Finalize();
534     }
535     else
536     {
537         /* Let all other processes wait till the master has printed
538          * the error message and issued MPI_Abort.
539          */
540         MPI_Barrier(MPI_COMM_WORLD);
541     }
542 #endif
543
544     exit(fatal_errno);
545 }
546
547 void _invalid_case(const char *fn, int line)
548 {
549     gmx_fatal(FARGS, "Invalid case in switch statement, file %s, line %d",
550               fn, line);
551 }
552
553 void _unexpected_eof(const char *fn, int line, const char *srcfn, int srcline)
554 {
555     gmx_fatal(FARGS, "Unexpected end of file in file %s at line %d\n"
556               "(Source file %s, line %d)", fn, line, srcfn, srcline);
557 }
558
559 /*
560  * These files are global variables in the gromacs preprocessor
561  * Every routine in a file that includes gmx_fatal.h can write to these
562  * debug channels. Depending on the debuglevel used
563  * 0 to 3 of these filed are redirected to /dev/null
564  *
565  */
566 FILE *debug           = NULL;
567 gmx_bool gmx_debug_at = FALSE;
568
569 void init_debug(const int dbglevel, const char *dbgfile)
570 {
571     tMPI_Thread_mutex_lock(&debug_mutex);
572     if (!bDebug) /* another thread hasn't already run this*/
573     {
574         no_buffers();
575         debug  = gmx_fio_fopen(dbgfile, "w+");
576         bDebug = TRUE;
577         if (dbglevel >= 2)
578         {
579             gmx_debug_at = TRUE;
580         }
581     }
582     tMPI_Thread_mutex_unlock(&debug_mutex);
583 }
584
585 #if (defined __sgi && defined USE_SGI_FPE)
586 static void user_routine(unsigned us[5], int ii[2])
587 {
588     fprintf(stderr, "User routine us=(%u,%u,%u,%u,%u) ii=(%d,%d)\n",
589             us[0], us[1], us[2], us[3], us[4], ii[0], ii[1]);
590     fprintf(stderr, "Exception encountered! Dumping core\n");
591     abort();
592 }
593
594 static void abort_routine(unsigned int **ii)
595 {
596     fprintf(stderr, "Abort routine\n");
597     abort();
598 }
599
600 static void handle_signals(int n)
601 {
602     fprintf(stderr, "Handle signals: n = %d\n", n);
603     fprintf(stderr, "Dumping core\n");
604     abort();
605 }
606
607 void doexceptions(void)
608 {
609 #include <sigfpe.h>
610 #include <signal.h>
611     int hs[] = { SIGILL, SIGFPE, SIGTRAP, SIGEMT, SIGSYS };
612
613     int onoff, en_mask, abort_action, i;
614
615     tMPI_Thread_mutex_lock(&debug_mutex);
616     onoff   = _DEBUG;
617     en_mask = _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO |
618         _EN_INVALID | _EN_INT_OVERFL;
619     abort_action = _ABORT_ON_ERROR;
620     handle_sigfpes(onoff, en_mask, user_routine, abort_action, abort_routine);
621
622     for (i = 0; (i < asize(hs)); i++)
623     {
624         signal(hs[i], handle_signals);
625     }
626     tMPI_Thread_mutex_unlock(&debug_mutex);
627 }
628 #endif /* __sgi and FPE */
629
630 static const char *gmxuser = "Please report this to the mailing list (gmx-users@gromacs.org)";
631
632 static void (*gmx_error_handler)(const char *msg) = quit_gmx;
633
634 void set_gmx_error_handler(void (*func)(const char *msg))
635 {
636     tMPI_Thread_mutex_lock(&debug_mutex);
637     gmx_error_handler = func;
638     tMPI_Thread_mutex_unlock(&debug_mutex);
639 }
640
641 char *gmx_strerror(const char *key)
642 {
643     typedef struct {
644         const char *key, *msg;
645     } error_msg_t;
646     error_msg_t msg[] = {
647         { "bug",    "Possible bug" },
648         { "call",   "Routine should not have been called" },
649         { "comm",   "Communication (parallel processing) problem" },
650         { "fatal",  "Fatal error" },
651         { "cmd",    "Invalid command line argument" },
652         { "file",   "File input/output error" },
653         { "impl",   "Implementation restriction" },
654         { "incons", "Software inconsistency error" },
655         { "input",  "Input error or input inconsistency" },
656         { "mem",    "Memory allocation/freeing error" },
657         { "open",   "Can not open file" },
658         { "range",  "Range checking error" }
659     };
660 #define NMSG asize(msg)
661     char buf[1024];
662     size_t i;
663
664     if (key == NULL)
665     {
666         return strdup("Empty message");
667     }
668     else
669     {
670         for (i = 0; (i < NMSG); i++)
671         {
672             if (strcmp(key, msg[i].key) == 0)
673             {
674                 break;
675             }
676         }
677         if (i == NMSG)
678         {
679             sprintf(buf, "No error message associated with key %s\n%s", key, gmxuser);
680             return strdup(buf);
681         }
682         else
683         {
684             return strdup(msg[i].msg);
685         }
686     }
687 }
688
689
690 void _gmx_error(const char *key, const char *msg, const char *file, int line)
691 {
692     char buf[10240], tmpbuf[1024], errerrbuf[1024];
693     int  cqnum;
694     const char *llines = "-------------------------------------------------------";
695     char *strerr;
696
697     /* protect the audience from suggestive discussions */
698
699     if (msg == NULL)
700     {
701         sprintf(errerrbuf, "Empty fatal_error message. %s", gmxuser);
702     }
703
704     cool_quote(tmpbuf, 1023, &cqnum);
705     strerr = gmx_strerror(key);
706     sprintf(buf, "\n%s\nProgram %s, %s\n"
707             "Source code file: %s, line: %d\n\n"
708             "%s:\n%s\nFor more information and tips for troubleshooting, please check the GROMACS\n"
709             "website at http://www.gromacs.org/Documentation/Errors\n%s\n\n%s\n",
710             llines, ShortProgram(), GromacsVersion(), file, line,
711             strerr, msg ? msg : errerrbuf, llines, tmpbuf);
712     free(strerr);
713
714     gmx_error_handler(buf);
715 }
716
717 void _range_check(int n, int n_min, int n_max, const char *warn_str,
718                   const char *var, const char *file, int line)
719 {
720     char buf[1024];
721
722     if ((n < n_min) || (n >= n_max))
723     {
724         if (warn_str != NULL)
725         {
726             strcpy(buf, warn_str);
727             strcat(buf, "\n");
728         }
729         else
730         {
731             buf[0] = '\0';
732         }
733
734         sprintf(buf+strlen(buf), "Variable %s has value %d. It should have been "
735                 "within [ %d .. %d ]\n", var, n, n_min, n_max);
736
737         _gmx_error("range", buf, file, line);
738     }
739 }
740
741 void gmx_warning(const char *fmt, ...)
742 {
743     va_list ap;
744     char msg[STRLEN];
745
746     va_start(ap, fmt);
747
748     parse_printf_args(fmt, &ap, msg);
749
750     va_end(ap);
751
752     fprintf(stderr, "\nWARNING: %s\n\n", msg);
753 }