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 class force_VFPT_to_top
67 {
68 public:
69   virtual ~force_VFPT_to_top() {}
70 };
71 
72 /**
73   Base class for all state machines to receive notification of
74   events.
75 
76   The Continuation class represents the main abstraction mechanism
77   used throughout the IO Core Event System to communicate its users
78   the occurrence of an event. A Continuation is a lightweight data
79   structure that implements a single method with which the user is
80   called back.
81 
82   Continuations are typically subclassed in order to implement
83   event-driven state machines. By including additional state and
84   methods, continuations can combine state with control flow, and
85   they are generally used to support split-phase, event-driven
86   control flow.
87 
88   Given the multithreaded nature of the Event System, every
89   continuation carries a reference to a ProxyMutex object to protect
90   its state and ensure atomic operations. This ProxyMutex object
91   must be allocated by continuation-derived classes or by clients
92   of the IO Core Event System and it is required as a parameter to
93   the Continuation's class constructor.
94 
95 */
96 
97 class Continuation : private force_VFPT_to_top
98 {
99 public:
100   /**
101     The current continuation handler function.
102 
103     The current handler should not be set directly. In order to
104     change it, first acquire the Continuation's lock and then use
105     the SET_HANDLER macro which takes care of the type casting
106     issues.
107 
108   */
109   ContinuationHandler handler = nullptr;
110 
111 #ifdef DEBUG
112   const char *handler_name = nullptr;
113 #endif
114 
115   /**
116     The Continuation's lock.
117 
118     A reference counted pointer to the Continuation's lock. This
119     lock is initialized in the constructor and should not be set
120     directly.
121 
122     TODO:  make this private.
123 
124   */
125   Ptr<ProxyMutex> mutex;
126 
127   ProxyMutex *
128   getMutex() const
129   {
130     return mutex.get();
131   }
132 
133   /**
134     Link to other continuations.
135 
136     A doubly-linked element to allow Lists of Continuations to be
137     assembled.
138 
139   */
140   LINK(Continuation, link);
141 
142   /**
143     Contains values for debug_override and future flags that
144     needs to be thread local while this continuation is running
145   */
146   ContFlags control_flags;
147 
148   EThread *thread_affinity = nullptr;
149 
150   bool
151   setThreadAffinity(EThread *ethread)
152   {
153     if (ethread != nullptr) {
154       thread_affinity = ethread;
155       return true;
156     }
157     return false;
158   }
159 
160   EThread *
161   getThreadAffinity()
162   {
163     return thread_affinity;
164   }
165 
166   void
167   clearThreadAffinity()
168   {
169     thread_affinity = nullptr;
170   }
171 
172   /**
173     Receives the event code and data for an Event.
174 
175     This function receives the event code and data for an event and
176     forwards them to the current continuation handler. The processor
177     calling back the continuation is responsible for acquiring its
178     lock.  If the lock is present and not held, this method will assert.
179 
180     @param event Event code to be passed at callback (Processor specific).
181     @param data General purpose data related to the event code (Processor specific).
182     @return State machine and processor specific return code.
183 
184   */
185   TS_INLINE int
186   handleEvent(int event = CONTINUATION_EVENT_NONE, void *data = nullptr)
187   {
188     // If there is a lock, we must be holding it on entry
189     ink_release_assert(!mutex || mutex->thread_holding == this_ethread());
190     return (this->*handler)(event, data);
191   }
192 
193 protected:
194   /**
195     Constructor of the Continuation object. It should not be used
196     directly. Instead create an object of a derived type.
197 
198     @param amutex Lock to be set for this Continuation.
199 
200   */
201   Continuation(ProxyMutex *amutex = nullptr);
202   Continuation(Ptr<ProxyMutex> &amutex);
203 };
204 
205 /**
206   Sets the Continuation's handler. The preferred mechanism for
207   setting the Continuation's handler.
208 
209   @param _h Pointer to the function used to callback with events.
210 
211 */
212 #ifdef DEBUG
213 #define SET_HANDLER(_h) (handler = ((ContinuationHandler)_h), handler_name = #_h)
214 #else
215 #define SET_HANDLER(_h) (handler = ((ContinuationHandler)_h))
216 #endif
217 
218 /**
219   Sets a Continuation's handler.
220 
221   The preferred mechanism for setting the Continuation's handler.
222 
223   @param _c Pointer to a Continuation whose handler is being set.
224   @param _h Pointer to the function used to callback with events.
225 
226 */
227 #ifdef DEBUG
228 #define SET_CONTINUATION_HANDLER(_c, _h) (_c->handler = ((ContinuationHandler)_h), _c->handler_name = #_h)
229 #else
230 #define SET_CONTINUATION_HANDLER(_c, _h) (_c->handler = ((ContinuationHandler)_h))
231 #endif
232 
233 inline Continuation::Continuation(Ptr<ProxyMutex> &amutex) : mutex(amutex)
234 {
235   // Pick up the control flags from the creating thread
236   this->control_flags.set_flags(get_cont_flags().get_flags());
237 }
238 
239 inline Continuation::Continuation(ProxyMutex *amutex) : mutex(amutex)
240 {
241   // Pick up the control flags from the creating thread
242   this->control_flags.set_flags(get_cont_flags().get_flags());
243 }
244