1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 module thrift.util.cancellation; 20 21 import core.atomic; 22 import thrift.base; 23 import thrift.util.awaitable; 24 25 /** 26 * A cancellation request for asynchronous or blocking synchronous operations. 27 * 28 * It is passed to the entity creating an operation, which will usually monitor 29 * it either by polling or by adding event handlers, and cancel the operation 30 * if it is triggered. 31 * 32 * For synchronous operations, this usually means either throwing a 33 * TCancelledException or immediately returning, depending on whether 34 * cancellation is an expected part of the task outcome or not. For 35 * asynchronous operations, cancellation typically entails stopping background 36 * work and cancelling a result future, if not already completed. 37 * 38 * An operation accepting a TCancellation does not need to guarantee that it 39 * will actually be able to react to the cancellation request. 40 */ 41 interface TCancellation { 42 /** 43 * Whether the cancellation request has been triggered. 44 */ 45 bool triggered() const @property; 46 47 /** 48 * Throws a TCancelledException if the cancellation request has already been 49 * triggered. 50 */ 51 void throwIfTriggered() const; 52 53 /** 54 * A TAwaitable that can be used to wait for cancellation triggering. 55 */ 56 TAwaitable triggering() @property; 57 } 58 59 /** 60 * The origin of a cancellation request, which provides a way to actually 61 * trigger it. 62 * 63 * This design allows operations to pass the TCancellation on to sub-tasks, 64 * while making sure that the cancellation can only be triggered by the 65 * »outermost« instance waiting for the result. 66 */ 67 final class TCancellationOrigin : TCancellation { 68 this() { 69 event_ = new TOneshotEvent; 70 } 71 72 /** 73 * Triggers the cancellation request. 74 */ 75 void trigger() { 76 atomicStore(triggered_, true); 77 event_.trigger(); 78 } 79 80 /+override+/ bool triggered() const @property { 81 return atomicLoad(triggered_); 82 } 83 84 /+override+/ void throwIfTriggered() const { 85 if (triggered) throw new TCancelledException; 86 } 87 88 /+override+/ TAwaitable triggering() @property { 89 return event_; 90 } 91 92 private: 93 shared bool triggered_; 94 TOneshotEvent event_; 95 } 96 97 /// 98 class TCancelledException : TException { 99 /// 100 this(string msg = null, string file = __FILE__, size_t line = __LINE__, 101 Throwable next = null 102 ) { 103 super(msg ? msg : "The operation has been cancelled.", file, line, next); 104 } 105 }