3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2004, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
33 * GROningen Mixture of Alchemy and Childrens' Stories
48 #include "gmx_fatal.h"
56 #include "thread_mpi.h"
59 static bool bDebug = FALSE;
60 static char *fatal_tmp_file = NULL;
61 static FILE *log_file = NULL;
64 static tMPI_Thread_mutex_t debug_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
71 tMPI_Thread_mutex_lock(&debug_mutex);
75 tMPI_Thread_mutex_unlock(&debug_mutex);
80 void gmx_fatal_set_log_file(FILE *fp)
85 void _where(const char *file,int line)
87 static bool bFirst = TRUE;
88 static int nskip = -1;
89 static int nwhere = 0;
94 tMPI_Thread_mutex_lock(&debug_mutex);
97 if ((temp=getenv("WHERE")) != NULL)
98 nskip = strtol(temp, NULL, 0);
103 /* Skip the first n occasions, this allows to see where it goes wrong */
104 if (nwhere >= nskip) {
109 fprintf(fp,"WHERE %d, file %s - line %d\n",nwhere,file,line);
114 tMPI_Thread_mutex_unlock(&debug_mutex);
118 static void bputc(char *msg,int *len,char ch)
123 static void bputs(char *msg,int *len,const char *s,int fld)
125 for (fld-=(int)strlen(s); fld>0; fld--)
128 bputc(msg,len,*(s++));
131 static void bputd(char *msg,int *len,int d)
133 if (d<10) bputc(msg,len,d+'0'); else bputc(msg,len,d-10+'a');
136 static void bputi(char *msg,int *len,int val,int radix,int fld,bool bNeg)
145 for (fld--; fld>fmax; fld--)
155 bputi(msg,len,val/radix,radix,fld-1,FALSE);
156 bputd(msg,len,val%radix);
160 static int getfld(const char **p)
165 while (isdigit(**p)) fld=(fld*10)+((*((*p)++))-'0');
169 /*static void _halt(char *file,int line,char *reason)
171 fprintf(stderr,"\nHALT in file %s line %d because:\n\t%s\n",
177 static int fatal_errno = 0;
179 static void quit_gmx(const char *msg)
182 tMPI_Thread_mutex_lock(&debug_mutex);
186 fprintf(log_file,"%s\n",msg);
187 fprintf(stderr,"%s\n",msg);
190 if (fatal_errno != -1)
195 if (gmx_parallel_env()) {
199 nnodes = gmx_node_num();
200 noderank = gmx_node_rank();
203 fprintf(stderr,"Error on node %d, will try to stop all the nodes\n",
205 gmx_abort(noderank,nnodes,-1);
210 fprintf(stderr,"dump core (y/n):");
212 if (toupper(getc(stdin))!='N')
219 tMPI_Thread_mutex_unlock(&debug_mutex);
223 void _set_fatal_tmp_file(const char *fn, const char *file, int line)
226 tMPI_Thread_mutex_lock(&debug_mutex);
228 if (fatal_tmp_file == NULL)
229 fatal_tmp_file = strdup(fn);
231 fprintf(stderr,"BUGWARNING: fatal_tmp_file already set at %s:%d",
234 tMPI_Thread_mutex_unlock(&debug_mutex);
238 void _unset_fatal_tmp_file(const char *fn, const char *file, int line)
241 tMPI_Thread_mutex_lock(&debug_mutex);
243 if (strcmp(fn,fatal_tmp_file) == 0) {
244 sfree(fatal_tmp_file);
245 fatal_tmp_file = NULL;
247 fprintf(stderr,"BUGWARNING: file %s not set as fatal_tmp_file at %s:%d",
250 tMPI_Thread_mutex_unlock(&debug_mutex);
254 static void clean_fatal_tmp_file()
257 tMPI_Thread_mutex_lock(&debug_mutex);
259 if (fatal_tmp_file) {
260 fprintf(stderr,"Cleaning up temporary file %s\n",fatal_tmp_file);
261 remove(fatal_tmp_file);
262 sfree(fatal_tmp_file);
263 fatal_tmp_file = NULL;
266 tMPI_Thread_mutex_unlock(&debug_mutex);
270 /* Old function do not use */
271 static void fatal_error(int f_errno,const char *fmt,...)
275 char cval,*sval,msg[STRLEN];
276 char ibuf[64],ifmt[64];
277 int index,ival,fld,len;
279 #ifdef _SPECIAL_VAR_ARG
284 tMPI_Thread_mutex_lock(&debug_mutex);
287 f_errno=va_arg(ap,int);
288 fmt=va_arg(ap,char *);
293 clean_fatal_tmp_file();
296 for (p=fmt; *p; p++) {
305 sprintf(ifmt,"0x%%%dx",fld);
306 sprintf(ibuf,ifmt,(unsigned int)ival);
307 for(index=0; (index<(int)strlen(ibuf)); index++)
308 bputc(msg,&len,ibuf[index]);
312 sprintf(ifmt,"%%%dd",fld);
313 sprintf(ibuf,ifmt,ival);
314 for(index=0; (index<(int)strlen(ibuf)); index++)
315 bputc(msg,&len,ibuf[index]);
318 dval=va_arg(ap,double);
319 sprintf(ifmt,"%%%df",fld);
320 sprintf(ibuf,ifmt,dval);
321 for(index=0; (index<(int)strlen(ibuf)); index++)
322 bputc(msg,&len,ibuf[index]);
325 cval=(char) va_arg(ap,int); /* char is promoted to int */
326 bputc(msg,&len,cval);
329 sval=va_arg(ap,char *);
330 bputs(msg,&len,sval,fld);
338 bputc(msg,&len,'\0');
340 fatal_errno = f_errno;
342 tMPI_Thread_mutex_unlock(&debug_mutex);
344 gmx_error("fatal",msg);
347 void gmx_fatal(int f_errno,const char *file,int line,const char *fmt,...)
351 char cval,*sval,msg[STRLEN];
352 char ibuf[64],ifmt[64];
353 int index,ival,fld,len;
355 #ifdef _SPECIAL_VAR_ARG
360 tMPI_Thread_mutex_lock(&debug_mutex);
363 f_errno = va_arg(ap,int);
364 file = va_arg(ap,char *);
365 line = va_arg(ap,int);
366 fmt = va_arg(ap,char *);
371 clean_fatal_tmp_file();
374 for (p=fmt; *p; p++) {
383 sprintf(ifmt,"0x%%%dx",fld);
384 sprintf(ibuf,ifmt,(unsigned int)ival);
385 for(index=0; (index<(int)strlen(ibuf)); index++)
386 bputc(msg,&len,ibuf[index]);
390 sprintf(ifmt,"%%%dd",fld);
391 sprintf(ibuf,ifmt,ival);
392 for(index=0; (index<(int)strlen(ibuf)); index++)
393 bputc(msg,&len,ibuf[index]);
396 ival=va_arg(ap,unsigned);
397 sprintf(ifmt,"%%%du",fld);
398 sprintf(ibuf,ifmt,ival);
399 for(index=0; (index<(int)strlen(ibuf)); index++)
400 bputc(msg,&len,ibuf[index]);
403 dval=va_arg(ap,double);
404 sprintf(ifmt,"%%%df",fld);
405 sprintf(ibuf,ifmt,dval);
406 for(index=0; (index<(int)strlen(ibuf)); index++)
407 bputc(msg,&len,ibuf[index]);
410 dval=va_arg(ap,double);
411 sprintf(ifmt,"%%%dg",fld);
412 sprintf(ibuf,ifmt,dval);
413 for(index=0; (index<(int)strlen(ibuf)); index++)
414 bputc(msg,&len,ibuf[index]);
417 cval=(char) va_arg(ap,int); /* char is promoted to int */
418 bputc(msg,&len,cval);
421 sval=va_arg(ap,char *);
423 sval = strdup("(null)");
424 bputs(msg,&len,sval,fld);
435 bputc(msg,&len,'\0');
437 fatal_errno = f_errno;
440 tMPI_Thread_mutex_unlock(&debug_mutex);
442 _gmx_error("fatal",msg,file,line);
445 static int nwarn_note = 0;
446 static int nwarn_warn = 0;
447 static int nwarn_error = 0;
448 static int maxwarn = 10;
449 static int lineno = 1;
450 static char filenm[256] = "";
451 char warn_buf[1024] = "";
453 void init_warning(int maxwarning)
456 tMPI_Thread_mutex_lock(&debug_mutex);
458 maxwarn = maxwarning;
463 tMPI_Thread_mutex_unlock(&debug_mutex);
467 void set_warning_line(const char *s,int line)
470 tMPI_Thread_mutex_lock(&debug_mutex);
473 gmx_incons("Calling set_warning_line with NULL pointer");
477 tMPI_Thread_mutex_unlock(&debug_mutex);
481 int get_warning_line()
485 tMPI_Thread_mutex_lock(&debug_mutex);
489 tMPI_Thread_mutex_unlock(&debug_mutex);
494 const char *get_warning_file()
499 static void low_warning(const char *wtype,int n,const char *s)
502 char linenobuf[32], *temp, *temp2;
508 sprintf(linenobuf,"%d",lineno);
510 strcpy(linenobuf,"unknown");
511 snew(temp,strlen(s)+indent+1);
512 for(i=0; i<indent; i++)
516 temp2 = wrap_lines(temp,78-indent,indent,FALSE);
517 if (strlen(filenm) > 0) {
518 fprintf(stderr,"\n%s %d [file %s, line %s]:\n%s\n\n",
519 wtype,n,filenm,linenobuf,temp2);
521 fprintf(stderr,"\n%s %d:\n%s\n\n",wtype,n,temp2);
527 void warning(const char *s)
530 tMPI_Thread_mutex_lock(&debug_mutex);
533 low_warning("WARNING",nwarn_warn,s);
535 tMPI_Thread_mutex_unlock(&debug_mutex);
539 void warning_note(const char *s)
542 tMPI_Thread_mutex_lock(&debug_mutex);
545 low_warning("NOTE",nwarn_note,s);
547 tMPI_Thread_mutex_unlock(&debug_mutex);
551 void warning_error(const char *s)
554 tMPI_Thread_mutex_lock(&debug_mutex);
557 low_warning("ERROR",nwarn_error,s);
559 tMPI_Thread_mutex_unlock(&debug_mutex);
563 static void print_warn_count(const char *type,int n)
566 fprintf(stderr,"\nThere %s %d %s%s\n",
567 (n==1) ? "was" : "were", n, type, (n==1) ? "" : "s");
571 void print_warn_num(bool bFatalError)
574 tMPI_Thread_mutex_lock(&debug_mutex);
576 print_warn_count("note",nwarn_note);
578 print_warn_count("warning",nwarn_warn);
579 if (bFatalError && nwarn_warn > maxwarn) {
580 gmx_fatal(FARGS,"Too many warnings (%d), %s terminated.\n"
581 "If you are sure all warnings are harmless, use the -maxwarn option.",nwarn_warn,Program());
584 tMPI_Thread_mutex_unlock(&debug_mutex);
588 void check_warning_error(int f_errno,const char *file,int line)
591 tMPI_Thread_mutex_lock(&debug_mutex);
593 if (nwarn_error > 0) {
594 print_warn_num(FALSE);
595 gmx_fatal(f_errno,file,line,"There %s %d error%s in input file(s)",
596 (nwarn_error==1) ? "was" : "were",nwarn_error,
597 (nwarn_error==1) ? "" : "s");
600 tMPI_Thread_mutex_unlock(&debug_mutex);
604 void _too_few(const char *fn,int line)
606 sprintf(warn_buf,"Too few parameters on line (source file %s, line %d)",
611 void _invalid_case(const char *fn,int line)
613 gmx_fatal(FARGS,"Invalid case in switch statement, file %s, line %d",
617 void _unexpected_eof(const char *fn,int line,const char *srcfn,int srcline)
619 gmx_fatal(FARGS,"Unexpected end of file in file %s at line %d\n"
620 "(Source file %s, line %d)",fn,line,srcfn,srcline);
624 * These files are global variables in the gromacs preprocessor
625 * Every routine in a file that includes gmx_fatal.h can write to these
626 * debug channels. Depending on the debuglevel used
627 * 0 to 3 of these filed are redirected to /dev/null
631 bool gmx_debug_at=FALSE;
633 void init_debug (const int dbglevel,const char *dbgfile)
636 tMPI_Thread_mutex_lock(&debug_mutex);
638 if (!bDebug) /* another thread hasn't already run this*/
641 debug=gmx_fio_fopen(dbgfile,"w");
647 tMPI_Thread_mutex_unlock(&debug_mutex);
651 #if (defined __sgi && defined USE_SGI_FPE)
652 static void user_routine(unsigned us[5], int ii[2])
654 fprintf(stderr,"User routine us=(%u,%u,%u,%u,%u) ii=(%d,%d)\n",
655 us[0],us[1],us[2],us[3],us[4],ii[0],ii[1]);
656 fprintf(stderr,"Exception encountered! Dumping core\n");
660 static void abort_routine(unsigned int **ii)
662 fprintf(stderr,"Abort routine\n");
666 static void handle_signals(int n)
668 fprintf(stderr,"Handle signals: n = %d\n",n);
669 fprintf(stderr,"Dumping core\n");
673 void doexceptions(void)
677 int hs[] = { SIGILL, SIGFPE, SIGTRAP, SIGEMT, SIGSYS };
679 int onoff,en_mask,abort_action,i;
682 tMPI_Thread_mutex_lock(&debug_mutex);
685 en_mask = _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO |
686 _EN_INVALID | _EN_INT_OVERFL;
687 abort_action = _ABORT_ON_ERROR;
688 handle_sigfpes(onoff,en_mask,user_routine,abort_action,abort_routine);
690 for(i=0; (i<asize(hs)); i++)
691 signal(hs[i],handle_signals);
693 tMPI_Thread_mutex_unlock(&debug_mutex);
696 #endif /* __sgi and FPE */
698 static const char *gmxuser = "Please report this to the mailing list (gmx-users@gromacs.org)";
700 static void (*gmx_error_handler)(const char *msg) = quit_gmx;
702 void set_gmx_error_handler(void (*func)(const char *msg))
705 tMPI_Thread_mutex_lock(&debug_mutex);
707 gmx_error_handler = func;
709 tMPI_Thread_mutex_unlock(&debug_mutex);
713 char *gmx_strerror(const char *key)
716 const char *key,*msg;
718 error_msg_t msg[] = {
719 { "bug", "Possible bug" },
720 { "call", "Routine should not have been called" },
721 { "comm", "Communication (parallel processing) problem" },
722 { "fatal", "Fatal error" },
723 { "cmd", "Invalid command line argument" },
724 { "file", "File input/output error" },
725 { "impl", "Implementation restriction" },
726 { "incons", "Software inconsistency error" },
727 { "input", "Input error or input inconsistency" },
728 { "mem", "Memory allocation/freeing error" },
729 { "open", "Can not open file" },
730 { "range", "Range checking error" }
732 #define NMSG asize(msg)
737 return strdup("Empty message");
739 for(i=0; (i<NMSG); i++)
740 if (strcmp(key,msg[i].key) == 0)
743 sprintf(buf,"No error message associated with key %s\n%s",key,gmxuser);
747 return strdup(msg[i].msg);
751 void _gmx_error(const char *key,const char *msg,const char *file,int line)
753 char buf[10240],tmpbuf[1024];
755 const char *llines = "-------------------------------------------------------";
758 tMPI_Thread_mutex_lock(&debug_mutex);
760 /* protect the audience from suggestive discussions */
762 cool_quote(tmpbuf,1023,&cqnum);
763 sprintf(buf,"\n%s\nProgram %s, %s\n"
764 "Source code file: %s, line: %d\n\n"
765 "%s:\n%s\nFor more information and tips for trouble shooting please check the GROMACS Wiki at\n"
766 "http://wiki.gromacs.org/index.php/Errors\n%s\n\n%s\n",
767 llines,ShortProgram(),GromacsVersion(),file,line,
768 gmx_strerror(key),msg ? msg : warn_buf,llines,tmpbuf);
770 tMPI_Thread_mutex_unlock(&debug_mutex);
772 gmx_error_handler(buf);
775 void _range_check(int n,int n_min,int n_max,const char *var,const char *file,int line)
779 if ((n < n_min) || (n >= n_max)) {
780 if (strlen(warn_buf) > 0) {
781 strcpy(buf,warn_buf);
788 sprintf(buf+strlen(buf),"Variable %s has value %d. It should have been "
789 "within [ %d .. %d ]\n",var,n,n_min,n_max);
791 _gmx_error("range",buf,file,line);