Integrate the Glib main loop into the libev event loop (C++)
Oleksandr Kozlov
aleks.a.kozlov at gmail.com
Wed Jul 7 00:06:37 CEST 2021
I am trying to integrate the Glib main loop into the libev event loop.
Actually,
I am using their C++ wrappers: glibmm [1] and ev++ [2]. The main idea was
taken
from the EV::Glib Perl module [3]. However, my implementation sometimes
hangs
when I try to perform some async task (e.g., reading a text file from the
filesystem):
#include <ev++.h>
#include <giomm.h>
#include <glibmm.h>
struct context;
int to_ev_events(Glib::IOCondition events) {
int result = EV_NONE;
if (events == (events & Glib::IOCondition::IO_IN)) result |= EV_READ;
if (events == (events & Glib::IOCondition::IO_OUT)) result |= EV_WRITE;
return result;
}
Glib::IOCondition to_glib_events(int events) {
Glib::IOCondition result{};
if (events == (events & EV_READ)) result |= Glib::IOCondition::IO_IN;
if (events == (events & EV_WRITE)) result |= Glib::IOCondition::IO_OUT;
return result;
}
struct prepare_watcher {
prepare_watcher(context &c) : ctx{c} {
watcher.priority = EV_MINPRI;
watcher.set(this);
watcher.start();
}
void operator()(ev::prepare &watcher, int revents);
ev::prepare watcher;
context &ctx;
};
struct check_watcher {
check_watcher(context &c) : ctx{c} {
watcher.priority = EV_MAXPRI;
watcher.set(this);
watcher.start();
}
void operator()(ev::check &watcher, int revents);
ev::check watcher;
context &ctx;
};
struct timer_watcher {
timer_watcher() { watcher.priority = EV_MINPRI; }
ev::timer watcher;
};
struct io_watcher {
io_watcher(int fd, int events) {
watcher.priority = EV_MINPRI;
watcher.start(fd, events);
}
ev::io watcher;
};
struct context {
Glib::RefPtr<Glib::MainContext> context =
Glib::MainContext::get_default();
ev::default_loop loop;
std::vector<Glib::PollFD> poll_fds;
int priority{};
prepare_watcher prepare{*this};
check_watcher check{*this};
timer_watcher timer;
std::map<int, io_watcher> ios;
};
void prepare_watcher::operator()(ev::prepare &watcher, int revents) {
ctx.context->dispatch();
ctx.context->prepare(ctx.priority);
ctx.poll_fds.clear();
int timeout = 0;
ctx.context->query(ctx.priority, timeout, ctx.poll_fds);
for (Glib::PollFD &poll_fd : ctx.poll_fds) {
int fd = poll_fd.get_fd();
ctx.ios.try_emplace(fd, fd, to_ev_events(poll_fd.get_events()));
}
if (timeout >= 0) ctx.timer.watcher.start(timeout * 1e-3);
}
void check_watcher::operator()(ev::check &watcher, int revents) {
for (Glib::PollFD &poll_fd : ctx.poll_fds) {
int fd = poll_fd.get_fd();
io_watcher &io = ctx.ios.at(fd);
if (io.watcher.is_pending())
poll_fd.set_revents(
to_glib_events(ev_clear_pending(ctx.loop.raw_loop, &io.watcher)));
ctx.ios.erase(fd);
}
if (ctx.timer.watcher.is_active() || ctx.timer.watcher.is_pending())
ctx.timer.watcher.stop();
ctx.context->check(ctx.priority, ctx.poll_fds);
}
int main() {
Gio::init();
context ctx;
Glib::RefPtr<Gio::File> file = Gio::File::create_for_path("file.txt");
file->read_async([&](Glib::RefPtr<Gio::AsyncResult> result) {
file->read_finish(result);
ctx.loop.break_loop(ev::ALL);
});
ctx.loop.run();
}
Any ideas?
* [1] https://github.com/GNOME/glibmm
* [2] http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#C_API-2
* [3] https://github.com/gitpan/EV-Glib/blob/master/Glib.xs
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.schmorp.de/pipermail/libev/attachments/20210707/62fa581a/attachment.htm>
More information about the libev
mailing list