aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/event/loop.c
diff options
context:
space:
mode:
authorThiago de Arruda <tpadilha84@gmail.com>2015-09-01 10:11:55 -0300
committerThiago de Arruda <tpadilha84@gmail.com>2015-09-06 09:18:53 -0300
commitc20b802511a3d0e3b2277186a545c7f9f687410c (patch)
tree7118c3a32883bd831f234d1d1df205871e0fba97 /src/nvim/event/loop.c
parent203a4d5650ced506ae82ed6c79bd056a547f28c6 (diff)
downloadrneovim-c20b802511a3d0e3b2277186a545c7f9f687410c.tar.gz
rneovim-c20b802511a3d0e3b2277186a545c7f9f687410c.tar.bz2
rneovim-c20b802511a3d0e3b2277186a545c7f9f687410c.zip
loop: Improvements for thread-safety
- Implement `loop_schedule` method for queueing events from other threads - Make `loop_poll_events` `recursive` static variable a field of the Loop structure
Diffstat (limited to 'src/nvim/event/loop.c')
-rw-r--r--src/nvim/event/loop.c42
1 files changed, 33 insertions, 9 deletions
diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c
index 3d3288f858..088e059d19 100644
--- a/src/nvim/event/loop.c
+++ b/src/nvim/event/loop.c
@@ -10,20 +10,19 @@
# include "event/loop.c.generated.h"
#endif
-typedef struct idle_event {
- uv_idle_t idle;
- Event event;
-} IdleEvent;
-
void loop_init(Loop *loop, void *data)
{
uv_loop_init(&loop->uv);
+ loop->recursive = 0;
loop->uv.data = loop;
loop->children = kl_init(WatcherPtr);
loop->children_stop_requests = 0;
loop->events = queue_new_parent(loop_on_put, loop);
loop->fast_events = queue_new_child(loop->events);
+ loop->thread_events = queue_new_parent(NULL, NULL);
+ uv_mutex_init(&loop->mutex);
+ uv_async_init(&loop->uv, &loop->async, async_cb);
uv_signal_init(&loop->uv, &loop->children_watcher);
uv_timer_init(&loop->uv, &loop->children_kill_timer);
uv_timer_init(&loop->uv, &loop->poll_timer);
@@ -31,9 +30,7 @@ void loop_init(Loop *loop, void *data)
void loop_poll_events(Loop *loop, int ms)
{
- static int recursive = 0;
-
- if (recursive++) {
+ if (loop->recursive++) {
abort(); // Should not re-enter uv_run
}
@@ -55,10 +52,19 @@ void loop_poll_events(Loop *loop, int ms)
uv_timer_stop(&loop->poll_timer);
}
- recursive--; // Can re-enter uv_run now
+ loop->recursive--; // Can re-enter uv_run now
queue_process_events(loop->fast_events);
}
+// Schedule an event from another thread
+void loop_schedule(Loop *loop, Event event)
+{
+ uv_mutex_lock(&loop->mutex);
+ queue_put_event(loop->thread_events, event);
+ uv_async_send(&loop->async);
+ uv_mutex_unlock(&loop->mutex);
+}
+
void loop_on_put(Queue *queue, void *data)
{
Loop *loop = data;
@@ -72,14 +78,32 @@ void loop_on_put(Queue *queue, void *data)
void loop_close(Loop *loop)
{
+ uv_mutex_destroy(&loop->mutex);
uv_close((uv_handle_t *)&loop->children_watcher, NULL);
uv_close((uv_handle_t *)&loop->children_kill_timer, NULL);
uv_close((uv_handle_t *)&loop->poll_timer, NULL);
+ uv_close((uv_handle_t *)&loop->async, NULL);
do {
uv_run(&loop->uv, UV_RUN_DEFAULT);
} while (uv_loop_close(&loop->uv));
+ queue_free(loop->events);
+ queue_free(loop->fast_events);
+ queue_free(loop->thread_events);
+ kl_destroy(WatcherPtr, loop->children);
+}
+
+static void async_cb(uv_async_t *handle)
+{
+ Loop *l = handle->loop->data;
+ uv_mutex_lock(&l->mutex);
+ while (!queue_empty(l->thread_events)) {
+ Event ev = queue_get(l->thread_events);
+ queue_put_event(l->fast_events, ev);
+ }
+ uv_mutex_unlock(&l->mutex);
}
static void timer_cb(uv_timer_t *handle)
{
}
+