1 module concurrency.signal;
2 
3 struct SignalHandler {
4   private __gshared void delegate(int) callback = null;
5   private void delegate(int) oldCallback;
6   extern (C) static void intr(int i) nothrow @nogc {
7     if (callback is null)
8       return;
9     // TODO: this cast is a bit sketchy
10     (cast(void delegate(int) nothrow @nogc) callback)(i);
11   }
12 
13   version (Posix) {
14     import core.sys.posix.signal;
15     private sigaction_t[int] previous;
16   } else version (Windows) {
17     alias Fun = extern (C) void function(int) nothrow @nogc @system;
18     private Fun[int] previous;
19   } else static assert("Platform not supported");
20 
21   void setup(void delegate(int) cb) @trusted {
22     oldCallback = callback;
23     callback = cb;
24   }
25 
26   void on(int s) @trusted {
27     version (Posix) {
28       import core.sys.posix.signal;
29 
30       sigaction_t old;
31       sigset_t sigset;
32       sigemptyset(&sigset);
33       sigaction_t siginfo;
34       siginfo.sa_handler = &intr;
35       siginfo.sa_mask = sigset;
36       siginfo.sa_flags = SA_RESTART;
37       sigaction(s, &siginfo, &old);
38     } else {
39       import core.stdc.signal;
40       Fun old = signal(s, &intr);
41     }
42     previous[s] = old;
43   }
44 
45   void forward(int sig) @trusted {
46     foreach(s, old; previous) {
47       if (s != sig)
48         continue;
49       version (Posix) {
50         if (old.sa_handler)
51           old.sa_handler(s);
52       }
53       else if (old)
54         old(s);
55     }
56   }
57 
58   void teardown() nothrow @trusted {
59     callback = oldCallback;
60     try {
61     foreach(s, old; previous) {
62       version (Posix) {
63         sigaction(s, &old, null);
64       } else {
65         import core.stdc.signal;
66         signal(s, old);
67       }
68     }
69     } catch (Exception e) {}
70   }
71 }