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