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