]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/assert.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / common / assert.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2008-2011 New Dream Network
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include "include/compat.h"
16 #include "common/debug.h"
17
18 using std::ostringstream;
19
20 namespace ceph {
21 static CephContext *g_assert_context = NULL;
22
23 /* If you register an assert context, ceph_assert() will try to lock the dout
24 * stream of that context before starting an assert. This is nice because the
25 * output looks better. Your assert will not be interleaved with other dout
26 * statements.
27 *
28 * However, this is strictly optional and library code currently does not
29 * register an assert context. The extra complexity of supporting this
30 * wouldn't really be worth it.
31 */
32 void register_assert_context(CephContext *cct)
33 {
34 ceph_assert(!g_assert_context);
35 g_assert_context = cct;
36 }
37
38 [[gnu::cold]] void __ceph_assert_fail(const char *assertion,
39 const char *file, int line,
40 const char *func)
41 {
42 g_assert_condition = assertion;
43 g_assert_file = file;
44 g_assert_line = line;
45 g_assert_func = func;
46 g_assert_thread = (unsigned long long)pthread_self();
47 ceph_pthread_getname(pthread_self(), g_assert_thread_name,
48 sizeof(g_assert_thread_name));
49
50 ostringstream tss;
51 tss << ceph_clock_now();
52
53 snprintf(g_assert_msg, sizeof(g_assert_msg),
54 "%s: In function '%s' thread %llx time %s\n"
55 "%s: %d: FAILED ceph_assert(%s)\n",
56 file, func, (unsigned long long)pthread_self(), tss.str().c_str(),
57 file, line, assertion);
58 dout_emergency(g_assert_msg);
59
60 // TODO: get rid of this memory allocation.
61 ostringstream oss;
62 oss << ClibBackTrace(1);
63 dout_emergency(oss.str());
64
65 if (g_assert_context) {
66 lderr(g_assert_context) << g_assert_msg << std::endl;
67 *_dout << oss.str() << dendl;
68
69 // dump recent only if the abort signal handler won't do it for us
70 if (!g_assert_context->_conf->fatal_signal_handlers) {
71 g_assert_context->_log->dump_recent();
72 }
73 }
74
75 abort();
76 }
77
78 [[gnu::cold]] void __ceph_assert_fail(const assert_data &ctx)
79 {
80 __ceph_assert_fail(ctx.assertion, ctx.file, ctx.line, ctx.function);
81 }
82
83 class BufAppender {
84 public:
85 BufAppender(char* buf, int size) : bufptr(buf), remaining(size) {}
86
87 void printf(const char * format, ...) {
88 va_list args;
89 va_start(args, format);
90 this->vprintf(format, args);
91 va_end(args);
92 }
93
94 void vprintf(const char * format, va_list args) {
95 int n = vsnprintf(bufptr, remaining, format, args);
96 if (n >= 0) {
97 if (n < remaining) {
98 remaining -= n;
99 bufptr += n;
100 } else {
101 remaining = 0;
102 }
103 }
104 }
105
106 private:
107 char* bufptr;
108 int remaining;
109 };
110
111
112 [[gnu::cold]] void __ceph_assertf_fail(const char *assertion,
113 const char *file, int line,
114 const char *func, const char* msg,
115 ...)
116 {
117 ostringstream tss;
118 tss << ceph_clock_now();
119
120 g_assert_condition = assertion;
121 g_assert_file = file;
122 g_assert_line = line;
123 g_assert_func = func;
124 g_assert_thread = (unsigned long long)pthread_self();
125 ceph_pthread_getname(pthread_self(), g_assert_thread_name,
126 sizeof(g_assert_thread_name));
127
128 BufAppender ba(g_assert_msg, sizeof(g_assert_msg));
129 BackTrace *bt = new ClibBackTrace(1);
130 ba.printf("%s: In function '%s' thread %llx time %s\n"
131 "%s: %d: FAILED ceph_assert(%s)\n",
132 file, func, (unsigned long long)pthread_self(), tss.str().c_str(),
133 file, line, assertion);
134 ba.printf("Assertion details: ");
135 va_list args;
136 va_start(args, msg);
137 ba.vprintf(msg, args);
138 va_end(args);
139 ba.printf("\n");
140 dout_emergency(g_assert_msg);
141
142 // TODO: get rid of this memory allocation.
143 ostringstream oss;
144 oss << *bt;
145 dout_emergency(oss.str());
146
147 if (g_assert_context) {
148 lderr(g_assert_context) << g_assert_msg << std::endl;
149 *_dout << oss.str() << dendl;
150
151 // dump recent only if the abort signal handler won't do it for us
152 if (!g_assert_context->_conf->fatal_signal_handlers) {
153 g_assert_context->_log->dump_recent();
154 }
155 }
156
157 abort();
158 }
159
160 [[gnu::cold]] void __ceph_abort(const char *file, int line,
161 const char *func, const std::string& msg)
162 {
163 ostringstream tss;
164 tss << ceph_clock_now();
165
166 g_assert_condition = "abort";
167 g_assert_file = file;
168 g_assert_line = line;
169 g_assert_func = func;
170 g_assert_thread = (unsigned long long)pthread_self();
171 ceph_pthread_getname(pthread_self(), g_assert_thread_name,
172 sizeof(g_assert_thread_name));
173
174 BackTrace *bt = new ClibBackTrace(1);
175 snprintf(g_assert_msg, sizeof(g_assert_msg),
176 "%s: In function '%s' thread %llx time %s\n"
177 "%s: %d: ceph_abort_msg(\"%s\")\n", file, func,
178 (unsigned long long)pthread_self(),
179 tss.str().c_str(), file, line,
180 msg.c_str());
181 dout_emergency(g_assert_msg);
182
183 // TODO: get rid of this memory allocation.
184 ostringstream oss;
185 oss << *bt;
186 dout_emergency(oss.str());
187
188 if (g_assert_context) {
189 lderr(g_assert_context) << g_assert_msg << std::endl;
190 *_dout << oss.str() << dendl;
191
192 // dump recent only if the abort signal handler won't do it for us
193 if (!g_assert_context->_conf->fatal_signal_handlers) {
194 g_assert_context->_log->dump_recent();
195 }
196 }
197
198 abort();
199 }
200
201 [[gnu::cold]] void __ceph_abortf(const char *file, int line,
202 const char *func, const char* msg,
203 ...)
204 {
205 ostringstream tss;
206 tss << ceph_clock_now();
207
208 g_assert_condition = "abort";
209 g_assert_file = file;
210 g_assert_line = line;
211 g_assert_func = func;
212 g_assert_thread = (unsigned long long)pthread_self();
213 ceph_pthread_getname(pthread_self(), g_assert_thread_name,
214 sizeof(g_assert_thread_name));
215
216 BufAppender ba(g_assert_msg, sizeof(g_assert_msg));
217 BackTrace *bt = new ClibBackTrace(1);
218 ba.printf("%s: In function '%s' thread %llx time %s\n"
219 "%s: %d: abort()\n",
220 file, func, (unsigned long long)pthread_self(), tss.str().c_str(),
221 file, line);
222 ba.printf("Abort details: ");
223 va_list args;
224 va_start(args, msg);
225 ba.vprintf(msg, args);
226 va_end(args);
227 ba.printf("\n");
228 dout_emergency(g_assert_msg);
229
230 // TODO: get rid of this memory allocation.
231 ostringstream oss;
232 oss << *bt;
233 dout_emergency(oss.str());
234
235 if (g_assert_context) {
236 lderr(g_assert_context) << g_assert_msg << std::endl;
237 *_dout << oss.str() << dendl;
238
239 // dump recent only if the abort signal handler won't do it for us
240 if (!g_assert_context->_conf->fatal_signal_handlers) {
241 g_assert_context->_log->dump_recent();
242 }
243 }
244
245 abort();
246 }
247
248 [[gnu::cold]] void __ceph_assert_warn(const char *assertion,
249 const char *file,
250 int line, const char *func)
251 {
252 char buf[8096];
253 snprintf(buf, sizeof(buf),
254 "WARNING: ceph_assert(%s) at: %s: %d: %s()\n",
255 assertion, file, line, func);
256 dout_emergency(buf);
257 }
258 }