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