mirror of
https://github.com/electron/electron.git
synced 2026-01-22 05:47:58 -05:00
159 lines
5.4 KiB
Diff
159 lines
5.4 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Jameson Nash <vtjnash@gmail.com>
|
|
Date: Wed, 23 Mar 2022 15:39:38 +0900
|
|
Subject: process: fix hang after NOTE_EXIT (#3521)
|
|
|
|
Bug #3504 seems to affect more platforms than just OpenBSD. As this
|
|
seems to be a race condition in these kernels, we do not want to fail
|
|
because of it. Instead, we remove the WNOHANG flag from waitpid, and
|
|
track exactly which processes have exited. Should also be a slight speed
|
|
improvement for excessively large numbers of live children.
|
|
|
|
diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c
|
|
index 857eb1d54bfde99754ce2c6e92a287c288bd9f52..036055149fcabcb9ff8f43522120c82b3474ab99 100644
|
|
--- a/deps/uv/src/unix/kqueue.c
|
|
+++ b/deps/uv/src/unix/kqueue.c
|
|
@@ -117,6 +117,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
|
unsigned int revents;
|
|
QUEUE* q;
|
|
uv__io_t* w;
|
|
+ uv_process_t* process;
|
|
sigset_t* pset;
|
|
sigset_t set;
|
|
uint64_t base;
|
|
@@ -284,12 +285,22 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
|
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
|
|
for (i = 0; i < nfds; i++) {
|
|
ev = events + i;
|
|
+ fd = ev->ident;
|
|
+
|
|
+ /* Handle kevent NOTE_EXIT results */
|
|
if (ev->filter == EVFILT_PROC) {
|
|
- loop->flags |= UV_LOOP_REAP_CHILDREN;
|
|
+ QUEUE_FOREACH(q, &loop->process_handles) {
|
|
+ process = QUEUE_DATA(q, uv_process_t, queue);
|
|
+ if (process->pid == fd) {
|
|
+ process->flags |= UV_HANDLE_REAP;
|
|
+ loop->flags |= UV_LOOP_REAP_CHILDREN;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
nevents++;
|
|
continue;
|
|
}
|
|
- fd = ev->ident;
|
|
+
|
|
/* Skip invalidated events, see uv__platform_invalidate_fd */
|
|
if (fd == -1)
|
|
continue;
|
|
diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c
|
|
index 147164e7ea25abbf655452930d78ee0a714cce36..c8816b85b7e531648064e739fb89257565ad64bb 100644
|
|
--- a/deps/uv/src/unix/process.c
|
|
+++ b/deps/uv/src/unix/process.c
|
|
@@ -63,12 +63,18 @@ extern char **environ;
|
|
# include "zos-base.h"
|
|
#endif
|
|
|
|
-#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
|
+#if defined(__APPLE__) || \
|
|
+ defined(__DragonFly__) || \
|
|
+ defined(__FreeBSD__) || \
|
|
+ defined(__NetBSD__) || \
|
|
+ defined(__OpenBSD__)
|
|
#include <sys/event.h>
|
|
+#else
|
|
+#define UV_USE_SIGCHLD
|
|
#endif
|
|
|
|
|
|
-#if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__))
|
|
+#ifdef UV_USE_SIGCHLD
|
|
static void uv__chld(uv_signal_t* handle, int signum) {
|
|
assert(signum == SIGCHLD);
|
|
uv__wait_children(handle->loop);
|
|
@@ -80,6 +86,7 @@ void uv__wait_children(uv_loop_t* loop) {
|
|
int exit_status;
|
|
int term_signal;
|
|
int status;
|
|
+ int options;
|
|
pid_t pid;
|
|
QUEUE pending;
|
|
QUEUE* q;
|
|
@@ -93,19 +100,33 @@ void uv__wait_children(uv_loop_t* loop) {
|
|
process = QUEUE_DATA(q, uv_process_t, queue);
|
|
q = QUEUE_NEXT(q);
|
|
|
|
+#ifndef UV_USE_SIGCHLD
|
|
+ if ((process->flags & UV_HANDLE_REAP) == 0)
|
|
+ continue;
|
|
+ options = 0;
|
|
+ process->flags &= ~UV_HANDLE_REAP;
|
|
+#else
|
|
+ options = WNOHANG;
|
|
+#endif
|
|
+
|
|
do
|
|
- pid = waitpid(process->pid, &status, WNOHANG);
|
|
+ pid = waitpid(process->pid, &status, options);
|
|
while (pid == -1 && errno == EINTR);
|
|
|
|
- if (pid == 0)
|
|
+#ifdef UV_USE_SIGCHLD
|
|
+ if (pid == 0) /* Not yet exited */
|
|
continue;
|
|
+#endif
|
|
|
|
if (pid == -1) {
|
|
if (errno != ECHILD)
|
|
abort();
|
|
+ /* The child died, and we missed it. This probably means someone else
|
|
+ * stole the waitpid from us. Handle this by not handling it at all. */
|
|
continue;
|
|
}
|
|
|
|
+ assert(pid == process->pid);
|
|
process->status = status;
|
|
QUEUE_REMOVE(&process->queue);
|
|
QUEUE_INSERT_TAIL(&pending, &process->queue);
|
|
@@ -964,7 +985,7 @@ int uv_spawn(uv_loop_t* loop,
|
|
goto error;
|
|
}
|
|
|
|
-#if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__))
|
|
+#ifdef UV_USE_SIGCHLD
|
|
uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
|
|
#endif
|
|
|
|
@@ -983,13 +1004,14 @@ int uv_spawn(uv_loop_t* loop,
|
|
* fail to open a stdio handle. This ensures we can eventually reap the child
|
|
* with waitpid. */
|
|
if (exec_errorno == 0) {
|
|
-#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
|
+#ifndef UV_USE_SIGCHLD
|
|
struct kevent event;
|
|
EV_SET(&event, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, 0);
|
|
if (kevent(loop->backend_fd, &event, 1, NULL, 0, NULL)) {
|
|
if (errno != ESRCH)
|
|
abort();
|
|
/* Process already exited. Call waitpid on the next loop iteration. */
|
|
+ process->flags |= UV_HANDLE_REAP;
|
|
loop->flags |= UV_LOOP_REAP_CHILDREN;
|
|
}
|
|
#endif
|
|
diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h
|
|
index 8a190bf8fa8c5a282feaf251aec2a30c95776888..6001b0cf68d0b0268b578218b664a737f43c9521 100644
|
|
--- a/deps/uv/src/uv-common.h
|
|
+++ b/deps/uv/src/uv-common.h
|
|
@@ -130,7 +130,10 @@ enum {
|
|
UV_SIGNAL_ONE_SHOT = 0x02000000,
|
|
|
|
/* Only used by uv_poll_t handles. */
|
|
- UV_HANDLE_POLL_SLOW = 0x01000000
|
|
+ UV_HANDLE_POLL_SLOW = 0x01000000,
|
|
+
|
|
+ /* Only used by uv_process_t handles. */
|
|
+ UV_HANDLE_REAP = 0x10000000
|
|
};
|
|
|
|
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
|