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