1 module hio.common;
2 
3 import std.exception;
4 import std.conv;
5 import std.format;
6 
7 import core.stdc.string: strerror;
8 import std.experimental.logger;
9 
10 import core.sys.posix.sys.socket;
11 import core.stdc.string;
12 import core.stdc.errno;
13 import core.sys.posix.unistd;
14 
15 auto s_strerror(T)(T e) @trusted {
16     return to!string(strerror(e));
17 }
18 
19 SocketPair makeSocketPair() @safe {
20     import core.sys.posix.fcntl;
21     int[2] pair;
22     auto r = (() @trusted => socketpair(AF_UNIX, SOCK_DGRAM, 0, pair))();
23     if ( r == -1 ) {
24         throw new Exception(s_strerror(errno()));
25     }
26     auto flags = (() @trusted => fcntl(pair[0], F_GETFL, 0) | O_NONBLOCK)();
27     (() @trusted => fcntl(pair[0], F_SETFL, flags))();
28     flags = (() @trusted => fcntl(pair[1], F_GETFL, 0) | O_NONBLOCK)();
29     (() @trusted => fcntl(pair[1], F_SETFL, flags))();
30     SocketPair result;
31     result._pair = pair;
32     return result;
33 }
34 
35 
36 struct SocketPair {
37     int[2]  _pair = [-1, -1];
38     ~this() @safe {
39         (() @trusted => close())();
40     }
41     public void close() {
42         if ( _pair[0] >= 0 ) {
43             core.sys.posix.unistd.close(_pair[0]);
44         }
45         if ( _pair[1] >= 0 ) {
46             core.sys.posix.unistd.close(_pair[1]);
47         }
48         _pair = [-1, -1];
49     }
50     auto opIndex(size_t i) const {
51         return _pair[i];
52     }
53     auto read(uint i, size_t len) @safe
54     {
55         enforce!Exception(i <= 1, "Index in socketpair must be 0 or 1");
56         if ( len <= 0 ) {
57             throw new Exception("read length must be > 0");
58         }
59         ubyte[] b = new ubyte[](len);
60         auto s = (() @trusted => core.sys.posix.unistd.read(_pair[i], b.ptr, len))();
61         enforce!Exception(s > 0, "failed to read from socketpair[%d], fd=%d".format(i, _pair[i]));
62         return b;
63     }
64     auto write(uint i, ubyte[] b) @safe {
65         return (() @trusted => core.sys.posix.unistd.write(_pair[i], b.ptr, b.length))();
66     }
67 }
68 
69 package
70 void safe_tracef(A...)(string f, scope A args, string file = __FILE__, int line = __LINE__) @safe @nogc nothrow
71 {
72     bool osx,ldc;
73     version(OSX)
74     {
75         osx = true;
76     }
77     version(LDC)
78     {
79         ldc = true;
80     }
81     debug (timingwheels) try
82     {
83         // this can fail on pair ldc2/osx, see https://github.com/ldc-developers/ldc/issues/3240
84         if (!osx || !ldc)
85         {
86             () @trusted @nogc {tracef("%s:%d " ~ f, file, line, args);}();
87         }
88     }
89     catch(Exception e)
90     {
91     }
92 }
93 
94 
95 //class NotificationChannel {
96 //    import  containers;
97 
98 //    private enum NotificationType {Signal, Broadcast}
99 //
100 //    private NotificationType _type = NotificationType.Signal;
101 //
102 //    private SList!(void delegate() @safe) _subscribers;
103 //
104 //    SocketPair  _pipe;
105 //
106 //    auto readEnd() const @safe @nogc {
107 //        return _pipe[0];
108 //    }
109 //
110 //    auto writeEnd() const @safe @nogc {
111 //        return _pipe[1];
112 //    }
113 //
114 //    void handler() @safe {
115 //        with (NotificationType) final switch(_type) {
116 //        case Signal:
117 //            auto s = _subscribers.front;
118 //            s();
119 //            break;
120 //        case Broadcast:
121 //            foreach(s; _subscribers) {
122 //                s();
123 //            }
124 //            break;
125 //        }
126 //    }
127 //
128 //    this() @safe {
129 //        _pipe = makeSocketPair();
130 //    }
131 //    shared this() @safe {
132 //        //_pipe = makeSocketPair();
133 //    }
134 //    void subscribe(void delegate() @safe h) @safe {
135 //        _subscribers ~= h;
136 //    }
137 //    void unsubscribe(void delegate() @safe h) @safe {
138 //        _subscribers.remove(h);
139 //    }
140 //
141 //    auto signal() @property @safe @nogc {
142 //        _type = NotificationType.Signal;
143 //        ubyte[1] b = [0];
144 //        auto s = _pipe.write(1, b);
145 //        return this;
146 //    }
147 //    auto broadcast() @property @safe @nogc {
148 //        _type = NotificationType.Broadcast;
149 //        ubyte[1] b = [0];
150 //        auto s = _pipe.write(1, b);
151 //        return this;
152 //    }
153 //}
154