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