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 95 @property fd_t id() const { 96 return m_evId; 97 } 98 99 package: 100 version(Posix) mixin EvInfoMixinsShared; 101 102 void handler() { 103 try m_sgh(); 104 catch {} 105 return; 106 } 107 } 108 109 package shared struct SignalHandler { 110 AsyncSignal ctxt; 111 void function(shared AsyncSignal) fct; 112 113 void opCall(shared AsyncSignal ctxt) { 114 assert(ctxt !is null); 115 fct(ctxt); 116 return; 117 } 118 } 119 120 121 /** 122 Determines if the given list of types has any non-immutable and unshared aliasing outside of their object tree. 123 124 The types in particular may only contain plain data, pointers or arrays to immutable or shared data, or references 125 encapsulated in stdx.typecons.Isolated. Values that do not have unshared and unisolated aliasing are safe to be passed 126 between threads. 127 */ 128 template isWeaklyIsolated(T...) 129 { 130 import std.typecons : Rebindable; 131 static if (T.length == 0) enum bool isWeaklyIsolated = true; 132 else static if (T.length > 1) enum bool isWeaklyIsolated = isWeaklyIsolated!(T[0 .. $/2]) && isWeaklyIsolated!(T[$/2 .. $]); 133 else { 134 static if(is(T[0] == immutable)) enum bool isWeaklyIsolated = true; 135 else static if (is(T[0] == shared)) enum bool isWeaklyIsolated = true; 136 else static if (isInstanceOf!(Rebindable, T[0])) enum bool isWeaklyIsolated = isWeaklyIsolated!(typeof(T[0].get())); 137 else static if (is(T[0] : Throwable)) enum bool isWeaklyIsolated = true; // WARNING: this is unsafe, but needed for send/receive! 138 else static if (is(typeof(T[0].__isIsolatedType))) enum bool isWeaklyIsolated = true; 139 else static if (is(typeof(T[0].__isWeakIsolatedType))) enum bool isWeaklyIsolated = true; 140 else static if (is(T[0] == class)) enum bool isWeaklyIsolated = false; 141 else static if (is(T[0] == interface)) enum bool isWeaklyIsolated = false; // can't know if the implementation is isolated 142 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 143 else static if (isDynamicArray!(T[0])) enum bool isWeaklyIsolated = is(typeof(T[0].init[0]) == immutable); 144 else static if (isAssociativeArray!(T[0])) enum bool isWeaklyIsolated = false; // TODO: be less strict here 145 else static if (isSomeFunction!(T[0])) enum bool isWeaklyIsolated = true; // functions are immutable 146 else static if (isPointer!(T[0])) enum bool isWeaklyIsolated = is(typeof(*T[0].init) == immutable) || is(typeof(*T[0].init) == shared); 147 else static if (isAggregateType!(T[0])) enum bool isWeaklyIsolated = isWeaklyIsolated!(FieldTypeTuple!(T[0])); 148 else enum bool isWeaklyIsolated = true; 149 } 150 }