1 module libasync.signal; 2 import std.traits; 3 4 import libasync.types; 5 import libasync.events; 6 import core.thread; 7 8 /// Enqueues a signal in the event loop of the AsyncSignal owner's thread, 9 /// which allows a foreign thread to trigger the callback handler safely. 10 shared final class AsyncSignal 11 { 12 private void delegate() m_sgh; 13 nothrow: 14 private: 15 Thread m_owner; 16 EventLoop m_evLoop; 17 fd_t m_evId; 18 19 public: 20 21 this(EventLoop evl) 22 in { 23 assert(evl !is null); 24 } 25 body { 26 m_evLoop = cast(shared) evl; 27 import core.thread : Thread; 28 m_owner = cast(shared) Thread.getThis(); 29 30 version(Posix) { 31 static if (EPOLL) { 32 import core.sys.posix.pthread : pthread_self; 33 m_pthreadId = cast(shared)pthread_self(); 34 } else /* if KQUEUE */ { 35 m_owner_id = cast(shared) g_threadId; 36 } 37 } 38 } 39 40 @property bool hasError() const 41 { 42 return (cast(EventLoop)m_evLoop).status.code != Status.OK; 43 } 44 45 /// Used to diagnose errors when run() or kill() returns false 46 @property StatusInfo status() const { 47 return (cast(EventLoop)m_evLoop).status; 48 } 49 50 /// Human-readable string describing the error 51 @property string error() const { 52 return (cast(EventLoop)m_evLoop).error; 53 } 54 55 /// Registers the signal handler in the event loop 56 bool run(void delegate() del) 57 in { 58 debug assert(Thread.getThis() is cast(Thread)m_owner); 59 } 60 body { 61 62 m_sgh = cast(void delegate()) del; 63 64 m_evId = (cast(EventLoop) m_evLoop).run(this); 65 if (m_evId != fd_t.init) 66 return true; 67 else 68 return false; 69 } 70 71 /// Cleans up underlying resources. This object must be run() again afterwards to be valid 72 bool kill() 73 in { 74 debug assert(Thread.getThis() is cast(Thread)m_owner); 75 } 76 body { 77 return (cast(EventLoop)m_evLoop).kill(cast(shared AsyncSignal) this); 78 } 79 80 /// Triggers the handler in its local thread 81 synchronized bool trigger(EventLoop evl) { 82 return evl.notify(m_evId, this); 83 } 84 85 /// ditto 86 synchronized bool trigger() { 87 return (cast(EventLoop)m_evLoop).notify(m_evId, this); 88 } 89 90 /// Returns the Thread that created this object. 91 synchronized @property Thread owner() const { 92 return cast(Thread) m_owner; 93 } 94 package: 95 96 97 98 version(Posix) mixin EvInfoMixinsShared; 99 100 @property id() const { 101 return m_evId; 102 } 103 104 void handler() { 105 try m_sgh(); 106 catch {} 107 return; 108 } 109 } 110 111 package shared struct SignalHandler { 112 AsyncSignal ctxt; 113 void function(shared AsyncSignal) fct; 114 115 void opCall(shared AsyncSignal ctxt) { 116 assert(ctxt !is null); 117 fct(ctxt); 118 return; 119 } 120 } 121 122 123 /** 124 Determines if the given list of types has any non-immutable and unshared aliasing outside of their object tree. 125 126 The types in particular may only contain plain data, pointers or arrays to immutable or shared data, or references 127 encapsulated in stdx.typecons.Isolated. Values that do not have unshared and unisolated aliasing are safe to be passed 128 between threads. 129 */ 130 template isWeaklyIsolated(T...) 131 { 132 import std.typecons : Rebindable; 133 static if (T.length == 0) enum bool isWeaklyIsolated = true; 134 else static if (T.length > 1) enum bool isWeaklyIsolated = isWeaklyIsolated!(T[0 .. $/2]) && isWeaklyIsolated!(T[$/2 .. $]); 135 else { 136 static if(is(T[0] == immutable)) enum bool isWeaklyIsolated = true; 137 else static if (is(T[0] == shared)) enum bool isWeaklyIsolated = true; 138 else static if (isInstanceOf!(Rebindable, T[0])) enum bool isWeaklyIsolated = isWeaklyIsolated!(typeof(T[0].get())); 139 else static if (is(T[0] : Throwable)) enum bool isWeaklyIsolated = true; // WARNING: this is unsafe, but needed for send/receive! 140 else static if (is(typeof(T[0].__isIsolatedType))) enum bool isWeaklyIsolated = true; 141 else static if (is(typeof(T[0].__isWeakIsolatedType))) enum bool isWeaklyIsolated = true; 142 else static if (is(T[0] == class)) enum bool isWeaklyIsolated = false; 143 else static if (is(T[0] == interface)) enum bool isWeaklyIsolated = false; // can't know if the implementation is isolated 144 else static if (is(T[0] == delegate)) enum bool isWeaklyIsolated = T[0].stringof.endsWith(" shared"); // can't know to what a delegate points - FIXME: use something better than a string comparison 145 else static if (isDynamicArray!(T[0])) enum bool isWeaklyIsolated = is(typeof(T[0].init[0]) == immutable); 146 else static if (isAssociativeArray!(T[0])) enum bool isWeaklyIsolated = false; // TODO: be less strict here 147 else static if (isSomeFunction!(T[0])) enum bool isWeaklyIsolated = true; // functions are immutable 148 else static if (isPointer!(T[0])) enum bool isWeaklyIsolated = is(typeof(*T[0].init) == immutable) || is(typeof(*T[0].init) == shared); 149 else static if (isAggregateType!(T[0])) enum bool isWeaklyIsolated = isWeaklyIsolated!(FieldTypeTuple!(T[0])); 150 else enum bool isWeaklyIsolated = true; 151 } 152 }