diff options
Diffstat (limited to 'src/nvim/event/queue.c')
-rw-r--r-- | src/nvim/event/queue.c | 208 |
1 files changed, 0 insertions, 208 deletions
diff --git a/src/nvim/event/queue.c b/src/nvim/event/queue.c deleted file mode 100644 index c5ef22d426..0000000000 --- a/src/nvim/event/queue.c +++ /dev/null @@ -1,208 +0,0 @@ -// Queue for selective async event processing. Instances of this queue support a -// parent/child relationship with the following properties: -// -// - pushing a node to a child queue will push a corresponding link node to the -// parent queue -// - removing a link node from a parent queue will remove the next node -// in the linked child queue -// - removing a node from a child queue will remove the corresponding link node -// in the parent queue -// -// These properties allow neovim to organize and process events from different -// sources with a certain degree of control. Here's how the queue is used: -// -// +----------------+ -// | Main loop | -// +----------------+ -// ^ -// | -// +----------------+ -// +-------------->| Event loop |<------------+ -// | +--+-------------+ | -// | ^ ^ | -// | | | | -// +-----------+ +-----------+ +---------+ +---------+ -// | Channel 1 | | Channel 2 | | Job 1 | | Job 2 | -// +-----------+ +-----------+ +---------+ +---------+ -// -// -// In the above diagram, the lower boxes represents event emitters, each with -// it's own private queue that have the event loop queue as the parent. -// -// When idle, the main loop spins the event loop which queues events from many -// sources(channels, jobs, user...). Each event emitter pushes events to its own -// private queue which is propagated to the event loop queue. When the main loop -// consumes an event, the corresponding event is removed from the emitter's -// queue. -// -// The main reason for this queue hierarchy is to allow focusing on a single -// event emitter while blocking the main loop. For example, if the `jobwait` -// vimscript function is called on job1, the main loop will temporarily stop -// polling the event loop queue and poll job1 queue instead. Same with channels, -// when calling `rpcrequest`, we want to temporarily stop processing events from -// other sources and focus on a specific channel. - -#include <assert.h> -#include <stdarg.h> -#include <stdbool.h> -#include <stdint.h> - - -#include <uv.h> - -#include "nvim/event/queue.h" -#include "nvim/memory.h" -#include "nvim/os/time.h" - -typedef struct queue_item QueueItem; -struct queue_item { - union { - Queue *queue; - struct { - Event event; - QueueItem *parent; - } item; - } data; - bool link; // this is just a link to a node in a child queue - QUEUE node; -}; - -struct queue { - Queue *parent; - QUEUE headtail; - put_callback put_cb; - void *data; -}; - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "event/queue.c.generated.h" -#endif - -static Event NILEVENT = {.handler = NULL, .argv = {NULL}}; - -Queue *queue_new_parent(put_callback put_cb, void *data) -{ - return queue_new(NULL, put_cb, data); -} - -Queue *queue_new_child(Queue *parent) - FUNC_ATTR_NONNULL_ALL -{ - assert(!parent->parent); - return queue_new(parent, NULL, NULL); -} - -static Queue *queue_new(Queue *parent, put_callback put_cb, void *data) -{ - Queue *rv = xmalloc(sizeof(Queue)); - QUEUE_INIT(&rv->headtail); - rv->parent = parent; - rv->put_cb = put_cb; - rv->data = data; - return rv; -} - -void queue_free(Queue *queue) -{ - assert(queue); - 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); - } - - xfree(queue); -} - -Event queue_get(Queue *queue) -{ - return queue_empty(queue) ? NILEVENT : queue_remove(queue); -} - -void queue_put_event(Queue *queue, Event event) -{ - assert(queue); - queue_push(queue, event); - if (queue->parent && queue->parent->put_cb) { - queue->parent->put_cb(queue->parent, queue->parent->data); - } -} - -void queue_process_events(Queue *queue) -{ - assert(queue); - while (!queue_empty(queue)) { - Event event = queue_get(queue); - if (event.handler) { - event.handler(event.argv); - } - } -} - -bool queue_empty(Queue *queue) -{ - assert(queue); - return QUEUE_EMPTY(&queue->headtail); -} - -void queue_replace_parent(Queue *queue, Queue *new_parent) -{ - assert(queue_empty(queue)); - queue->parent = new_parent; -} - -static Event queue_remove(Queue *queue) -{ - assert(!queue_empty(queue)); - QUEUE *h = QUEUE_HEAD(&queue->headtail); - QUEUE_REMOVE(h); - QueueItem *item = queue_node_data(h); - Event rv; - - if (item->link) { - assert(!queue->parent); - // remove the next node in the linked queue - Queue *linked = item->data.queue; - assert(!queue_empty(linked)); - QueueItem *child = - queue_node_data(QUEUE_HEAD(&linked->headtail)); - QUEUE_REMOVE(&child->node); - rv = child->data.item.event; - xfree(child); - } else { - 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; - } - - xfree(item); - return rv; -} - -static void queue_push(Queue *queue, Event event) -{ - QueueItem *item = xmalloc(sizeof(QueueItem)); - item->link = false; - item->data.item.event = event; - QUEUE_INSERT_TAIL(&queue->headtail, &item->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) -{ - return QUEUE_DATA(q, QueueItem, node); -} |