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