]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/assert.cc
import ceph quincy 17.2.6
[ceph.git] / ceph / src / common / assert.cc
CommitLineData
7c673cae
FG
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
11fdf7f2 15#include "include/compat.h"
7c673cae 16#include "common/debug.h"
7c673cae 17
f67539c2
TL
18using std::ostringstream;
19
7c673cae
FG
20namespace ceph {
21 static CephContext *g_assert_context = NULL;
22
11fdf7f2 23 /* If you register an assert context, ceph_assert() will try to lock the dout
7c673cae
FG
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 {
11fdf7f2 34 ceph_assert(!g_assert_context);
7c673cae
FG
35 g_assert_context = cct;
36 }
37
11fdf7f2
TL
38 [[gnu::cold]] void __ceph_assert_fail(const char *assertion,
39 const char *file, int line,
40 const char *func)
7c673cae 41 {
11fdf7f2
TL
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
7c673cae
FG
50 ostringstream tss;
51 tss << ceph_clock_now();
52
11fdf7f2 53 snprintf(g_assert_msg, sizeof(g_assert_msg),
7c673cae 54 "%s: In function '%s' thread %llx time %s\n"
11fdf7f2 55 "%s: %d: FAILED ceph_assert(%s)\n",
7c673cae
FG
56 file, func, (unsigned long long)pthread_self(), tss.str().c_str(),
57 file, line, assertion);
11fdf7f2 58 dout_emergency(g_assert_msg);
7c673cae
FG
59
60 // TODO: get rid of this memory allocation.
61 ostringstream oss;
20effc67 62 oss << ClibBackTrace(1);
7c673cae
FG
63 dout_emergency(oss.str());
64
7c673cae 65 if (g_assert_context) {
11fdf7f2
TL
66 lderr(g_assert_context) << g_assert_msg << std::endl;
67 *_dout << oss.str() << dendl;
7c673cae 68
11fdf7f2
TL
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 }
7c673cae
FG
73 }
74
75 abort();
76 }
77
11fdf7f2 78 [[gnu::cold]] void __ceph_assert_fail(const assert_data &ctx)
7c673cae 79 {
11fdf7f2
TL
80 __ceph_assert_fail(ctx.assertion, ctx.file, ctx.line, ctx.function);
81 }
7c673cae 82
11fdf7f2
TL
83 class BufAppender {
84 public:
85 BufAppender(char* buf, int size) : bufptr(buf), remaining(size) {}
7c673cae 86
11fdf7f2
TL
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 }
7c673cae 93
11fdf7f2
TL
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;
7c673cae
FG
102 }
103 }
11fdf7f2 104 }
7c673cae 105
11fdf7f2
TL
106 private:
107 char* bufptr;
108 int remaining;
109 };
7c673cae 110
11fdf7f2
TL
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));
20effc67 129 BackTrace *bt = new ClibBackTrace(1);
7c673cae 130 ba.printf("%s: In function '%s' thread %llx time %s\n"
11fdf7f2 131 "%s: %d: FAILED ceph_assert(%s)\n",
7c673cae
FG
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");
11fdf7f2 140 dout_emergency(g_assert_msg);
7c673cae
FG
141
142 // TODO: get rid of this memory allocation.
143 ostringstream oss;
144 oss << *bt;
145 dout_emergency(oss.str());
146
11fdf7f2
TL
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,
f67539c2 161 const char *func, const std::string& msg)
11fdf7f2
TL
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
20effc67 174 BackTrace *bt = new ClibBackTrace(1);
11fdf7f2
TL
175 snprintf(g_assert_msg, sizeof(g_assert_msg),
176 "%s: In function '%s' thread %llx time %s\n"
81eedcae
TL
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());
11fdf7f2
TL
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());
7c673cae
FG
187
188 if (g_assert_context) {
11fdf7f2
TL
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));
7c673cae 215
11fdf7f2 216 BufAppender ba(g_assert_msg, sizeof(g_assert_msg));
20effc67 217 BackTrace *bt = new ClibBackTrace(1);
11fdf7f2
TL
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 }
7c673cae
FG
243 }
244
245 abort();
246 }
247
11fdf7f2
TL
248 [[gnu::cold]] void __ceph_assert_warn(const char *assertion,
249 const char *file,
250 int line, const char *func)
7c673cae
FG
251 {
252 char buf[8096];
253 snprintf(buf, sizeof(buf),
11fdf7f2 254 "WARNING: ceph_assert(%s) at: %s: %d: %s()\n",
7c673cae
FG
255 assertion, file, line, func);
256 dout_emergency(buf);
257 }
258}