Skip to content

Instantly share code, notes, and snippets.

@jonthn
Created June 13, 2017 09:59
Show Gist options
  • Save jonthn/5e34b7b516b6297386464de9ffcddf24 to your computer and use it in GitHub Desktop.
Save jonthn/5e34b7b516b6297386464de9ffcddf24 to your computer and use it in GitHub Desktop.
--- work/neovim/src/nvim/event/process.c 2017-06-08 09:36:08.000000000 +0200
+++ process.c 2017-06-13 11:51:28.000000000 +0200
@@ -34,9 +34,37 @@
static bool process_is_tearing_down = false;
+static void
+process_exists(void *prgm)
+{
+ int *pid = prgm;
+ while (0 < getpgid(*pid))
+ {
+ ILOG("PROCESS %d is alive", *pid);
+ usleep(50);
+ }
+ ILOG("PROCESS %d has quit", *pid);
+ free(pid);
+}
+
/// @returns zero on success, or negative error code
int process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
{
+ ILOG("type %d", proc->type);
+ if (proc->argv)
+ {
+ int pos = 0;
+ char *euh = NULL;
+ euh = proc->argv[pos];
+ do
+ {
+ ILOG("--- %s", euh);
+ pos++;
+ euh = proc->argv[pos];
+
+ } while (euh != NULL);
+
+ }
if (proc->in) {
uv_pipe_init(&proc->loop->uv, &proc->in->uv.pipe, 0);
}
@@ -58,9 +86,23 @@
status = pty_process_spawn((PtyProcess *)proc);
break;
default:
+ ILOG("%s:%d", __func__, __LINE__);
abort();
}
+ ILOG("process %d %s", proc->pid, 0 < getpgid(proc->pid) ? "exists" : "disappeared");
+
+ /** DEBUG process exists */
+ pthread_t thr_ex;
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+
+ int *pid_in_heap = calloc(1, sizeof *pid_in_heap);
+ *pid_in_heap = proc->pid;
+ pthread_create(&thr_ex, &attr, process_exists, pid_in_heap);
+
+ ILOG("launched pid %d : %d", proc->pid, status);
if (status) {
if (proc->in) {
uv_close((uv_handle_t *)&proc->in->uv.pipe, NULL);
@@ -79,9 +121,12 @@
}
shell_free_argv(proc->argv);
proc->status = -1;
+ ILOG("process %d %s", proc->pid, 0 < getpgid(proc->pid) ? "exists" : "disappeared");
+ ILOG("%d status %d", proc->pid, status);
return status;
}
+ ILOG("process %d %s", proc->pid, 0 < getpgid(proc->pid) ? "exists" : "disappeared");
if (proc->in) {
stream_init(NULL, proc->in, -1,
STRUCT_CAST(uv_stream_t, &proc->in->uv.pipe));
@@ -109,15 +154,23 @@
proc->refcount++;
}
+ ILOG("process %d %s", proc->pid, 0 < getpgid(proc->pid) ? "exists" : "disappeared");
proc->internal_exit_cb = on_process_exit;
proc->internal_close_cb = decref;
proc->refcount++;
kl_push(WatcherPtr, proc->loop->children, proc);
+ ILOG("%d added to children", proc->pid);
+
return 0;
}
void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL
{
+ ILOG("%s:%d ====== ", __func__, __LINE__);
+
+ kliter_t(WatcherPtr) **nodes[128] = {0};
+ int nodes_num = 0;
+
process_is_tearing_down = true;
kl_iter(WatcherPtr, loop->children, current) {
Process *proc = (*current)->data;
@@ -125,40 +178,68 @@
// Close handles to process without killing it.
CREATE_EVENT(loop->events, process_close_handles, 1, proc);
} else {
- uv_kill(proc->pid, SIGTERM);
+ ILOG("%s:%d pid: %d", __func__, __LINE__, proc->pid);
+ uv_errno_t r = uv_kill(proc->pid, SIGTERM);
proc->term_sent = true;
- process_stop(proc);
+ if (UV_ESRCH == r)
+ {
+ ILOG("%s:%d pid: %d doesn't exist anymore", __func__, __LINE__, proc->pid);
+ if (nodes_num < 128 - 1)
+ nodes[nodes_num++] = current;
+ } else {
+ ILOG("%s:%d pid: %d", __func__, __LINE__, proc->pid);
+ process_stop(proc);
+ }
}
}
+ ILOG("%s:%d %d", __func__, __LINE__, kl_empty(loop->children));
+ for (int node_i = 0; node_i < nodes_num ; node_i++)
+ {
+ kl_shift_at(WatcherPtr, loop->children, nodes[node_i]);
+ }
+ ILOG("%s:%d %d", __func__, __LINE__, kl_empty(loop->children));
+ ILOG("%s:%d %d", __func__, __LINE__, multiqueue_empty(loop->events));
+
// Wait until all children exit and all close events are processed.
LOOP_PROCESS_EVENTS_UNTIL(
loop, loop->events, -1,
kl_empty(loop->children) && multiqueue_empty(loop->events));
pty_process_teardown(loop);
+ ILOG("%s:%d", __func__, __LINE__);
}
// Wrappers around `stream_close` that protect against double-closing.
void process_close_streams(Process *proc) FUNC_ATTR_NONNULL_ALL
{
+ ILOG("%d 0/3", proc->pid);
process_close_in(proc);
+ ILOG("%d 1/3", proc->pid);
process_close_out(proc);
+ ILOG("%d 2/3", proc->pid);
process_close_err(proc);
+ ILOG("%d 3/3", proc->pid);
}
void process_close_in(Process *proc) FUNC_ATTR_NONNULL_ALL
{
+ ILOG("%d", proc->pid);
CLOSE_PROC_STREAM(proc, in);
+ ILOG("%d", proc->pid);
}
void process_close_out(Process *proc) FUNC_ATTR_NONNULL_ALL
{
+ ILOG("%d", proc->pid);
CLOSE_PROC_STREAM(proc, out);
+ ILOG("%d", proc->pid);
}
void process_close_err(Process *proc) FUNC_ATTR_NONNULL_ALL
{
+ ILOG("%d", proc->pid);
CLOSE_PROC_STREAM(proc, err);
+ ILOG("%d", proc->pid);
}
/// Synchronously wait for a process to finish
@@ -172,11 +253,14 @@
int process_wait(Process *proc, int ms, MultiQueue *events)
FUNC_ATTR_NONNULL_ARG(1)
{
+ ILOG("%d wait for %d ms", __func__, __LINE__, proc->pid, ms);
int status = -1; // default
bool interrupted = false;
if (!proc->refcount) {
status = proc->status;
LOOP_PROCESS_EVENTS(proc->loop, proc->events, 0);
+
+ ILOG("%d status %d", proc->pid, status);
return status;
}
@@ -221,13 +305,16 @@
proc->refcount--;
}
+ ILOG("%d status %d", proc->pid, status);
return status;
}
/// Ask a process to terminate and eventually kill if it doesn't respond
void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
{
+ ILOG("%d", proc->pid);
if (proc->stopped_time) {
+ ILOG("%d", proc->pid);
return;
}
@@ -245,6 +332,7 @@
pty_process_close_master((PtyProcess *)proc);
break;
default:
+ ILOG("%d", proc->pid);
abort();
}
@@ -252,15 +340,17 @@
if (!loop->children_stop_requests++) {
// When there's at least one stop request pending, start a timer that
// will periodically check if a signal should be send to a to the job
- DLOG("Starting job kill timer");
+ ILOG("Starting job kill timer");
uv_timer_start(&loop->children_kill_timer, children_kill_cb, 100, 100);
}
+ ILOG("%d", proc->pid);
}
/// Iterates the process list sending SIGTERM to stopped processes and SIGKILL
/// to those that didn't die from SIGTERM after a while(exit_timeout is 0).
static void children_kill_cb(uv_timer_t *handle)
{
+ ILOG("BEGIN");
Loop *loop = handle->loop->data;
uint64_t now = os_hrtime();
@@ -280,11 +370,13 @@
uv_kill(proc->pid, SIGKILL);
}
}
+ ILOG("END");
}
static void process_close_event(void **argv)
{
Process *proc = argv[0];
+ ILOG("%d", proc->pid);
shell_free_argv(proc->argv);
if (proc->type == kProcessTypePty) {
xfree(((PtyProcess *)proc)->term_name);
@@ -292,6 +384,7 @@
if (proc->cb) {
proc->cb(proc, proc->status, proc->data);
}
+ ILOG("%d", proc->pid);
}
static void decref(Process *proc)
@@ -316,10 +409,12 @@
static void process_close(Process *proc)
FUNC_ATTR_NONNULL_ARG(1)
{
+ ILOG("%d", proc->pid);
if (process_is_tearing_down && (proc->detach || proc->type == kProcessTypePty)
&& proc->closed) {
// If a detached/pty process dies while tearing down it might get closed
// twice.
+ ILOG("%d", proc->pid);
return;
}
assert(!proc->closed);
@@ -332,8 +427,10 @@
pty_process_close((PtyProcess *)proc);
break;
default:
+ ILOG("%d", proc->pid);
abort();
}
+ ILOG("%d", proc->pid);
}
/// Flush output stream.
@@ -343,7 +440,9 @@
static void flush_stream(Process *proc, Stream *stream)
FUNC_ATTR_NONNULL_ARG(1)
{
+ ILOG("%d", proc->pid);
if (!stream || stream->closed) {
+ ILOG("%d", proc->pid);
return;
}
@@ -382,40 +481,52 @@
break;
}
}
+ ILOG("%d", proc->pid);
}
static void process_close_handles(void **argv)
{
Process *proc = argv[0];
+ ILOG("%d", proc->pid);
+ ILOG("%d 0/4", proc->pid);
flush_stream(proc, proc->out);
+ ILOG("%d 1/4", proc->pid);
flush_stream(proc, proc->err);
+ ILOG("%d 2/4", proc->pid);
process_close_streams(proc);
+ ILOG("%d 3/4", proc->pid);
process_close(proc);
+ ILOG("%d 4/4", proc->pid);
}
static void on_process_exit(Process *proc)
{
+ ILOG("%d finished !!!", proc->pid);
Loop *loop = proc->loop;
if (proc->stopped_time && loop->children_stop_requests
&& !--loop->children_stop_requests) {
// Stop the timer if no more stop requests are pending
- DLOG("Stopping process kill timer");
+ ILOG("Stopping process kill timer");
uv_timer_stop(&loop->children_kill_timer);
}
+
// 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
// queueing process_close_handles() as an event.
MultiQueue *queue = proc->events ? proc->events : loop->events;
CREATE_EVENT(queue, process_close_handles, 1, proc);
+ ILOG("%d", proc->pid);
}
static void on_process_stream_close(Stream *stream, void *data)
{
Process *proc = data;
+ ILOG("%d", proc->pid);
decref(proc);
+ ILOG("%d", proc->pid);
}
--- work/neovim/src/nvim/event/process.c 2017-06-08 09:36:08.000000000 +0200
+++ process.c 2017-06-13 11:51:28.000000000 +0200
@@ -34,9 +34,37 @@
static bool process_is_tearing_down = false;
+static void
+process_exists(void *prgm)
+{
+ int *pid = prgm;
+ while (0 < getpgid(*pid))
+ {
+ ILOG("PROCESS %d is alive", *pid);
+ usleep(50);
+ }
+ ILOG("PROCESS %d has quit", *pid);
+ free(pid);
+}
+
/// @returns zero on success, or negative error code
int process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
{
+ ILOG("type %d", proc->type);
+ if (proc->argv)
+ {
+ int pos = 0;
+ char *euh = NULL;
+ euh = proc->argv[pos];
+ do
+ {
+ ILOG("--- %s", euh);
+ pos++;
+ euh = proc->argv[pos];
+
+ } while (euh != NULL);
+
+ }
if (proc->in) {
uv_pipe_init(&proc->loop->uv, &proc->in->uv.pipe, 0);
}
@@ -58,9 +86,23 @@
status = pty_process_spawn((PtyProcess *)proc);
break;
default:
+ ILOG("%s:%d", __func__, __LINE__);
abort();
}
+ ILOG("process %d %s", proc->pid, 0 < getpgid(proc->pid) ? "exists" : "disappeared");
+
+ /** DEBUG process exists */
+ pthread_t thr_ex;
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+
+ int *pid_in_heap = calloc(1, sizeof *pid_in_heap);
+ *pid_in_heap = proc->pid;
+ pthread_create(&thr_ex, &attr, process_exists, pid_in_heap);
+
+ ILOG("launched pid %d : %d", proc->pid, status);
if (status) {
if (proc->in) {
uv_close((uv_handle_t *)&proc->in->uv.pipe, NULL);
@@ -79,9 +121,12 @@
}
shell_free_argv(proc->argv);
proc->status = -1;
+ ILOG("process %d %s", proc->pid, 0 < getpgid(proc->pid) ? "exists" : "disappeared");
+ ILOG("%d status %d", proc->pid, status);
return status;
}
+ ILOG("process %d %s", proc->pid, 0 < getpgid(proc->pid) ? "exists" : "disappeared");
if (proc->in) {
stream_init(NULL, proc->in, -1,
STRUCT_CAST(uv_stream_t, &proc->in->uv.pipe));
@@ -109,15 +154,23 @@
proc->refcount++;
}
+ ILOG("process %d %s", proc->pid, 0 < getpgid(proc->pid) ? "exists" : "disappeared");
proc->internal_exit_cb = on_process_exit;
proc->internal_close_cb = decref;
proc->refcount++;
kl_push(WatcherPtr, proc->loop->children, proc);
+ ILOG("%d added to children", proc->pid);
+
return 0;
}
void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL
{
+ ILOG("%s:%d ====== ", __func__, __LINE__);
+
+ kliter_t(WatcherPtr) **nodes[128] = {0};
+ int nodes_num = 0;
+
process_is_tearing_down = true;
kl_iter(WatcherPtr, loop->children, current) {
Process *proc = (*current)->data;
@@ -125,40 +178,68 @@
// Close handles to process without killing it.
CREATE_EVENT(loop->events, process_close_handles, 1, proc);
} else {
- uv_kill(proc->pid, SIGTERM);
+ ILOG("%s:%d pid: %d", __func__, __LINE__, proc->pid);
+ uv_errno_t r = uv_kill(proc->pid, SIGTERM);
proc->term_sent = true;
- process_stop(proc);
+ if (UV_ESRCH == r)
+ {
+ ILOG("%s:%d pid: %d doesn't exist anymore", __func__, __LINE__, proc->pid);
+ if (nodes_num < 128 - 1)
+ nodes[nodes_num++] = current;
+ } else {
+ ILOG("%s:%d pid: %d", __func__, __LINE__, proc->pid);
+ process_stop(proc);
+ }
}
}
+ ILOG("%s:%d %d", __func__, __LINE__, kl_empty(loop->children));
+ for (int node_i = 0; node_i < nodes_num ; node_i++)
+ {
+ kl_shift_at(WatcherPtr, loop->children, nodes[node_i]);
+ }
+ ILOG("%s:%d %d", __func__, __LINE__, kl_empty(loop->children));
+ ILOG("%s:%d %d", __func__, __LINE__, multiqueue_empty(loop->events));
+
// Wait until all children exit and all close events are processed.
LOOP_PROCESS_EVENTS_UNTIL(
loop, loop->events, -1,
kl_empty(loop->children) && multiqueue_empty(loop->events));
pty_process_teardown(loop);
+ ILOG("%s:%d", __func__, __LINE__);
}
// Wrappers around `stream_close` that protect against double-closing.
void process_close_streams(Process *proc) FUNC_ATTR_NONNULL_ALL
{
+ ILOG("%d 0/3", proc->pid);
process_close_in(proc);
+ ILOG("%d 1/3", proc->pid);
process_close_out(proc);
+ ILOG("%d 2/3", proc->pid);
process_close_err(proc);
+ ILOG("%d 3/3", proc->pid);
}
void process_close_in(Process *proc) FUNC_ATTR_NONNULL_ALL
{
+ ILOG("%d", proc->pid);
CLOSE_PROC_STREAM(proc, in);
+ ILOG("%d", proc->pid);
}
void process_close_out(Process *proc) FUNC_ATTR_NONNULL_ALL
{
+ ILOG("%d", proc->pid);
CLOSE_PROC_STREAM(proc, out);
+ ILOG("%d", proc->pid);
}
void process_close_err(Process *proc) FUNC_ATTR_NONNULL_ALL
{
+ ILOG("%d", proc->pid);
CLOSE_PROC_STREAM(proc, err);
+ ILOG("%d", proc->pid);
}
/// Synchronously wait for a process to finish
@@ -172,11 +253,14 @@
int process_wait(Process *proc, int ms, MultiQueue *events)
FUNC_ATTR_NONNULL_ARG(1)
{
+ ILOG("%d wait for %d ms", __func__, __LINE__, proc->pid, ms);
int status = -1; // default
bool interrupted = false;
if (!proc->refcount) {
status = proc->status;
LOOP_PROCESS_EVENTS(proc->loop, proc->events, 0);
+
+ ILOG("%d status %d", proc->pid, status);
return status;
}
@@ -221,13 +305,16 @@
proc->refcount--;
}
+ ILOG("%d status %d", proc->pid, status);
return status;
}
/// Ask a process to terminate and eventually kill if it doesn't respond
void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
{
+ ILOG("%d", proc->pid);
if (proc->stopped_time) {
+ ILOG("%d", proc->pid);
return;
}
@@ -245,6 +332,7 @@
pty_process_close_master((PtyProcess *)proc);
break;
default:
+ ILOG("%d", proc->pid);
abort();
}
@@ -252,15 +340,17 @@
if (!loop->children_stop_requests++) {
// When there's at least one stop request pending, start a timer that
// will periodically check if a signal should be send to a to the job
- DLOG("Starting job kill timer");
+ ILOG("Starting job kill timer");
uv_timer_start(&loop->children_kill_timer, children_kill_cb, 100, 100);
}
+ ILOG("%d", proc->pid);
}
/// Iterates the process list sending SIGTERM to stopped processes and SIGKILL
/// to those that didn't die from SIGTERM after a while(exit_timeout is 0).
static void children_kill_cb(uv_timer_t *handle)
{
+ ILOG("BEGIN");
Loop *loop = handle->loop->data;
uint64_t now = os_hrtime();
@@ -280,11 +370,13 @@
uv_kill(proc->pid, SIGKILL);
}
}
+ ILOG("END");
}
static void process_close_event(void **argv)
{
Process *proc = argv[0];
+ ILOG("%d", proc->pid);
shell_free_argv(proc->argv);
if (proc->type == kProcessTypePty) {
xfree(((PtyProcess *)proc)->term_name);
@@ -292,6 +384,7 @@
if (proc->cb) {
proc->cb(proc, proc->status, proc->data);
}
+ ILOG("%d", proc->pid);
}
static void decref(Process *proc)
@@ -316,10 +409,12 @@
static void process_close(Process *proc)
FUNC_ATTR_NONNULL_ARG(1)
{
+ ILOG("%d", proc->pid);
if (process_is_tearing_down && (proc->detach || proc->type == kProcessTypePty)
&& proc->closed) {
// If a detached/pty process dies while tearing down it might get closed
// twice.
+ ILOG("%d", proc->pid);
return;
}
assert(!proc->closed);
@@ -332,8 +427,10 @@
pty_process_close((PtyProcess *)proc);
break;
default:
+ ILOG("%d", proc->pid);
abort();
}
+ ILOG("%d", proc->pid);
}
/// Flush output stream.
@@ -343,7 +440,9 @@
static void flush_stream(Process *proc, Stream *stream)
FUNC_ATTR_NONNULL_ARG(1)
{
+ ILOG("%d", proc->pid);
if (!stream || stream->closed) {
+ ILOG("%d", proc->pid);
return;
}
@@ -382,40 +481,52 @@
break;
}
}
+ ILOG("%d", proc->pid);
}
static void process_close_handles(void **argv)
{
Process *proc = argv[0];
+ ILOG("%d", proc->pid);
+ ILOG("%d 0/4", proc->pid);
flush_stream(proc, proc->out);
+ ILOG("%d 1/4", proc->pid);
flush_stream(proc, proc->err);
+ ILOG("%d 2/4", proc->pid);
process_close_streams(proc);
+ ILOG("%d 3/4", proc->pid);
process_close(proc);
+ ILOG("%d 4/4", proc->pid);
}
static void on_process_exit(Process *proc)
{
+ ILOG("%d finished !!!", proc->pid);
Loop *loop = proc->loop;
if (proc->stopped_time && loop->children_stop_requests
&& !--loop->children_stop_requests) {
// Stop the timer if no more stop requests are pending
- DLOG("Stopping process kill timer");
+ ILOG("Stopping process kill timer");
uv_timer_stop(&loop->children_kill_timer);
}
+
// 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
// queueing process_close_handles() as an event.
MultiQueue *queue = proc->events ? proc->events : loop->events;
CREATE_EVENT(queue, process_close_handles, 1, proc);
+ ILOG("%d", proc->pid);
}
static void on_process_stream_close(Stream *stream, void *data)
{
Process *proc = data;
+ ILOG("%d", proc->pid);
decref(proc);
+ ILOG("%d", proc->pid);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment