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