summaryrefslogtreecommitdiff
path: root/src/common/assert.cc
blob: 7889ad043a692c9f436d13e1eafca8213d01e4c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2008-2011 New Dream Network
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "BackTrace.h"
#include "common/ceph_context.h"
#include "common/config.h"
#include "common/debug.h"
#include "common/Clock.h"
#include "include/assert.h"

#include <errno.h>
#include <iostream>
#include <pthread.h>
#include <sstream>
#include <time.h>

namespace ceph {
  static CephContext *g_assert_context = NULL;

  /* If you register an assert context, assert() will try to lock the dout
   * stream of that context before starting an assert. This is nice because the
   * output looks better. Your assert will not be interleaved with other dout
   * statements.
   *
   * However, this is strictly optional and library code currently does not
   * register an assert context. The extra complexity of supporting this
   * wouldn't really be worth it.
   */
  void register_assert_context(CephContext *cct)
  {
    assert(!g_assert_context);
    g_assert_context = cct;
  }

  void __ceph_assert_fail(const char *assertion, const char *file, int line, const char *func)
  {
    ostringstream tss;
    tss << ceph_clock_now(g_assert_context);

    char buf[8096];
    BackTrace *bt = new BackTrace(1);
    snprintf(buf, sizeof(buf),
	     "%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);
    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)
  {
    char buf[8096];
    snprintf(buf, sizeof(buf),
	     "WARNING: assert(%s) at: %s: %d: %s()\n",
	     assertion, file, line, func);
    dout_emergency(buf);
  }
}