Valgrind suppression for OS X 10.9
[alexxy/gromacs.git] / src / gromacs / 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  * Copyright (c) 2013,2014, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #include "gmx_fatal.h"
38 #include "gmx_fatal_collective.h"
39
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43
44 #include <ctype.h>
45 #include <errno.h>
46 #include <stdarg.h>
47 #include <string.h>
48
49 #include "thread_mpi/threads.h"
50
51 #include "main.h"
52 #include "types/commrec.h"
53 #include "network.h"
54 #include "copyrite.h"
55 #include "macros.h"
56
57 #include "gromacs/fileio/futil.h"
58 #include "gromacs/fileio/gmxfio.h"
59 #include "gromacs/utility/cstringutil.h"
60 #include "gromacs/utility/gmxmpi.h"
61 #include "gromacs/utility/smalloc.h"
62
63 static gmx_bool            bDebug         = FALSE;
64 static FILE               *log_file       = NULL;
65
66 static tMPI_Thread_mutex_t debug_mutex     = TMPI_THREAD_MUTEX_INITIALIZER;
67 static tMPI_Thread_mutex_t where_mutex     = TMPI_THREAD_MUTEX_INITIALIZER;
68
69 gmx_bool bDebugMode(void)
70 {
71     gmx_bool ret;
72 #if 0
73     tMPI_Thread_mutex_lock(&debug_mutex);
74 #endif
75     ret = bDebug;
76 #if 0
77     tMPI_Thread_mutex_unlock(&debug_mutex);
78 #endif
79     return bDebug;
80 }
81
82 void gmx_fatal_set_log_file(FILE *fp)
83 {
84     log_file = fp;
85 }
86
87 void _where(const char *file, int line)
88 {
89     static gmx_bool bFirst = TRUE;
90     static int      nskip  = -1;
91     static int      nwhere =  0;
92     FILE           *fp;
93     char           *temp;
94
95     if (bFirst)
96     {
97         tMPI_Thread_mutex_lock(&where_mutex);
98         if (bFirst) /* we repeat the check in the locked section because things
99                        might have changed */
100         {
101             if ((temp = getenv("GMX_PRINT_DEBUG_LINES")) != NULL)
102             {
103                 nskip = strtol(temp, NULL, 10);
104             }
105             bFirst = FALSE;
106         }
107         tMPI_Thread_mutex_unlock(&where_mutex);
108     }
109
110     if (nskip >= 0)
111     {
112         /* Skip the first n occasions, this allows to see where it goes wrong */
113         if (nwhere >= nskip)
114         {
115             if (log_file)
116             {
117                 fp = log_file;
118             }
119             else
120             {
121                 fp = stderr;
122             }
123             fprintf(fp, "WHERE %d, file %s - line %d\n", nwhere, file, line);
124         }
125         nwhere++;
126     }
127 }
128
129 static int fatal_errno = 0;
130
131 static void quit_gmx(const char *msg)
132 {
133     tMPI_Thread_mutex_lock(&debug_mutex);
134     if (fatal_errno == 0)
135     {
136         if (log_file)
137         {
138             fprintf(log_file, "%s\n", msg);
139         }
140         fprintf(stderr, "%s\n", msg);
141         /* we set it to no-zero because if this function is called, something
142            has gone wrong */
143         fatal_errno = 255;
144     }
145     else
146     {
147         if (fatal_errno != -1)
148         {
149             errno = fatal_errno;
150         }
151         perror(msg);
152     }
153
154 #ifdef GMX_LIB_MPI
155     if (gmx_mpi_initialized())
156     {
157         int  nnodes;
158         int  noderank;
159
160         nnodes   = gmx_node_num();
161         noderank = gmx_node_rank();
162
163         if (nnodes > 1)
164         {
165             fprintf(stderr, "Error on rank %d, will try to stop all ranks\n",
166                     noderank);
167         }
168         gmx_abort(noderank, nnodes, -1);
169     }
170 #endif
171
172     if (debug)
173     {
174         fflush(debug);
175     }
176     if (bDebugMode())
177     {
178         fprintf(stderr, "dump core (y/n):");
179         fflush(stderr);
180         if (toupper(getc(stdin)) != 'N')
181         {
182             (void) abort();
183         }
184     }
185
186     exit(fatal_errno);
187     tMPI_Thread_mutex_unlock(&debug_mutex);
188 }
189
190 /* The function below should be identical to quit_gmx,
191  * except that is does not actually quit and call gmx_abort.
192  */
193 static void quit_gmx_noquit(const char *msg)
194 {
195     tMPI_Thread_mutex_lock(&debug_mutex);
196     if (!fatal_errno)
197     {
198         if (log_file)
199         {
200             fprintf(log_file, "%s\n", msg);
201         }
202         fprintf(stderr, "%s\n", msg);
203         /* we set it to no-zero because if this function is called, something
204            has gone wrong */
205         fatal_errno = 255;
206     }
207     else
208     {
209         if (fatal_errno != -1)
210         {
211             errno = fatal_errno;
212         }
213         perror(msg);
214     }
215
216 #ifndef GMX_LIB_MPI
217     if (debug)
218     {
219         fflush(debug);
220     }
221     if (bDebugMode())
222     {
223         fprintf(stderr, "dump core (y/n):");
224         fflush(stderr);
225         if (toupper(getc(stdin)) != 'N')
226         {
227             (void) abort();
228         }
229     }
230 #endif
231
232     tMPI_Thread_mutex_unlock(&debug_mutex);
233 }
234
235 void gmx_fatal(int f_errno, const char *file, int line, const char *fmt, ...)
236 {
237     va_list ap;
238     char    msg[STRLEN];
239
240     va_start(ap, fmt);
241     vsprintf(msg, fmt, ap);
242     va_end(ap);
243
244     tMPI_Thread_mutex_lock(&debug_mutex);
245     fatal_errno = f_errno;
246     tMPI_Thread_mutex_unlock(&debug_mutex);
247
248     _gmx_error("fatal", msg, file, line);
249 }
250
251 void gmx_fatal_collective(int f_errno, const char *file, int line,
252                           const t_commrec *cr, gmx_domdec_t *dd,
253                           const char *fmt, ...)
254 {
255     gmx_bool    bFinalize;
256     va_list     ap;
257     char        msg[STRLEN];
258 #ifdef GMX_MPI
259     int         result;
260 #endif
261
262     bFinalize = TRUE;
263
264 #ifdef GMX_MPI
265     /* Check if we are calling on all processes in MPI_COMM_WORLD */
266     if (cr != NULL)
267     {
268         MPI_Comm_compare(cr->mpi_comm_mysim, MPI_COMM_WORLD, &result);
269     }
270     else
271     {
272         MPI_Comm_compare(dd->mpi_comm_all, MPI_COMM_WORLD, &result);
273     }
274     /* Any result except MPI_UNEQUAL allows us to call MPI_Finalize */
275     bFinalize = (result != MPI_UNEQUAL);
276 #endif
277
278     if ((cr != NULL && MASTER(cr)  ) ||
279         (dd != NULL && DDMASTER(dd)))
280     {
281         va_start(ap, fmt);
282         vsprintf(msg, fmt, ap);
283         va_end(ap);
284
285         tMPI_Thread_mutex_lock(&debug_mutex);
286         fatal_errno = f_errno;
287         tMPI_Thread_mutex_unlock(&debug_mutex);
288
289         if (bFinalize)
290         {
291             /* Use an error handler that does not quit */
292             set_gmx_error_handler(quit_gmx_noquit);
293         }
294
295         _gmx_error("fatal", msg, file, line);
296     }
297
298 #ifdef GMX_MPI
299     if (bFinalize)
300     {
301         /* Broadcast the fatal error number possibly modified
302          * on the master process, in case the user would like
303          * to use the return status on a non-master process.
304          * The master process in cr and dd always has global rank 0.
305          */
306         MPI_Bcast(&fatal_errno, sizeof(fatal_errno), MPI_BYTE,
307                   0, MPI_COMM_WORLD);
308
309         /* Finalize nicely instead of aborting */
310         MPI_Finalize();
311     }
312     else
313     {
314         /* Let all other processes wait till the master has printed
315          * the error message and issued MPI_Abort.
316          */
317         MPI_Barrier(MPI_COMM_WORLD);
318     }
319 #endif
320
321     exit(fatal_errno);
322 }
323
324 /*
325  * These files are global variables in the gromacs preprocessor
326  * Every routine in a file that includes gmx_fatal.h can write to these
327  * debug channels. Depending on the debuglevel used
328  * 0 to 3 of these filed are redirected to /dev/null
329  *
330  */
331 FILE    *debug           = NULL;
332 gmx_bool gmx_debug_at    = FALSE;
333
334 void init_debug(const int dbglevel, const char *dbgfile)
335 {
336     tMPI_Thread_mutex_lock(&debug_mutex);
337     if (!bDebug) /* another thread hasn't already run this*/
338     {
339         no_buffers();
340         debug  = gmx_fio_fopen(dbgfile, "w+");
341         bDebug = TRUE;
342         if (dbglevel >= 2)
343         {
344             gmx_debug_at = TRUE;
345         }
346     }
347     tMPI_Thread_mutex_unlock(&debug_mutex);
348 }
349
350 static const char *gmxuser = "Please report this to the mailing list (gmx-users@gromacs.org)";
351
352 static void        (*gmx_error_handler)(const char *msg) = quit_gmx;
353
354 void set_gmx_error_handler(void (*func)(const char *msg))
355 {
356     tMPI_Thread_mutex_lock(&debug_mutex);
357     gmx_error_handler = func;
358     tMPI_Thread_mutex_unlock(&debug_mutex);
359 }
360
361 char *gmx_strerror(const char *key)
362 {
363     typedef struct {
364         const char *key, *msg;
365     } error_msg_t;
366     error_msg_t msg[] = {
367         { "bug",    "Possible bug" },
368         { "call",   "Routine should not have been called" },
369         { "comm",   "Communication (parallel processing) problem" },
370         { "fatal",  "Fatal error" },
371         { "cmd",    "Invalid command line argument" },
372         { "file",   "File input/output error" },
373         { "impl",   "Implementation restriction" },
374         { "incons", "Software inconsistency error" },
375         { "input",  "Input error or input inconsistency" },
376         { "mem",    "Memory allocation/freeing error" },
377         { "open",   "Can not open file" },
378         { "range",  "Range checking error" }
379     };
380 #define NMSG asize(msg)
381     char        buf[1024];
382     size_t      i;
383
384     if (key == NULL)
385     {
386         return strdup("Empty message");
387     }
388     else
389     {
390         for (i = 0; (i < NMSG); i++)
391         {
392             if (strcmp(key, msg[i].key) == 0)
393             {
394                 break;
395             }
396         }
397         if (i == NMSG)
398         {
399             sprintf(buf, "No error message associated with key %s\n%s", key, gmxuser);
400             return strdup(buf);
401         }
402         else
403         {
404             return strdup(msg[i].msg);
405         }
406     }
407 }
408
409
410 void _gmx_error(const char *key, const char *msg, const char *file, int line)
411 {
412     char        buf[10240], errerrbuf[1024];
413     const char *llines = "-------------------------------------------------------";
414     char       *strerr;
415
416     /* protect the audience from suggestive discussions */
417
418     if (msg == NULL)
419     {
420         sprintf(errerrbuf, "Empty fatal_error message. %s", gmxuser);
421     }
422
423     strerr = gmx_strerror(key);
424     sprintf(buf, "\n%s\nProgram %s, %s\n"
425             "Source code file: %s, line: %d\n\n"
426             "%s:\n%s\nFor more information and tips for troubleshooting, please check the GROMACS\n"
427             "website at http://www.gromacs.org/Documentation/Errors\n%s\n",
428             llines, ShortProgram(), GromacsVersion(), file, line,
429             strerr, msg ? msg : errerrbuf, llines);
430     free(strerr);
431
432     gmx_error_handler(buf);
433 }
434
435 void _range_check(int n, int n_min, int n_max, const char *warn_str,
436                   const char *var, const char *file, int line)
437 {
438     char buf[1024];
439
440     if ((n < n_min) || (n >= n_max))
441     {
442         if (warn_str != NULL)
443         {
444             strcpy(buf, warn_str);
445             strcat(buf, "\n");
446         }
447         else
448         {
449             buf[0] = '\0';
450         }
451
452         sprintf(buf+strlen(buf), "Variable %s has value %d. It should have been "
453                 "within [ %d .. %d ]\n", var, n, n_min, n_max);
454
455         _gmx_error("range", buf, file, line);
456     }
457 }
458
459 void gmx_warning(const char *fmt, ...)
460 {
461     va_list ap;
462     char    msg[STRLEN];
463
464     va_start(ap, fmt);
465     vsprintf(msg, fmt, ap);
466     va_end(ap);
467
468     fprintf(stderr, "\nWARNING: %s\n\n", msg);
469 }