minor fixes in ditribution files
[gromacs/qmmm-gamess-us.git] / src / gmxlib / gmx_fatal.c
blobcacbef55efccd3860a0a932c12b6c4d8cd0032fb
1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
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.
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.
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.
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.
31 * For more info, check our website at http://www.gromacs.org
33 * And Hey:
34 * GROningen Mixture of Alchemy and Childrens' Stories
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
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"
56 #ifdef GMX_THREADS
57 #include "thread_mpi.h"
58 #endif
60 static bool bDebug = FALSE;
61 static char *fatal_tmp_file = NULL;
62 static FILE *log_file = NULL;
64 #ifdef GMX_THREADS
65 static tMPI_Thread_mutex_t debug_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
66 static tMPI_Thread_mutex_t where_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
67 static tMPI_Thread_mutex_t fatal_tmp_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
68 #endif
71 bool bDebugMode(void)
73 bool ret;
74 /*#ifdef GMX_THREADS*/
75 #if 0
76 tMPI_Thread_mutex_lock(&debug_mutex);
77 #endif
78 ret=bDebug;
79 /*#ifdef GMX_THREADS*/
80 #if 0
81 tMPI_Thread_mutex_unlock(&debug_mutex);
82 #endif
83 return bDebug;
86 void gmx_fatal_set_log_file(FILE *fp)
88 log_file = fp;
91 void _where(const char *file,int line)
93 static bool bFirst = TRUE;
94 static int nskip = -1;
95 static int nwhere = 0;
96 FILE *fp;
97 char *temp;
99 if ( bFirst ) {
100 #ifdef GMX_THREADS
101 tMPI_Thread_mutex_lock(&where_mutex);
102 if (bFirst) /* we repeat the check in the locked section because things
103 might have changed */
105 #endif
106 if ((temp=getenv("WHERE")) != NULL)
107 nskip = strtol(temp, NULL, 10);
108 bFirst = FALSE;
109 #ifdef GMX_THREADS
111 tMPI_Thread_mutex_unlock(&where_mutex);
112 #endif
116 if (nskip >= 0) {
117 /* Skip the first n occasions, this allows to see where it goes wrong */
118 if (nwhere >= nskip) {
119 if (log_file)
120 fp = log_file;
121 else
122 fp = stderr;
123 fprintf(fp,"WHERE %d, file %s - line %d\n",nwhere,file,line);
125 nwhere++;
129 static void bputc(char *msg,int *len,char ch)
131 msg[(*len)++]=ch;
134 static void bputs(char *msg,int *len,const char *s,int fld)
136 for (fld-=(int)strlen(s); fld>0; fld--)
137 bputc(msg,len,' ');
138 while (*s)
139 bputc(msg,len,*(s++));
142 static void bputd(char *msg,int *len,int d)
144 if (d<10) bputc(msg,len,d+'0'); else bputc(msg,len,d-10+'a');
147 static void bputi(char *msg,int *len,int val,int radix,int fld,bool bNeg)
149 int fmax=0;
151 if (bNeg)
152 fmax=1;
154 if (val<radix)
156 for (fld--; fld>fmax; fld--)
157 bputc(msg,len,' ');
158 if (bNeg)
159 bputc(msg,len,'-');
160 bputd(msg,len,val);
162 else
164 if (bNeg)
165 bputc(msg,len,'-');
166 bputi(msg,len,val/radix,radix,fld-1,FALSE);
167 bputd(msg,len,val%radix);
171 static int getfld(const char **p)
173 int fld;
175 fld=0;
176 while (isdigit(**p)) fld=(fld*10)+((*((*p)++))-'0');
177 return fld;
180 /*static void _halt(char *file,int line,char *reason)
182 fprintf(stderr,"\nHALT in file %s line %d because:\n\t%s\n",
183 file,line,reason);
184 exit(1);
188 static int fatal_errno = 0;
190 static void quit_gmx(const char *msg)
192 #ifdef GMX_THREADS
193 tMPI_Thread_mutex_lock(&debug_mutex);
194 #endif
195 if (!fatal_errno)
197 if (log_file)
198 fprintf(log_file,"%s\n",msg);
199 fprintf(stderr,"%s\n",msg);
200 /* we set it to no-zero because if this function is called, something
201 has gone wrong */
202 fatal_errno=255;
204 else
206 if (fatal_errno != -1)
207 errno=fatal_errno;
208 perror(msg);
211 #ifndef GMX_THREADS
212 if (gmx_parallel_env_initialized()) {
213 int nnodes;
214 int noderank;
216 nnodes = gmx_node_num();
217 noderank = gmx_node_rank();
219 if (nnodes > 1)
220 fprintf(stderr,"Error on node %d, will try to stop all the nodes\n",
221 noderank);
222 gmx_abort(noderank,nnodes,-1);
224 else
225 #endif
227 if (debug)
228 fflush(debug);
229 if (bDebugMode()) {
230 fprintf(stderr,"dump core (y/n):");
231 fflush(stderr);
232 if (toupper(getc(stdin))!='N')
233 (void) abort();
237 exit(fatal_errno);
238 #ifdef GMX_THREADS
239 tMPI_Thread_mutex_unlock(&debug_mutex);
240 #endif
243 void _set_fatal_tmp_file(const char *fn, const char *file, int line)
245 #ifdef GMX_THREADS
246 tMPI_Thread_mutex_lock(&fatal_tmp_mutex);
247 #endif
248 if (fatal_tmp_file == NULL)
249 fatal_tmp_file = strdup(fn);
250 else
251 fprintf(stderr,"BUGWARNING: fatal_tmp_file already set at %s:%d",
252 file,line);
253 #ifdef GMX_THREADS
254 tMPI_Thread_mutex_unlock(&fatal_tmp_mutex);
255 #endif
258 void _unset_fatal_tmp_file(const char *fn, const char *file, int line)
260 #ifdef GMX_THREADS
261 tMPI_Thread_mutex_lock(&fatal_tmp_mutex);
262 #endif
263 if (strcmp(fn,fatal_tmp_file) == 0) {
264 sfree(fatal_tmp_file);
265 fatal_tmp_file = NULL;
266 } else
267 fprintf(stderr,"BUGWARNING: file %s not set as fatal_tmp_file at %s:%d",
268 fn,file,line);
269 #ifdef GMX_THREADS
270 tMPI_Thread_mutex_unlock(&fatal_tmp_mutex);
271 #endif
274 static void clean_fatal_tmp_file()
276 #ifdef GMX_THREADS
277 tMPI_Thread_mutex_lock(&fatal_tmp_mutex);
278 #endif
279 if (fatal_tmp_file) {
280 fprintf(stderr,"Cleaning up temporary file %s\n",fatal_tmp_file);
281 remove(fatal_tmp_file);
282 sfree(fatal_tmp_file);
283 fatal_tmp_file = NULL;
285 #ifdef GMX_THREADS
286 tMPI_Thread_mutex_unlock(&fatal_tmp_mutex);
287 #endif
290 static void parse_printf_args(const char *fmt,va_list *ap,char *msg)
292 int len;
293 const char *p;
294 char cval,*sval;
295 char ibuf[64],ifmt[64];
296 int index,ival,fld;
297 double dval;
299 len = 0;
300 for(p=fmt; *p; p++)
302 if (*p!='%')
304 bputc(msg,&len,*p);
306 else
308 p++;
309 fld = getfld(&p);
310 switch(*p) {
311 case 'x':
312 ival = va_arg(*ap,int);
313 sprintf(ifmt,"0x%%%dx",fld);
314 sprintf(ibuf,ifmt,(unsigned int)ival);
315 for(index=0; (index<(int)strlen(ibuf)); index++)
316 bputc(msg,&len,ibuf[index]);
317 break;
318 case 'd':
319 ival = va_arg(*ap,int);
320 sprintf(ifmt,"%%%dd",fld);
321 sprintf(ibuf,ifmt,ival);
322 for(index=0; (index<(int)strlen(ibuf)); index++)
323 bputc(msg,&len,ibuf[index]);
324 break;
325 case 'u':
326 ival = va_arg(*ap,unsigned);
327 sprintf(ifmt,"%%%du",fld);
328 sprintf(ibuf,ifmt,ival);
329 for(index=0; (index<(int)strlen(ibuf)); index++)
330 bputc(msg,&len,ibuf[index]);
331 break;
332 case 'f':
333 dval = va_arg(*ap,double);
334 sprintf(ifmt,"%%%df",fld);
335 sprintf(ibuf,ifmt,dval);
336 for(index=0; (index<(int)strlen(ibuf)); index++)
337 bputc(msg,&len,ibuf[index]);
338 break;
339 case 'g':
340 dval = va_arg(*ap,double);
341 sprintf(ifmt,"%%%dg",fld);
342 sprintf(ibuf,ifmt,dval);
343 for(index=0; (index<(int)strlen(ibuf)); index++)
344 bputc(msg,&len,ibuf[index]);
345 break;
346 case 'c':
347 cval = (char) va_arg(*ap,int); /* char is promoted to int */
348 bputc(msg,&len,cval);
349 break;
350 case 's':
351 sval = va_arg(*ap,char *);
352 if (sval == NULL)
353 sval = strdup("(null)");
354 bputs(msg,&len,sval,fld);
355 break;
356 case '%':
357 bputc(msg,&len,*p);
358 break;
359 default:
360 break;
365 bputc(msg,&len,'\0');
368 void gmx_fatal(int f_errno,const char *file,int line,const char *fmt,...)
370 va_list ap;
371 char msg[STRLEN];
373 va_start(ap,fmt);
375 clean_fatal_tmp_file();
377 parse_printf_args(fmt,&ap,msg);
379 va_end(ap);
381 #ifdef GMX_THREADS
382 tMPI_Thread_mutex_lock(&debug_mutex);
383 #endif
385 fatal_errno = f_errno;
387 #ifdef GMX_THREADS
388 tMPI_Thread_mutex_unlock(&debug_mutex);
389 #endif
391 _gmx_error("fatal",msg,file,line);
394 void gmx_fatal_collective(int f_errno,const char *file,int line,
395 bool bMaster,
396 const char *fmt,...)
398 va_list ap;
399 char msg[STRLEN];
401 if (bMaster)
403 va_start(ap,fmt);
405 clean_fatal_tmp_file();
407 parse_printf_args(fmt,&ap,msg);
409 va_end(ap);
411 #ifdef GMX_THREADS
412 tMPI_Thread_mutex_lock(&debug_mutex);
413 #endif
415 fatal_errno = f_errno;
417 #ifdef GMX_THREADS
418 tMPI_Thread_mutex_unlock(&debug_mutex);
419 #endif
421 _gmx_error("fatal",msg,file,line);
424 #ifdef GMX_MPI
425 /* Let all other processes wait till the master has printed
426 * the error message and issued MPI_Abort.
428 MPI_Barrier(MPI_COMM_WORLD);
429 #endif
432 void _invalid_case(const char *fn,int line)
434 gmx_fatal(FARGS,"Invalid case in switch statement, file %s, line %d",
435 fn,line);
438 void _unexpected_eof(const char *fn,int line,const char *srcfn,int srcline)
440 gmx_fatal(FARGS,"Unexpected end of file in file %s at line %d\n"
441 "(Source file %s, line %d)",fn,line,srcfn,srcline);
445 * These files are global variables in the gromacs preprocessor
446 * Every routine in a file that includes gmx_fatal.h can write to these
447 * debug channels. Depending on the debuglevel used
448 * 0 to 3 of these filed are redirected to /dev/null
451 FILE *debug=NULL;
452 bool gmx_debug_at=FALSE;
454 void init_debug (const int dbglevel,const char *dbgfile)
456 #ifdef GMX_THREADS
457 tMPI_Thread_mutex_lock(&debug_mutex);
458 #endif
459 if (!bDebug) /* another thread hasn't already run this*/
461 no_buffers();
462 debug=gmx_fio_fopen(dbgfile,"w+");
463 bDebug = TRUE;
464 if (dbglevel >= 2)
465 gmx_debug_at = TRUE;
467 #ifdef GMX_THREADS
468 tMPI_Thread_mutex_unlock(&debug_mutex);
469 #endif
472 #if (defined __sgi && defined USE_SGI_FPE)
473 static void user_routine(unsigned us[5], int ii[2])
475 fprintf(stderr,"User routine us=(%u,%u,%u,%u,%u) ii=(%d,%d)\n",
476 us[0],us[1],us[2],us[3],us[4],ii[0],ii[1]);
477 fprintf(stderr,"Exception encountered! Dumping core\n");
478 abort();
481 static void abort_routine(unsigned int **ii)
483 fprintf(stderr,"Abort routine\n");
484 abort();
487 static void handle_signals(int n)
489 fprintf(stderr,"Handle signals: n = %d\n",n);
490 fprintf(stderr,"Dumping core\n");
491 abort();
494 void doexceptions(void)
496 #include <sigfpe.h>
497 #include <signal.h>
498 int hs[] = { SIGILL, SIGFPE, SIGTRAP, SIGEMT, SIGSYS };
500 int onoff,en_mask,abort_action,i;
502 #ifdef GMX_THREADS
503 tMPI_Thread_mutex_lock(&debug_mutex);
504 #endif
505 onoff = _DEBUG;
506 en_mask = _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO |
507 _EN_INVALID | _EN_INT_OVERFL;
508 abort_action = _ABORT_ON_ERROR;
509 handle_sigfpes(onoff,en_mask,user_routine,abort_action,abort_routine);
511 for(i=0; (i<asize(hs)); i++)
512 signal(hs[i],handle_signals);
513 #ifdef GMX_THREADS
514 tMPI_Thread_mutex_unlock(&debug_mutex);
515 #endif
517 #endif /* __sgi and FPE */
519 static const char *gmxuser = "Please report this to the mailing list (gmx-users@gromacs.org)";
521 static void (*gmx_error_handler)(const char *msg) = quit_gmx;
523 void set_gmx_error_handler(void (*func)(const char *msg))
525 #ifdef GMX_THREADS
526 tMPI_Thread_mutex_lock(&debug_mutex);
527 #endif
528 gmx_error_handler = func;
529 #ifdef GMX_THREADS
530 tMPI_Thread_mutex_unlock(&debug_mutex);
531 #endif
534 char *gmx_strerror(const char *key)
536 typedef struct {
537 const char *key,*msg;
538 } error_msg_t;
539 error_msg_t msg[] = {
540 { "bug", "Possible bug" },
541 { "call", "Routine should not have been called" },
542 { "comm", "Communication (parallel processing) problem" },
543 { "fatal", "Fatal error" },
544 { "cmd", "Invalid command line argument" },
545 { "file", "File input/output error" },
546 { "impl", "Implementation restriction" },
547 { "incons", "Software inconsistency error" },
548 { "input", "Input error or input inconsistency" },
549 { "mem", "Memory allocation/freeing error" },
550 { "open", "Can not open file" },
551 { "range", "Range checking error" }
553 #define NMSG asize(msg)
554 char buf[1024];
555 size_t i;
557 if (key == NULL)
558 return strdup("Empty message");
559 else {
560 for(i=0; (i<NMSG); i++)
561 if (strcmp(key,msg[i].key) == 0)
562 break;
563 if (i == NMSG) {
564 sprintf(buf,"No error message associated with key %s\n%s",key,gmxuser);
565 return strdup(buf);
567 else
568 return strdup(msg[i].msg);
573 void _gmx_error(const char *key,const char *msg,const char *file,int line)
575 char buf[10240],tmpbuf[1024],errerrbuf[1024];
576 int cqnum;
577 const char *llines = "-------------------------------------------------------";
578 char *strerr;
580 /* protect the audience from suggestive discussions */
582 if (msg == NULL)
584 sprintf(errerrbuf,"Empty fatal_error message. %s",gmxuser);
587 cool_quote(tmpbuf,1023,&cqnum);
588 strerr = gmx_strerror(key);
589 sprintf(buf,"\n%s\nProgram %s, %s\n"
590 "Source code file: %s, line: %d\n\n"
591 "%s:\n%s\nFor more information and tips for troubleshooting, please check the GROMACS\n"
592 "website at http://www.gromacs.org/Documentation/Errors\n%s\n\n%s\n",
593 llines,ShortProgram(),GromacsVersion(),file,line,
594 strerr,msg ? msg : errerrbuf,llines,tmpbuf);
595 free(strerr);
597 gmx_error_handler(buf);
600 void _range_check(int n,int n_min,int n_max,const char *warn_str,
601 const char *var,const char *file,int line)
603 char buf[1024];
605 if ((n < n_min) || (n >= n_max)) {
606 if (warn_str != NULL) {
607 strcpy(buf,warn_str);
608 strcat(buf,"\n");
610 else
611 buf[0] = '\0';
613 sprintf(buf+strlen(buf),"Variable %s has value %d. It should have been "
614 "within [ %d .. %d ]\n",var,n,n_min,n_max);
616 _gmx_error("range",buf,file,line);
620 void gmx_warning(const char *fmt,...)
622 va_list ap;
623 char msg[STRLEN];
625 va_start(ap,fmt);
627 parse_printf_args(fmt,&ap,msg);
629 va_end(ap);
631 fprintf(stderr,"\nWARNING: %s\n\n",msg);