]> git.ipfire.org Git - thirdparty/squid.git/blob - src/base/CodeContext.h
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / base / CodeContext.h
1 /*
2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS code_contexts for details.
7 */
8
9 #ifndef SQUID_BASE_CODE_CONTEXT_H
10 #define SQUID_BASE_CODE_CONTEXT_H
11
12 #include "base/InstanceId.h"
13 #include "base/RefCount.h"
14
15 #include <iosfwd>
16
17 /// Interface for reporting what Squid code is working on.
18 /// Such reports are usually requested outside creator's call stack.
19 /// They are especially useful for attributing low-level errors to transactions.
20 class CodeContext: public RefCountable
21 {
22 public:
23 typedef RefCount<CodeContext> Pointer;
24
25 /// \returns the known global context or, to indicate unknown context, nil
26 static const Pointer &Current();
27
28 /// forgets the current context, setting it to nil/unknown
29 static void Reset();
30
31 /// changes the current context; nil argument sets it to nil/unknown
32 static void Reset(const Pointer);
33
34 virtual ~CodeContext() {}
35
36 /// \returns a small, permanent ID of the current context
37 /// gists persist forever and are suitable for passing to other SMP workers
38 virtual ScopedId codeContextGist() const = 0;
39
40 /// appends human-friendly context description line(s) to a cache.log record
41 virtual std::ostream &detailCodeContext(std::ostream &os) const = 0;
42
43 private:
44 static void ForgetCurrent();
45 static void Entering(const Pointer &codeCtx);
46 static void Leaving();
47 };
48
49 /// by default, only small context gist is printed
50 inline
51 std::ostream &operator <<(std::ostream &os, const CodeContext &ctx)
52 {
53 return os << ctx.codeContextGist();
54 }
55
56 /* convenience context-reporting wrappers that also reduce linking problems */
57 std::ostream &CurrentCodeContextBrief(std::ostream &os);
58 std::ostream &CurrentCodeContextDetail(std::ostream &os);
59
60 /// Convenience class that automatically restores the current/outer CodeContext
61 /// when leaving the scope of the new-context following/inner code. \see Run().
62 class CodeContextGuard
63 {
64 public:
65 CodeContextGuard(const CodeContext::Pointer &newContext): savedCodeContext(CodeContext::Current()) { CodeContext::Reset(newContext); }
66 ~CodeContextGuard() { CodeContext::Reset(savedCodeContext); }
67
68 // no copying of any kind (for simplicity and to prevent accidental copies)
69 CodeContextGuard(CodeContextGuard &&) = delete;
70
71 CodeContext::Pointer savedCodeContext;
72 };
73
74 /// Executes service `callback` in `callbackContext`. If an exception occurs,
75 /// the callback context is preserved, so that the exception is associated with
76 /// the callback that triggered them (rather than with the service).
77 ///
78 /// Service code running in its own service context should use this function.
79 template <typename Fun>
80 inline void
81 CallBack(const CodeContext::Pointer &callbackContext, Fun &&callback)
82 {
83 // TODO: Consider catching exceptions and letting CodeContext handle them.
84 const auto savedCodeContext(CodeContext::Current());
85 CodeContext::Reset(callbackContext);
86 callback();
87 CodeContext::Reset(savedCodeContext);
88 }
89
90 /// Executes `service` in `serviceContext` but due to automatic caller context
91 /// restoration, service exceptions are associated with the caller that suffered
92 /// from (and/or caused) them (rather than with the service itself).
93 ///
94 /// Service code running in caller's context should use this function to escape
95 /// into service context (e.g., for submitting caller-agnostic requests).
96 template <typename Fun>
97 inline void
98 CallService(const CodeContext::Pointer &serviceContext, Fun &&service)
99 {
100 // TODO: Consider catching exceptions and letting CodeContext handle them.
101 CodeContextGuard guard(serviceContext);
102 service();
103 }
104
105 /// Executes context `creator` in the service context. If an exception occurs,
106 /// the creator context is preserved, so that the exception is associated with
107 /// the creator that triggered them (rather than with the service).
108 ///
109 /// Service code running in its own context should use this function to create
110 /// new code contexts. TODO: Use or, if this pattern is not repeated, remove.
111 template <typename Fun>
112 inline void
113 CallContextCreator(Fun &&creator)
114 {
115 const auto savedCodeContext(CodeContext::Current());
116 creator();
117 CodeContext::Reset(savedCodeContext);
118 }
119
120 #endif
121