aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2024-02-25 15:02:48 +0100
committerbfredl <bjorn.linse@gmail.com>2024-03-07 09:39:46 +0100
commitdc37c1550bed46fffbb677d343cdc5bc94056219 (patch)
tree86213752366e016637f9e155a975facb408decad /src
parent6525832a8c4d44a8ebabba02a5ea1ce09b389a4f (diff)
downloadrneovim-dc37c1550bed46fffbb677d343cdc5bc94056219.tar.gz
rneovim-dc37c1550bed46fffbb677d343cdc5bc94056219.tar.bz2
rneovim-dc37c1550bed46fffbb677d343cdc5bc94056219.zip
refactor(msgpack): allow flushing buffer while packing msgpack
Before, we needed to always pack an entire msgpack_rpc Object to a continous memory buffer before sending it out to a channel. But this is generally wasteful. it is better to just flush whatever is in the buffer and then continue packing to a new buffer. This is also done for the UI event packer where there are some extra logic to "finish" of an existing batch of nevents/ncalls. This doesn't really stop us from flushing the buffer, just that we need to update the state machine accordingly so the next call to prepare_call() always will start with a new event (even though the buffer might contain overflow data from a large event).
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/private/defs.h8
-rw-r--r--src/nvim/api/private/helpers.c3
-rw-r--r--src/nvim/api/ui.c235
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua1
-rw-r--r--src/nvim/lua/converter.c6
-rw-r--r--src/nvim/main.c5
-rw-r--r--src/nvim/memory.c42
-rw-r--r--src/nvim/memory.h2
-rw-r--r--src/nvim/msgpack_rpc/channel.c247
-rw-r--r--src/nvim/msgpack_rpc/helpers.c245
-rw-r--r--src/nvim/msgpack_rpc/helpers.h17
-rw-r--r--src/nvim/msgpack_rpc/packer.c235
-rw-r--r--src/nvim/msgpack_rpc/packer.h76
-rw-r--r--src/nvim/msgpack_rpc/packer_defs.h24
-rw-r--r--src/nvim/msgpack_rpc/unpacker.c1
-rw-r--r--src/nvim/shada.c1
-rw-r--r--src/nvim/strings.c2
-rw-r--r--src/nvim/ui_defs.h13
18 files changed, 560 insertions, 603 deletions
diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h
index 0cdc90e50f..ca088d7a55 100644
--- a/src/nvim/api/private/defs.h
+++ b/src/nvim/api/private/defs.h
@@ -105,6 +105,14 @@ typedef enum {
kObjectTypeTabpage,
} ObjectType;
+/// Value by which objects represented as EXT type are shifted
+///
+/// Subtracted when packing, added when unpacking. Used to allow moving
+/// buffer/window/tabpage block inside ObjectType enum. This block yet cannot be
+/// split or reordered.
+#define EXT_OBJECT_TYPE_SHIFT kObjectTypeBuffer
+#define EXT_OBJECT_TYPE_MAX (kObjectTypeTabpage - EXT_OBJECT_TYPE_SHIFT)
+
struct object {
ObjectType type;
union {
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 97ba15e871..1cd98aa0c4 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -29,7 +29,6 @@
#include "nvim/memory.h"
#include "nvim/memory_defs.h"
#include "nvim/message.h"
-#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/msgpack_rpc/unpacker.h"
#include "nvim/pos_defs.h"
#include "nvim/types_defs.h"
@@ -984,7 +983,7 @@ Dictionary api_keydict_to_dict(void *value, KeySetLink *table, size_t max_size,
val = DICTIONARY_OBJ(*(Dictionary *)mem);
} else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow
|| field->type == kObjectTypeTabpage) {
- val.data.integer = *(Integer *)mem;
+ val.data.integer = *(handle_T *)mem;
val.type = field->type;
} else if (field->type == kObjectTypeLuaRef) {
// do nothing
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 0f016d2f29..638a4fdcc4 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -12,6 +12,7 @@
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/validate.h"
#include "nvim/api/ui.h"
+#include "nvim/assert_defs.h"
#include "nvim/autocmd.h"
#include "nvim/autocmd_defs.h"
#include "nvim/channel.h"
@@ -33,12 +34,12 @@
#include "nvim/memory_defs.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/msgpack_rpc/channel_defs.h"
-#include "nvim/msgpack_rpc/helpers.h"
+#include "nvim/msgpack_rpc/packer.h"
#include "nvim/option.h"
#include "nvim/types_defs.h"
#include "nvim/ui.h"
-#define BUF_POS(data) ((size_t)((data)->buf_wptr - (data)->buf))
+#define BUF_POS(data) ((size_t)((data)->packer.ptr - (data)->packer.startptr))
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/ui.c.generated.h"
@@ -47,55 +48,6 @@
static PMap(uint64_t) connected_uis = MAP_INIT;
-#define mpack_w(b, byte) *(*(b))++ = (char)(byte);
-static void mpack_w2(char **b, uint32_t v)
-{
- *(*b)++ = (char)((v >> 8) & 0xff);
- *(*b)++ = (char)(v & 0xff);
-}
-
-static void mpack_w4(char **b, uint32_t v)
-{
- *(*b)++ = (char)((v >> 24) & 0xff);
- *(*b)++ = (char)((v >> 16) & 0xff);
- *(*b)++ = (char)((v >> 8) & 0xff);
- *(*b)++ = (char)(v & 0xff);
-}
-
-static void mpack_uint(char **buf, uint32_t val)
-{
- if (val > 0xffff) {
- mpack_w(buf, 0xce);
- mpack_w4(buf, val);
- } else if (val > 0xff) {
- mpack_w(buf, 0xcd);
- mpack_w2(buf, val);
- } else if (val > 0x7f) {
- mpack_w(buf, 0xcc);
- mpack_w(buf, val);
- } else {
- mpack_w(buf, val);
- }
-}
-
-static void mpack_bool(char **buf, bool val)
-{
- mpack_w(buf, 0xc2 | (val ? 1 : 0));
-}
-
-static void mpack_array(char **buf, uint32_t len)
-{
- if (len < 0x10) {
- mpack_w(buf, 0x90 | len);
- } else if (len < 0x10000) {
- mpack_w(buf, 0xdc);
- mpack_w2(buf, len);
- } else {
- mpack_w(buf, 0xdd);
- mpack_w4(buf, len);
- }
-}
-
static char *mpack_array_dyn16(char **buf)
{
mpack_w(buf, 0xdc);
@@ -104,9 +56,9 @@ static char *mpack_array_dyn16(char **buf)
return pos;
}
-static void mpack_str(char **buf, const char *str, size_t len)
+static void mpack_str_small(char **buf, const char *str, size_t len)
{
- assert(sizeof(schar_T) - 1 < 0x20);
+ assert(len < 0x20);
mpack_w(buf, 0xa0 | len);
memcpy(*buf, str, len);
*buf += len;
@@ -117,6 +69,7 @@ static void remote_ui_destroy(UI *ui)
{
UIData *data = ui->data;
kv_destroy(data->call_buf);
+ xfree(data->packer.startptr);
XFREE_CLEAR(ui->term_name);
xfree(ui);
}
@@ -231,8 +184,13 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona
data->ncalls_pos = NULL;
data->ncalls = 0;
data->ncells_pending = 0;
- data->buf_wptr = data->buf;
- data->temp_buf = NULL;
+ data->packer = (PackerBuffer) {
+ .startptr = NULL,
+ .ptr = NULL,
+ .endptr = NULL,
+ .packer_flush = ui_flush_callback,
+ .anydata = data,
+ };
data->wildmenu_active = false;
data->call_buf = (Array)ARRAY_DICT_INIT;
kv_ensure_space(data->call_buf, 16);
@@ -561,72 +519,29 @@ void nvim_ui_term_event(uint64_t channel_id, String event, Object value, Error *
static void flush_event(UIData *data)
{
if (data->cur_event) {
- mpack_w2(&data->ncalls_pos, data->ncalls);
+ mpack_w2(&data->ncalls_pos, 1 + data->ncalls);
data->cur_event = NULL;
+ data->ncalls_pos = NULL;
+ data->ncalls = 0;
}
- if (!data->nevents_pos) {
- assert(BUF_POS(data) == 0);
- char **buf = &data->buf_wptr;
- // [2, "redraw", [...]]
- mpack_array(buf, 3);
- mpack_uint(buf, 2);
- mpack_str(buf, S_LEN("redraw"));
- data->nevents_pos = mpack_array_dyn16(buf);
- }
-}
-
-static inline int write_cb(void *vdata, const char *buf, size_t len)
-{
- UIData *data = (UIData *)vdata;
- if (!buf) {
- return 0;
- }
-
- data->pack_totlen += len;
- if (!data->temp_buf && UI_BUF_SIZE - BUF_POS(data) < len) {
- return 0;
- }
-
- memcpy(data->buf_wptr, buf, len);
- data->buf_wptr += len;
-
- return 0;
}
-static inline int size_cb(void *vdata, const char *buf, size_t len)
+static void ui_alloc_buf(UIData *data)
{
- UIData *data = (UIData *)vdata;
- if (!buf) {
- return 0;
- }
-
- data->pack_totlen += len;
- return 0;
+ data->packer.startptr = alloc_block();
+ data->packer.ptr = data->packer.startptr;
+ data->packer.endptr = data->packer.startptr + UI_BUF_SIZE;
}
-static void prepare_call(UI *ui, const char *name, size_t size_needed)
+static void prepare_call(UI *ui, const char *name)
{
UIData *data = ui->data;
- size_t name_len = strlen(name);
- const size_t overhead = name_len + 20;
- bool oversized_message = size_needed + overhead > UI_BUF_SIZE;
-
- if (oversized_message || BUF_POS(data) > UI_BUF_SIZE - size_needed - overhead) {
- remote_ui_flush_buf(ui);
+ if (data->packer.startptr && BUF_POS(data) > UI_BUF_SIZE - EVENT_BUF_SIZE) {
+ ui_flush_buf(data);
}
- if (oversized_message) {
- // TODO(bfredl): manually testable by setting UI_BUF_SIZE to 1024 (mode_info_set)
- data->temp_buf = xmalloc(20 + name_len + size_needed);
- data->buf_wptr = data->temp_buf;
- char **buf = &data->buf_wptr;
- mpack_array(buf, 3);
- mpack_uint(buf, 2);
- mpack_str(buf, S_LEN("redraw"));
- mpack_array(buf, 1);
- mpack_array(buf, 2);
- mpack_str(buf, name, name_len);
- return;
+ if (data->packer.startptr == NULL) {
+ ui_alloc_buf(data);
}
// To optimize data transfer(especially for "grid_line"), we bundle adjacent
@@ -634,26 +549,23 @@ static void prepare_call(UI *ui, const char *name, size_t size_needed)
// method call is different from "name"
if (!data->cur_event || !strequal(data->cur_event, name)) {
+ char **buf = &data->packer.ptr;
+ if (!data->nevents_pos) {
+ // [2, "redraw", [...]]
+ mpack_array(buf, 3);
+ mpack_uint(buf, 2);
+ mpack_str_small(buf, S_LEN("redraw"));
+ data->nevents_pos = mpack_array_dyn16(buf);
+ assert(data->cur_event == NULL);
+ }
flush_event(data);
data->cur_event = name;
- char **buf = &data->buf_wptr;
data->ncalls_pos = mpack_array_dyn16(buf);
- mpack_str(buf, name, strlen(name));
+ mpack_str_small(buf, name, strlen(name));
data->nevents++;
data->ncalls = 1;
- return;
- }
-}
-
-static void send_oversized_message(UIData *data)
-{
- if (data->temp_buf) {
- size_t size = (size_t)(data->buf_wptr - data->temp_buf);
- WBuffer *buf = wstream_new_buffer(data->temp_buf, size, 1, xfree);
- rpc_write_raw(data->channel_id, buf);
- data->temp_buf = NULL;
- data->buf_wptr = data->buf;
- data->nevents_pos = NULL;
+ } else {
+ data->ncalls++;
}
}
@@ -661,23 +573,15 @@ static void send_oversized_message(UIData *data)
static void push_call(UI *ui, const char *name, Array args)
{
UIData *data = ui->data;
+ prepare_call(ui, name);
+ mpack_object_array(args, &data->packer);
+}
- msgpack_packer pac;
- data->pack_totlen = 0;
- // First determine the needed size
- msgpack_packer_init(&pac, data, size_cb);
- msgpack_rpc_from_array(args, &pac);
- // Then send the actual message
- prepare_call(ui, name, data->pack_totlen);
- msgpack_packer_init(&pac, data, write_cb);
- msgpack_rpc_from_array(args, &pac);
-
- // Oversized messages need to be sent immediately
- if (data->temp_buf) {
- send_oversized_message(data);
- }
-
- data->ncalls++;
+static void ui_flush_callback(PackerBuffer *packer)
+{
+ UIData *data = packer->anydata;
+ ui_flush_buf(data);
+ ui_alloc_buf(data);
}
void remote_ui_grid_clear(UI *ui, Integer grid)
@@ -869,12 +773,15 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
Integer clearcol, Integer clearattr, LineFlags flags, const schar_T *chunk,
const sattr_T *attrs)
{
+ // If MAX_SCHAR_SIZE is made larger, we need to refactor implementation below
+ // to not only use FIXSTR (only up to 0x20 bytes)
+ STATIC_ASSERT(MAX_SCHAR_SIZE - 1 < 0x20, "SCHAR doesn't fit in fixstr");
+
UIData *data = ui->data;
if (ui->ui_ext[kUILinegrid]) {
- prepare_call(ui, "grid_line", EVENT_BUF_SIZE);
- data->ncalls++;
+ prepare_call(ui, "grid_line");
- char **buf = &data->buf_wptr;
+ char **buf = &data->packer.ptr;
mpack_array(buf, 5);
mpack_uint(buf, (uint32_t)grid);
mpack_uint(buf, (uint32_t)row);
@@ -898,10 +805,9 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
// We only ever set the wrap field on the final "grid_line" event for the line.
mpack_bool(buf, false);
- remote_ui_flush_buf(ui);
+ ui_flush_buf(data);
- prepare_call(ui, "grid_line", EVENT_BUF_SIZE);
- data->ncalls++;
+ prepare_call(ui, "grid_line");
mpack_array(buf, 5);
mpack_uint(buf, (uint32_t)grid);
mpack_uint(buf, (uint32_t)row);
@@ -934,7 +840,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
nelem++;
data->ncells_pending += 1;
mpack_array(buf, 3);
- mpack_str(buf, S_LEN(" "));
+ mpack_str_small(buf, S_LEN(" "));
mpack_uint(buf, (uint32_t)clearattr);
mpack_uint(buf, (uint32_t)(clearcol - endcol));
}
@@ -943,7 +849,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
if (data->ncells_pending > 500) {
// pass off cells to UI to let it start processing them
- remote_ui_flush_buf(ui);
+ ui_flush_buf(data);
}
} else {
for (int i = 0; i < endcol - startcol; i++) {
@@ -977,28 +883,27 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
///
/// This might happen multiple times before the actual ui_flush, if the
/// total redraw size is large!
-void remote_ui_flush_buf(UI *ui)
+static void ui_flush_buf(UIData *data)
{
- UIData *data = ui->data;
- if (!data->nevents_pos) {
+ if (!data->packer.startptr || !BUF_POS(data)) {
return;
}
- if (data->cur_event) {
- flush_event(data);
+
+ flush_event(data);
+ if (data->nevents_pos != NULL) {
+ mpack_w2(&data->nevents_pos, data->nevents);
+ data->nevents = 0;
+ data->nevents_pos = NULL;
}
- mpack_w2(&data->nevents_pos, data->nevents);
- data->nevents = 0;
- data->nevents_pos = NULL;
- // TODO(bfredl): elide copy by a length one free-list like the arena
- size_t size = BUF_POS(data);
- WBuffer *buf = wstream_new_buffer(xmemdup(data->buf, size), size, 1, xfree);
+ WBuffer *buf = wstream_new_buffer(data->packer.startptr, BUF_POS(data), 1, free_block);
rpc_write_raw(data->channel_id, buf);
- data->buf_wptr = data->buf;
- // we have sent events to the client, but possibly not yet the final "flush"
- // event.
- data->flushed_events = true;
+ data->packer.startptr = NULL;
+ data->packer.ptr = NULL;
+
+ // we have sent events to the client, but possibly not yet the final "flush" event.
+ data->flushed_events = true;
data->ncells_pending = 0;
}
@@ -1014,7 +919,7 @@ void remote_ui_flush(UI *ui)
remote_ui_cursor_goto(ui, data->cursor_row, data->cursor_col);
}
push_call(ui, "flush", (Array)ARRAY_DICT_INIT);
- remote_ui_flush_buf(ui);
+ ui_flush_buf(data);
data->flushed_events = false;
}
}
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index 78a83445af..04b4363e42 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -307,7 +307,6 @@ output:write([[
#include "nvim/globals.h"
#include "nvim/log.h"
#include "nvim/map_defs.h"
-#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/api/autocmd.h"
#include "nvim/api/buffer.h"
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index 0b7f58cec6..bba771f8a5 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -1381,9 +1381,11 @@ void nlua_push_keydict(lua_State *L, void *value, KeySetLink *table)
lua_pushstring(L, field->str);
if (field->type == kObjectTypeNil) {
nlua_push_Object(L, (Object *)mem, false);
- } else if (field->type == kObjectTypeInteger || field->type == kObjectTypeBuffer
- || field->type == kObjectTypeWindow || field->type == kObjectTypeTabpage) {
+ } else if (field->type == kObjectTypeInteger) {
lua_pushinteger(L, *(Integer *)mem);
+ } else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow
+ || field->type == kObjectTypeTabpage) {
+ lua_pushinteger(L, *(handle_T *)mem);
} else if (field->type == kObjectTypeFloat) {
lua_pushnumber(L, *(Float *)mem);
} else if (field->type == kObjectTypeBoolean) {
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 6b862f2ed9..6b8c8253dc 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -70,7 +70,6 @@
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/msgpack_rpc/channel.h"
-#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/msgpack_rpc/server.h"
#include "nvim/normal.h"
#include "nvim/ops.h"
@@ -152,11 +151,9 @@ void event_init(void)
loop_init(&main_loop, NULL);
resize_events = multiqueue_new_child(main_loop.events);
- // early msgpack-rpc initialization
- msgpack_rpc_helpers_init();
input_init();
signal_init();
- // finish mspgack-rpc initialization
+ // mspgack-rpc initialization
channel_init();
terminal_init();
ui_init();
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index 4520635137..37e53e4453 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -554,7 +554,6 @@ void time_to_bytes(time_t time_, uint8_t buf[8])
}
}
-#define ARENA_BLOCK_SIZE 4096
#define REUSE_MAX 4
static struct consumed_blk *arena_reuse_blk;
@@ -583,17 +582,26 @@ ArenaMem arena_finish(Arena *arena)
return res;
}
-void alloc_block(Arena *arena)
+/// allocate a block of ARENA_BLOCK_SIZE
+///
+/// free it with free_block
+void *alloc_block(void)
{
- struct consumed_blk *prev_blk = (struct consumed_blk *)arena->cur_blk;
if (arena_reuse_blk_count > 0) {
- arena->cur_blk = (char *)arena_reuse_blk;
+ void *retval = (char *)arena_reuse_blk;
arena_reuse_blk = arena_reuse_blk->prev;
arena_reuse_blk_count--;
+ return retval;
} else {
arena_alloc_count++;
- arena->cur_blk = xmalloc(ARENA_BLOCK_SIZE);
+ return xmalloc(ARENA_BLOCK_SIZE);
}
+}
+
+void arena_alloc_block(Arena *arena)
+{
+ struct consumed_blk *prev_blk = (struct consumed_blk *)arena->cur_blk;
+ arena->cur_blk = alloc_block();
arena->pos = 0;
arena->size = ARENA_BLOCK_SIZE;
struct consumed_blk *blk = arena_alloc(arena, sizeof(struct consumed_blk), true);
@@ -615,7 +623,7 @@ void *arena_alloc(Arena *arena, size_t size, bool align)
return xmalloc(size);
}
if (!arena->cur_blk) {
- alloc_block(arena);
+ arena_alloc_block(arena);
}
size_t alloc_pos = align ? arena_align_offset(arena->pos) : arena->pos;
if (alloc_pos + size > arena->size) {
@@ -637,7 +645,7 @@ void *arena_alloc(Arena *arena, size_t size, bool align)
cur_blk->prev = fix_blk;
return alloc + aligned_hdr_size;
} else {
- alloc_block(arena); // resets arena->pos
+ arena_alloc_block(arena); // resets arena->pos
alloc_pos = align ? arena_align_offset(arena->pos) : arena->pos;
}
}
@@ -647,17 +655,27 @@ void *arena_alloc(Arena *arena, size_t size, bool align)
return mem;
}
+void free_block(void *block)
+{
+ if (arena_reuse_blk_count < REUSE_MAX) {
+ struct consumed_blk *reuse_blk = block;
+ reuse_blk->prev = arena_reuse_blk;
+ arena_reuse_blk = reuse_blk;
+ arena_reuse_blk_count++;
+ } else {
+ xfree(block);
+ }
+}
+
void arena_mem_free(ArenaMem mem)
{
struct consumed_blk *b = mem;
// peel of the first block, as it is guaranteed to be ARENA_BLOCK_SIZE,
// not a custom fix_blk
- if (arena_reuse_blk_count < REUSE_MAX && b != NULL) {
+ if (b != NULL) {
struct consumed_blk *reuse_blk = b;
b = b->prev;
- reuse_blk->prev = arena_reuse_blk;
- arena_reuse_blk = reuse_blk;
- arena_reuse_blk_count++;
+ free_block(reuse_blk);
}
while (b) {
@@ -695,7 +713,6 @@ char *arena_memdupz(Arena *arena, const char *buf, size_t size)
# include "nvim/grid.h"
# include "nvim/mark.h"
# include "nvim/msgpack_rpc/channel.h"
-# include "nvim/msgpack_rpc/helpers.h"
# include "nvim/ops.h"
# include "nvim/option.h"
# include "nvim/os/os.h"
@@ -862,7 +879,6 @@ void free_all_mem(void)
ui_comp_free_all_mem();
nlua_free_all_mem();
rpc_free_all_mem();
- msgpack_rpc_helpers_free_all_mem();
// should be last, in case earlier free functions deallocates arenas
arena_free_reuse_blks();
diff --git a/src/nvim/memory.h b/src/nvim/memory.h
index e98a5dc228..0788670142 100644
--- a/src/nvim/memory.h
+++ b/src/nvim/memory.h
@@ -45,6 +45,8 @@ EXTERN size_t arena_alloc_count INIT( = 0);
((v).capacity = (s), \
(v).items = (void *)arena_alloc(a, sizeof((v).items[0]) * (v).capacity, true))
+#define ARENA_BLOCK_SIZE 4096
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "memory.h.generated.h"
#endif
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index ee7359c476..a8fde5a652 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -1,7 +1,6 @@
#include <assert.h>
#include <inttypes.h>
#include <msgpack/object.h>
-#include <msgpack/pack.h>
#include <msgpack/sbuffer.h>
#include <msgpack/unpack.h>
#include <stdbool.h>
@@ -29,7 +28,7 @@
#include "nvim/message.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/msgpack_rpc/channel_defs.h"
-#include "nvim/msgpack_rpc/helpers.h"
+#include "nvim/msgpack_rpc/packer.h"
#include "nvim/msgpack_rpc/unpacker.h"
#include "nvim/os/input.h"
#include "nvim/rbuffer.h"
@@ -44,73 +43,31 @@
# define NOT "[notify] "
# define ERR "[error] "
-// Cannot define array with negative offsets, so this one is needed to be added
-// to MSGPACK_UNPACK_\* values.
-# define MUR_OFF 2
+# define SEND "->"
+# define RECV "<-"
-static const char *const msgpack_error_messages[] = {
- [MSGPACK_UNPACK_EXTRA_BYTES + MUR_OFF] = "extra bytes found",
- [MSGPACK_UNPACK_CONTINUE + MUR_OFF] = "incomplete string",
- [MSGPACK_UNPACK_PARSE_ERROR + MUR_OFF] = "parse error",
- [MSGPACK_UNPACK_NOMEM_ERROR + MUR_OFF] = "not enough memory",
-};
-
-static void log_close(FILE *f)
+static void log_request(char *dir, uint64_t channel_id, uint32_t req_id, const char *name)
{
- fputc('\n', f);
- fflush(f);
- fclose(f);
- log_unlock();
+ DLOGN("RPC %s %" PRIu64 ": %s id=%u: %s\n", dir, channel_id, REQ, req_id, name);
}
-static void log_server_msg(uint64_t channel_id, msgpack_sbuffer *packed)
+static void log_response(char *dir, uint64_t channel_id, char *kind, uint32_t req_id)
{
- msgpack_unpacked unpacked;
- msgpack_unpacked_init(&unpacked);
- DLOGN("RPC ->ch %" PRIu64 ": ", channel_id);
- const msgpack_unpack_return result =
- msgpack_unpack_next(&unpacked, packed->data, packed->size, NULL);
- switch (result) {
- case MSGPACK_UNPACK_SUCCESS: {
- uint64_t type = unpacked.data.via.array.ptr[0].via.u64;
- log_lock();
- FILE *f = open_log_file();
- fprintf(f, type ? (type == 1 ? RES : NOT) : REQ);
- msgpack_object_print(f, unpacked.data);
- log_close(f);
- msgpack_unpacked_destroy(&unpacked);
- break;
- }
- case MSGPACK_UNPACK_EXTRA_BYTES:
- case MSGPACK_UNPACK_CONTINUE:
- case MSGPACK_UNPACK_PARSE_ERROR:
- case MSGPACK_UNPACK_NOMEM_ERROR: {
- log_lock();
- FILE *f = open_log_file();
- fprintf(f, ERR);
- fprintf(f, "%s", msgpack_error_messages[result + MUR_OFF]);
- log_close(f);
- break;
- }
- }
+ DLOGN("RPC %s %" PRIu64 ": %s id=%u\n", dir, channel_id, kind, req_id);
}
-static void log_client_msg(uint64_t channel_id, bool is_request, const char *name)
+static void log_notify(char *dir, uint64_t channel_id, const char *name)
{
- DLOGN("RPC <-ch %" PRIu64 ": ", channel_id);
- log_lock();
- FILE *f = open_log_file();
- fprintf(f, "%s: %s", is_request ? REQ : RES, name);
- log_close(f);
+ DLOGN("RPC %s %" PRIu64 ": %s %s\n", dir, channel_id, NOT, name);
}
#else
-# define log_client_msg(...)
-# define log_server_msg(...)
+# define log_request(...)
+# define log_response(...)
+# define log_notify(...)
#endif
static Set(cstr_t) event_strings = SET_INIT;
-static msgpack_sbuffer out_buffer;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "msgpack_rpc/channel.c.generated.h"
@@ -119,7 +76,6 @@ static msgpack_sbuffer out_buffer;
void rpc_init(void)
{
ch_before_blocking_events = multiqueue_new_child(main_loop.events);
- msgpack_sbuffer_init(&out_buffer);
}
void rpc_start(Channel *channel)
@@ -169,8 +125,9 @@ bool rpc_send_event(uint64_t id, const char *name, Array args)
return false;
}
+ log_notify(SEND, channel ? channel->id : 0, name);
if (channel) {
- send_event(channel, name, args);
+ serialize_request(&channel, 1, 0, name, args);
} else {
broadcast_event(name, args);
}
@@ -199,7 +156,9 @@ Object rpc_send_call(uint64_t id, const char *method_name, Array args, ArenaMem
RpcState *rpc = &channel->rpc;
uint32_t request_id = rpc->next_request_id++;
// Send the msgpack-rpc request
- send_request(channel, request_id, method_name, args);
+ serialize_request(&channel, 1, request_id, method_name, args);
+
+ log_request(SEND, channel->id, request_id, method_name);
// Push the frame
ChannelCallFrame frame = { request_id, false, false, NIL, NULL };
@@ -361,8 +320,13 @@ static void parse_msgpack(Channel *channel)
frame->result = p->result;
}
frame->result_mem = arena_finish(&p->arena);
+ log_response(RECV, channel->id, frame->errored ? ERR : RES, p->request_id);
} else {
- log_client_msg(channel->id, p->type == kMessageTypeRequest, p->handler.name);
+ if (p->type == kMessageTypeNotification) {
+ log_notify(RECV, channel->id, p->handler.name);
+ } else {
+ log_request(RECV, channel->id, p->request_id, p->handler.name);
+ }
Object res = p->result;
if (p->result.type != kObjectTypeArray) {
@@ -442,15 +406,7 @@ static void request_event(void **argv)
Object result = handler.fn(channel->id, e->args, &e->used_mem, &error);
if (e->type == kMessageTypeRequest || ERROR_SET(&error)) {
// Send the response.
- msgpack_packer response;
- msgpack_packer_init(&response, &out_buffer, msgpack_sbuffer_write);
- channel_write(channel, serialize_response(channel->id,
- e->handler,
- e->type,
- e->request_id,
- &error,
- &result,
- &out_buffer));
+ serialize_response(channel, e->handler, e->type, e->request_id, &error, &result);
}
if (handler.ret_alloc) {
api_free_object(result);
@@ -533,41 +489,14 @@ static void send_error(Channel *chan, MsgpackRpcRequestHandler handler, MessageT
{
Error e = ERROR_INIT;
api_set_error(&e, kErrorTypeException, "%s", err);
- channel_write(chan, serialize_response(chan->id,
- handler,
- type,
- id,
- &e,
- &NIL,
- &out_buffer));
+ serialize_response(chan, handler, type, id, &e, &NIL);
api_clear_error(&e);
}
-static void send_request(Channel *channel, uint32_t id, const char *name, Array args)
-{
- const String method = cstr_as_string(name);
- channel_write(channel, serialize_request(channel->id,
- id,
- method,
- args,
- &out_buffer,
- 1));
-}
-
-static void send_event(Channel *channel, const char *name, Array args)
-{
- const String method = cstr_as_string(name);
- channel_write(channel, serialize_request(channel->id,
- 0,
- method,
- args,
- &out_buffer,
- 1));
-}
-
static void broadcast_event(const char *name, Array args)
{
- kvec_t(Channel *) subscribed = KV_INITIAL_VALUE;
+ kvec_withinit_t(Channel *, 4) subscribed = KV_INITIAL_VALUE;
+ kvi_init(subscribed);
Channel *channel;
map_foreach_value(&channels, channel, {
@@ -577,25 +506,11 @@ static void broadcast_event(const char *name, Array args)
}
});
- if (!kv_size(subscribed)) {
- goto end;
- }
-
- const String method = cstr_as_string(name);
- WBuffer *buffer = serialize_request(0,
- 0,
- method,
- args,
- &out_buffer,
- kv_size(subscribed));
-
- for (size_t i = 0; i < kv_size(subscribed); i++) {
- Channel *c = kv_A(subscribed, i);
- channel_write(c, buffer);
+ if (kv_size(subscribed)) {
+ serialize_request(subscribed.items, kv_size(subscribed), 0, name, args);
}
-end:
- kv_destroy(subscribed);
+ kvi_destroy(subscribed);
}
static void unsubscribe(Channel *channel, char *event)
@@ -653,27 +568,28 @@ static void chan_close_with_error(Channel *channel, char *msg, int loglevel)
channel_close(channel->id, kChannelPartRpc, NULL);
}
-static WBuffer *serialize_request(uint64_t channel_id, uint32_t request_id, const String method,
- Array args, msgpack_sbuffer *sbuffer, size_t refcount)
+static void serialize_request(Channel **chans, size_t nchans, uint32_t request_id,
+ const char *method, Array args)
{
- msgpack_packer pac;
- msgpack_packer_init(&pac, sbuffer, msgpack_sbuffer_write);
- msgpack_rpc_serialize_request(request_id, method, args, &pac);
- log_server_msg(channel_id, sbuffer);
- WBuffer *rv = wstream_new_buffer(xmemdup(sbuffer->data, sbuffer->size),
- sbuffer->size,
- refcount,
- xfree);
- msgpack_sbuffer_clear(sbuffer);
- return rv;
+ PackerBuffer packer;
+ packer_buffer_init_channels(chans, nchans, &packer);
+
+ mpack_array(&packer.ptr, request_id ? 4 : 3);
+ mpack_w(&packer.ptr, request_id ? 0 : 2);
+
+ if (request_id) {
+ mpack_uint(&packer.ptr, request_id);
+ }
+
+ mpack_str(cstr_as_string(method), &packer);
+ mpack_object_array(args, &packer);
+
+ packer_buffer_finish_channels(&packer);
}