aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/channel.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/channel.c')
-rw-r--r--src/nvim/channel.c139
1 files changed, 87 insertions, 52 deletions
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index e8fe80a3b6..ebeaffe5a1 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -10,16 +10,21 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/autocmd.h"
+#include "nvim/autocmd_defs.h"
#include "nvim/buffer_defs.h"
#include "nvim/channel.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
+#include "nvim/event/loop.h"
+#include "nvim/event/multiqueue.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/garray.h"
-#include "nvim/gettext.h"
+#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/log.h"
#include "nvim/lua/executor.h"
@@ -28,10 +33,14 @@
#include "nvim/message.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/msgpack_rpc/server.h"
+#include "nvim/os/fs.h"
#include "nvim/os/os_defs.h"
#include "nvim/os/shell.h"
#include "nvim/path.h"
#include "nvim/rbuffer.h"
+#include "nvim/rbuffer_defs.h"
+#include "nvim/terminal.h"
+#include "nvim/types_defs.h"
#ifdef MSWIN
# include "nvim/os/fs.h"
@@ -53,12 +62,24 @@ static uint64_t next_chan_id = CHAN_STDERR + 1;
/// Teardown the module
void channel_teardown(void)
{
- Channel *channel;
+ Channel *chan;
+ map_foreach_value(&channels, chan, {
+ channel_close(chan->id, kChannelPartAll, NULL);
+ });
+}
- map_foreach_value(&channels, channel, {
- channel_close(channel->id, kChannelPartAll, NULL);
+#ifdef EXITFREE
+void channel_free_all_mem(void)
+{
+ Channel *chan;
+ map_foreach_value(&channels, chan, {
+ channel_destroy(chan);
});
+ map_destroy(uint64_t, &channels);
+
+ callback_free(&on_print);
}
+#endif
/// Closes a channel
///
@@ -217,16 +238,17 @@ void channel_create_event(Channel *chan, const char *ext_source)
}
assert(chan->id <= VARNUMBER_MAX);
- Dictionary info = channel_info(chan->id);
+ Arena arena = ARENA_EMPTY;
+ Dictionary info = channel_info(chan->id, &arena);
typval_T tv = TV_INITIAL_VALUE;
// TODO(bfredl): do the conversion in one step. Also would be nice
// to pretty print top level dict in defined order
- (void)object_to_vim(DICTIONARY_OBJ(info), &tv, NULL);
+ object_to_vim(DICTIONARY_OBJ(info), &tv, NULL);
assert(tv.v_type == VAR_DICT);
char *str = encode_tv2json(&tv, NULL);
ILOG("new channel %" PRIu64 " (%s) : %s", chan->id, source, str);
xfree(str);
- api_free_dictionary(info);
+ arena_mem_free(arena_finish(&arena));
#else
(void)ext_source;
@@ -244,7 +266,7 @@ void channel_decref(Channel *chan)
{
if (!(--chan->refcount)) {
// delay free, so that libuv is done with the handles
- multiqueue_put(main_loop.events, free_channel_event, 1, chan);
+ multiqueue_put(main_loop.events, free_channel_event, chan);
}
}
@@ -260,9 +282,8 @@ void callback_reader_start(CallbackReader *reader, const char *type)
reader->type = type;
}
-static void free_channel_event(void **argv)
+static void channel_destroy(Channel *chan)
{
- Channel *chan = argv[0];
if (chan->is_rpc) {
rpc_free(chan);
}
@@ -275,11 +296,17 @@ static void free_channel_event(void **argv)
callback_reader_free(&chan->on_stderr);
callback_free(&chan->on_exit);
- pmap_del(uint64_t)(&channels, chan->id, NULL);
multiqueue_free(chan->events);
xfree(chan);
}
+static void free_channel_event(void **argv)
+{
+ Channel *chan = argv[0];
+ pmap_del(uint64_t)(&channels, chan->id, NULL);
+ channel_destroy(chan);
+}
+
static void channel_destroy_early(Channel *chan)
{
if ((chan->id != --next_chan_id)) {
@@ -293,7 +320,7 @@ static void channel_destroy_early(Channel *chan)
}
// uv will keep a reference to handles until next loop tick, so delay free
- multiqueue_put(main_loop.events, free_channel_event, 1, chan);
+ multiqueue_put(main_loop.events, free_channel_event, chan);
}
static void close_cb(Stream *stream, void *data)
@@ -553,7 +580,10 @@ size_t channel_send(uint64_t id, char *data, size_t len, bool data_owned, const
goto retfree;
}
// unbuffered write
- written = len * fwrite(data, len, 1, stderr);
+ ptrdiff_t wres = os_write(STDERR_FILENO, data, len, false);
+ if (wres >= 0) {
+ written = (size_t)wres;
+ }
goto retfree;
}
@@ -657,7 +687,7 @@ static void schedule_channel_event(Channel *chan)
{
if (!chan->callback_scheduled) {
if (!chan->callback_busy) {
- multiqueue_put(chan->events, on_channel_event, 1, chan);
+ multiqueue_put(chan->events, on_channel_event, chan);
channel_incref(chan);
}
chan->callback_scheduled = true;
@@ -682,7 +712,7 @@ static void on_channel_event(void **args)
chan->callback_busy = false;
if (chan->callback_scheduled) {
// further callback was deferred to avoid recursion.
- multiqueue_put(chan->events, on_channel_event, 1, chan);
+ multiqueue_put(chan->events, on_channel_event, chan);
channel_incref(chan);
}
@@ -777,19 +807,21 @@ static void channel_callback_call(Channel *chan, CallbackReader *reader)
/// and `buf` is assumed to be a new, unmodified buffer.
void channel_terminal_open(buf_T *buf, Channel *chan)
{
- TerminalOptions topts;
- topts.data = chan;
- topts.width = chan->stream.pty.width;
- topts.height = chan->stream.pty.height;
- topts.write_cb = term_write;
- topts.resize_cb = term_resize;
- topts.close_cb = term_close;
+ TerminalOptions topts = {
+ .data = chan,
+ .width = chan->stream.pty.width,
+ .height = chan->stream.pty.height,
+ .write_cb = term_write,
+ .resize_cb = term_resize,
+ .close_cb = term_close,
+ .force_crlf = false,
+ };
buf->b_p_channel = (OptInt)chan->id; // 'channel' option
channel_incref(chan);
terminal_open(&chan->term, buf, topts);
}
-static void term_write(char *buf, size_t size, void *data)
+static void term_write(const char *buf, size_t size, void *data)
{
Channel *chan = data;
if (chan->stream.proc.in.closed) {
@@ -812,7 +844,7 @@ static inline void term_delayed_free(void **argv)
{
Channel *chan = argv[0];
if (chan->stream.proc.in.pending_reqs || chan->stream.proc.out.pending_reqs) {
- multiqueue_put(chan->events, term_delayed_free, 1, chan);
+ multiqueue_put(chan->events, term_delayed_free, chan);
return;
}
@@ -826,7 +858,7 @@ static void term_close(void *data)
{
Channel *chan = data;
process_stop(&chan->stream.proc);
- multiqueue_put(chan->events, term_delayed_free, 1, data);
+ multiqueue_put(chan->events, term_delayed_free, data);
}
void channel_info_changed(Channel *chan, bool new_chan)
@@ -834,7 +866,7 @@ void channel_info_changed(Channel *chan, bool new_chan)
event_T event = new_chan ? EVENT_CHANOPEN : EVENT_CHANINFO;
if (has_event(event)) {
channel_incref(chan);
- multiqueue_put(main_loop.events, set_info_event, 2, chan, event);
+ multiqueue_put(main_loop.events, set_info_event, chan, (void *)(intptr_t)event);
}
}
@@ -845,9 +877,10 @@ static void set_info_event(void **argv)
save_v_event_T save_v_event;
dict_T *dict = get_v_event(&save_v_event);
- Dictionary info = channel_info(chan->id);
+ Arena arena = ARENA_EMPTY;
+ Dictionary info = channel_info(chan->id, &arena);
typval_T retval;
- (void)object_to_vim(DICTIONARY_OBJ(info), &retval, NULL);
+ object_to_vim(DICTIONARY_OBJ(info), &retval, NULL);
assert(retval.v_type == VAR_DICT);
tv_dict_add_dict(dict, S_LEN("info"), retval.vval.v_dict);
tv_dict_set_keys_readonly(dict);
@@ -855,7 +888,7 @@ static void set_info_event(void **argv)
apply_autocmds(event, NULL, NULL, false, curbuf);
restore_v_event(dict, &save_v_event);
- api_free_dictionary(info);
+ arena_mem_free(arena_finish(&arena));
channel_decref(chan);
}
@@ -867,15 +900,15 @@ bool channel_job_running(uint64_t id)
&& !process_is_stopped(&chan->stream.proc));
}
-Dictionary channel_info(uint64_t id)
+Dictionary channel_info(uint64_t id, Arena *arena)
{
Channel *chan = find_channel(id);
if (!chan) {
return (Dictionary)ARRAY_DICT_INIT;
}
- Dictionary info = ARRAY_DICT_INIT;
- PUT(info, "id", INTEGER_OBJ((Integer)chan->id));
+ Dictionary info = arena_dict(arena, 8);
+ PUT_C(info, "id", INTEGER_OBJ((Integer)chan->id));
const char *stream_desc, *mode_desc;
switch (chan->streamtype) {
@@ -883,18 +916,20 @@ Dictionary channel_info(uint64_t id)
stream_desc = "job";
if (chan->stream.proc.type == kProcessTypePty) {
const char *name = pty_process_tty_name(&chan->stream.pty);
- PUT(info, "pty", CSTR_TO_OBJ(name));
+ PUT_C(info, "pty", CSTR_TO_ARENA_OBJ(arena, name));
}
- char **p = chan->stream.proc.argv;
+ char **args = chan->stream.proc.argv;
Array argv = ARRAY_DICT_INIT;
- if (p != NULL) {
- while (*p != NULL) {
- ADD(argv, CSTR_TO_OBJ(*p));
- p++;
+ if (args != NULL) {
+ size_t n;
+ for (n = 0; args[n] != NULL; n++) {}
+ argv = arena_array(arena, n);
+ for (size_t i = 0; i < n; i++) {
+ ADD_C(argv, CSTR_AS_OBJ(args[i]));
}
}
- PUT(info, "argv", ARRAY_OBJ(argv));
+ PUT_C(info, "argv", ARRAY_OBJ(argv));
break;
}
@@ -907,51 +942,51 @@ Dictionary channel_info(uint64_t id)
break;
case kChannelStreamInternal:
- PUT(info, "internal", BOOLEAN_OBJ(true));
+ PUT_C(info, "internal", BOOLEAN_OBJ(true));
FALLTHROUGH;
case kChannelStreamSocket:
stream_desc = "socket";
break;
}
- PUT(info, "stream", CSTR_TO_OBJ(stream_desc));
+ PUT_C(info, "stream", CSTR_AS_OBJ(stream_desc));
if (chan->is_rpc) {
mode_desc = "rpc";
- PUT(info, "client", DICTIONARY_OBJ(rpc_client_info(chan)));
+ PUT_C(info, "client", DICTIONARY_OBJ(chan->rpc.info));
} else if (chan->term) {
mode_desc = "terminal";
- PUT(info, "buffer", BUFFER_OBJ(terminal_buf(chan->term)));
+ PUT_C(info, "buffer", BUFFER_OBJ(terminal_buf(chan->term)));
} else {
mode_desc = "bytes";
}
- PUT(info, "mode", CSTR_TO_OBJ(mode_desc));
+ PUT_C(info, "mode", CSTR_AS_OBJ(mode_desc));
return info;
}
/// Simple int64_t comparison function for use with qsort()
-static int int64_t_cmp(const void *a, const void *b)
+static int int64_t_cmp(const void *pa, const void *pb)
{
- int64_t diff = *(int64_t *)a - *(int64_t *)b;
- return (diff < 0) ? -1 : (diff > 0);
+ const int64_t a = *(const int64_t *)pa;
+ const int64_t b = *(const int64_t *)pb;
+ return a == b ? 0 : a > b ? 1 : -1;
}
-Array channel_all_info(void)
+Array channel_all_info(Arena *arena)
{
// order the items in the array by channel number, for Determinismâ„¢
kvec_t(int64_t) ids = KV_INITIAL_VALUE;
- kv_resize(ids, map_size(&channels));
+ kv_fixsize_arena(arena, ids, map_size(&channels));
uint64_t id;
map_foreach_key(&channels, id, {
kv_push(ids, (int64_t)id);
});
qsort(ids.items, ids.size, sizeof ids.items[0], int64_t_cmp);
- Array ret = ARRAY_DICT_INIT;
+ Array ret = arena_array(arena, ids.size);
for (size_t i = 0; i < ids.size; i++) {
- ADD(ret, DICTIONARY_OBJ(channel_info((uint64_t)ids.items[i])));
+ ADD_C(ret, DICTIONARY_OBJ(channel_info((uint64_t)ids.items[i], arena)));
}
- kv_destroy(ids);
return ret;
}