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