Mercurial > hg > sv-dependency-builds
comparison osx/include/kj/exception.h @ 49:3ab5a40c4e3b
Add Capnp and KJ builds for OSX
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Tue, 25 Oct 2016 14:48:23 +0100 |
parents | |
children | 0994c39f1e94 |
comparison
equal
deleted
inserted
replaced
48:9530b331f8c1 | 49:3ab5a40c4e3b |
---|---|
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors | |
2 // Licensed under the MIT License: | |
3 // | |
4 // Permission is hereby granted, free of charge, to any person obtaining a copy | |
5 // of this software and associated documentation files (the "Software"), to deal | |
6 // in the Software without restriction, including without limitation the rights | |
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 // copies of the Software, and to permit persons to whom the Software is | |
9 // furnished to do so, subject to the following conditions: | |
10 // | |
11 // The above copyright notice and this permission notice shall be included in | |
12 // all copies or substantial portions of the Software. | |
13 // | |
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
20 // THE SOFTWARE. | |
21 | |
22 #ifndef KJ_EXCEPTION_H_ | |
23 #define KJ_EXCEPTION_H_ | |
24 | |
25 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS | |
26 #pragma GCC system_header | |
27 #endif | |
28 | |
29 #include "memory.h" | |
30 #include "array.h" | |
31 #include "string.h" | |
32 | |
33 namespace kj { | |
34 | |
35 class ExceptionImpl; | |
36 | |
37 class Exception { | |
38 // Exception thrown in case of fatal errors. | |
39 // | |
40 // Actually, a subclass of this which also implements std::exception will be thrown, but we hide | |
41 // that fact from the interface to avoid #including <exception>. | |
42 | |
43 public: | |
44 enum class Type { | |
45 // What kind of failure? | |
46 | |
47 FAILED = 0, | |
48 // Something went wrong. This is the usual error type. KJ_ASSERT and KJ_REQUIRE throw this | |
49 // error type. | |
50 | |
51 OVERLOADED = 1, | |
52 // The call failed because of a temporary lack of resources. This could be space resources | |
53 // (out of memory, out of disk space) or time resources (request queue overflow, operation | |
54 // timed out). | |
55 // | |
56 // The operation might work if tried again, but it should NOT be repeated immediately as this | |
57 // may simply exacerbate the problem. | |
58 | |
59 DISCONNECTED = 2, | |
60 // The call required communication over a connection that has been lost. The callee will need | |
61 // to re-establish connections and try again. | |
62 | |
63 UNIMPLEMENTED = 3 | |
64 // The requested method is not implemented. The caller may wish to revert to a fallback | |
65 // approach based on other methods. | |
66 | |
67 // IF YOU ADD A NEW VALUE: | |
68 // - Update the stringifier. | |
69 // - Update Cap'n Proto's RPC protocol's Exception.Type enum. | |
70 }; | |
71 | |
72 Exception(Type type, const char* file, int line, String description = nullptr) noexcept; | |
73 Exception(Type type, String file, int line, String description = nullptr) noexcept; | |
74 Exception(const Exception& other) noexcept; | |
75 Exception(Exception&& other) = default; | |
76 ~Exception() noexcept; | |
77 | |
78 const char* getFile() const { return file; } | |
79 int getLine() const { return line; } | |
80 Type getType() const { return type; } | |
81 StringPtr getDescription() const { return description; } | |
82 ArrayPtr<void* const> getStackTrace() const { return arrayPtr(trace, traceCount); } | |
83 | |
84 struct Context { | |
85 // Describes a bit about what was going on when the exception was thrown. | |
86 | |
87 const char* file; | |
88 int line; | |
89 String description; | |
90 Maybe<Own<Context>> next; | |
91 | |
92 Context(const char* file, int line, String&& description, Maybe<Own<Context>>&& next) | |
93 : file(file), line(line), description(mv(description)), next(mv(next)) {} | |
94 Context(const Context& other) noexcept; | |
95 }; | |
96 | |
97 inline Maybe<const Context&> getContext() const { | |
98 KJ_IF_MAYBE(c, context) { | |
99 return **c; | |
100 } else { | |
101 return nullptr; | |
102 } | |
103 } | |
104 | |
105 void wrapContext(const char* file, int line, String&& description); | |
106 // Wraps the context in a new node. This becomes the head node returned by getContext() -- it | |
107 // is expected that contexts will be added in reverse order as the exception passes up the | |
108 // callback stack. | |
109 | |
110 KJ_NOINLINE void extendTrace(uint ignoreCount); | |
111 // Append the current stack trace to the exception's trace, ignoring the first `ignoreCount` | |
112 // frames (see `getStackTrace()` for discussion of `ignoreCount`). | |
113 | |
114 KJ_NOINLINE void truncateCommonTrace(); | |
115 // Remove the part of the stack trace which the exception shares with the caller of this method. | |
116 // This is used by the async library to remove the async infrastructure from the stack trace | |
117 // before replacing it with the async trace. | |
118 | |
119 void addTrace(void* ptr); | |
120 // Append the given pointer to the backtrace, if it is not already full. This is used by the | |
121 // async library to trace through the promise chain that led to the exception. | |
122 | |
123 private: | |
124 String ownFile; | |
125 const char* file; | |
126 int line; | |
127 Type type; | |
128 String description; | |
129 Maybe<Own<Context>> context; | |
130 void* trace[32]; | |
131 uint traceCount; | |
132 | |
133 friend class ExceptionImpl; | |
134 }; | |
135 | |
136 StringPtr KJ_STRINGIFY(Exception::Type type); | |
137 String KJ_STRINGIFY(const Exception& e); | |
138 | |
139 // ======================================================================================= | |
140 | |
141 enum class LogSeverity { | |
142 INFO, // Information describing what the code is up to, which users may request to see | |
143 // with a flag like `--verbose`. Does not indicate a problem. Not printed by | |
144 // default; you must call setLogLevel(INFO) to enable. | |
145 WARNING, // A problem was detected but execution can continue with correct output. | |
146 ERROR, // Something is wrong, but execution can continue with garbage output. | |
147 FATAL, // Something went wrong, and execution cannot continue. | |
148 DBG // Temporary debug logging. See KJ_DBG. | |
149 | |
150 // Make sure to update the stringifier if you add a new severity level. | |
151 }; | |
152 | |
153 StringPtr KJ_STRINGIFY(LogSeverity severity); | |
154 | |
155 class ExceptionCallback { | |
156 // If you don't like C++ exceptions, you may implement and register an ExceptionCallback in order | |
157 // to perform your own exception handling. For example, a reasonable thing to do is to have | |
158 // onRecoverableException() set a flag indicating that an error occurred, and then check for that | |
159 // flag just before writing to storage and/or returning results to the user. If the flag is set, | |
160 // discard whatever you have and return an error instead. | |
161 // | |
162 // ExceptionCallbacks must always be allocated on the stack. When an exception is thrown, the | |
163 // newest ExceptionCallback on the calling thread's stack is called. The default implementation | |
164 // of each method calls the next-oldest ExceptionCallback for that thread. Thus the callbacks | |
165 // behave a lot like try/catch blocks, except that they are called before any stack unwinding | |
166 // occurs. | |
167 | |
168 public: | |
169 ExceptionCallback(); | |
170 KJ_DISALLOW_COPY(ExceptionCallback); | |
171 virtual ~ExceptionCallback() noexcept(false); | |
172 | |
173 virtual void onRecoverableException(Exception&& exception); | |
174 // Called when an exception has been raised, but the calling code has the ability to continue by | |
175 // producing garbage output. This method _should_ throw the exception, but is allowed to simply | |
176 // return if garbage output is acceptable. | |
177 // | |
178 // The global default implementation throws an exception unless the library was compiled with | |
179 // -fno-exceptions, in which case it logs an error and returns. | |
180 | |
181 virtual void onFatalException(Exception&& exception); | |
182 // Called when an exception has been raised and the calling code cannot continue. If this method | |
183 // returns normally, abort() will be called. The method must throw the exception to avoid | |
184 // aborting. | |
185 // | |
186 // The global default implementation throws an exception unless the library was compiled with | |
187 // -fno-exceptions, in which case it logs an error and returns. | |
188 | |
189 virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth, | |
190 String&& text); | |
191 // Called when something wants to log some debug text. `contextDepth` indicates how many levels | |
192 // of context the message passed through; it may make sense to indent the message accordingly. | |
193 // | |
194 // The global default implementation writes the text to stderr. | |
195 | |
196 protected: | |
197 ExceptionCallback& next; | |
198 | |
199 private: | |
200 ExceptionCallback(ExceptionCallback& next); | |
201 | |
202 class RootExceptionCallback; | |
203 friend ExceptionCallback& getExceptionCallback(); | |
204 }; | |
205 | |
206 ExceptionCallback& getExceptionCallback(); | |
207 // Returns the current exception callback. | |
208 | |
209 KJ_NOINLINE KJ_NORETURN(void throwFatalException(kj::Exception&& exception, uint ignoreCount = 0)); | |
210 // Invoke the exception callback to throw the given fatal exception. If the exception callback | |
211 // returns, abort. | |
212 | |
213 KJ_NOINLINE void throwRecoverableException(kj::Exception&& exception, uint ignoreCount = 0); | |
214 // Invoke the exception callback to throw the given recoverable exception. If the exception | |
215 // callback returns, return normally. | |
216 | |
217 // ======================================================================================= | |
218 | |
219 namespace _ { class Runnable; } | |
220 | |
221 template <typename Func> | |
222 Maybe<Exception> runCatchingExceptions(Func&& func) noexcept; | |
223 // Executes the given function (usually, a lambda returning nothing) catching any exceptions that | |
224 // are thrown. Returns the Exception if there was one, or null if the operation completed normally. | |
225 // Non-KJ exceptions will be wrapped. | |
226 // | |
227 // If exception are disabled (e.g. with -fno-exceptions), this will still detect whether any | |
228 // recoverable exceptions occurred while running the function and will return those. | |
229 | |
230 class UnwindDetector { | |
231 // Utility for detecting when a destructor is called due to unwind. Useful for: | |
232 // - Avoiding throwing exceptions in this case, which would terminate the program. | |
233 // - Detecting whether to commit or roll back a transaction. | |
234 // | |
235 // To use this class, either inherit privately from it or declare it as a member. The detector | |
236 // works by comparing the exception state against that when the constructor was called, so for | |
237 // an object that was actually constructed during exception unwind, it will behave as if no | |
238 // unwind is taking place. This is usually the desired behavior. | |
239 | |
240 public: | |
241 UnwindDetector(); | |
242 | |
243 bool isUnwinding() const; | |
244 // Returns true if the current thread is in a stack unwind that it wasn't in at the time the | |
245 // object was constructed. | |
246 | |
247 template <typename Func> | |
248 void catchExceptionsIfUnwinding(Func&& func) const; | |
249 // Runs the given function (e.g., a lambda). If isUnwinding() is true, any exceptions are | |
250 // caught and treated as secondary faults, meaning they are considered to be side-effects of the | |
251 // exception that is unwinding the stack. Otherwise, exceptions are passed through normally. | |
252 | |
253 private: | |
254 uint uncaughtCount; | |
255 | |
256 void catchExceptionsAsSecondaryFaults(_::Runnable& runnable) const; | |
257 }; | |
258 | |
259 namespace _ { // private | |
260 | |
261 class Runnable { | |
262 public: | |
263 virtual void run() = 0; | |
264 }; | |
265 | |
266 template <typename Func> | |
267 class RunnableImpl: public Runnable { | |
268 public: | |
269 RunnableImpl(Func&& func): func(kj::mv(func)) {} | |
270 void run() override { | |
271 func(); | |
272 } | |
273 private: | |
274 Func func; | |
275 }; | |
276 | |
277 Maybe<Exception> runCatchingExceptions(Runnable& runnable) noexcept; | |
278 | |
279 } // namespace _ (private) | |
280 | |
281 template <typename Func> | |
282 Maybe<Exception> runCatchingExceptions(Func&& func) noexcept { | |
283 _::RunnableImpl<Decay<Func>> runnable(kj::fwd<Func>(func)); | |
284 return _::runCatchingExceptions(runnable); | |
285 } | |
286 | |
287 template <typename Func> | |
288 void UnwindDetector::catchExceptionsIfUnwinding(Func&& func) const { | |
289 if (isUnwinding()) { | |
290 _::RunnableImpl<Decay<Func>> runnable(kj::fwd<Func>(func)); | |
291 catchExceptionsAsSecondaryFaults(runnable); | |
292 } else { | |
293 func(); | |
294 } | |
295 } | |
296 | |
297 #define KJ_ON_SCOPE_SUCCESS(code) \ | |
298 ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \ | |
299 KJ_DEFER(if (!KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; }) | |
300 // Runs `code` if the current scope is exited normally (not due to an exception). | |
301 | |
302 #define KJ_ON_SCOPE_FAILURE(code) \ | |
303 ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \ | |
304 KJ_DEFER(if (KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; }) | |
305 // Runs `code` if the current scope is exited due to an exception. | |
306 | |
307 // ======================================================================================= | |
308 | |
309 KJ_NOINLINE ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount); | |
310 // Attempt to get the current stack trace, returning a list of pointers to instructions. The | |
311 // returned array is a slice of `space`. Provide a larger `space` to get a deeper stack trace. | |
312 // If the platform doesn't support stack traces, returns an empty array. | |
313 // | |
314 // `ignoreCount` items will be truncated from the front of the trace. This is useful for chopping | |
315 // off a prefix of the trace that is uninteresting to the developer because it's just locations | |
316 // inside the debug infrastructure that is requesting the trace. Be careful to mark functions as | |
317 // KJ_NOINLINE if you intend to count them in `ignoreCount`. Note that, unfortunately, the | |
318 // ignored entries will still waste space in the `space` array (and the returned array's `begin()` | |
319 // is never exactly equal to `space.begin()` due to this effect, even if `ignoreCount` is zero | |
320 // since `getStackTrace()` needs to ignore its own internal frames). | |
321 | |
322 String stringifyStackTrace(ArrayPtr<void* const>); | |
323 // Convert the stack trace to a string with file names and line numbers. This may involve executing | |
324 // suprocesses. | |
325 | |
326 void printStackTraceOnCrash(); | |
327 // Registers signal handlers on common "crash" signals like SIGSEGV that will (attempt to) print | |
328 // a stack trace. You should call this as early as possible on program startup. Programs using | |
329 // KJ_MAIN get this automatically. | |
330 | |
331 kj::StringPtr trimSourceFilename(kj::StringPtr filename); | |
332 // Given a source code file name, trim off noisy prefixes like "src/" or | |
333 // "/ekam-provider/canonical/". | |
334 | |
335 } // namespace kj | |
336 | |
337 #endif // KJ_EXCEPTION_H_ |