You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

177 lines
3.6 KiB

module io.events;
import std.socket;
import std.outofmemory;
private struct evloop {
}
private struct ev_io {
}
enum Event {
NONE = 0,
READ = 1,
WRITE = 2,
TIMEOUT = 4,
ERROR = 128,
}
private extern (C) void ioev_event_callback(Watcher watcher, int revents) {
watcher.callback(revents);
}
private extern (C) evloop* ioev_ev_default_loop(uint flags); /* is a inline function... */
private extern (C) evloop* ev_loop_new(uint flags);
private extern (C) void ev_default_destroy(evloop *loop);
private extern (C) void ev_loop_destroy(evloop *loop);
private extern (C) void ev_loop(evloop *loop, int flags);
private extern (C) void ev_io_start(evloop *loop, ev_io *w);
private extern (C) void ev_io_stop(evloop *loop, ev_io *w);
private extern (C) ev_io* ioev_io_watcher_new(Watcher watcher);
private extern (C) void ioev_io_watcher_free(ev_io *w);
private extern (C) void ioev_io_set(ev_io *w, int fd, int events);
class Watcher {
protected Loop m_cur_loop = null;
protected bool m_active = false;
protected final Loop loop(Loop l) {
if (m_cur_loop is l) return l;
if (m_cur_loop !is null) stop();
return m_cur_loop = l;
}
~this() {
loop = null;
}
abstract void callback(int revents);
abstract protected void do_start();
abstract protected void do_stop();
final public Loop loop() {
return m_cur_loop;
}
final public void start(Loop l) {
if (l is null) throw new Exception("Cannot start on null loop");
loop = l;
do_start();
m_active = true;
}
final public void start() {
start(m_cur_loop);
}
final public void stop() {
if (!m_active) return;
if (m_cur_loop !is null && m_cur_loop.loop !is null)
do_stop();
m_active = false;
}
}
class IOWatcher : Watcher {
private ev_io *m_w;
private Socket m_socket;
private Event m_events;
private int m_fd = -1;
void delegate() read, write, error;
this() {
m_w = ioev_io_watcher_new(this);
if (m_w is null) throw new OutOfMemoryException;
}
~this() {
ioev_io_watcher_free(m_w);
}
override final void callback(int revents) {
if (revents & Event.READ) read();
if (revents & Event.WRITE) write();
if (revents & Event.ERROR) error();
}
private final void set(int fd, int ev) {
bool active = m_active;
stop();
m_fd = fd; m_events = cast(Event)(ev);
ioev_io_set(m_w, m_fd, m_events);
if (active) start();
}
final Socket socket(Socket s) {
m_socket = s;
if (m_fd != s.handle)
set(s.handle, m_events);
return m_socket;
}
final Event events() { return m_events; }
final Event events(int ev) {
if (m_events != ev) set(m_fd, ev);
return m_events;
}
final void events(bool waitForRead, bool waitForWrite) {
Event ev = Event.NONE;
if (waitForRead) ev = ev | Event.READ;
if (waitForWrite) ev = ev | Event.WRITE;
events(ev);
}
override final protected void do_start() {
ev_io_start(loop.loop, m_w);
}
override final protected void do_stop() {
ev_io_stop(loop.loop, m_w);
}
}
class Loop {
protected evloop* loop;
private bool default_loop;
private static Loop def = null;
private this(evloop* loop) {
this.loop = loop;
default_loop = true;
}
static synchronized Loop defaultloop() {
if (def !is null) return def;
evloop* l = ioev_ev_default_loop(0);
if (l is null) throw new Exception("ev_default_loop failed");
def = new Loop(l);
return def;
}
this() {
default_loop = false;
loop = ev_loop_new(0);
if (loop is null) throw new Exception("ev_loop_new failed");
}
~this() {
if (loop !is null) {
if (default_loop) {
ev_default_destroy(loop);
} else {
ev_loop_destroy(loop);
}
}
}
final void run() {
ev_loop(loop, 0);
}
}