1 /****************************************************************************** 2 3 Task extension which makes it possible to store exceptions from a callback 4 so that is gets thrown after the task is resumed. This is useful for 5 providing meaningful stacktraces which point to the origin of the faulty 6 operation rather than to the event loop context. 7 8 Usage example: 9 See the documented unittest of the ExceptionForwarding struct 10 11 Copyright: 12 Copyright (c) 2009-2016 dunnhumby Germany GmbH. 13 All rights reserved. 14 15 License: 16 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 17 Alternatively, this file may be distributed under the terms of the Tango 18 3-Clause BSD License (see LICENSE_BSD.txt for details). 19 20 ******************************************************************************/ 21 22 module ocean.task.extensions.ExceptionForwarding; 23 24 version (unittest) 25 { 26 import ocean.core.Test; 27 import ocean.task.Task; 28 import core.thread; 29 } 30 31 /****************************************************************************** 32 33 Task extension to be used with the `TaskWith` class. 34 35 ******************************************************************************/ 36 37 struct ExceptionForwarding 38 { 39 public Exception to_throw; 40 41 void onResumed ( ) 42 { 43 if (this.to_throw !is null) 44 { 45 // reset the reference so it won't throw again 46 // if the same fiber handles an exception and suspends again 47 auto to_throw = this.to_throw; 48 this.to_throw = null; 49 throw to_throw; 50 } 51 } 52 } 53 54 /// 55 unittest 56 { 57 class ExceptionExternal : Exception 58 { 59 this ( ) 60 { 61 super("external"); 62 } 63 } 64 65 class MyTask : TaskWith!(ExceptionForwarding) 66 { 67 bool caught = false; 68 69 override protected void run ( ) 70 { 71 try 72 { 73 // when the following call to `this.suspend()` exit (== after 74 // resuming by a callback or the scheduler), the stored 75 // exception (if any) will be thrown 76 this.suspend(); 77 } 78 catch (ExceptionExternal e) 79 { 80 caught = true; 81 } 82 } 83 } 84 85 // create a task and assign it to a worker fiber 86 auto task = new MyTask; 87 task.assignTo(new WorkerFiber(10240)); 88 89 // will start the task (which then yields immediately) 90 task.resume(); 91 92 // makes stored exception instance thrown from within the task when 93 // resumed 94 task.extensions.exception_forwarding.to_throw = new ExceptionExternal; 95 task.resume(); 96 test(task.caught); 97 }