diff options
Diffstat (limited to 'src/nvim/msgpack_rpc')
-rw-r--r-- | src/nvim/msgpack_rpc/channel.c | 107 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/channel.h | 2 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/channel_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/helpers.c | 42 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/server.c | 21 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/unpacker.c | 50 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/unpacker.h | 6 |
7 files changed, 125 insertions, 105 deletions
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 1ca68979f4..d60e18590f 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -1,36 +1,43 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include <assert.h> #include <inttypes.h> -#include <msgpack.h> +#include <msgpack/object.h> +#include <msgpack/pack.h> +#include <msgpack/sbuffer.h> +#include <msgpack/unpack.h> #include <stdbool.h> -#include <string.h> +#include <stdio.h> +#include <stdlib.h> #include <uv.h> +#include "klib/kvec.h" +#include "nvim/api/private/defs.h" +#include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" #include "nvim/api/ui.h" -#include "nvim/api/vim.h" -#include "nvim/ascii.h" #include "nvim/channel.h" -#include "nvim/eval.h" -#include "nvim/event/libuv_process.h" +#include "nvim/event/defs.h" #include "nvim/event/loop.h" +#include "nvim/event/process.h" #include "nvim/event/rstream.h" -#include "nvim/event/socket.h" +#include "nvim/event/stream.h" #include "nvim/event/wstream.h" -#include "nvim/lib/kvec.h" #include "nvim/log.h" #include "nvim/main.h" #include "nvim/map.h" #include "nvim/memory.h" #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/unpacker.h" #include "nvim/os/input.h" -#include "nvim/os_unix.h" +#include "nvim/rbuffer.h" +#include "nvim/types.h" #include "nvim/ui.h" -#include "nvim/vim.h" +#include "nvim/ui_client.h" #if MIN_LOG_LEVEL > LOGLVL_DBG # define log_client_msg(...) @@ -94,7 +101,6 @@ bool rpc_send_event(uint64_t id, const char *name, Array args) Channel *channel = NULL; if (id && (!(channel = find_rpc_channel(id)))) { - api_free_array(args); return false; } @@ -130,6 +136,7 @@ Object rpc_send_call(uint64_t id, const char *method_name, Array args, ArenaMem uint32_t request_id = rpc->next_request_id++; // Send the msgpack-rpc request send_request(channel, request_id, method_name, args); + api_free_array(args); // Push the frame ChannelCallFrame frame = { request_id, false, false, NIL, NULL }; @@ -158,7 +165,7 @@ Object rpc_send_call(uint64_t id, const char *method_name, Array args, ArenaMem } // frame.result was allocated in an arena - arena_mem_free(frame.result_mem, &rpc->unpacker->reuse_blk); + arena_mem_free(frame.result_mem); frame.result_mem = NULL; } @@ -244,8 +251,8 @@ static void parse_msgpack(Channel *channel) ui_client_event_raw_line(p->grid_line_event); } else if (p->ui_handler.fn != NULL && p->result.type == kObjectTypeArray) { p->ui_handler.fn(p->result.data.array); - arena_mem_free(arena_finish(&p->arena), &p->reuse_blk); } + arena_mem_free(arena_finish(&p->arena)); } else if (p->type == kMessageTypeResponse) { ChannelCallFrame *frame = kv_last(channel->rpc.call_stack); if (p->request_id != frame->request_id) { @@ -293,9 +300,9 @@ static void handle_request(Channel *channel, Unpacker *p, Array args) assert(p->type == kMessageTypeRequest || p->type == kMessageTypeNotification); if (!p->handler.fn) { - send_error(channel, p->type, p->request_id, p->unpack_error.msg); + send_error(channel, p->handler, p->type, p->request_id, p->unpack_error.msg); api_clear_error(&p->unpack_error); - arena_mem_free(arena_finish(&p->arena), &p->reuse_blk); + arena_mem_free(arena_finish(&p->arena)); return; } @@ -304,7 +311,8 @@ static void handle_request(Channel *channel, Unpacker *p, Array args) evdata->channel = channel; evdata->handler = p->handler; evdata->args = args; - evdata->used_mem = arena_finish(&p->arena); + evdata->used_mem = p->arena; + p->arena = (Arena)ARENA_EMPTY; evdata->request_id = p->request_id; channel_incref(channel); if (p->handler.fast) { @@ -344,24 +352,27 @@ static void request_event(void **argv) // channel was closed, abort any pending requests goto free_ret; } - Object result = handler.fn(channel->id, e->args, &error); + + 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)); - } else { + } + if (!handler.arena_return) { api_free_object(result); } free_ret: - // e->args is allocated in an arena - arena_mem_free(e->used_mem, &channel->rpc.unpacker->reuse_blk); + // e->args (and possibly result) are allocated in an arena + arena_mem_free(arena_finish(&e->used_mem)); channel_decref(channel); xfree(e); api_clear_error(&error); @@ -431,11 +442,13 @@ static void internal_read_event(void **argv) wstream_release_wbuffer(buffer); } -static void send_error(Channel *chan, MessageType type, uint32_t id, char *err) +static void send_error(Channel *chan, MsgpackRpcRequestHandler handler, MessageType type, + uint32_t id, char *err) { Error e = ERROR_INIT; api_set_error(&e, kErrorTypeException, "%s", err); channel_write(chan, serialize_response(chan->id, + handler, type, id, &e, @@ -479,7 +492,6 @@ static void broadcast_event(const char *name, Array args) }); if (!kv_size(subscribed)) { - api_free_array(args); goto end; } @@ -534,26 +546,8 @@ void rpc_close(Channel *channel) channel_decref(channel); if (channel->streamtype == kChannelStreamStdio - || channel->id == ui_client_channel_id) { - multiqueue_put(main_loop.fast_events, exit_event, 0); - } -} - -static void exit_delay_cb(uv_timer_t *handle) -{ - uv_timer_stop(&main_loop.exit_delay_timer); - multiqueue_put(main_loop.fast_events, exit_event, 0); -} - -static void exit_event(void **argv) -{ - if (exit_need_delay) { - uv_timer_start(&main_loop.exit_delay_timer, exit_delay_cb, 0, 0); - return; - } - - if (!exiting) { - os_exit(0); + || (channel->id == ui_client_channel_id && channel->streamtype != kChannelStreamProc)) { + exit_from_channel(0); } } @@ -599,22 +593,30 @@ static WBuffer *serialize_request(uint64_t channel_id, uint32_t request_id, cons refcount, xfree); msgpack_sbuffer_clear(sbuffer); - api_free_array(args); return rv; } -static WBuffer *serialize_response(uint64_t channel_id, MessageType type, uint32_t response_id, - Error *err, Object arg, msgpack_sbuffer *sbuffer) +static WBuffer *serialize_response(uint64_t channel_id, MsgpackRpcRequestHandler handler, + MessageType type, uint32_t response_id, Error *err, Object arg, + msgpack_sbuffer *sbuffer) { msgpack_packer pac; msgpack_packer_init(&pac, sbuffer, msgpack_sbuffer_write); if (ERROR_SET(err) && type == kMessageTypeNotification) { - Array args = ARRAY_DICT_INIT; - ADD(args, INTEGER_OBJ(err->type)); - ADD(args, STRING_OBJ(cstr_to_string(err->msg))); - msgpack_rpc_serialize_request(0, cstr_as_string("nvim_error_event"), - args, &pac); - api_free_array(args); + if (handler.fn == handle_nvim_paste) { + // TODO(bfredl): this is pretty much ad-hoc. maybe TUI and UI:s should be + // allowed to ask nvim to just scream directly in the users face + // instead of sending nvim_error_event, in general. + semsg("paste: %s", err->msg); + api_clear_error(err); + } else { + Array args = ARRAY_DICT_INIT; + ADD(args, INTEGER_OBJ(err->type)); + ADD(args, STRING_OBJ(cstr_to_string(err->msg))); + msgpack_rpc_serialize_request(0, cstr_as_string("nvim_error_event"), + args, &pac); + api_free_array(args); + } } else { msgpack_rpc_serialize_response(response_id, err, arg, &pac); } @@ -624,7 +626,6 @@ static WBuffer *serialize_response(uint64_t channel_id, MessageType type, uint32 1, // responses only go though 1 channel xfree); msgpack_sbuffer_clear(sbuffer); - api_free_object(arg); return rv; } @@ -642,7 +643,7 @@ void rpc_set_client_info(uint64_t id, Dictionary info) Dictionary rpc_client_info(Channel *chan) { - return copy_dictionary(chan->rpc.info); + return copy_dictionary(chan->rpc.info, NULL); } const char *rpc_client_name(Channel *chan) diff --git a/src/nvim/msgpack_rpc/channel.h b/src/nvim/msgpack_rpc/channel.h index ac7911bb2c..ce5806930c 100644 --- a/src/nvim/msgpack_rpc/channel.h +++ b/src/nvim/msgpack_rpc/channel.h @@ -6,8 +6,10 @@ #include "nvim/api/private/defs.h" #include "nvim/channel.h" +#include "nvim/event/multiqueue.h" #include "nvim/event/process.h" #include "nvim/event/socket.h" +#include "nvim/macros.h" #include "nvim/vim.h" #define METHOD_MAXLEN 512 diff --git a/src/nvim/msgpack_rpc/channel_defs.h b/src/nvim/msgpack_rpc/channel_defs.h index e622ebddf5..404e68329a 100644 --- a/src/nvim/msgpack_rpc/channel_defs.h +++ b/src/nvim/msgpack_rpc/channel_defs.h @@ -27,7 +27,7 @@ typedef struct { MsgpackRpcRequestHandler handler; Array args; uint32_t request_id; - ArenaMem used_mem; + Arena used_mem; } RequestEvent; typedef struct { diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c index 488321be42..5f0f03dd69 100644 --- a/src/nvim/msgpack_rpc/helpers.c +++ b/src/nvim/msgpack_rpc/helpers.c @@ -1,21 +1,25 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -#include <inttypes.h> -#include <msgpack.h> +#include <msgpack/object.h> +#include <msgpack/sbuffer.h> +#include <msgpack/unpack.h> +#include <msgpack/zone.h> #include <stdbool.h> +#include <stddef.h> +#include <stdint.h> -#include "nvim/api/private/dispatch.h" +#include "klib/kvec.h" +#include "msgpack/pack.h" #include "nvim/api/private/helpers.h" #include "nvim/assert.h" -#include "nvim/lib/kvec.h" -#include "nvim/log.h" +#include "nvim/event/wstream.h" #include "nvim/memory.h" #include "nvim/msgpack_rpc/helpers.h" -#include "nvim/vim.h" +#include "nvim/types.h" #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "keysets.generated.h" +# include "keysets.generated.h" // IWYU pragma: export # include "msgpack_rpc/helpers.c.generated.h" #endif @@ -35,6 +39,8 @@ typedef struct { size_t idx; } MPToAPIObjectStackItem; +// uncrustify:off + /// Convert type used by msgpack parser to Nvim API type. /// /// @param[in] obj Msgpack value to convert. @@ -95,9 +101,8 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg) dest = conv(((String) { \ .size = obj->via.attr.size, \ .data = (obj->via.attr.ptr == NULL || obj->via.attr.size == 0 \ - ? xmemdupz("", 0) \ - : xmemdupz(obj->via.attr.ptr, obj->via.attr.size)), \ - })); \ + ? xmemdupz("", 0) \ + : xmemdupz(obj->via.attr.ptr, obj->via.attr.size)), })); \ break; \ } STR_CASE(MSGPACK_OBJECT_STR, str, cur.mobj, *cur.aobj, STRING_OBJ) @@ -115,7 +120,7 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg) .mobj = &cur.mobj->via.array.ptr[idx], .aobj = &cur.aobj->data.array.items[idx], .container = false, - })); + })); } } else { *cur.aobj = ARRAY_OBJ(((Array) { @@ -124,7 +129,7 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg) .items = (size > 0 ? xcalloc(size, sizeof(*cur.aobj->data.array.items)) : NULL), - })); + })); cur.container = true; kv_last(stack) = cur; } @@ -168,7 +173,7 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg) .mobj = &cur.mobj->via.map.ptr[idx].val, .aobj = &cur.aobj->data.dictionary.items[idx].value, .container = false, - })); + })); } } } else { @@ -178,7 +183,7 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg) .items = (size > 0 ? xcalloc(size, sizeof(*cur.aobj->data.dictionary.items)) : NULL), - })); + })); cur.container = true; kv_last(stack) = cur; } @@ -368,7 +373,7 @@ void msgpack_rpc_from_object(const Object result, msgpack_packer *const res) kvi_push(stack, ((APIToMPObjectStackItem) { .aobj = &cur.aobj->data.array.items[idx], .container = false, - })); + })); } } else { msgpack_pack_array(res, size); @@ -386,12 +391,11 @@ void msgpack_rpc_from_object(const Object result, msgpack_packer *const res) const size_t idx = cur.idx; cur.idx++; kv_last(stack) = cur; - msgpack_rpc_from_string(cur.aobj->data.dictionary.items[idx].key, - res); + msgpack_rpc_from_string(cur.aobj->data.dictionary.items[idx].key, res); kvi_push(stack, ((APIToMPObjectStackItem) { .aobj = &cur.aobj->data.dictionary.items[idx].value, .container = false, - })); + })); } } else { msgpack_pack_map(res, size); @@ -408,6 +412,8 @@ void msgpack_rpc_from_object(const Object result, msgpack_packer *const res) kvi_destroy(stack); } +// uncrustify:on + void msgpack_rpc_from_array(Array result, msgpack_packer *res) FUNC_ATTR_NONNULL_ARG(2) { diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c index b252f0998e..1d75c208be 100644 --- a/src/nvim/msgpack_rpc/server.c +++ b/src/nvim/msgpack_rpc/server.c @@ -1,25 +1,22 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -#include <assert.h> #include <inttypes.h> -#include <stdlib.h> +#include <stdbool.h> +#include <stdio.h> #include <string.h> +#include <uv.h> -#include "nvim/ascii.h" +#include "nvim/channel.h" #include "nvim/eval.h" #include "nvim/event/socket.h" -#include "nvim/fileio.h" #include "nvim/garray.h" #include "nvim/log.h" #include "nvim/main.h" #include "nvim/memory.h" -#include "nvim/msgpack_rpc/channel.h" #include "nvim/msgpack_rpc/server.h" #include "nvim/os/os.h" -#include "nvim/path.h" -#include "nvim/strings.h" -#include "nvim/vim.h" +#include "nvim/os/stdpaths_defs.h" #define MAX_CONNECTIONS 32 #define ENV_LISTEN "NVIM_LISTEN_ADDRESS" // deprecated @@ -94,7 +91,7 @@ char *server_address_new(const char *name) { static uint32_t count = 0; char fmt[ADDRESS_MAX_SIZE]; -#ifdef WIN32 +#ifdef MSWIN int r = snprintf(fmt, sizeof(fmt), "\\\\.\\pipe\\%s.%" PRIu64 ".%" PRIu32, name ? name : "nvim", os_get_pid(), count++); #else @@ -104,7 +101,7 @@ char *server_address_new(const char *name) xfree(dir); #endif if ((size_t)r >= sizeof(fmt)) { - ELOG("truncated server address"); + ELOG("truncated server address: %.40s...", fmt); } return xstrdup(fmt); } @@ -173,7 +170,7 @@ int server_start(const char *addr) ((SocketWatcher **)watchers.ga_data)[watchers.ga_len++] = watcher; // Update v:servername, if not set. - if (STRLEN(get_vim_var_str(VV_SEND_SERVER)) == 0) { + if (strlen(get_vim_var_str(VV_SEND_SERVER)) == 0) { set_vservername(&watchers); } @@ -216,7 +213,7 @@ bool server_stop(char *endpoint) watchers.ga_len--; // Bump v:servername to the next available server, if any. - if (strequal(addr, (char *)get_vim_var_str(VV_SEND_SERVER))) { + if (strequal(addr, get_vim_var_str(VV_SEND_SERVER))) { set_vservername(&watchers); } diff --git a/src/nvim/msgpack_rpc/unpacker.c b/src/nvim/msgpack_rpc/unpacker.c index c8e9fdd4c3..44a16beb48 100644 --- a/src/nvim/msgpack_rpc/unpacker.c +++ b/src/nvim/msgpack_rpc/unpacker.c @@ -1,9 +1,17 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include <assert.h> +#include <stdbool.h> +#include <stdlib.h> + +#include "klib/kvec.h" +#include "mpack/conv.h" #include "nvim/api/private/helpers.h" -#include "nvim/log.h" +#include "nvim/ascii.h" +#include "nvim/macros.h" #include "nvim/memory.h" +#include "nvim/msgpack_rpc/channel_defs.h" #include "nvim/msgpack_rpc/helpers.h" #include "nvim/msgpack_rpc/unpacker.h" #include "nvim/ui_client.h" @@ -178,16 +186,14 @@ void unpacker_init(Unpacker *p) mpack_parser_init(&p->parser, 0); p->parser.data.p = p; mpack_tokbuf_init(&p->reader); - p->unpack_error = (Error)ERROR_INIT; + p->unpack_error = ERROR_INIT; p->arena = (Arena)ARENA_EMPTY; - p->reuse_blk = NULL; } void unpacker_teardown(Unpacker *p) { - arena_mem_free(p->reuse_blk, NULL); - arena_mem_free(arena_finish(&p->arena), NULL); + arena_mem_free(arena_finish(&p->arena)); } bool unpacker_parse_header(Unpacker *p) @@ -292,7 +298,7 @@ error: // // When method is "grid_line", we furthermore decode a cell at a time like: // -// <0>[2, "redraw", <10>[{11}["grid_line", <13>[g, r, c, [<14>[cell], <14>[cell], ...]], ...], <11>[...], ...]] +// <0>[2, "redraw", <10>[{11}["grid_line", <14>[g, r, c, [<15>[cell], <15>[cell], ...]], ...], <11>[...], ...]] // // where [cell] is [char, repeat, attr], where 'repeat' and 'attr' is optional @@ -308,21 +314,23 @@ bool unpacker_advance(Unpacker *p) p->state = 10; } else { p->state = p->type == kMessageTypeResponse ? 1 : 2; - arena_start(&p->arena, &p->reuse_blk); + p->arena = (Arena)ARENA_EMPTY; } } - if (p->state >= 10 && p->state != 12) { + if (p->state >= 10 && p->state != 13) { if (!unpacker_parse_redraw(p)) { return false; } - if (p->state == 14) { + if (p->state == 15) { // grid_line event already unpacked goto done; } else { + assert(p->state == 12); // unpack other ui events using mpack_parse() - arena_start(&p->arena, &p->reuse_blk); + p->arena = (Arena)ARENA_EMPTY; + p->state = 13; } } @@ -349,11 +357,11 @@ done: case 2: p->state = 0; return true; - case 12: - case 14: + case 13: + case 15: p->ncalls--; if (p->ncalls > 0) { - p->state = (p->state == 14) ? 13 : 12; + p->state = (p->state == 15) ? 14 : 12; } else if (p->nevents > 0) { p->state = 11; } else { @@ -374,6 +382,7 @@ bool unpacker_parse_redraw(Unpacker *p) size_t size = p->read_size; GridLineEvent *g = p->grid_line_event; +// -V:NEXT_TYPE:501 #define NEXT_TYPE(tok, typ) \ result = mpack_rtoken(&data, &size, &tok); \ if (result == MPACK_EOF) { \ @@ -416,19 +425,19 @@ redo: if (p->ui_handler.fn != ui_client_event_grid_line) { p->state = 12; if (p->grid_line_event) { - arena_mem_free(arena_finish(&p->arena), &p->reuse_blk); + arena_mem_free(arena_finish(&p->arena)); p->grid_line_event = NULL; } return true; } else { - p->state = 13; - arena_start(&p->arena, &p->reuse_blk); + p->state = 14; + p->arena = (Arena)ARENA_EMPTY; p->grid_line_event = arena_alloc(&p->arena, sizeof *p->grid_line_event, true); g = p->grid_line_event; } FALLTHROUGH; - case 13: + case 14: NEXT_TYPE(tok, MPACK_TOKEN_ARRAY); int eventarrsize = (int)tok.length; if (eventarrsize != 4) { @@ -449,10 +458,10 @@ redo: p->read_ptr = data; p->read_size = size; - p->state = 14; + p->state = 15; FALLTHROUGH; - case 14: + case 15: assert(g->icell < g->ncells); NEXT_TYPE(tok, MPACK_TOKEN_ARRAY); @@ -506,6 +515,9 @@ redo: } goto redo; + case 12: + return true; + default: abort(); } diff --git a/src/nvim/msgpack_rpc/unpacker.h b/src/nvim/msgpack_rpc/unpacker.h index f39439be63..b8b2d38d3b 100644 --- a/src/nvim/msgpack_rpc/unpacker.h +++ b/src/nvim/msgpack_rpc/unpacker.h @@ -7,10 +7,14 @@ #include "mpack/mpack_core.h" #include "mpack/object.h" +#include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" +#include "nvim/grid_defs.h" #include "nvim/memory.h" #include "nvim/msgpack_rpc/channel_defs.h" +#include "nvim/types.h" +#include "nvim/ui_client.h" struct Unpacker { mpack_parser_t parser; @@ -32,8 +36,6 @@ struct Unpacker { Error unpack_error; Arena arena; - // one length free-list of reusable blocks - ArenaMem reuse_blk; int nevents; int ncalls; |