diff --git a/system/libuv/0001-libuv-port-for-nuttx.patch b/system/libuv/0001-libuv-port-for-nuttx.patch index 9ea208416..bcec2bd70 100644 --- a/system/libuv/0001-libuv-port-for-nuttx.patch +++ b/system/libuv/0001-libuv-port-for-nuttx.patch @@ -736,47 +736,411 @@ index 0f4bf938..dd36028b 100644 assert(timeout >= -1); time_base = loop->time; +diff --git a/src/unix/process-spawn.c b/src/unix/process-spawn.c +new file mode 100644 +index 00000000..78401ca5 +--- /dev/null ++++ b/src/unix/process-spawn.c +@@ -0,0 +1,368 @@ ++/* Copyright Xiaomi, Inc. and other Node contributors. All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#define __USE_GNU ++#include "uv.h" ++#include "internal.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef SIGCHLD ++static void uv__chld(uv_signal_t* handle, int signum) { ++ uv_process_t* process; ++ uv_loop_t* loop; ++ int exit_status; ++ int term_signal; ++ int status; ++ pid_t pid; ++ QUEUE pending; ++ QUEUE* q; ++ QUEUE* h; ++ ++ assert(signum == SIGCHLD); ++ ++ QUEUE_INIT(&pending); ++ loop = handle->loop; ++ ++ h = &loop->process_handles; ++ q = QUEUE_HEAD(h); ++ while (q != h) { ++ process = QUEUE_DATA(q, uv_process_t, queue); ++ q = QUEUE_NEXT(q); ++ ++ do ++ pid = waitpid(process->pid, &status, WNOHANG); ++ while (pid == -1 && errno == EINTR); ++ ++ if (pid == 0) ++ continue; ++ ++ if (pid == -1) { ++ if (errno != ECHILD) ++ abort(); ++ continue; ++ } ++ ++ process->status = status; ++ QUEUE_REMOVE(&process->queue); ++ QUEUE_INSERT_TAIL(&pending, &process->queue); ++ } ++ ++ h = &pending; ++ q = QUEUE_HEAD(h); ++ while (q != h) { ++ process = QUEUE_DATA(q, uv_process_t, queue); ++ q = QUEUE_NEXT(q); ++ ++ QUEUE_REMOVE(&process->queue); ++ QUEUE_INIT(&process->queue); ++ uv__handle_stop(process); ++ ++ if (process->exit_cb == NULL) ++ continue; ++ ++ exit_status = 0; ++ if (WIFEXITED(process->status)) ++ exit_status = WEXITSTATUS(process->status); ++ ++ term_signal = 0; ++ if (WIFSIGNALED(process->status)) ++ term_signal = WTERMSIG(process->status); ++ ++ process->exit_cb(process, exit_status, term_signal); ++ } ++ assert(QUEUE_EMPTY(&pending)); ++} ++#endif ++ ++/* ++ * Used for initializing stdio streams like options.stdin_stream. Returns ++ * zero on success. See also the cleanup section in uv_spawn(). ++ */ ++static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { ++ int mask; ++ int fd; ++ ++ mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM; ++ ++ switch (container->flags & mask) { ++ case UV_IGNORE: ++ return 0; ++ ++ case UV_CREATE_PIPE: ++ assert(container->data.stream != NULL); ++ if (container->data.stream->type != UV_NAMED_PIPE) ++ return UV_EINVAL; ++ else ++ return uv_socketpair(SOCK_STREAM, 0, fds, 0, 0); ++ ++ case UV_INHERIT_FD: ++ case UV_INHERIT_STREAM: ++ if (container->flags & UV_INHERIT_FD) ++ fd = container->data.fd; ++ else ++ fd = uv__stream_fd(container->data.stream); ++ ++ if (fd == -1) ++ return UV_EINVAL; ++ ++ fds[0] = fds[1] = fd; ++ return 0; ++ ++ default: ++ assert(0 && "Unexpected flags"); ++ return UV_EINVAL; ++ } ++} ++ ++ ++static int uv__process_open_stream(uv_stdio_container_t* container, ++ int pipefds[2]) { ++ int flags; ++ ++ if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0) ++ return 0; ++ ++ uv__nonblock(pipefds[0], 1); ++ ++ flags = 0; ++ if (container->flags & UV_WRITABLE_PIPE) ++ flags |= UV_HANDLE_READABLE; ++ if (container->flags & UV_READABLE_PIPE) ++ flags |= UV_HANDLE_WRITABLE; ++ ++ return uv__stream_open(container->data.stream, pipefds[0], flags); ++} ++ ++ ++static void uv__process_close_stream(uv_stdio_container_t* container) { ++ if (!(container->flags & UV_CREATE_PIPE)) return; ++ uv__stream_close(container->data.stream); ++} ++ ++ ++static int uv__process_child_spawn(const uv_process_options_t* options, ++ int stdio_count, ++ int (*pipes)[2], ++ pid_t *pid) { ++ posix_spawn_file_actions_t file_actions; ++ posix_spawnattr_t attr; ++ sigset_t set; ++ int use_fd; ++ int flags; ++ int err; ++ int fd; ++ ++ posix_spawn_file_actions_init(&file_actions); ++ posix_spawnattr_init(&attr); ++ ++ /* Reset signal disposition and mask */ ++ flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; ++ ++ sigfillset(&set); ++ posix_spawnattr_setsigdefault(&attr, &set); ++ ++ sigemptyset(&set); ++ posix_spawnattr_setsigmask(&attr, &set); ++ ++ if (options->flags & UV_PROCESS_DETACHED) ++ flags |= POSIX_SPAWN_SETSID; ++ ++ /* First duplicate low numbered fds, since it's not safe to duplicate them, ++ * they could get replaced. Example: swapping stdout and stderr; without ++ * this fd 2 (stderr) would be duplicated into fd 1, thus making both ++ * stdout and stderr go to the same fd, which was not the intention. */ ++ for (fd = 0; fd < stdio_count; fd++) { ++ use_fd = pipes[fd][1]; ++ if (use_fd < 0 || use_fd >= fd) ++ continue; ++ pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); ++ if (pipes[fd][1] == -1) { ++ err = errno; ++ goto error; ++ } ++ } ++ ++ for (fd = 0; fd < stdio_count; fd++) { ++ use_fd = pipes[fd][1]; ++ ++ if (use_fd < 0) { ++ if (fd >= 3) ++ continue; ++ else { ++ /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is ++ * set ++ */ ++ use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); ++ pipes[fd][1] = use_fd; ++ ++ if (use_fd < 0) { ++ err = errno; ++ goto error; ++ } ++ } ++ } ++ ++ if (fd == use_fd) ++ uv__cloexec_fcntl(use_fd, 0); ++ else ++ posix_spawn_file_actions_adddup2(&file_actions, use_fd, fd); ++ ++ if (fd <= 2) ++ uv__nonblock_fcntl(use_fd, 0); ++ } ++ ++ if (options->flags & UV_PROCESS_SETUID) { ++ err = options->uid ? ENOTSUP : EPERM; ++ goto error; ++ } ++ ++ if (options->flags & UV_PROCESS_SETGID) { ++ if (options->gid == 0) { ++ err = EPERM; ++ goto error; ++ } ++ ++ posix_spawnattr_setpgroup(&attr, options->gid); ++ flags |= POSIX_SPAWN_SETPGROUP; ++ } ++ ++ posix_spawnattr_setflags(&attr, flags); ++ err = posix_spawn(pid, options->file, &file_actions, &attr, ++ options->args, options->env ? options->env : environ); ++ ++error: ++ for (fd = 0; fd < stdio_count; fd++) { ++ if (pipes[fd][1] >= 0 && pipes[fd][1] != pipes[fd][0]) { ++ close(pipes[fd][1]); ++ pipes[fd][1] = -1; ++ } ++ } ++ ++ posix_spawn_file_actions_destroy(&file_actions); ++ posix_spawnattr_destroy(&attr); ++ return UV__ERR(err); ++} ++ ++ ++int uv_spawn(uv_loop_t* loop, ++ uv_process_t* process, ++ const uv_process_options_t* options) { ++ int pipes_storage[8][2]; ++ int (*pipes)[2]; ++ int stdio_count; ++ pid_t pid; ++ int err; ++ int i; ++ ++ assert(options->file != NULL); ++ assert(!(options->flags & ~(UV_PROCESS_DETACHED | ++ UV_PROCESS_SETGID | ++ UV_PROCESS_SETUID | ++ UV_PROCESS_WINDOWS_HIDE | ++ UV_PROCESS_WINDOWS_HIDE_CONSOLE | ++ UV_PROCESS_WINDOWS_HIDE_GUI | ++ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); ++ ++ uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); ++ QUEUE_INIT(&process->queue); ++ ++ stdio_count = options->stdio_count; ++ if (stdio_count < 3) ++ stdio_count = 3; ++ ++ err = UV_ENOMEM; ++ pipes = pipes_storage; ++ if (stdio_count > (int)ARRAY_SIZE(pipes_storage)) ++ pipes = uv__malloc(stdio_count * sizeof(*pipes)); ++ ++ if (pipes == NULL) ++ goto error; ++ ++ for (i = 0; i < stdio_count; i++) { ++ pipes[i][0] = -1; ++ pipes[i][1] = -1; ++ } ++ ++ for (i = 0; i < options->stdio_count; i++) { ++ err = uv__process_init_stdio(options->stdio + i, pipes[i]); ++ if (err) ++ goto error; ++ } ++ ++#ifdef SIGCHLD ++ uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); ++#endif ++ ++ err = uv__process_child_spawn(options, stdio_count, pipes, &pid); ++ if (err) ++ goto error; ++ ++ for (i = 0; i < options->stdio_count; i++) { ++ err = uv__process_open_stream(options->stdio + i, pipes[i]); ++ if (err == 0) ++ continue; ++ ++ while (i--) ++ uv__process_close_stream(options->stdio + i); ++ ++ goto error; ++ } ++ ++ QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue); ++ uv__handle_start(process); ++ ++ process->status = 0; ++ process->pid = pid; ++ process->exit_cb = options->exit_cb; ++ ++ if (pipes != pipes_storage) ++ uv__free(pipes); ++ ++ return 0; ++ ++error: ++ if (pipes != NULL) { ++ for (i = 0; i < stdio_count; i++) { ++ if (i < options->stdio_count) ++ if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM)) ++ continue; ++ if (pipes[i][0] != -1) ++ uv__close_nocheckstdio(pipes[i][0]); ++ if (pipes[i][1] != -1) ++ uv__close_nocheckstdio(pipes[i][1]); ++ } ++ ++ if (pipes != pipes_storage) ++ uv__free(pipes); ++ } ++ ++ return err; ++} diff --git a/src/unix/process.c b/src/unix/process.c -index f4aebb04..00409cbc 100644 +index f4aebb04..61b8db5d 100644 --- a/src/unix/process.c +++ b/src/unix/process.c -@@ -36,8 +36,6 @@ - #if defined(__APPLE__) && !TARGET_OS_IPHONE - # include - # define environ (*_NSGetEnviron()) --#else --extern char **environ; +@@ -509,24 +509,3 @@ error: + return err; #endif - - #if defined(__linux__) || defined(__GLIBC__) -@@ -48,7 +46,7 @@ extern char **environ; - # include "zos-base.h" - #endif - -- -+#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) && !defined(__NuttX__) - static void uv__chld(uv_signal_t* handle, int signum) { - uv_process_t* process; - uv_loop_t* loop; -@@ -207,7 +205,6 @@ static void uv__write_errno(int error_fd) { } - - --#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) - /* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be - * avoided. Since this isn't called on those targets, the function - * doesn't even need to be defined for them. -@@ -345,7 +342,7 @@ static void uv__process_child_init(const uv_process_options_t* options, - int uv_spawn(uv_loop_t* loop, - uv_process_t* process, - const uv_process_options_t* options) { --#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) -+#if (defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) || defined(__NuttX__) - /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */ - return UV_ENOSYS; - #else +- +- +-int uv_process_kill(uv_process_t* process, int signum) { +- return uv_kill(process->pid, signum); +-} +- +- +-int uv_kill(int pid, int signum) { +- if (kill(pid, signum)) +- return UV__ERR(errno); +- else +- return 0; +-} +- +- +-void uv__process_close(uv_process_t* handle) { +- QUEUE_REMOVE(&handle->queue); +- uv__handle_stop(handle); +- if (QUEUE_EMPTY(&handle->loop->process_handles)) +- uv_signal_stop(&handle->loop->child_watcher); +-} diff --git a/src/unix/signal.c b/src/unix/signal.c -index 1133c73a..1827832b 100644 +index 1133c73a..791938b8 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -20,6 +20,7 @@ @@ -815,6 +1179,28 @@ index 1133c73a..1827832b 100644 RB_GENERATE_STATIC(uv__signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare) +@@ -556,3 +543,21 @@ static void uv__signal_stop(uv_signal_t* handle) { + handle->signum = 0; + uv__handle_stop(handle); + } ++ ++int uv_process_kill(uv_process_t* process, int signum) { ++ return uv_kill(process->pid, signum); ++} ++ ++int uv_kill(int pid, int signum) { ++ if (kill(pid, signum)) ++ return UV__ERR(errno); ++ else ++ return 0; ++} ++ ++void uv__process_close(uv_process_t* handle) { ++ QUEUE_REMOVE(&handle->queue); ++ uv__handle_stop(handle); ++ if (QUEUE_EMPTY(&handle->loop->process_handles)) ++ uv_signal_stop(&handle->loop->child_watcher); ++} diff --git a/src/unix/thread.c b/src/unix/thread.c old mode 100644 new mode 100755 diff --git a/system/libuv/Makefile b/system/libuv/Makefile index 1fcad0766..e8b3c4688 100644 --- a/system/libuv/Makefile +++ b/system/libuv/Makefile @@ -85,7 +85,9 @@ CSRCS += pipe.c CSRCS += fs.c CSRCS += fs-poll.c CSRCS += timer.c -CSRCS += process.c +ifneq ($(CONFIG_LIBC_EXECFUNCS),) +CSRCS += process-spawn.c +endif CSRCS += sysinfo-loadavg.c CSRCS += sysinfo-memory.c