-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
106 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,73 +1,93 @@ | ||
/* | ||
* Taken from https://github.com/endlessm/eos-knowledge-content-node/blob/master/src/mainloop.cc | ||
* Relicensed in https://github.com/Place1/node-gir/issues/24 | ||
*/ | ||
|
||
#include <glib.h> | ||
#include <uv.h> | ||
|
||
#include "loop.h" | ||
#include "util.h" | ||
|
||
/* Integration for the GLib main loop and uv's main loop */ | ||
|
||
/* The way that this works is that we take uv's loop and nest it inside GLib's | ||
* mainloop, since nesting GLib inside uv seems to be fairly impossible until | ||
* either uv allows external sources to drive prepare/check, or until GLib | ||
* exposes an epoll fd to wait on... */ | ||
using namespace v8; | ||
|
||
namespace GNodeJS { | ||
|
||
struct uv_loop_source { | ||
GSource source; | ||
uv_loop_t *loop; | ||
struct ThreadData { | ||
uv_thread_t thread_handle; | ||
uv_mutex_t mutex_handle; | ||
uv_async_t async_handle; | ||
GPollFD *fds; | ||
gint nfds; | ||
}; | ||
|
||
static gboolean uv_loop_source_prepare (GSource *base, int *timeout) { | ||
struct uv_loop_source *source = (struct uv_loop_source *) base; | ||
uv_update_time (source->loop); | ||
/* | ||
* GLibs mainloop is not easy to embed directly right now. So rather then | ||
* embedding glib's mainloop inside libuvs mainloop, we are running glibs | ||
* mainloop in a separate thread. However we still want to be able to callback | ||
* into v8 javascript context from glib async code, so we call the dispatch | ||
* phase of glibs mainloop back on libuvs main thread. The flow is something | ||
* like | ||
* | ||
* glib thread: poll for events | ||
* glib thread: got events. wakeup libuv thread and lock | ||
* libuv thread: dispatch glib events | ||
* libuv thread: unlock glib thread | ||
* glib thread: poll for events | ||
* ... | ||
* | ||
* If in the future glib moves to epoll to drive its mainloop, we could easily | ||
* embed it inside of libuvs mainloop on the same thread, by polling on a single | ||
* fd. See https://bugzilla.gnome.org/show_bug.cgi?id=156048 | ||
*/ | ||
static void DispatchGLibMainloop (uv_async_t *async_handle) { | ||
ThreadData *data = (ThreadData *)async_handle->data; | ||
GMainContext *context = g_main_context_default (); | ||
g_main_context_acquire (context); | ||
g_main_context_dispatch (context); | ||
g_main_context_release (context); | ||
uv_mutex_unlock (&data->mutex_handle); | ||
} | ||
|
||
bool loop_alive = uv_loop_alive (source->loop); | ||
static void IterateGLibMainloop (ThreadData *data) { | ||
GMainContext *context = g_main_context_default (); | ||
gint max_priority, timeout; | ||
g_main_context_prepare (context, &max_priority); | ||
|
||
/* If the loop is dead, we can simply sleep forever until a GTK+ source | ||
* (presumably) wakes us back up again. */ | ||
if (!loop_alive) | ||
return FALSE; | ||
gint nfds; | ||
while ((nfds = g_main_context_query (context, max_priority, &timeout, data->fds, data->nfds)) > data->nfds) { | ||
delete[] data->fds; | ||
data->fds = new GPollFD[nfds]; | ||
data->nfds = nfds; | ||
} | ||
|
||
/* Otherwise, check the timeout. If the timeout is 0, that means we're | ||
* ready to go. Otherwise, keep sleeping until the timeout happens again. */ | ||
int t = uv_backend_timeout (source->loop); | ||
*timeout = t; | ||
g_poll (data->fds, data->nfds, timeout); | ||
|
||
if (t == 0) | ||
return TRUE; | ||
else | ||
return FALSE; | ||
} | ||
gboolean some_ready = g_main_context_check (context, max_priority, data->fds, data->nfds); | ||
|
||
static gboolean uv_loop_source_dispatch (GSource *base, GSourceFunc callback, gpointer user_data) { | ||
struct uv_loop_source *source = (struct uv_loop_source *) base; | ||
uv_run (source->loop, UV_RUN_NOWAIT); | ||
Util::CallNextTickCallback(); | ||
return G_SOURCE_CONTINUE; | ||
if (some_ready) { | ||
g_main_context_release (context); | ||
uv_async_send(&data->async_handle); | ||
uv_mutex_lock (&data->mutex_handle); | ||
g_main_context_acquire (context); | ||
} | ||
} | ||
|
||
static GSourceFuncs uv_loop_source_funcs = { | ||
uv_loop_source_prepare, | ||
NULL, | ||
uv_loop_source_dispatch, | ||
NULL, | ||
|
||
NULL, NULL, | ||
}; | ||
|
||
static GSource *uv_loop_source_new (uv_loop_t *loop) { | ||
struct uv_loop_source *source = (struct uv_loop_source *) g_source_new (&uv_loop_source_funcs, sizeof (*source)); | ||
source->loop = loop; | ||
g_source_add_unix_fd (&source->source, | ||
uv_backend_fd (loop), | ||
(GIOCondition) (G_IO_IN | G_IO_OUT | G_IO_ERR)); | ||
return &source->source; | ||
static void RunGLibMainloop (ThreadData *data) { | ||
g_main_context_acquire (g_main_context_default ()); | ||
uv_mutex_lock (&data->mutex_handle); | ||
while (uv_loop_alive (uv_default_loop ())) | ||
IterateGLibMainloop(data); | ||
delete data; | ||
} | ||
|
||
void StartLoop() { | ||
GSource *source = uv_loop_source_new (uv_default_loop ()); | ||
g_source_attach (source, NULL); | ||
ThreadData *data = new ThreadData(); | ||
uv_mutex_init (&data->mutex_handle); | ||
uv_async_init (uv_default_loop (), &data->async_handle, DispatchGLibMainloop); | ||
data->async_handle.data = data; | ||
|
||
uv_thread_create (&data->thread_handle, (uv_thread_cb)RunGLibMainloop, data); | ||
} | ||
|
||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* | ||
* loop.js | ||
*/ | ||
|
||
|
||
const gi = require('../lib/') | ||
const Gtk = gi.require('Gtk', '3.0') | ||
|
||
gi.startLoop() | ||
Gtk.init() | ||
|
||
setTimeout(() => { | ||
console.log('timeout') | ||
}, 1000) | ||
|
||
const promise = new Promise(resolve => resolve('promise resolved')) | ||
promise.then(result => console.log(result)) | ||
|
||
setTimeout(() => { | ||
console.log('quit') | ||
Gtk.mainQuit() | ||
}, 5000) | ||
Gtk.main() |