aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/event
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/event')
-rw-r--r--src/nvim/event/libuv_process.c25
-rw-r--r--src/nvim/event/libuv_process.h3
-rw-r--r--src/nvim/event/loop.c49
-rw-r--r--src/nvim/event/loop.h6
-rw-r--r--src/nvim/event/multiqueue.c6
-rw-r--r--src/nvim/event/process.c44
-rw-r--r--src/nvim/event/process.h14
-rw-r--r--src/nvim/event/rstream.c9
-rw-r--r--src/nvim/event/signal.c1
-rw-r--r--src/nvim/event/signal.h3
-rw-r--r--src/nvim/event/socket.c13
-rw-r--r--src/nvim/event/socket.h3
-rw-r--r--src/nvim/event/stream.c12
-rw-r--r--src/nvim/event/stream.h8
-rw-r--r--src/nvim/event/time.h4
-rw-r--r--src/nvim/event/wstream.c6
-rw-r--r--src/nvim/event/wstream.h3
17 files changed, 155 insertions, 54 deletions
diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c
index 0251ea9957..e528d21a71 100644
--- a/src/nvim/event/libuv_process.c
+++ b/src/nvim/event/libuv_process.c
@@ -2,16 +2,18 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <assert.h>
+#include <stdint.h>
#include <uv.h>
+#include "nvim/eval/typval.h"
#include "nvim/event/libuv_process.h"
#include "nvim/event/loop.h"
#include "nvim/event/process.h"
-#include "nvim/event/rstream.h"
-#include "nvim/event/wstream.h"
+#include "nvim/event/stream.h"
#include "nvim/log.h"
#include "nvim/macros.h"
#include "nvim/os/os.h"
+#include "nvim/ui_client.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/libuv_process.c.generated.h"
@@ -25,7 +27,7 @@ int libuv_process_spawn(LibuvProcess *uvproc)
uvproc->uvopts.file = proc->argv[0];
uvproc->uvopts.args = proc->argv;
uvproc->uvopts.flags = UV_PROCESS_WINDOWS_HIDE;
-#ifdef WIN32
+#ifdef MSWIN
// libuv collapses the argv to a CommandLineToArgvW()-style string. cmd.exe
// expects a different syntax (must be prepared by the caller before now).
if (os_shell_is_cmdexe(proc->argv[0])) {
@@ -40,11 +42,19 @@ int libuv_process_spawn(LibuvProcess *uvproc)
#endif
uvproc->uvopts.exit_cb = exit_cb;
uvproc->uvopts.cwd = proc->cwd;
+
uvproc->uvopts.stdio = uvproc->uvstdio;
uvproc->uvopts.stdio_count = 3;
uvproc->uvstdio[0].flags = UV_IGNORE;
uvproc->uvstdio[1].flags = UV_IGNORE;
uvproc->uvstdio[2].flags = UV_IGNORE;
+
+ if (ui_client_forward_stdin) {
+ assert(UI_CLIENT_STDIN_FD == 3);
+ uvproc->uvopts.stdio_count = 4;
+ uvproc->uvstdio[3].data.fd = 0;
+ uvproc->uvstdio[3].flags = UV_INHERIT_FD;
+ }
uvproc->uv.data = proc;
if (proc->env) {
@@ -55,7 +65,7 @@ int libuv_process_spawn(LibuvProcess *uvproc)
if (!proc->in.closed) {
uvproc->uvstdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
-#ifdef WIN32
+#ifdef MSWIN
uvproc->uvstdio[0].flags |= proc->overlapped ? UV_OVERLAPPED_PIPE : 0;
#endif
uvproc->uvstdio[0].data.stream = STRUCT_CAST(uv_stream_t,
@@ -64,7 +74,7 @@ int libuv_process_spawn(LibuvProcess *uvproc)
if (!proc->out.closed) {
uvproc->uvstdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
-#ifdef WIN32
+#ifdef MSWIN
// pipe must be readable for IOCP to work on Windows.
uvproc->uvstdio[1].flags |= proc->overlapped ?
(UV_READABLE_PIPE | UV_OVERLAPPED_PIPE) : 0;
@@ -77,6 +87,9 @@ int libuv_process_spawn(LibuvProcess *uvproc)
uvproc->uvstdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
uvproc->uvstdio[2].data.stream = STRUCT_CAST(uv_stream_t,
&proc->err.uv.pipe);
+ } else if (proc->fwd_err) {
+ uvproc->uvstdio[2].flags = UV_INHERIT_FD;
+ uvproc->uvstdio[2].data.fd = STDERR_FILENO;
}
int status;
@@ -113,7 +126,7 @@ static void close_cb(uv_handle_t *handle)
static void exit_cb(uv_process_t *handle, int64_t status, int term_signal)
{
Process *proc = handle->data;
-#if defined(WIN32)
+#if defined(MSWIN)
// Use stored/expected signal.
term_signal = proc->exit_signal;
#endif
diff --git a/src/nvim/event/libuv_process.h b/src/nvim/event/libuv_process.h
index 1132ce79ca..4472839944 100644
--- a/src/nvim/event/libuv_process.h
+++ b/src/nvim/event/libuv_process.h
@@ -3,13 +3,14 @@
#include <uv.h>
+#include "nvim/event/loop.h"
#include "nvim/event/process.h"
typedef struct libuv_process {
Process process;
uv_process_t uv;
uv_process_options_t uvopts;
- uv_stdio_container_t uvstdio[3];
+ uv_stdio_container_t uvstdio[4];
} LibuvProcess;
static inline LibuvProcess libuv_process_init(Loop *loop, void *data)
diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c
index 1b5cc23b09..ab2524c1a9 100644
--- a/src/nvim/event/loop.c
+++ b/src/nvim/event/loop.c
@@ -1,13 +1,16 @@
// 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 <stdarg.h>
+#include <stdbool.h>
#include <stdint.h>
+#include <stdlib.h>
#include <uv.h>
+#include "nvim/event/defs.h"
#include "nvim/event/loop.h"
-#include "nvim/event/process.h"
#include "nvim/log.h"
+#include "nvim/memory.h"
+#include "nvim/os/time.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/loop.c.generated.h"
@@ -31,41 +34,57 @@ void loop_init(Loop *loop, void *data)
loop->poll_timer.data = xmalloc(sizeof(bool)); // "timeout expired" flag
}
-/// Processes one `Loop.uv` event (at most).
-/// Processes all `Loop.fast_events` events.
-/// Does NOT process `Loop.events`, that is an application-specific decision.
+/// Process `Loop.uv` events with a timeout.
///
/// @param loop
-/// @param ms 0: non-blocking poll.
-/// >0: timeout after `ms`.
-/// <0: wait forever.
-/// @returns true if `ms` timeout was reached
-bool loop_poll_events(Loop *loop, int ms)
+/// @param ms 0: non-blocking poll.
+/// > 0: timeout after `ms`.
+/// < 0: wait forever.
+/// @param once true: process at most one `Loop.uv` event.
+/// false: process until `ms` timeout (only has effect if `ms` > 0).
+/// @return true if `ms` > 0 and was reached
+bool loop_uv_run(Loop *loop, int64_t ms, bool once)
{
if (loop->recursive++) {
abort(); // Should not re-enter uv_run
}
uv_run_mode mode = UV_RUN_ONCE;
- bool timeout_expired = false;
+ bool *timeout_expired = loop->poll_timer.data;
+ *timeout_expired = false;
if (ms > 0) {
- *((bool *)loop->poll_timer.data) = false; // reset "timeout expired" flag
- // Dummy timer to ensure UV_RUN_ONCE does not block indefinitely for I/O.
+ // This timer ensures UV_RUN_ONCE does not block indefinitely for I/O.
uv_timer_start(&loop->poll_timer, timer_cb, (uint64_t)ms, (uint64_t)ms);
} else if (ms == 0) {
// For ms == 0, do a non-blocking event poll.
mode = UV_RUN_NOWAIT;
}
- uv_run(&loop->uv, mode);
+ do { // -V1044
+ uv_run(&loop->uv, mode);
+ } while (ms > 0 && !once && !*timeout_expired); // -V560
if (ms > 0) {
- timeout_expired = *((bool *)loop->poll_timer.data);
uv_timer_stop(&loop->poll_timer);
}
loop->recursive--; // Can re-enter uv_run now
+ return *timeout_expired;
+}
+
+/// Processes one `Loop.uv` event (at most).
+/// Processes all `Loop.fast_events` events.
+/// Does NOT process `Loop.events`, that is an application-specific decision.
+///
+/// @param loop
+/// @param ms 0: non-blocking poll.
+/// > 0: timeout after `ms`.
+/// < 0: wait forever.
+/// @return true if `ms` > 0 and was reached
+bool loop_poll_events(Loop *loop, int64_t ms)
+{
+ bool timeout_expired = loop_uv_run(loop, ms, true);
multiqueue_process_events(loop->fast_events);
return timeout_expired;
}
diff --git a/src/nvim/event/loop.h b/src/nvim/event/loop.h
index 65980c6c05..b2265a726d 100644
--- a/src/nvim/event/loop.h
+++ b/src/nvim/event/loop.h
@@ -4,8 +4,8 @@
#include <stdint.h>
#include <uv.h>
+#include "klib/klist.h"
#include "nvim/event/multiqueue.h"
-#include "nvim/lib/klist.h"
#include "nvim/os/time.h"
typedef void *WatcherPtr;
@@ -58,7 +58,7 @@ typedef struct loop {
// Poll for events until a condition or timeout
#define LOOP_PROCESS_EVENTS_UNTIL(loop, multiqueue, timeout, condition) \
do { \
- int remaining = timeout; \
+ int64_t remaining = timeout; \
uint64_t before = (remaining > 0) ? os_hrtime() : 0; \
while (!(condition)) { \
LOOP_PROCESS_EVENTS(loop, multiqueue, remaining); \
@@ -66,7 +66,7 @@ typedef struct loop {
break; \
} else if (remaining > 0) { \
uint64_t now = os_hrtime(); \
- remaining -= (int)((now - before) / 1000000); \
+ remaining -= (int64_t)((now - before) / 1000000); \
before = now; \
if (remaining <= 0) { \
break; \
diff --git a/src/nvim/event/multiqueue.c b/src/nvim/event/multiqueue.c
index 40d20033e0..e05084b656 100644
--- a/src/nvim/event/multiqueue.c
+++ b/src/nvim/event/multiqueue.c
@@ -46,14 +46,14 @@
// other sources and focus on a specific channel.
#include <assert.h>
-#include <stdarg.h>
#include <stdbool.h>
-#include <stdint.h>
+#include <stddef.h>
#include <uv.h>
+#include "nvim/event/defs.h"
#include "nvim/event/multiqueue.h"
+#include "nvim/lib/queue.h"
#include "nvim/memory.h"
-#include "nvim/os/time.h"
typedef struct multiqueue_item MultiQueueItem;
struct multiqueue_item {
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index e029f778f6..1a524a56ca 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -2,20 +2,25 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <assert.h>
+#include <inttypes.h>
+#include <signal.h>
#include <stdlib.h>
#include <uv.h>
+#include "klib/klist.h"
#include "nvim/event/libuv_process.h"
#include "nvim/event/loop.h"
#include "nvim/event/process.h"
-#include "nvim/event/rstream.h"
-#include "nvim/event/wstream.h"
#include "nvim/globals.h"
#include "nvim/log.h"
#include "nvim/macros.h"
+#include "nvim/main.h"
#include "nvim/os/process.h"
#include "nvim/os/pty_process.h"
#include "nvim/os/shell.h"
+#include "nvim/os/time.h"
+#include "nvim/rbuffer.h"
+#include "nvim/ui_client.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/process.c.generated.h"
@@ -32,10 +37,16 @@ void __gcov_flush(void);
static bool process_is_tearing_down = false;
+// Delay exit until handles are closed, to avoid deadlocks
+static int exit_need_delay = 0;
+
/// @returns zero on success, or negative error code
int process_spawn(Process *proc, bool in, bool out, bool err)
FUNC_ATTR_NONNULL_ALL
{
+ // forwarding stderr contradicts with processing it internally
+ assert(!(err && proc->fwd_err));
+
if (in) {
uv_pipe_init(&proc->loop->uv, &proc->in.uv.pipe, 0);
} else {
@@ -395,12 +406,41 @@ static void process_close_handles(void **argv)
exit_need_delay--;
}
+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, 1, main_loop.exit_delay_timer.data);
+}
+
+static void exit_event(void **argv)
+{
+ int status = (int)(intptr_t)argv[0];
+ if (exit_need_delay) {
+ main_loop.exit_delay_timer.data = argv[0];
+ uv_timer_start(&main_loop.exit_delay_timer, exit_delay_cb, 0, 0);
+ return;
+ }
+
+ if (!exiting) {
+ os_exit(status);
+ }
+}
+
+void exit_from_channel(int status)
+{
+ multiqueue_put(main_loop.fast_events, exit_event, 1, status);
+}
+
static void on_process_exit(Process *proc)
{
Loop *loop = proc->loop;
ILOG("exited: pid=%d status=%d stoptime=%" PRIu64, proc->pid, proc->status,
proc->stopped_time);
+ if (ui_client_channel_id) {
+ exit_from_channel(proc->status);
+ }
+
// Process has terminated, but there could still be data to be read from the
// OS. We are still in the libuv loop, so we cannot call code that polls for
// more data directly. Instead delay the reading after the libuv loop by
diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h
index 30254bfe07..e0057faffb 100644
--- a/src/nvim/event/process.h
+++ b/src/nvim/event/process.h
@@ -1,11 +1,20 @@
#ifndef NVIM_EVENT_PROCESS_H
#define NVIM_EVENT_PROCESS_H
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/event/loop.h"
+#include "nvim/event/multiqueue.h"
#include "nvim/event/rstream.h"
+#include "nvim/event/stream.h"
#include "nvim/event/wstream.h"
+struct process;
+
typedef enum {
kProcessTypeUv,
kProcessTypePty,
@@ -29,7 +38,7 @@ struct process {
/// Exit handler. If set, user must call process_free().
process_exit_cb cb;
internal_process_cb internal_exit_cb, internal_close_cb;
- bool closed, detach, overlapped;
+ bool closed, detach, overlapped, fwd_err;
MultiQueue *events;
};
@@ -53,7 +62,8 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data)
.closed = false,
.internal_close_cb = NULL,
.internal_exit_cb = NULL,
- .detach = false
+ .detach = false,
+ .fwd_err = false,
};
}
diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c
index 2847788ef8..a88d62fd6b 100644
--- a/src/nvim/event/rstream.c
+++ b/src/nvim/event/rstream.c
@@ -3,17 +3,18 @@
#include <assert.h>
#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
-#include <stdlib.h>
#include <uv.h>
-#include "nvim/ascii.h"
#include "nvim/event/loop.h"
#include "nvim/event/rstream.h"
+#include "nvim/event/stream.h"
#include "nvim/log.h"
+#include "nvim/macros.h"
#include "nvim/main.h"
-#include "nvim/memory.h"
-#include "nvim/vim.h"
+#include "nvim/os/os_defs.h"
+#include "nvim/rbuffer.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/rstream.c.generated.h"
diff --git a/src/nvim/event/signal.c b/src/nvim/event/signal.c
index 4a45a2ec2f..8256ca2091 100644
--- a/src/nvim/event/signal.c
+++ b/src/nvim/event/signal.c
@@ -1,6 +1,7 @@
// 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 <stddef.h>
#include <uv.h>
#include "nvim/event/loop.h"
diff --git a/src/nvim/event/signal.h b/src/nvim/event/signal.h
index 7fe352edef..f9adf62c20 100644
--- a/src/nvim/event/signal.h
+++ b/src/nvim/event/signal.h
@@ -4,6 +4,9 @@
#include <uv.h>
#include "nvim/event/loop.h"
+#include "nvim/event/multiqueue.h"
+
+struct signal_watcher;
typedef struct signal_watcher SignalWatcher;
typedef void (*signal_cb)(SignalWatcher *watcher, int signum, void *data);
diff --git a/src/nvim/event/socket.c b/src/nvim/event/socket.c
index 9496a568b9..10756015ad 100644
--- a/src/nvim/event/socket.c
+++ b/src/nvim/event/socket.c
@@ -2,23 +2,24 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <assert.h>
-#include <stdint.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
#include <uv.h>
#include "nvim/ascii.h"
#include "nvim/charset.h"
#include "nvim/event/loop.h"
-#include "nvim/event/rstream.h"
#include "nvim/event/socket.h"
-#include "nvim/event/wstream.h"
+#include "nvim/event/stream.h"
+#include "nvim/gettext.h"
#include "nvim/log.h"
#include "nvim/macros.h"
#include "nvim/main.h"
#include "nvim/memory.h"
#include "nvim/os/os.h"
#include "nvim/path.h"
-#include "nvim/strings.h"
-#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/socket.c.generated.h"
@@ -125,7 +126,7 @@ int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb)
// Libuv converts ENOENT to EACCES for Windows compatibility, but if
// the parent directory does not exist, ENOENT would be more accurate.
*path_tail(watcher->addr) = NUL;
- if (!os_path_exists((char_u *)watcher->addr)) {
+ if (!os_path_exists(watcher->addr)) {
result = UV_ENOENT;
}
}
diff --git a/src/nvim/event/socket.h b/src/nvim/event/socket.h
index d30ae45502..c6fcdec4bb 100644
--- a/src/nvim/event/socket.h
+++ b/src/nvim/event/socket.h
@@ -4,9 +4,12 @@
#include <uv.h>
#include "nvim/event/loop.h"
+#include "nvim/event/multiqueue.h"
#include "nvim/event/rstream.h"
#include "nvim/event/wstream.h"
+struct socket_watcher;
+
#define ADDRESS_MAX_SIZE 256
typedef struct socket_watcher SocketWatcher;
diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c
index b34fd73d52..0a4918636a 100644
--- a/src/nvim/event/stream.c
+++ b/src/nvim/event/stream.c
@@ -3,14 +3,16 @@
#include <assert.h>
#include <stdbool.h>
-#include <stdio.h>
+#include <stddef.h>
#include <uv.h>
+#include <uv/version.h>
+#include "nvim/event/loop.h"
#include "nvim/event/stream.h"
#include "nvim/log.h"
#include "nvim/macros.h"
#include "nvim/rbuffer.h"
-#ifdef WIN32
+#ifdef MSWIN
# include "nvim/os/os_win_console.h"
#endif
@@ -60,7 +62,7 @@ void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream)
stream->uv.idle.data = stream;
} else {
assert(type == UV_NAMED_PIPE || type == UV_TTY);
-#ifdef WIN32
+#ifdef MSWIN
if (type == UV_TTY) {
uv_tty_init(&loop->uv, &stream->uv.tty, fd, 0);
uv_tty_set_mode(&stream->uv.tty, UV_TTY_MODE_RAW);
@@ -75,7 +77,7 @@ void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream)
uv_pipe_init(&loop->uv, &stream->uv.pipe, 0);
uv_pipe_open(&stream->uv.pipe, fd);
stream->uvstream = STRUCT_CAST(uv_stream_t, &stream->uv.pipe);
-#ifdef WIN32
+#ifdef MSWIN
}
#endif
}
@@ -109,7 +111,7 @@ void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data)
stream->close_cb = on_stream_close;
stream->close_cb_data = data;
-#ifdef WIN32
+#ifdef MSWIN
if (UV_TTY == uv_guess_handle(stream->fd)) {
// Undo UV_TTY_MODE_RAW from stream_init(). #10801
uv_tty_set_mode(&stream->uv.tty, UV_TTY_MODE_NORMAL);
diff --git a/src/nvim/event/stream.h b/src/nvim/event/stream.h
index 02e816b4be..33d2d6e775 100644
--- a/src/nvim/event/stream.h
+++ b/src/nvim/event/stream.h
@@ -6,8 +6,11 @@
#include <uv.h>
#include "nvim/event/loop.h"
+#include "nvim/event/multiqueue.h"
#include "nvim/rbuffer.h"
+struct stream;
+
typedef struct stream Stream;
/// Type of function called when the Stream buffer is filled with data
///
@@ -16,8 +19,7 @@ typedef struct stream Stream;
/// @param count Number of bytes that was read.
/// @param data User-defined data
/// @param eof If the stream reached EOF.
-typedef void (*stream_read_cb)(Stream *stream, RBuffer *buf, size_t count,
- void *data, bool eof);
+typedef void (*stream_read_cb)(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof);
/// Type of function called when the Stream has information about a write
/// request.
@@ -35,7 +37,7 @@ struct stream {
uv_pipe_t pipe;
uv_tcp_t tcp;
uv_idle_t idle;
-#ifdef WIN32
+#ifdef MSWIN
uv_tty_t tty;
#endif
} uv;
diff --git a/src/nvim/event/time.h b/src/nvim/event/time.h
index a6de89ad6e..e84488fdd6 100644
--- a/src/nvim/event/time.h
+++ b/src/nvim/event/time.h
@@ -1,9 +1,13 @@
#ifndef NVIM_EVENT_TIME_H
#define NVIM_EVENT_TIME_H
+#include <stdbool.h>
#include <uv.h>
#include "nvim/event/loop.h"
+#include "nvim/event/multiqueue.h"
+
+struct time_watcher;
typedef struct time_watcher TimeWatcher;
typedef void (*time_cb)(TimeWatcher *watcher, void *data);
diff --git a/src/nvim/event/wstream.c b/src/nvim/event/wstream.c
index d81ffa5c15..65391ba5cf 100644
--- a/src/nvim/event/wstream.c
+++ b/src/nvim/event/wstream.c
@@ -3,15 +3,13 @@
#include <assert.h>
#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
#include <uv.h>
#include "nvim/event/loop.h"
+#include "nvim/event/stream.h"
#include "nvim/event/wstream.h"
-#include "nvim/log.h"
+#include "nvim/macros.h"
#include "nvim/memory.h"
-#include "nvim/vim.h"
#define DEFAULT_MAXMEM 1024 * 1024 * 2000
diff --git a/src/nvim/event/wstream.h b/src/nvim/event/wstream.h
index d599d29913..ef1311c619 100644
--- a/src/nvim/event/wstream.h
+++ b/src/nvim/event/wstream.h
@@ -2,12 +2,15 @@
#define NVIM_EVENT_WSTREAM_H
#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
#include <uv.h>
#include "nvim/event/loop.h"
#include "nvim/event/stream.h"
+struct wbuffer;
+
typedef struct wbuffer WBuffer;
typedef void (*wbuffer_data_finalizer)(void *data);