1 #ifndef DUNE_ASSERT_HH
2 #define DUNE_ASSERT_HH
3 
4 #include <cstdlib>
5 #include <unistd.h>
6 #include <iostream>
7 #if HAVE_MPI
8 #include <mpi.h>
9 #endif
10 
11 // combination of suggestions made in
12 // http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
13 // and
14 // http://www.open-mpi.de/faq/?category=debugging
15 
16 namespace
17 {
18   // Call to stop a program so that it is possible to attach a debugger.
19   // The process id (PID) and calling host are printed to the error stream
20   // If the parameter p is added in a parallel code only the process with
21   // that rank will wait to allow a debugger to attach.
22   //
23   // To attach for example gdb simply call (on the correct host):
24   // gdb -pid PID
25   // you can continue the program by calling at the gdb prompt:
26   // > set var cont = 1
27   // > continue
28   int attach(int p=-1);
29   //
30   // dune_assert( bool ) or dune_assert( bool, p )
31   // This is a special assert like macro that allows a bit more flexibility
32   // then the standard assert. There are three different available
33   // behaviors of a failed dune_assert call:
34   // - If ASSERTATTACH is defined then attach is called with the optional
35   //   process rank p, i.e., the assert is ignored except on the process
36   //   with rank p.
37   // - If ASSERTATTACH is not defined but ASSERTCONTINUE then the assert
38   //   message is printed but the program tries to continue regardless. This
39   //   can be usefull for some unit tests
40   // - If neither ASSERTATTACH nor ASSERTCONTINUE is defined then the program
41   //   will be aborted.
attach(int p)42   int attach(int p)
43   {
44     int cont = 0;
45     char hostname[256];
46     gethostname(hostname, sizeof(hostname));
47 #if HAVE_MPI
48     int mpirank = -1;
49     MPI_Comm_rank(MPI_COMM_WORLD,&mpirank);
50     if (p >= 0 && p != mpirank)
51     {
52       std::cout << "[" << mpirank << "] has PID " << getpid() << " on " << hostname << " continuing" << std::endl;
53       return 1;
54     }
55     else
56       std::cout << "[" << mpirank << "] has PID " << getpid() << " on " << hostname << " ready to attach" << std::endl;
57 #else
58     std::cout << "PID " << getpid() << " on " << hostname << " ready to attach" << std::endl;
59 #endif
60     while (0 == cont)
61         sleep(5);
62     return 1;
63   }
64 
65   // a handle for the dune_assert macro.
66   // The usual output from the C assert (including the mpi rank on a
67   // parallel run) is printed to std::cerr.
68   typedef int (*AssertHandler)(char const*, char const*, int);
default_assert_handler(char const * expr,char const * file,int line)69   int default_assert_handler(char const* expr, char const* file, int line)
70   {
71 #if HAVE_MPI
72     int mpirank = -1;
73     MPI_Comm_rank(MPI_COMM_WORLD,&mpirank);
74     std::cout << "[" << mpirank << "]: ";
75 #endif
76     std::cerr << "Assertion " << expr << " failed in " << file << ":" << line << std::endl;
77     return 1;
78   }
79     AssertHandler assert_handler = default_assert_handler;
80 }
81 
82 
83 // the ASSERT_HALT macro is available in three flavours depending on some
84 // defines:
85 #if defined(ASSERTATTACH)
86 #define ASSERT_HALT(p) attach(p)
87 #elif defined(ASSERTCONTINUE)
88 #define ASSERT_HALT(p) ((void)sizeof(p)), std::cout << "... trying to continue ..." << std::endl
89 #else
90 #define ASSERT_HALT(p) ((void)sizeof(p)), abort()
91 #endif
92 
93 // The actual implementation fo the dune_assert macro
94 #ifndef NDEBUG
95 #define dune_assert_(x,p) ((void)(!(x) && assert_handler(#x, __FILE__, __LINE__) && (ASSERT_HALT(p), 1)))
96 #else
97 #define dune_assert_(x,p) ((void)sizeof(x),sizeof(p))
98 #endif
99 
100 // Allow for calling dune_assert with one or two arguments
101 #define dune_assert0_(x) dune_assert_(x,-1)
102 #define dune_assert1_(x,p) dune_assert_(x,p)
103 #define GET_ASSERT_MACRO(_1,_2,NAME,...) NAME
104 #define dune_assert(...) GET_ASSERT_MACRO(__VA_ARGS__, dune_assert1_, dune_assert0_)(__VA_ARGS__)
105 
106 #endif
107