aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/os/job.c
diff options
context:
space:
mode:
authorThiago de Arruda <tpadilha84@gmail.com>2014-10-20 09:25:58 -0300
committerThiago de Arruda <tpadilha84@gmail.com>2014-10-21 11:05:49 -0300
commit264e0d872c598062be2b2a118d38c89a6ed5a023 (patch)
treecd4867f0e7b4448c33ed9f0141f00a3cb6512569 /src/nvim/os/job.c
parent77cc078c41c4348a3649cc366a262e6fab43980b (diff)
downloadrneovim-264e0d872c598062be2b2a118d38c89a6ed5a023.tar.gz
rneovim-264e0d872c598062be2b2a118d38c89a6ed5a023.tar.bz2
rneovim-264e0d872c598062be2b2a118d38c89a6ed5a023.zip
event: Remove automatic event deferall
This is how asynchronous events are currently handled by Nvim: - Libuv event loop is entered when Nvim blocks for user input(os_inchar is called) - Any event delivered by libuv that is not user input is queued for processing - The `K_EVENT` special key code is returned by os_inchar - `K_EVENT` is returned to a loop that is reading keys for the current Nvim mode, which will be handled by calling event_process() This approach has the advantage of integrating nicely with the current codebase, eg: vimscript code can be executed asynchronously with little surprises(Its the same as if the user typed a key). The problem with using keys to represent any event is that it also interferes with operators, and not every event needs or should do that. For example, consider this scenario: - A msgpack-rpc client calls vim_feedkeys("d") - Nvim processes K_EVENT, pushing "d" to the input queue - Nvim processes "d", entering operator-pending mode to wait for a motion - The client calls vim_feedkeys("w"), expecting Nvim to delete a word - Nvim processes K_EVENT, breaking out of operator-pending and pushing "w" - Nvim processes "w", moving a word This commit fixes the above problem by removing all automatic calls to `event_push`(which is what generates K_EVENT input). Right now this also breaks redrawing initiated by asynchronous events(and possibly other stuff too, Nvim is a complex state machine and we can't simply run vimscript code anywhere). In future commits the calls to `event_push` will be inserted only where it's absolutely necessary to run code in "key reading loops", such as when executing vimscript code or mutating editor data structures in ways that currently can only be done by the user.
Diffstat (limited to 'src/nvim/os/job.c')
-rw-r--r--src/nvim/os/job.c55
1 files changed, 13 insertions, 42 deletions
diff --git a/src/nvim/os/job.c b/src/nvim/os/job.c
index d0ac82c047..091da5d213 100644
--- a/src/nvim/os/job.c
+++ b/src/nvim/os/job.c
@@ -14,7 +14,6 @@
#include "nvim/os/event_defs.h"
#include "nvim/os/time.h"
#include "nvim/os/shell.h"
-#include "nvim/os/signal.h"
#include "nvim/vim.h"
#include "nvim/memory.h"
#include "nvim/term.h"
@@ -103,21 +102,24 @@ void job_teardown(void)
// Prepare to start shooting
for (i = 0; i < MAX_RUNNING_JOBS; i++) {
- if ((job = table[i]) == NULL) {
- continue;
- }
+ job = table[i];
// Still alive
- while (is_alive(job) && remaining_tries--) {
+ while (job && is_alive(job) && remaining_tries--) {
os_delay(50, 0);
// Acknowledge child exits
uv_run(uv_default_loop(), UV_RUN_NOWAIT);
+ // It's possible that the uv_run call removed the job from the table,
+ // reset 'job' so the next iteration won't run in that case.
+ job = table[i];
}
- if (is_alive(job)) {
+ if (job && is_alive(job)) {
uv_process_kill(&job->proc, SIGKILL);
}
}
+ // Last run to ensure all children were removed
+ uv_run(uv_default_loop(), UV_RUN_NOWAIT);
}
/// Tries to start a new job.
@@ -213,14 +215,8 @@ Job *job_start(char **argv,
job->in = wstream_new(maxmem);
wstream_set_stream(job->in, (uv_stream_t *)&job->proc_stdin);
// Start the readable streams
- job->out = rstream_new(read_cb,
- rbuffer_new(JOB_BUFFER_SIZE),
- job,
- job_event_source(job));
- job->err = rstream_new(read_cb,
- rbuffer_new(JOB_BUFFER_SIZE),
- job,
- job_event_source(job));
+ job->out = rstream_new(read_cb, rbuffer_new(JOB_BUFFER_SIZE), job);
+ job->err = rstream_new(read_cb, rbuffer_new(JOB_BUFFER_SIZE), job);
rstream_set_stream(job->out, (uv_stream_t *)&job->proc_stdout);
rstream_set_stream(job->err, (uv_stream_t *)&job->proc_stderr);
rstream_start(job->out);
@@ -277,8 +273,6 @@ int job_wait(Job *job, int ms) FUNC_ATTR_NONNULL_ALL
int old_mode = cur_tmode;
settmode(TMODE_COOK);
- EventSource sources[] = {job_event_source(job), signal_event_source(), NULL};
-
// keep track of the elapsed time if ms > 0
uint64_t before = (ms > 0) ? os_hrtime() : 0;
@@ -288,7 +282,7 @@ int job_wait(Job *job, int ms) FUNC_ATTR_NONNULL_ALL
break;
}
- event_poll(ms, sources);
+ event_poll(ms);
// we'll assume that a user frantically hitting interrupt doesn't like
// the current job. Signal that it has to be killed.
@@ -369,14 +363,6 @@ bool job_write(Job *job, WBuffer *buffer)
return wstream_write(job->in, buffer);
}
-/// Runs the read callback associated with the job exit event
-///
-/// @param event Object containing data necessary to invoke the callback
-void job_exit_event(Event event)
-{
- job_exit_callback(event.data.job);
-}
-
/// Get the job id
///
/// @param job A pointer to the job
@@ -395,11 +381,6 @@ void *job_data(Job *job)
return job->data;
}
-EventSource job_event_source(Job *job)
-{
- return job;
-}
-
static void job_exit_callback(Job *job)
{
// Free the slot now, 'exit_cb' may want to start another job to replace
@@ -470,7 +451,7 @@ static void read_cb(RStream *rstream, void *data, bool eof)
}
if (eof && --job->pending_refs == 0) {
- emit_exit_event(job);
+ job_exit_callback(job);
}
}
@@ -481,20 +462,10 @@ static void exit_cb(uv_process_t *proc, int64_t status, int term_signal)
job->status = status;
if (--job->pending_refs == 0) {
- emit_exit_event(job);
+ job_exit_callback(job);
}
}
-static void emit_exit_event(Job *job)
-{
- Event event = {
- .source = job_event_source(job),
- .handler = job_exit_event,
- .data.job = job
- };
- event_push(event);
-}
-
static void close_cb(uv_handle_t *handle)
{
Job *job = handle_get_job(handle);