1 /** @file
2 
3   Generic interface which enables any event or async activity to be cancelled
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  */
24 
25 #pragma once
26 
27 #include "tscore/ink_platform.h"
28 #include "I_Thread.h"
29 #include "I_Continuation.h"
30 
31 /**
32   Represents an operation initiated on a Processor.
33 
34   The Action class is an abstract representation of an operation
35   being executed by some Processor. A reference to an Action object
36   allows you to cancel an ongoing asynchronous operation before it
37   completes. This means that the Continuation specified for the
38   operation will not be called back.
39 
40   Actions or classes derived from Action are the typical return
41   type of methods exposed by Processors in the Event System and
42   throughout the IO Core libraries.
43 
44   The canceller of an action must be the state machine that will
45   be called back by the task and that state machine's lock must be
46   held while calling cancel.
47 
48   Processor implementers:
49 
50   You must ensure that no events are sent to the state machine after
51   the operation has been cancelled appropriately.
52 
53   Returning an Action:
54 
55   Processor functions that are asynchronous must return actions to
56   allow the calling state machine to cancel the task before completion.
57   Because some processor functions are reentrant, they can call
58   back the state machine before the returning from the call that
59   creates the actions. To handle this case, special values are
60   returned in place of an action to indicate to the state machine
61   that the action is already completed.
62 
63     - @b ACTION_RESULT_DONE The processor has completed the task
64       and called the state machine back inline.
65     - @b ACTION_RESULT_INLINE Not currently used.
66     - @b ACTION_RESULT_IO_ERROR Not currently used.
67 
68   To make matters more complicated, it's possible if the result is
69   ACTION_RESULT_DONE that state machine deallocated itself on the
70   reentrant callback. Thus, state machine implementers MUST either
71   use a scheme to never deallocate their machines on reentrant
72   callbacks OR immediately check the returned action when creating
73   an asynchronous task and if it is ACTION_RESULT_DONE neither read
74   nor write any state variables. With either method, it's imperative
75   that the returned action always be checked for special values and
76   the value handled accordingly.
77 
78   Allocation policy:
79 
80   Actions are allocated by the Processor performing the actions.
81   It is the processor's responsibility to handle deallocation once
82   the action is complete or cancelled. A state machine MUST NOT
83   access an action once the operation that returned the Action has
84   completed or it has cancelled the Action.
85 
86   Action pointer sanity checks must also check whether the lowest
87   bit of the pointer is 1. If it is 1, then the value must not be
88   treated as a pointer, and should be used as one of the values
89   defined below (e.g. ACTION_RESULT_DONE).
90 
91 */
92 class Action
93 {
94 public:
95   /**
96     Continuation that initiated this action.
97 
98     The reference to the initiating continuation is only used to
99     verify that the action is being cancelled by the correct
100     continuation.  This field should not be accessed or modified
101     directly by the state machine.
102 
103   */
104   Continuation *continuation = nullptr;
105 
106   /**
107     Reference to the Continuation's lock.
108 
109     Keeps a reference to the Continuation's lock to preserve the
110     access to the cancelled field valid even when the state machine
111     has been deallocated. This field should not be accessed or
112     modified directly by the state machine.
113 
114   */
115   Ptr<ProxyMutex> mutex;
116 
117   /**
118     Internal flag used to indicate whether the action has been
119     cancelled.
120 
121     This flag is set after a call to cancel or cancel_action and
122     it should not be accessed or modified directly by the state
123     machine.
124 
125   */
126   int cancelled = false;
127 
128   /**
129     Cancels the asynchronous operation represented by this action.
130 
131     This method is called by state machines willing to cancel an
132     ongoing asynchronous operation. Classes derived from Action may
133     perform additional steps before flagging this action as cancelled.
134     There are certain rules that must be followed in order to cancel
135     an action (see the Remarks section).
136 
137     @param c Continuation associated with this Action.
138 
139   */
140   virtual void
141   cancel(Continuation *c = nullptr)
142   {
143     ink_assert(!c || c == continuation);
144 #ifdef DEBUG
145     ink_assert(!cancelled);
146     cancelled = true;
147 #else
148     if (!cancelled) {
149       cancelled = true;
150     }
151 #endif
152   }
153 
154   /**
155     Cancels the asynchronous operation represented by this action.
156 
157     This method is called by state machines willing to cancel an
158     ongoing asynchronous operation. There are certain rules that
159     must be followed in order to cancel an action (see the Remarks
160     section).
161 
162     @param c Continuation associated with this Action.
163 
164   */
165   void
166   cancel_action(Continuation *c = nullptr)
167   {
168     ink_assert(!c || c == continuation);
169 #ifdef DEBUG
170     ink_assert(!cancelled);
171     cancelled = true;
172 #else
173     if (!cancelled) {
174       cancelled = true;
175     }
176 #endif
177   }
178 
179   Continuation *
180   operator=(Continuation *acont)
181   {
182     continuation = acont;
183     if (acont) {
184       mutex = acont->mutex;
185     } else {
186       mutex = nullptr;
187     }
188     return acont;
189   }
190 
191   /**
192     Constructor of the Action object. Processor implementers are
193     responsible for associating this action with the proper
194     Continuation.
195 
196   */
Action()197   Action() {}
~Action()198   virtual ~Action() {}
199 };
200 
201 #define ACTION_RESULT_DONE MAKE_ACTION_RESULT(1)
202 #define ACTION_IO_ERROR MAKE_ACTION_RESULT(2)
203 
204 // Use these classes by
205 // #define ACTION_RESULT_HOST_DB_OFFLINE
206 //   MAKE_ACTION_RESULT(ACTION_RESULT_HOST_DB_BASE + 0)
207 
208 #define MAKE_ACTION_RESULT(_x) (Action *)(((uintptr_t)((_x << 1) + 1)))
209