From: Adam Crume Date: Fri, 18 Jul 2014 19:06:19 +0000 (-0700) Subject: Add assertf macro X-Git-Tag: v0.86~231^2~60 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=4eac5187db6b907a54902f569fe898d9312d2134;p=ceph.git Add assertf macro Signed-off-by: Adam Crume --- diff --git a/src/common/assert.cc b/src/common/assert.cc index 7889ad043a69..67c43df1b782 100644 --- a/src/common/assert.cc +++ b/src/common/assert.cc @@ -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 ` " + "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 ` " + << "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) { diff --git a/src/include/assert.h b/src/include/assert.h index 5ff41ba69d7a..ec0aa34d601f 100644 --- a/src/include/assert.h +++ b/src/include/assert.h @@ -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__))