diff options
Diffstat (limited to 'src/nvim/event')
| -rw-r--r-- | src/nvim/event/defs.h | 3 | ||||
| -rw-r--r-- | src/nvim/event/loop.c | 42 | ||||
| -rw-r--r-- | src/nvim/event/loop.h | 5 | ||||
| -rw-r--r-- | src/nvim/event/queue.c | 38 |
4 files changed, 58 insertions, 30 deletions
diff --git a/src/nvim/event/defs.h b/src/nvim/event/defs.h index 5126d52241..b802866a3d 100644 --- a/src/nvim/event/defs.h +++ b/src/nvim/event/defs.h @@ -4,7 +4,7 @@ #include <assert.h> #include <stdarg.h> -#define EVENT_HANDLER_MAX_ARGC 4 +#define EVENT_HANDLER_MAX_ARGC 6 typedef void (*argv_callback)(void **argv); typedef struct message { @@ -12,6 +12,7 @@ typedef struct message { argv_callback handler; void *argv[EVENT_HANDLER_MAX_ARGC]; } Event; +typedef void(*event_scheduler)(Event event, void *data); #define VA_EVENT_INIT(event, p, h, a) \ do { \ 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) { } + diff --git a/src/nvim/event/loop.h b/src/nvim/event/loop.h index 9212a45aa4..0c1fcb5ed9 100644 --- a/src/nvim/event/loop.h +++ b/src/nvim/event/loop.h @@ -16,11 +16,14 @@ KLIST_INIT(WatcherPtr, WatcherPtr, _noop) typedef struct loop { uv_loop_t uv; - Queue *events, *fast_events; + Queue *events, *fast_events, *thread_events; klist_t(WatcherPtr) *children; uv_signal_t children_watcher; uv_timer_t children_kill_timer, poll_timer; size_t children_stop_requests; + uv_async_t async; + uv_mutex_t mutex; + int recursive; } Loop; #define CREATE_EVENT(queue, handler, argc, ...) \ diff --git a/src/nvim/event/queue.c b/src/nvim/event/queue.c index 19eca14144..c5ef22d426 100644 --- a/src/nvim/event/queue.c +++ b/src/nvim/event/queue.c @@ -105,16 +105,15 @@ static Queue *queue_new(Queue *parent, put_callback put_cb, void *data) void queue_free(Queue *queue) { assert(queue); - if (queue->parent) { - while (!QUEUE_EMPTY(&queue->headtail)) { - QUEUE *q = QUEUE_HEAD(&queue->headtail); - QueueItem *item = queue_node_data(q); - assert(!item->link); + while (!QUEUE_EMPTY(&queue->headtail)) { + QUEUE *q = QUEUE_HEAD(&queue->headtail); + QueueItem *item = queue_node_data(q); + if (queue->parent) { QUEUE_REMOVE(&item->data.item.parent->node); xfree(item->data.item.parent); - QUEUE_REMOVE(q); - xfree(item); } + QUEUE_REMOVE(q); + xfree(item); } xfree(queue); @@ -128,9 +127,8 @@ Event queue_get(Queue *queue) void queue_put_event(Queue *queue, Event event) { assert(queue); - assert(queue->parent); // don't push directly to the parent queue queue_push(queue, event); - if (queue->parent->put_cb) { + if (queue->parent && queue->parent->put_cb) { queue->parent->put_cb(queue->parent, queue->parent->data); } } @@ -177,11 +175,11 @@ static Event queue_remove(Queue *queue) rv = child->data.item.event; xfree(child); } else { - assert(queue->parent); - assert(!queue_empty(queue->parent)); - // remove the corresponding link node in the parent queue - QUEUE_REMOVE(&item->data.item.parent->node); - xfree(item->data.item.parent); + if (queue->parent) { + // remove the corresponding link node in the parent queue + QUEUE_REMOVE(&item->data.item.parent->node); + xfree(item->data.item.parent); + } rv = item->data.item.event; } @@ -195,11 +193,13 @@ static void queue_push(Queue *queue, Event event) item->link = false; item->data.item.event = event; QUEUE_INSERT_TAIL(&queue->headtail, &item->node); - // push link node to the parent queue - item->data.item.parent = xmalloc(sizeof(QueueItem)); - item->data.item.parent->link = true; - item->data.item.parent->data.queue = queue; - QUEUE_INSERT_TAIL(&queue->parent->headtail, &item->data.item.parent->node); + if (queue->parent) { + // push link node to the parent queue + item->data.item.parent = xmalloc(sizeof(QueueItem)); + item->data.item.parent->link = true; + item->data.item.parent->data.queue = queue; + QUEUE_INSERT_TAIL(&queue->parent->headtail, &item->data.item.parent->node); + } } static QueueItem *queue_node_data(QUEUE *q) |