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