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