]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
Add assertf macro
authorAdam Crume <adamcrume@gmail.com>
Fri, 18 Jul 2014 19:06:19 +0000 (12:06 -0700)
committerSage Weil <sage@redhat.com>
Thu, 21 Aug 2014 17:57:29 +0000 (10:57 -0700)
Signed-off-by: Adam Crume <adamcrume@gmail.com>
src/common/assert.cc
src/include/assert.h

index 7889ad043a692c9f436d13e1eafca8213d01e4c1..67c43df1b782e9f57e829b90ae297b4a0a62a804 100644 (file)
@@ -77,6 +77,75 @@ namespace ceph {
     throw FailedAssertion(bt);
   }
 
+  void __ceph_assertf_fail(const char *assertion, const char *file, int line, const char *func, const char* msg, ...)
+  {
+    ostringstream tss;
+    tss << ceph_clock_now(g_assert_context);
+
+    class BufAppender {
+    public:
+      BufAppender(char* buf, int size) : bufptr(buf), remaining(size) {
+      }
+
+      void printf(const char * format, ...) {
+       va_list args;
+       va_start(args, format);
+       this->vprintf(format, args);
+       va_end(args);
+      }
+
+      void vprintf(const char * format, va_list args) {
+       int n = vsnprintf(bufptr, remaining, format, args);
+       if (n >= 0) {
+         if (n < remaining) {
+           remaining -= n;
+           bufptr += n;
+         } else {
+           remaining = 0;
+         }
+       }
+      }
+
+    private:
+      char* bufptr;
+      int remaining;
+    };
+
+    char buf[8096];
+    BufAppender ba(buf, sizeof(buf));
+    BackTrace *bt = new BackTrace(1);
+    ba.printf("%s: In function '%s' thread %llx time %s\n"
+            "%s: %d: FAILED assert(%s)\n",
+            file, func, (unsigned long long)pthread_self(), tss.str().c_str(),
+            file, line, assertion);
+    ba.printf("Assertion details: ");
+    va_list args;
+    va_start(args, msg);
+    ba.vprintf(msg, args);
+    va_end(args);
+    ba.printf("\n");
+    dout_emergency(buf);
+
+    // TODO: get rid of this memory allocation.
+    ostringstream oss;
+    bt->print(oss);
+    dout_emergency(oss.str());
+
+    dout_emergency(" NOTE: a copy of the executable, or `objdump -rdS <executable>` "
+                  "is needed to interpret this.\n");
+
+    if (g_assert_context) {
+      lderr(g_assert_context) << buf << std::endl;
+      bt->print(*_dout);
+      *_dout << " NOTE: a copy of the executable, or `objdump -rdS <executable>` "
+            << "is needed to interpret this.\n" << dendl;
+
+      g_assert_context->_log->dump_recent();
+    }
+
+    throw FailedAssertion(bt);
+  }
+
   void __ceph_assert_warn(const char *assertion, const char *file,
                          int line, const char *func)
   {
index 5ff41ba69d7a30f732d7a1151fe6ccdf9953be86..ec0aa34d601f89be9e5addffea7369017c01631b 100644 (file)
@@ -68,6 +68,8 @@ struct FailedAssertion {
 extern void register_assert_context(CephContext *cct);
 extern void __ceph_assert_fail(const char *assertion, const char *file, int line, const char *function)
   __attribute__ ((__noreturn__));
+extern void __ceph_assertf_fail(const char *assertion, const char *file, int line, const char *function, const char* msg, ...)
+  __attribute__ ((__noreturn__));
 extern void __ceph_assert_warn(const char *assertion, const char *file, int line, const char *function);
 
 #define ceph_assert(expr)                                                      \
@@ -138,3 +140,9 @@ using namespace ceph;
    ? __CEPH_ASSERT_VOID_CAST (0)                                       \
    : __ceph_assert_fail (__STRING(expr), __FILE__, __LINE__, __CEPH_ASSERT_FUNCTION))
 
+// Named by analogy with printf.  Along with an expression, takes a format
+// string and parameters which are printed if the assertion fails.
+#define assertf(expr, ...)                  \
+  ((expr)                                                              \
+   ? __CEPH_ASSERT_VOID_CAST (0)                                       \
+   : __ceph_assertf_fail (__STRING(expr), __FILE__, __LINE__, __CEPH_ASSERT_FUNCTION, __VA_ARGS__))