1 /** @file
2
3 A brief file description
4
5 @section license License
6
7 Licensed to the Apache Software Foundation (ASF) under one
8 or more contributor license agreements. See the NOTICE file
9 distributed with this work for additional information
10 regarding copyright ownership. The ASF licenses this file
11 to you under the Apache License, Version 2.0 (the
12 "License"); you may not use this file except in compliance
13 with the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22
23 @section details Details
24
25 Continuations have a handleEvent() method to invoke them. Users
26 can determine the behavior of a Continuation by supplying a
27 "ContinuationHandler" (member function name) which is invoked
28 when events arrive. This function can be changed with the
29 "setHandler" method.
30
31 Continuations can be subclassed to add additional state and
32 methods.
33
34 */
35
36 #pragma once
37
38 #include "tscore/ink_platform.h"
39 #include "tscore/List.h"
40 #include "I_Lock.h"
41 #include "tscore/ContFlags.h"
42
43 class Continuation;
44 class ContinuationQueue;
45 class Processor;
46 class ProxyMutex;
47 class EThread;
48 class Event;
49
50 extern EThread *this_ethread();
51 extern EThread *this_event_thread();
52
53 //////////////////////////////////////////////////////////////////////////////
54 //
55 // Constants and Type Definitions
56 //
57 //////////////////////////////////////////////////////////////////////////////
58
59 #define CONTINUATION_EVENT_NONE 0
60
61 #define CONTINUATION_DONE 0
62 #define CONTINUATION_CONT 1
63
64 typedef int (Continuation::*ContinuationHandler)(int event, void *data);
65
66 // Convert event handler pointer fp to type ContinuationHandler, but with a compiler error if class C is not
67 // derived from the class Continuation.
68 //
69 template <class C, typename T>
70 constexpr ContinuationHandler
continuation_handler_void_ptr(int (C::* fp)(int,T *))71 continuation_handler_void_ptr(int (C::*fp)(int, T *))
72 {
73 auto fp2 = reinterpret_cast<int (C::*)(int, void *)>(fp);
74 return static_cast<ContinuationHandler>(fp2);
75 }
76
77 // Overload for nullptr.
78 //
continuation_handler_void_ptr(std::nullptr_t)79 constexpr ContinuationHandler continuation_handler_void_ptr(std::nullptr_t)
80 {
81 #undef X
82 #if !defined(__GNUC__)
83 #define X 1
84 #else
85 #define X (__GNUC__ > 7)
86 #endif
87 #if X
88 static_assert(!static_cast<ContinuationHandler>(nullptr));
89 #endif
90 #undef X
91
92 return static_cast<ContinuationHandler>(nullptr);
93 }
94
95 class force_VFPT_to_top
96 {
97 public:
~force_VFPT_to_top()98 virtual ~force_VFPT_to_top() {}
99 };
100
101 /**
102 Base class for all state machines to receive notification of
103 events.
104
105 The Continuation class represents the main abstraction mechanism
106 used throughout the IO Core Event System to communicate its users
107 the occurrence of an event. A Continuation is a lightweight data
108 structure that implements a single method with which the user is
109 called back.
110
111 Continuations are typically subclassed in order to implement
112 event-driven state machines. By including additional state and
113 methods, continuations can combine state with control flow, and
114 they are generally used to support split-phase, event-driven
115 control flow.
116
117 Given the multithreaded nature of the Event System, every
118 continuation carries a reference to a ProxyMutex object to protect
119 its state and ensure atomic operations. This ProxyMutex object
120 must be allocated by continuation-derived classes or by clients
121 of the IO Core Event System and it is required as a parameter to
122 the Continuation's class constructor.
123
124 */
125
126 class Continuation : private force_VFPT_to_top
127 {
128 public:
129 /**
130 The current continuation handler function.
131
132 The current handler should not be set directly. In order to
133 change it, first acquire the Continuation's lock and then use
134 the SET_HANDLER macro which takes care of the type casting
135 issues.
136
137 */
138 ContinuationHandler handler = nullptr;
139
140 #ifdef DEBUG
141 const char *handler_name = nullptr;
142 #endif
143
144 /**
145 The Continuation's lock.
146
147 A reference counted pointer to the Continuation's lock. This
148 lock is initialized in the constructor and should not be set
149 directly.
150
151 TODO: make this private.
152
153 */
154 Ptr<ProxyMutex> mutex;
155
156 ProxyMutex *
getMutex()157 getMutex() const
158 {
159 return mutex.get();
160 }
161
162 /**
163 Link to other continuations.
164
165 A doubly-linked element to allow Lists of Continuations to be
166 assembled.
167
168 */
169 LINK(Continuation, link);
170
171 /**
172 Contains values for debug_override and future flags that
173 needs to be thread local while this continuation is running
174 */
175 ContFlags control_flags;
176
177 EThread *thread_affinity = nullptr;
178
179 bool
setThreadAffinity(EThread * ethread)180 setThreadAffinity(EThread *ethread)
181 {
182 if (ethread != nullptr) {
183 thread_affinity = ethread;
184 return true;
185 }
186 return false;
187 }
188
189 EThread *
getThreadAffinity()190 getThreadAffinity()
191 {
192 return thread_affinity;
193 }
194
195 void
clearThreadAffinity()196 clearThreadAffinity()
197 {
198 thread_affinity = nullptr;
199 }
200
201 /**
202 Receives the event code and data for an Event.
203
204 This function receives the event code and data for an event and
205 forwards them to the current continuation handler. The processor
206 calling back the continuation is responsible for acquiring its
207 lock. If the lock is present and not held, this method will assert.
208
209 @param event Event code to be passed at callback (Processor specific).
210 @param data General purpose data related to the event code (Processor specific).
211 @return State machine and processor specific return code.
212
213 */
214 TS_INLINE int
215 handleEvent(int event = CONTINUATION_EVENT_NONE, void *data = nullptr)
216 {
217 // If there is a lock, we must be holding it on entry
218 ink_release_assert(!mutex || mutex->thread_holding == this_ethread());
219 return (this->*handler)(event, data);
220 }
221
222 protected:
223 /**
224 Constructor of the Continuation object. It should not be used
225 directly. Instead create an object of a derived type.
226
227 @param amutex Lock to be set for this Continuation.
228
229 */
230 explicit Continuation(ProxyMutex *amutex = nullptr);
231 explicit Continuation(Ptr<ProxyMutex> &amutex);
232 };
233
234 /**
235 Sets the Continuation's handler. The preferred mechanism for
236 setting the Continuation's handler.
237
238 @param _h Pointer to the function used to callback with events.
239
240 */
241 #ifdef DEBUG
242 #define SET_HANDLER(_h) (handler = continuation_handler_void_ptr(_h), handler_name = #_h)
243 #else
244 #define SET_HANDLER(_h) (handler = continuation_handler_void_ptr(_h))
245 #endif
246
247 /**
248 Sets a Continuation's handler.
249
250 The preferred mechanism for setting the Continuation's handler.
251
252 @param _c Pointer to a Continuation whose handler is being set.
253 @param _h Pointer to the function used to callback with events.
254
255 */
256 #ifdef DEBUG
257 #define SET_CONTINUATION_HANDLER(_c, _h) (_c->handler = continuation_handler_void_ptr(_h), _c->handler_name = #_h)
258 #else
259 #define SET_CONTINUATION_HANDLER(_c, _h) (_c->handler = continuation_handler_void_ptr(_h))
260 #endif
261
Continuation(Ptr<ProxyMutex> & amutex)262 inline Continuation::Continuation(Ptr<ProxyMutex> &amutex) : mutex(amutex)
263 {
264 // Pick up the control flags from the creating thread
265 this->control_flags.set_flags(get_cont_flags().get_flags());
266 }
267
Continuation(ProxyMutex * amutex)268 inline Continuation::Continuation(ProxyMutex *amutex) : mutex(amutex)
269 {
270 // Pick up the control flags from the creating thread
271 this->control_flags.set_flags(get_cont_flags().get_flags());
272 }
273