2 * This file is part of the GROMACS molecular simulation package.
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.
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.
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.
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.
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.
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.
51 #include "gmx_fatal.h"
57 #include "gmx_fatal_collective.h"
66 static gmx_bool bDebug = FALSE;
67 static char *fatal_tmp_file = NULL;
68 static FILE *log_file = NULL;
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;
77 gmx_bool bDebugMode(void)
80 /*#ifdef GMX_THREAD_MPI*/
82 tMPI_Thread_mutex_lock(&debug_mutex);
85 /*#ifdef GMX_THREAD_MPI*/
87 tMPI_Thread_mutex_unlock(&debug_mutex);
92 void gmx_fatal_set_log_file(FILE *fp)
97 void _where(const char *file,int line)
99 static gmx_bool bFirst = TRUE;
100 static int nskip = -1;
101 static int nwhere = 0;
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 */
112 if ((temp=getenv("WHERE")) != NULL)
113 nskip = strtol(temp, NULL, 10);
115 #ifdef GMX_THREAD_MPI
117 tMPI_Thread_mutex_unlock(&where_mutex);
123 /* Skip the first n occasions, this allows to see where it goes wrong */
124 if (nwhere >= nskip) {
129 fprintf(fp,"WHERE %d, file %s - line %d\n",nwhere,file,line);
135 static void bputc(char *msg,int *len,char ch)
140 static void bputs(char *msg,int *len,const char *s,int fld)
142 for (fld-=(int)strlen(s); fld>0; fld--)
145 bputc(msg,len,*(s++));
148 static void bputd(char *msg,int *len,int d)
150 if (d<10) bputc(msg,len,d+'0'); else bputc(msg,len,d-10+'a');
153 static void bputi(char *msg,int *len,int val,int radix,int fld,gmx_bool bNeg)
162 for (fld--; fld>fmax; fld--)
172 bputi(msg,len,val/radix,radix,fld-1,FALSE);
173 bputd(msg,len,val%radix);
177 static int getfld(const char **p)
182 while (isdigit(**p)) fld=(fld*10)+((*((*p)++))-'0');
186 /*static void _halt(char *file,int line,char *reason)
188 fprintf(stderr,"\nHALT in file %s line %d because:\n\t%s\n",
194 static int fatal_errno = 0;
196 static void quit_gmx(const char *msg)
198 #ifdef GMX_THREAD_MPI
199 tMPI_Thread_mutex_lock(&debug_mutex);
201 if (fatal_errno == 0)
205 fprintf(log_file,"%s\n",msg);
207 fprintf(stderr,"%s\n",msg);
208 /* we set it to no-zero because if this function is called, something
214 if (fatal_errno != -1)
222 if (gmx_mpi_initialized())
227 nnodes = gmx_node_num();
228 noderank = gmx_node_rank();
232 fprintf(stderr,"Error on node %d, will try to stop all the nodes\n",
235 gmx_abort(noderank,nnodes,-1);
245 fprintf(stderr,"dump core (y/n):");
247 if (toupper(getc(stdin))!='N')
254 #ifdef GMX_THREAD_MPI
255 tMPI_Thread_mutex_unlock(&debug_mutex);
259 /* The function below should be identical to quit_gmx,
260 * except that is does not actually quit and call gmx_abort.
262 static void quit_gmx_noquit(const char *msg)
264 #ifdef GMX_THREAD_MPI
265 tMPI_Thread_mutex_lock(&debug_mutex);
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
278 if (fatal_errno != -1)
290 fprintf(stderr,"dump core (y/n):");
292 if (toupper(getc(stdin))!='N')
299 #ifdef GMX_THREAD_MPI
300 tMPI_Thread_mutex_unlock(&debug_mutex);
304 void _set_fatal_tmp_file(const char *fn, const char *file, int line)
306 #ifdef GMX_THREAD_MPI
307 tMPI_Thread_mutex_lock(&fatal_tmp_mutex);
309 if (fatal_tmp_file == NULL)
310 fatal_tmp_file = strdup(fn);
312 fprintf(stderr,"BUGWARNING: fatal_tmp_file already set at %s:%d",
314 #ifdef GMX_THREAD_MPI
315 tMPI_Thread_mutex_unlock(&fatal_tmp_mutex);
319 void _unset_fatal_tmp_file(const char *fn, const char *file, int line)
321 #ifdef GMX_THREAD_MPI
322 tMPI_Thread_mutex_lock(&fatal_tmp_mutex);
324 if (strcmp(fn,fatal_tmp_file) == 0) {
325 sfree(fatal_tmp_file);
326 fatal_tmp_file = NULL;
328 fprintf(stderr,"BUGWARNING: file %s not set as fatal_tmp_file at %s:%d",
330 #ifdef GMX_THREAD_MPI
331 tMPI_Thread_mutex_unlock(&fatal_tmp_mutex);
335 static void clean_fatal_tmp_file()
337 #ifdef GMX_THREAD_MPI
338 tMPI_Thread_mutex_lock(&fatal_tmp_mutex);
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;
346 #ifdef GMX_THREAD_MPI
347 tMPI_Thread_mutex_unlock(&fatal_tmp_mutex);
351 static void parse_printf_args(const char *fmt,va_list *ap,char *msg)
356 char ibuf[64],ifmt[64];
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]);
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]);
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]);
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]);
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]);
408 cval = (char) va_arg(*ap,int); /* char is promoted to int */
409 bputc(msg,&len,cval);
412 sval = va_arg(*ap,char *);
414 sval = strdup("(null)");
415 bputs(msg,&len,sval,fld);
426 bputc(msg,&len,'\0');
429 void gmx_fatal(int f_errno,const char *file,int line,const char *fmt,...)
436 clean_fatal_tmp_file();
438 parse_printf_args(fmt,&ap,msg);
442 #ifdef GMX_THREAD_MPI
443 tMPI_Thread_mutex_lock(&debug_mutex);
446 fatal_errno = f_errno;
448 #ifdef GMX_THREAD_MPI
449 tMPI_Thread_mutex_unlock(&debug_mutex);
452 _gmx_error("fatal",msg,file,line);
455 void gmx_fatal_collective(int f_errno,const char *file,int line,
456 const t_commrec *cr,gmx_domdec_t *dd,
469 /* Check if we are calling on all processes in MPI_COMM_WORLD */
472 MPI_Comm_compare(cr->mpi_comm_mysim,MPI_COMM_WORLD,&result);
476 MPI_Comm_compare(dd->mpi_comm_all,MPI_COMM_WORLD,&result);
478 /* Any result except MPI_UNEQUAL allows us to call MPI_Finalize */
479 bFinalize = (result != MPI_UNEQUAL);
482 if ((cr != NULL && MASTER(cr) ) ||
483 (dd != NULL && DDMASTER(dd)))
487 clean_fatal_tmp_file();
489 parse_printf_args(fmt,&ap,msg);
493 #ifdef GMX_THREAD_MPI
494 tMPI_Thread_mutex_lock(&debug_mutex);
497 fatal_errno = f_errno;
499 #ifdef GMX_THREAD_MPI
500 tMPI_Thread_mutex_unlock(&debug_mutex);
505 /* Use an error handler that does not quit */
506 set_gmx_error_handler(quit_gmx_noquit);
509 _gmx_error("fatal",msg,file,line);
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.
520 MPI_Bcast(&fatal_errno,sizeof(fatal_errno),MPI_BYTE,
523 /* Finalize nicely instead of aborting */
528 /* Let all other processes wait till the master has printed
529 * the error message and issued MPI_Abort.
531 MPI_Barrier(MPI_COMM_WORLD);
538 void _invalid_case(const char *fn,int line)
540 gmx_fatal(FARGS,"Invalid case in switch statement, file %s, line %d",
544 void _unexpected_eof(const char *fn,int line,const char *srcfn,int srcline)
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);
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
558 gmx_bool gmx_debug_at=FALSE;
560 void init_debug (const int dbglevel,const char *dbgfile)
562 #ifdef GMX_THREAD_MPI
563 tMPI_Thread_mutex_lock(&debug_mutex);
565 if (!bDebug) /* another thread hasn't already run this*/
568 debug=gmx_fio_fopen(dbgfile,"w+");
573 #ifdef GMX_THREAD_MPI
574 tMPI_Thread_mutex_unlock(&debug_mutex);
578 #if (defined __sgi && defined USE_SGI_FPE)
579 static void user_routine(unsigned us[5], int ii[2])
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");
587 static void abort_routine(unsigned int **ii)
589 fprintf(stderr,"Abort routine\n");
593 static void handle_signals(int n)
595 fprintf(stderr,"Handle signals: n = %d\n",n);
596 fprintf(stderr,"Dumping core\n");
600 void doexceptions(void)
604 int hs[] = { SIGILL, SIGFPE, SIGTRAP, SIGEMT, SIGSYS };
606 int onoff,en_mask,abort_action,i;
608 #ifdef GMX_THREAD_MPI
609 tMPI_Thread_mutex_lock(&debug_mutex);
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);
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);
623 #endif /* __sgi and FPE */
625 static const char *gmxuser = "Please report this to the mailing list (gmx-users@gromacs.org)";
627 static void (*gmx_error_handler)(const char *msg) = quit_gmx;
629 void set_gmx_error_handler(void (*func)(const char *msg))
631 #ifdef GMX_THREAD_MPI
632 tMPI_Thread_mutex_lock(&debug_mutex);
634 gmx_error_handler = func;
635 #ifdef GMX_THREAD_MPI
636 tMPI_Thread_mutex_unlock(&debug_mutex);
640 char *gmx_strerror(const char *key)
643 const char *key,*msg;
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" }
659 #define NMSG asize(msg)
664 return strdup("Empty message");
666 for(i=0; (i<NMSG); i++)
667 if (strcmp(key,msg[i].key) == 0)
670 sprintf(buf,"No error message associated with key %s\n%s",key,gmxuser);
674 return strdup(msg[i].msg);
679 void _gmx_error(const char *key,const char *msg,const char *file,int line)
681 char buf[10240],tmpbuf[1024],errerrbuf[1024];
683 const char *llines = "-------------------------------------------------------";
686 /* protect the audience from suggestive discussions */
690 sprintf(errerrbuf,"Empty fatal_error message. %s",gmxuser);
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);
703 gmx_error_handler(buf);
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)
711 if ((n < n_min) || (n >= n_max)) {
712 if (warn_str != NULL) {
713 strcpy(buf,warn_str);
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);
722 _gmx_error("range",buf,file,line);
726 void gmx_warning(const char *fmt,...)
733 parse_printf_args(fmt,&ap,msg);
737 fprintf(stderr,"\nWARNING: %s\n\n",msg);