You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2020/11/08 16:11:59 UTC

[incubator-nuttx-apps] branch master updated (2e8f068 -> c1c488e)

This is an automated email from the ASF dual-hosted git repository.

acassis pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx-apps.git.


    from 2e8f068  examples/watchdog/watchdog_main.c: Elapsed var  is now being updated through clock
     new efd8174  libuv: fix bugs and add partial pipe support
     new c1c488e  system: add Android Debug Bridge daemon

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 system/adb/Kconfig                                 |  158 +++
 system/{libuv/Makefile => adb/Make.defs}           |    8 +-
 system/adb/Makefile                                |   92 ++
 system/adb/adb_banner.c                            |  117 ++
 system/adb/adb_main.c                              |  119 +++
 system/adb/logcat_service.c                        |  213 ++++
 system/adb/shell_pipe.c                            |  237 +++++
 .../dhcpd_daemon.h => system/adb/shell_pipe.h      |   49 +-
 system/adb/shell_service.c                         |  209 ++++
 .../libuv/0001-initial-libuv-port-to-nuttx.patch   | 1122 ++++++++++++++------
 system/libuv/libuv/Kconfig                         |    7 +
 system/libuv/libuv/Makefile                        |    4 +
 system/libuv/tests/Makefile                        |    4 +-
 13 files changed, 1989 insertions(+), 350 deletions(-)
 create mode 100644 system/adb/Kconfig
 copy system/{libuv/Makefile => adb/Make.defs} (90%)
 create mode 100644 system/adb/Makefile
 create mode 100644 system/adb/adb_banner.c
 create mode 100644 system/adb/adb_main.c
 create mode 100644 system/adb/logcat_service.c
 create mode 100644 system/adb/shell_pipe.c
 copy examples/dhcpd/dhcpd_daemon.h => system/adb/shell_pipe.h (62%)
 create mode 100644 system/adb/shell_service.c


[incubator-nuttx-apps] 02/02: system: add Android Debug Bridge daemon

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx-apps.git

commit c1c488e835f7433ddec4de57024a4e3444359f96
Author: Simon Piriou <sp...@gmail.com>
AuthorDate: Mon Oct 26 17:18:48 2020 +0100

    system: add Android Debug Bridge daemon
---
 system/adb/Kconfig          | 158 +++++++++++++++++++++++++++++
 system/adb/Make.defs        |  23 +++++
 system/adb/Makefile         |  92 +++++++++++++++++
 system/adb/adb_banner.c     | 117 ++++++++++++++++++++++
 system/adb/adb_main.c       | 119 ++++++++++++++++++++++
 system/adb/logcat_service.c | 213 +++++++++++++++++++++++++++++++++++++++
 system/adb/shell_pipe.c     | 237 ++++++++++++++++++++++++++++++++++++++++++++
 system/adb/shell_pipe.h     |  56 +++++++++++
 system/adb/shell_service.c  | 209 ++++++++++++++++++++++++++++++++++++++
 9 files changed, 1224 insertions(+)

diff --git a/system/adb/Kconfig b/system/adb/Kconfig
new file mode 100644
index 0000000..83a8019
--- /dev/null
+++ b/system/adb/Kconfig
@@ -0,0 +1,158 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+menuconfig SYSTEM_ADBD
+	tristate "ADB daemon application"
+	default n
+	---help---
+		Enable support for adb daemon.
+
+if SYSTEM_ADBD
+
+config ADBD_PROGNAME
+	string "Program name"
+	default "adbd"
+	---help---
+		This is the name of the program that will be used.
+
+config ADBD_STACKSIZE
+	int "Stack size"
+	default DEFAULT_TASK_STACKSIZE
+	---help---
+		The size of stack allocated for the adb daemon task.
+
+config ADBD_PRIORITY
+	int "Task priority"
+	default 100
+	---help---
+		The priority of the adb daemon task.
+
+config ADBD_AUTHENTICATION
+	bool "Authentication support"
+	default n
+	---help---
+		Enable authentication for adb daemon.
+
+if ADBD_AUTHENTICATION
+
+config ADBD_AUTH_PUBKEY
+	bool "Public key authentication"
+	default n
+	---help---
+		Enable hook to accept new public keys.
+
+config ADBD_TOKEN_SIZE
+	int "Authentication token size"
+	default 20
+
+endif # ADBD_AUTHENTICATION
+
+if ! BOARDCTL_UNIQUEID
+config ADBD_DEVICE_ID
+	string "Default adb device id"
+	default ""
+endif # BOARDCTL_UNIQUEID
+
+config ADBD_PRODUCT_NAME
+	string "Default adb product name"
+	default "adb dev"
+
+config ADBD_PRODUCT_MODEL
+	string "Default adb product model"
+	default "adb board"
+
+config ADBD_PRODUCT_DEVICE
+	string "Default adb product device"
+	default "NuttX device"
+
+config ADBD_FEATURES
+	string "Default adb server features list"
+	default "cmd"
+
+config ADBD_PAYLOAD_SIZE
+	int "Normal ADB frame size"
+	default 64
+	---help---
+		Normal frame size in bytes.
+
+config ADBD_CNXN_PAYLOAD_SIZE
+	int "Connection frame size"
+	default 1024
+	---help---
+		Connection frame is bigger than others.
+		Can be between 128 to 256 bytes in most of the cases.
+		If authentication is enabled, frame size must bigger
+		to receive public key from host (around 1024 bytes).
+
+config ADBD_FRAME_MAX
+	int "Frame pool size"
+	default 1
+	---help---
+		ADB frame pool size.
+
+config ADBD_TCP_SERVER
+	bool "Network socket transport support"
+	depends on NET_TCP
+	default n
+	---help---
+		Run adb daemon on network socket.
+
+config ADBD_TCP_SERVER_PORT
+	int "Network socket transport port"
+	depends on ADBD_TCP_SERVER
+	default 5555
+	---help---
+		Port used by adb daemon socket server
+
+config ADBD_USB_SERVER
+	bool "USB transport support"
+	depends on USBADB
+	default n
+	---help---
+		Run adb daemon on USB bus
+
+config ADBD_LOGCAT_SERVICE
+	bool "ADB logcat support"
+	depends on RAMLOG_SYSLOG
+	default n
+	---help---
+		Enable "adb logcat" feature.
+
+config ADBD_FILE_SERVICE
+	bool "ADB file sync support"
+	default n
+	---help---
+		Enable "adb ls/push/pull" feature.
+
+ config ADBD_SHELL_SERVICE
+	bool "ADB shell support"
+	depends on NSH_CONSOLE
+	default n
+	---help---
+		Enable "adb shell" feature.
+
+config ADBD_FILE_SYMLINK
+	bool "File service symlink support"
+	default n
+	depends on PSEUDOFS_SOFTLINKS
+	---help---
+		Enable fs symlink support.
+
+config ADBD_BOARD_INIT
+	bool "Board initialization"
+	depends on LIB_BOARDCTL
+	default n
+	---help---
+		Setup board before running adb daemon.
+
+config ADBD_NET_INIT
+    bool "Network initialization"
+    default n
+    depends on NET
+    select NETUTILS_NETINIT
+    ---help---
+        This option enables/disables all network initialization in ADB server.
+
+endif # SYSTEM_ADBD
diff --git a/system/adb/Make.defs b/system/adb/Make.defs
new file mode 100644
index 0000000..ead70b7
--- /dev/null
+++ b/system/adb/Make.defs
@@ -0,0 +1,23 @@
+############################################################################
+# system/adb/Make.defs
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+ifneq ($(CONFIG_SYSTEM_ADBD),)
+CONFIGURED_APPS += $(APPDIR)/system/adb
+endif
diff --git a/system/adb/Makefile b/system/adb/Makefile
new file mode 100644
index 0000000..f5e7778
--- /dev/null
+++ b/system/adb/Makefile
@@ -0,0 +1,92 @@
+############################################################################
+# system/adb/Makefile
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+include $(APPDIR)/Make.defs
+
+ADB_DIR := $(APPDIR)/system/adb
+CONFIG_ADBD_URL ?= "https://github.com/spiriou/microADB.git"
+CONFIG_ADBD_VERSION ?= bbd1e74bd795aa2fc53eae2b76bff993d6ccaa37
+
+ADB_UNPACKNAME := microADB
+ADB_UNPACKDIR := $(ADB_DIR)/$(ADB_UNPACKNAME)
+
+$(ADB_UNPACKDIR):
+	@echo "Downloading: $(ADB_UNPACKNAME)"
+	$(call DELDIR, "$@")
+	$(Q) mkdir "$@"
+	$(Q) cd "$@" && git init && \
+	git remote add origin "$(CONFIG_ADBD_URL)" && \
+	git fetch origin $(CONFIG_ADBD_VERSION) --depth=1 && \
+	git reset --hard FETCH_HEAD
+
+# adb server app
+
+PROGNAME  := $(CONFIG_ADBD_PROGNAME)
+PRIORITY  := $(CONFIG_ADBD_PRIORITY)
+STACKSIZE := $(CONFIG_ADBD_STACKSIZE)
+MODULE    := $(CONFIG_ADB_SERVER)
+
+# Files
+
+MAINSRC := adb_main.c
+CSRCS += adb_banner.c
+CSRCS += $(ADB_UNPACKNAME)/adb_client.c
+CSRCS += $(ADB_UNPACKNAME)/adb_frame.c
+
+CSRCS += $(ADB_UNPACKNAME)/hal/hal_uv.c
+CSRCS += $(ADB_UNPACKNAME)/hal/hal_uv_packet.c
+
+CFLAGS += -D__NUTTX__=1
+CFLAGS += -I$(ADB_UNPACKNAME)
+
+ifeq ($(CONFIG_ADBD_TCP_SERVER),y)
+CSRCS += $(ADB_UNPACKNAME)/hal/hal_uv_client_tcp.c
+endif
+
+ifeq ($(CONFIG_ADBD_USB_SERVER),y)
+CSRCS += $(ADB_UNPACKNAME)/hal/hal_uv_client_usb.c
+endif
+
+ifeq ($(CONFIG_ADBD_AUTHENTICATION),y)
+CSRCS += $(ADB_UNPACKNAME)/adb_auth_key.c
+endif
+
+ifeq ($(CONFIG_ADBD_FILE_SERVICE),y)
+CSRCS += $(ADB_UNPACKNAME)/file_sync_service.c
+endif
+
+ifeq ($(CONFIG_ADBD_LOGCAT_SERVICE),y)
+CSRCS += logcat_service.c
+endif
+
+ifeq ($(CONFIG_ADBD_SHELL_SERVICE),y)
+CSRCS += shell_service.c
+CSRCS += shell_pipe.c
+endif
+
+context:: $(ADB_UNPACKDIR)
+
+clean::
+	$(call DELFILE, $(OBJS))
+
+distclean::
+	$(call DELDIR, $(ADB_UNPACKDIR))
+
+include $(APPDIR)/Application.mk
diff --git a/system/adb/adb_banner.c b/system/adb/adb_banner.c
new file mode 100644
index 0000000..e446756
--- /dev/null
+++ b/system/adb/adb_banner.c
@@ -0,0 +1,117 @@
+/****************************************************************************
+ * system/adb/adb_main.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include "adb.h"
+#ifdef CONFIG_BOARDCTL_UNIQUEID
+#include <sys/boardctl.h>
+#include <string.h>
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int adb_fill_connect_data(char *buf, size_t bufsize)
+{
+  size_t len;
+  size_t remaining = bufsize;
+
+#ifdef CONFIG_BOARDCTL_UNIQUEID
+  /* Get board id */
+
+  int ret;
+  uint8_t board_id[CONFIG_BOARDCTL_UNIQUEID_SIZE];
+
+  memset(board_id, 0, CONFIG_BOARDCTL_UNIQUEID_SIZE);
+  ret = boardctl(BOARDIOC_UNIQUEID, (uintptr_t)board_id);
+
+  if (ret)
+    {
+      /* Failed to get board id */
+
+      adb_log("failed to get board id\n");
+      len = snprintf(buf, remaining, "device::");
+    }
+  else
+    {
+      /* FIXME only keep first 4 bytes */
+
+      len = snprintf(buf, remaining, "device:%x:", *(uint32_t *)board_id);
+    }
+#else
+  len = snprintf(buf, remaining, "device:" CONFIG_ADBD_DEVICE_ID ":");
+#endif
+
+  if (len >= remaining)
+    {
+      return -1;
+    }
+
+#ifdef CONFIG_ADBD_PRODUCT_NAME
+  remaining -= len;
+  buf += len;
+  len = snprintf(buf, remaining,
+                 "ro.product.name=" CONFIG_ADBD_PRODUCT_NAME ";");
+
+  if (len >= remaining)
+    {
+      return bufsize;
+    }
+#endif
+
+#ifdef CONFIG_ADBD_PRODUCT_MODEL
+  remaining -= len;
+  buf += len;
+  len = snprintf(buf, remaining,
+                 "ro.product.model=" CONFIG_ADBD_PRODUCT_MODEL ";");
+
+  if (len >= remaining)
+    {
+      return bufsize;
+    }
+#endif
+
+#ifdef CONFIG_ADBD_PRODUCT_DEVICE
+  remaining -= len;
+  buf += len;
+  len = snprintf(buf, remaining,
+                 "ro.product.device=" CONFIG_ADBD_PRODUCT_DEVICE ";");
+
+  if (len >= remaining)
+    {
+      return bufsize;
+    }
+#endif
+
+  remaining -= len;
+  buf += len;
+  len = snprintf(buf, remaining, "features=" CONFIG_ADBD_FEATURES);
+
+  if (len >= remaining)
+    {
+      return bufsize;
+    }
+
+  return bufsize - remaining + len;
+}
diff --git a/system/adb/adb_main.c b/system/adb/adb_main.c
new file mode 100644
index 0000000..d80c746
--- /dev/null
+++ b/system/adb/adb_main.c
@@ -0,0 +1,119 @@
+/****************************************************************************
+ * system/adb/adb_main.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include "adb.h"
+
+#ifdef CONFIG_ADBD_BOARD_INIT
+#include <sys/boardctl.h>
+#endif
+
+#ifdef CONFIG_ADBD_NET_INIT
+#include "netutils/netinit.h"
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+void adb_log_impl(FAR const char *func, int line, FAR const char *fmt, ...)
+{
+  va_list ap;
+  fprintf(stderr, "%s (%d): ", func, line);
+
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+}
+
+int main(int argc, FAR char **argv)
+{
+  UNUSED(argc);
+  UNUSED(argv);
+
+  adb_context_t *ctx;
+
+#ifdef CONFIG_ADBD_BOARD_INIT
+{
+  boardctl(BOARDIOC_INIT, 0);
+
+#if defined(CONFIG_ADBD_USB_SERVER) && \
+    defined(CONFIG_USBDEV_COMPOSITE) && \
+    defined (CONFIG_BOARDCTL_USBDEVCTRL)
+
+  /* Setup composite USB device */
+
+  struct boardioc_usbdev_ctrl_s ctrl;
+  int ret;
+  FAR void *handle;
+
+  /* Perform architecture-specific initialization */
+
+  ctrl.usbdev   = BOARDIOC_USBDEV_COMPOSITE;
+  ctrl.action   = BOARDIOC_USBDEV_INITIALIZE;
+  ctrl.instance = 0;
+  ctrl.config   = 0;
+  ctrl.handle   = NULL;
+
+  ret = boardctl(BOARDIOC_USBDEV_CONTROL, (uintptr_t)&ctrl);
+  if (ret < 0)
+    {
+      printf("boardctl(BOARDIOC_USBDEV_CONTROL) failed: %d\n", ret);
+      return 1;
+    }
+
+  /* Initialize the USB composite device device */
+
+  ctrl.usbdev   = BOARDIOC_USBDEV_COMPOSITE;
+  ctrl.action   = BOARDIOC_USBDEV_CONNECT;
+  ctrl.instance = 0;
+  ctrl.config   = 0;
+  ctrl.handle   = &handle;
+
+  ret = boardctl(BOARDIOC_USBDEV_CONTROL, (uintptr_t)&ctrl);
+  if (ret < 0)
+    {
+      printf("boardctl(BOARDIOC_USBDEV_CONTROL) failed: %d\n", ret);
+      return 1;
+    }
+#endif /* ADBD_USB_SERVER && USBDEV_COMPOSITE && BOARDCTL_USBDEVCTRL */
+}
+
+#endif /* CONFIG_ADBD_BOARD_INIT */
+
+#ifdef CONFIG_ADBD_NET_INIT
+  /* Bring up the network */
+
+  netinit_bringup();
+#endif
+
+  ctx = adb_hal_create_context();
+  if (!ctx)
+    {
+      return -1;
+    }
+
+  adb_hal_run(ctx);
+  adb_hal_destroy_context(ctx);
+  return 0;
+}
diff --git a/system/adb/logcat_service.c b/system/adb/logcat_service.c
new file mode 100644
index 0000000..c65f3de
--- /dev/null
+++ b/system/adb/logcat_service.c
@@ -0,0 +1,213 @@
+/****************************************************************************
+ * system/adb/logcat_service_uv.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <nuttx/syslog/ramlog.h>
+#include <unistd.h>
+
+#include "adb.h"
+#include "logcat_service.h"
+#include "hal/hal_uv_priv.h"
+
+/****************************************************************************
+ * Private types
+ ****************************************************************************/
+
+typedef struct alog_service_s
+{
+  adb_service_t service;
+  uv_poll_t poll;
+  int wait_ack;
+} alog_service_t;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void logcat_on_data_available(uv_poll_t * handle,
+                                     int status, int events);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int alog_on_write(adb_service_t *service, apacket *p)
+{
+  UNUSED(p);
+  UNUSED(service);
+  return -1;
+}
+
+static void alog_on_kick(struct adb_service_s *service)
+{
+  alog_service_t *svc = container_of(service, alog_service_t, service);
+  if (!svc->wait_ack)
+    {
+      int ret;
+      ret = uv_poll_start(&svc->poll, UV_READABLE, logcat_on_data_available);
+      assert(ret == 0);
+    }
+}
+
+static int alog_on_ack(adb_service_t *service, apacket *p)
+{
+  UNUSED(p);
+  alog_service_t *svc = container_of(service, alog_service_t, service);
+  svc->wait_ack = 0;
+  alog_on_kick(service);
+  return 0;
+}
+
+static void close_cb(uv_handle_t *handle)
+{
+  alog_service_t *service = container_of(handle, alog_service_t, poll);
+  free(service);
+}
+
+static void alog_close(struct adb_service_s *service)
+{
+  int fd;
+  int ret;
+  alog_service_t *svc = container_of(service, alog_service_t, service);
+
+  ret = uv_fileno((uv_handle_t *)&svc->poll, &fd);
+  assert(ret == 0);
+
+  close(fd);
+  uv_close((uv_handle_t *)&svc->poll, close_cb);
+}
+
+static const adb_service_ops_t logcat_ops =
+{
+  .on_write_frame = alog_on_write,
+  .on_ack_frame   = alog_on_ack,
+  .on_kick        = alog_on_kick,
+  .close          = alog_close
+};
+
+static void logcat_on_data_available(uv_poll_t * handle,
+                                     int status, int events)
+{
+  int ret;
+  int fd;
+  apacket_uv_t *ap;
+  alog_service_t *service = container_of(handle, alog_service_t, poll);
+  adb_client_uv_t *client = (adb_client_uv_t *)handle->data;
+
+  ap = adb_uv_packet_allocate(client, 0);
+  if (ap == NULL)
+    {
+      uv_poll_stop(handle);
+      return;
+    }
+
+  if (status)
+    {
+      adb_log("status error %d\n", status);
+
+      /* Fatal error, stop service */
+
+      goto exit_stop_service;
+    }
+
+  assert(uv_fileno((uv_handle_t *)handle, &fd) == 0);
+  ret = read(fd, ap->p.data, CONFIG_ADBD_PAYLOAD_SIZE);
+
+  if (ret < 0)
+    {
+      adb_log("frame read failed %d %d\n", ret, errno);
+      if (errno == EAGAIN)
+        {
+          /* TODO this should never happen */
+
+          goto exit_release_packet;
+        }
+
+      /* Fatal error, stop service */
+
+      goto exit_stop_service;
+    }
+
+  if (ret == 0)
+    {
+      goto exit_release_packet;
+    }
+
+  service->wait_ack = 1;
+  uv_poll_stop(handle);
+
+  ap->p.write_len = ret;
+  ap->p.msg.arg0 = service->service.id;
+  ap->p.msg.arg1 = service->service.peer_id;
+  adb_send_data_frame(&client->client, &ap->p);
+  return;
+
+exit_release_packet:
+  adb_hal_apacket_release(&client->client, &ap->p);
+  return;
+
+exit_stop_service:
+  adb_service_close(&client->client, &service->service, &ap->p);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+adb_service_t * logcat_service(adb_client_t *client, const char *params)
+{
+  int ret;
+  alog_service_t *service =
+      (alog_service_t *)malloc(sizeof(alog_service_t));
+
+  if (service == NULL)
+    {
+      return NULL;
+    }
+
+  service->service.ops = &logcat_ops;
+  service->wait_ack = 0;
+
+  /* TODO parse params string to extract logcat parameters */
+
+  ret = open(CONFIG_SYSLOG_DEVPATH, O_RDONLY | O_CLOEXEC);
+
+  if (ret < 0)
+    {
+      adb_log("failed to open %s (%d)\n", CONFIG_SYSLOG_DEVPATH, errno);
+      free(service);
+      return NULL;
+    }
+
+  uv_handle_t *handle = adb_uv_get_client_handle(client);
+  ret = uv_poll_init(handle->loop, &service->poll, ret);
+  assert(ret == 0);
+
+  service->poll.data = client;
+  alog_on_kick(&service->service);
+
+  return &service->service;
+}
diff --git a/system/adb/shell_pipe.c b/system/adb/shell_pipe.c
new file mode 100644
index 0000000..ad59b71
--- /dev/null
+++ b/system/adb/shell_pipe.c
@@ -0,0 +1,237 @@
+/****************************************************************************
+ * system/adb/shell_pipe.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <uv.h>
+#include <unistd.h>
+#include "adb.h"
+#include "shell_pipe.h"
+#include "hal/hal_uv_priv.h"
+
+#include <nshlib/nshlib.h>
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void shell_on_data_available(uv_poll_t * handle,
+                                    int status, int events)
+{
+  int ret;
+  apacket_uv_t *ap;
+  shell_pipe_t *pipe = container_of(handle, shell_pipe_t, handle);
+
+  adb_client_t *client = (adb_client_t *)pipe->handle.data;
+
+  if (status)
+    {
+      adb_log("status error %d\n", status);
+
+      /* FIXME missing logic here */
+
+      pipe->on_data_cb(pipe, NULL);
+      return;
+    }
+
+  ap = adb_uv_packet_allocate((adb_client_uv_t *)client, 0);
+  if (ap == NULL)
+    {
+      /* frame allocation failed. Try again later */
+
+      uv_poll_stop(&pipe->handle);
+      return;
+    }
+
+  int nread = 0;
+  do
+    {
+      ret = read(handle->io_watcher.fd, &ap->p.data[nread], 1);
+
+      if (ret == 0)
+        {
+          /* EOF */
+
+          break;
+        }
+
+      if (ret < 0)
+        {
+          /* Revisit. EAGAIN should not happen but it happens a lot */
+
+          if (errno == EAGAIN)
+            {
+              if (nread <= 0)
+                {
+                  adb_hal_apacket_release(
+                    (adb_client_t *)pipe->handle.data, &ap->p);
+                  return;
+                }
+              break;
+            }
+
+          /* Release packet and forward error */
+
+          adb_hal_apacket_release((adb_client_t *)pipe->handle.data, &ap->p);
+          pipe->on_data_cb(pipe, NULL);
+          return;
+        }
+
+      /* FIXME CR LF conversion */
+
+      if (ap->p.data[nread++] == '\n')
+        {
+          ap->p.data[nread++] = '\r';
+        }
+    }
+  while (nread < CONFIG_ADBD_PAYLOAD_SIZE - 1);
+
+  ap->p.msg.data_length = nread;
+  pipe->on_data_cb(pipe, &ap->p);
+}
+
+static void shell_pipe_close_callback(uv_handle_t *handle)
+{
+  shell_pipe_t *pipe = container_of(handle, shell_pipe_t, handle);
+
+  /* Notify caller pipe is closed */
+
+  pipe->close_cb(pipe);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int shell_pipe_setup(adb_client_t *client, shell_pipe_t *apipe)
+{
+  apipe->handle.data = client;
+  return 0;
+}
+
+void shell_pipe_destroy(shell_pipe_t *pipe, void (*close_cb)(shell_pipe_t *))
+{
+  pipe->close_cb = close_cb;
+  close(pipe->write_fd);
+  uv_close((uv_handle_t *)&pipe->handle, shell_pipe_close_callback);
+}
+
+int shell_pipe_write(shell_pipe_t *pipe, const void *buf, size_t count)
+{
+  /* TODO revisit */
+
+  return write(pipe->write_fd, buf, count);
+}
+
+int shell_pipe_start(shell_pipe_t *pipe,
+                     void (*on_data_cb)(shell_pipe_t *, apacket *))
+{
+  pipe->on_data_cb = on_data_cb;
+  return uv_poll_start(&pipe->handle, UV_READABLE, shell_on_data_available);
+}
+
+int shell_pipe_exec(char * const argv[], shell_pipe_t *apipe,
+                    void (*on_data_cb)(shell_pipe_t *, apacket *))
+{
+  int ret;
+  int in_fds[2];
+  int out_fds[2];
+
+  adb_client_uv_t *client = (adb_client_uv_t *)apipe->handle.data;
+
+  /* Create pipe for stdin */
+
+  ret = pipe(in_fds);
+  assert(ret == 0);
+  ret = pipe(out_fds);
+  assert(ret == 0);
+
+  /* TODO check return code */
+
+  apipe->write_fd = in_fds[1];
+
+  /* Setup stdout (read: adb, write: child) */
+
+  ret = dup2(out_fds[1], 1);
+  assert(ret == 0);
+
+  ret = close(out_fds[1]);
+  assert(ret == 0);
+
+  ret = fcntl(out_fds[0], F_GETFD);
+  assert(ret >= 0);
+  ret = fcntl(out_fds[0], F_SETFD, ret | FD_CLOEXEC);
+  assert(ret == 0);
+  ret = fcntl(out_fds[0], F_GETFL);
+  assert(ret >= 0);
+  ret = fcntl(out_fds[0], F_SETFL, ret | O_NONBLOCK);
+  assert(ret >= 0);
+
+  /* Setup stdin */
+
+  ret = dup2(in_fds[0], 0);
+  assert(ret == 0);
+
+  ret = close(in_fds[0]);
+  assert(ret == 0);
+
+  ret = fcntl(in_fds[1], F_GETFD);
+  assert(ret >= 0);
+  ret = fcntl(in_fds[1], F_SETFD, ret | FD_CLOEXEC);
+  assert(ret == 0);
+  ret = fcntl(in_fds[1], F_GETFL);
+  assert(ret >= 0);
+  ret = fcntl(in_fds[1], F_SETFL, ret | O_NONBLOCK);
+  assert(ret == 0);
+
+  ret = uv_poll_init(
+      adb_uv_get_client_handle(client)->loop,
+      &apipe->handle, out_fds[0]);
+
+  /* TODO check return code */
+
+  assert(ret == 0);
+
+  /* Create shell process */
+
+  ret = task_create("ADB shell", CONFIG_SYSTEM_NSH_PRIORITY,
+                    CONFIG_SYSTEM_NSH_STACKSIZE, nsh_consolemain,
+                    argv);
+
+  /* Close stdin and stdout */
+
+  dup2(2, 0);
+  dup2(2, 1);
+
+  /* TODO check return code */
+
+  assert(ret >= 0);
+
+  /* Start listening shell process stdout */
+
+  ret = shell_pipe_start(apipe, on_data_cb);
+
+  /* TODO check return code */
+
+  assert(ret == 0);
+  return 0;
+}
diff --git a/system/adb/shell_pipe.h b/system/adb/shell_pipe.h
new file mode 100644
index 0000000..16ca80f
--- /dev/null
+++ b/system/adb/shell_pipe.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+ * system/adb/shell_pipe.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <uv.h>
+#include "adb.h"
+
+/****************************************************************************
+ * Private types
+ ****************************************************************************/
+
+struct shell_pipe_s
+{
+  uv_poll_t handle;
+  int write_fd;
+  void (*close_cb)(struct shell_pipe_s *);
+  void (*on_data_cb)(struct shell_pipe_s *, struct apacket_s *);
+};
+
+typedef struct shell_pipe_s shell_pipe_t;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+int shell_pipe_setup(adb_client_t *client, shell_pipe_t *pipe);
+int shell_pipe_start(shell_pipe_t *pipe,
+                     void (*on_data_cb)(shell_pipe_t *, apacket *));
+void shell_pipe_destroy(shell_pipe_t *pipe,
+                        void (*close_cb)(shell_pipe_t *));
+int shell_pipe_write(shell_pipe_t *pipe, const void *buf, size_t count);
+
+int shell_pipe_exec(char * const argv[], shell_pipe_t *pipe,
+                    void (*on_data_cb)(shell_pipe_t *, apacket *));
+int shell_exec_builtin(const char *appname, FAR char *const *argv,
+                       shell_pipe_t *apipe);
diff --git a/system/adb/shell_service.c b/system/adb/shell_service.c
new file mode 100644
index 0000000..04bdfeb
--- /dev/null
+++ b/system/adb/shell_service.c
@@ -0,0 +1,209 @@
+/****************************************************************************
+ * system/adb/shell_service.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdlib.h>
+
+#include "adb.h"
+#include "shell_service.h"
+#include "shell_pipe.h"
+
+/****************************************************************************
+ * Private types
+ ****************************************************************************/
+
+typedef struct ash_service_s
+{
+  adb_service_t service;
+  shell_pipe_t pipe;
+  adb_client_t *client;
+} ash_service_t;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void exec_on_data_available(shell_pipe_t * pipe, apacket * p);
+
+static int shell_ack(adb_service_t *service, apacket *p);
+static int shell_write(adb_service_t *service, apacket *p);
+static void shell_close(struct adb_service_s *service);
+static void shell_kick(adb_service_t *service);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void exec_on_data_available(shell_pipe_t * pipe, apacket * p)
+{
+  ash_service_t *service = container_of(pipe, ash_service_t, pipe);
+
+  if (p->msg.data_length <= 0)
+    {
+      /* Got EOF */
+
+      adb_service_close(service->client, &service->service, p);
+      return;
+    }
+
+  p->write_len = p->msg.data_length;
+  p->msg.arg0 = service->service.id;
+  p->msg.arg1 = service->service.peer_id;
+  adb_send_data_frame(service->client, p);
+}
+
+static int shell_write(adb_service_t *service, apacket *p)
+{
+  int ret;
+  ash_service_t *svc = container_of(service, ash_service_t, service);
+  UNUSED(svc);
+
+  if (p->msg.data_length <= 0)
+    {
+      return -1;
+    }
+
+  ret = shell_pipe_write(&svc->pipe, p->data, p->msg.data_length);
+
+  if (ret < 0)
+    {
+      /* Shell process terminated, close service */
+
+      return -1;
+    }
+
+  assert(ret == p->msg.data_length);
+  return 0;
+}
+
+static int shell_ack(adb_service_t *service, apacket *p)
+{
+  UNUSED(service);
+  UNUSED(p);
+  return 0;
+}
+
+static void shell_kick(adb_service_t *service)
+{
+  int ret;
+  ash_service_t *svc = container_of(service, ash_service_t, service);
+  ret = shell_pipe_start(&svc->pipe, exec_on_data_available);
+
+  /* TODO handle return code */
+
+  assert(ret == 0);
+}
+
+static void shell_on_close(shell_pipe_t *pipe)
+{
+  ash_service_t *svc = container_of(pipe, ash_service_t, pipe);
+  free(svc);
+}
+
+static void shell_close(adb_service_t *service)
+{
+  ash_service_t *svc = container_of(service, ash_service_t, service);
+
+  /* FIXME missing logic here if shell process is still running */
+
+  shell_pipe_destroy(&svc->pipe, shell_on_close);
+}
+
+static const adb_service_ops_t shell_ops =
+{
+  .on_write_frame = shell_write,
+  .on_ack_frame   = shell_ack,
+  .on_kick        = shell_kick,
+  .close          = shell_close
+};
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+adb_service_t * shell_service(adb_client_t *client, const char *params)
+{
+  UNUSED(params);
+  UNUSED(client);
+
+  int ret;
+  char **argv;
+  const char *target;
+  ash_service_t *service =
+      (ash_service_t *)malloc(sizeof(ash_service_t));
+
+  if (service == NULL)
+    {
+      return NULL;
+    }
+
+  service->client = client;
+  service->service.ops = &shell_ops;
+
+  ret = shell_pipe_setup(client, &service->pipe);
+
+  /* TODO check return code */
+
+  assert(ret == 0);
+
+  /* Check parameters after "shell:" */
+
+  target = &params[6];
+
+  if (target[0] != 0)
+    {
+      /* Build argv: <nsh -c "command">
+       * argv[0] => "-c"
+       * argv[1] => command
+       * argv[2] => NULL
+       *
+       * malloc content:
+       * - x3 argv pointers
+       * - 3 characters: "-c\0"
+       * - space for command string
+       */
+
+      argv = malloc(sizeof(char *) * 3 + 3 + (strlen(target)+1));
+
+      argv[0] = (char *)&argv[3];
+      argv[1] = &((char *)&argv[3])[3];
+      argv[2] = NULL;
+      strcpy(argv[0], "-c");
+      strcpy(argv[1], target);
+    }
+  else
+    {
+      argv = NULL;
+    }
+
+  ret = shell_pipe_exec(argv, &service->pipe,
+                        exec_on_data_available);
+
+  /* TODO check return code */
+
+  assert(ret == 0);
+
+  free(argv);
+
+  return &service->service;
+}


[incubator-nuttx-apps] 01/02: libuv: fix bugs and add partial pipe support

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx-apps.git

commit efd81744d10c4e3895663e7c37b6fc9b588d8b37
Author: Simon Piriou <sp...@gmail.com>
AuthorDate: Mon Oct 26 11:39:28 2020 +0100

    libuv: fix bugs and add partial pipe support
---
 .../libuv/0001-initial-libuv-port-to-nuttx.patch   | 1122 ++++++++++++++------
 system/libuv/libuv/Kconfig                         |    7 +
 system/libuv/libuv/Makefile                        |    4 +
 system/libuv/tests/Makefile                        |    4 +-
 4 files changed, 815 insertions(+), 322 deletions(-)

diff --git a/system/libuv/0001-initial-libuv-port-to-nuttx.patch b/system/libuv/0001-initial-libuv-port-to-nuttx.patch
index d7d4e1b..8f22764 100644
--- a/system/libuv/0001-initial-libuv-port-to-nuttx.patch
+++ b/system/libuv/0001-initial-libuv-port-to-nuttx.patch
@@ -1,26 +1,27 @@
-From e589c4790e8367c5d3c0c37ba20338539ee6f76e Mon Sep 17 00:00:00 2001
+From 3307fabda302b693acbec3a9f11b6542428d5b96 Mon Sep 17 00:00:00 2001
 From: Simon Piriou <sp...@gmail.com>
 Date: Fri, 7 Aug 2020 19:48:02 +0200
 Subject: [PATCH] initial libuv port to nuttx
 
 ---
- include/uv.h                        |  108 ++-
+ include/uv.h                        |  109 ++-
  include/uv/nuttx.h                  |   67 ++
- include/uv/unix.h                   |  146 +++-
+ include/uv/unix.h                   |  155 +++-
  src/inet.c                          |   50 +-
  src/queue.h                         |    4 +-
- src/random.c                        |    4 +
+ src/random.c                        |   42 +-
  src/unix/async.c                    |   71 +-
- src/unix/core.c                     |  178 ++++-
- src/unix/fs.c                       |   62 +-
- src/unix/internal.h                 |   30 +-
+ src/unix/core.c                     |  209 +++++-
+ src/unix/fs.c                       |   77 +-
+ src/unix/internal.h                 |   32 +-
  src/unix/loop.c                     |   98 ++-
  src/unix/no-proctitle.c             |   28 +
- src/unix/nuttx.c                    |  238 ++++++
- src/unix/nuttx_stream.c             | 1077 +++++++++++++++++++++++++++
+ src/unix/nuttx.c                    |  238 +++++++
+ src/unix/nuttx_stream.c             | 1016 +++++++++++++++++++++++++++
  src/unix/nuttx_tcp.c                |  311 ++++++++
- src/unix/nuttx_threadpool.c         |  361 +++++++++
- src/unix/nuttx_timer.c              |  199 +++++
+ src/unix/nuttx_threadpool.c         |  361 ++++++++++
+ src/unix/nuttx_timer.c              |  199 ++++++
+ src/unix/pipe.c                     |   24 +-
  src/unix/poll.c                     |   26 +
  src/unix/process.c                  |   35 +-
  src/unix/random-devurandom.c        |   19 +-
@@ -33,24 +34,25 @@ Subject: [PATCH] initial libuv port to nuttx
  test/task.h                         |   58 +-
  test/test-active.c                  |   12 +-
  test/test-async.c                   |   36 +-
- test/test-fs-copyfile.c             |   27 +-
- test/test-fs-poll.c                 |  162 ++--
+ test/test-fs-copyfile.c             |   30 +-
+ test/test-fs-poll.c                 |  162 +++--
  test/test-idle.c                    |   20 +-
  test/test-ip4-addr.c                |    2 +-
- test/test-list.h                    |   75 +-
+ test/test-list.h                    |   85 ++-
  test/test-loop-close.c              |   13 +-
  test/test-loop-stop.c               |   24 +-
  test/test-loop-time.c               |   44 +-
- test/test-poll-close.c              |   15 +-
+ test/test-ping-pong.c               |   92 ++-
+ test/test-poll-close.c              |   16 +-
  test/test-random.c                  |   23 +-
  test/test-tcp-read-stop.c           |   13 +-
  test/test-tcp-write-after-connect.c |   17 +-
  test/test-threadpool.c              |   28 +-
  test/test-timer-again.c             |   28 +-
  test/test-timer-from-check.c        |   21 +-
- test/test-timer.c                   |  160 ++--
+ test/test-timer.c                   |  160 +++--
  test/test-walk-handles.c            |    8 +-
- 46 files changed, 3929 insertions(+), 363 deletions(-)
+ 48 files changed, 4024 insertions(+), 433 deletions(-)
  create mode 100644 include/uv/nuttx.h
  create mode 100644 src/unix/nuttx.c
  create mode 100644 src/unix/nuttx_stream.c
@@ -59,7 +61,7 @@ Subject: [PATCH] initial libuv port to nuttx
  create mode 100644 src/unix/nuttx_timer.c
 
 diff --git a/include/uv.h b/include/uv.h
-index fec663136..e4b989afb 100644
+index fec663136..d025e8a0b 100644
 --- a/include/uv.h
 +++ b/include/uv.h
 @@ -1,3 +1,23 @@
@@ -161,7 +163,15 @@ index fec663136..e4b989afb 100644
  
  UV_EXTERN int uv_backend_fd(const uv_loop_t*);
  UV_EXTERN int uv_backend_timeout(const uv_loop_t*);
-@@ -423,7 +473,7 @@ struct uv_shutdown_s {
+@@ -399,7 +449,6 @@ UV_EXTERN char* uv_err_name_r(int err, char* buf, size_t buflen);
+   /* read-only */                                                             \
+   uv_req_type type;                                                           \
+   /* private */                                                               \
+-  void* reserved[6];                                                          \
+   UV_REQ_PRIVATE_FIELDS                                                       \
+ 
+ /* Abstract base class of all requests. */
+@@ -423,7 +472,7 @@ struct uv_shutdown_s {
    UV_SHUTDOWN_PRIVATE_FIELDS
  };
  
@@ -170,7 +180,7 @@ index fec663136..e4b989afb 100644
  #define UV_HANDLE_FIELDS                                                      \
    /* public */                                                                \
    void* data;                                                                 \
-@@ -439,6 +489,20 @@ struct uv_shutdown_s {
+@@ -439,6 +488,20 @@ struct uv_shutdown_s {
    } u;                                                                        \
    UV_HANDLE_PRIVATE_FIELDS                                                    \
  
@@ -191,7 +201,7 @@ index fec663136..e4b989afb 100644
  /* The abstract base class of all handles. */
  struct uv_handle_s {
    UV_HANDLE_FIELDS
-@@ -857,12 +921,12 @@ struct uv_timer_s {
+@@ -857,12 +920,12 @@ struct uv_timer_s {
  UV_EXTERN int uv_timer_init(uv_loop_t*, uv_timer_t* handle);
  UV_EXTERN int uv_timer_start(uv_timer_t* handle,
                               uv_timer_cb cb,
@@ -208,7 +218,7 @@ index fec663136..e4b989afb 100644
  
  
  /*
-@@ -1770,6 +1834,10 @@ union uv_any_req {
+@@ -1770,6 +1833,10 @@ union uv_any_req {
  struct uv_loop_s {
    /* User data - use this for whatever. */
    void* data;
@@ -219,7 +229,7 @@ index fec663136..e4b989afb 100644
    /* Loop reference counting. */
    unsigned int active_handles;
    void* handle_queue[2];
-@@ -1779,12 +1847,28 @@ struct uv_loop_s {
+@@ -1779,12 +1846,28 @@ struct uv_loop_s {
    } active_reqs;
    /* Internal flag to signal loop stop. */
    unsigned int stop_flag;
@@ -322,7 +332,7 @@ index 000000000..62574f93b
 +
 +#endif /* UV_NUTTX_H */
 diff --git a/include/uv/unix.h b/include/uv/unix.h
-index 3a131638f..294708654 100644
+index 3a131638f..2c56e8a55 100644
 --- a/include/uv/unix.h
 +++ b/include/uv/unix.h
 @@ -1,3 +1,23 @@
@@ -360,17 +370,17 @@ index 3a131638f..294708654 100644
  # include "uv/linux.h"
  #elif defined (__MVS__)
  # include "uv/os390.h"
-@@ -93,7 +115,9 @@ typedef struct uv__io_s uv__io_t;
+@@ -93,7 +115,8 @@ typedef struct uv__io_s uv__io_t;
  
  struct uv__io_s {
    uv__io_cb cb;
-+#if 0
-   void* pending_queue[2];
-+#endif
+-  void* pending_queue[2];
++  /* FIXME moved in uv_stream_t for now.
++   * void* pending_queue[2]; */
    void* watcher_queue[2];
    unsigned int pevents; /* Pending event mask i.e. mask at next tick. */
    unsigned int events;  /* Current event mask. */
-@@ -218,37 +242,103 @@ typedef struct {
+@@ -218,37 +241,105 @@ typedef struct {
    char* errmsg;
  } uv_lib_t;
  
@@ -475,11 +485,12 @@ index 3a131638f..294708654 100644
 +  unsigned int nfds;
 +#endif
 +
-+#if 0
-+#define UV_LOOP_PRIVATE_TODO_FIELDS                                           \
++#ifdef CONFIG_LIBUV_STREAM
++/* FIXME pending_queue is only required for uv_streams for now */
++#define UV_LOOP_PRIVATE_STREAM_FIELDS                                         \
 +  void* pending_queue[2];
 +#else
-+#define UV_LOOP_PRIVATE_TODO_FIELDS
++#define UV_LOOP_PRIVATE_STREAM_FIELDS
 +#endif
 +
 +#define UV_LOOP_PRIVATE_FIELDS                                                \
@@ -489,23 +500,28 @@ index 3a131638f..294708654 100644
 +  UV_LOOP_PRIVATE_WATCHERS_FIELDS                                             \
 +  UV_LOOP_PRIVATE_ASYNC_FIELDS                                                \
 +  UV_LOOP_PRIVATE_TIMER_FIELDS                                                \
-+  uv_time_t time;                                                              \
++  uv_time_t time;                                                             \
 +  UV_LOOP_PRIVATE_SIGNAL_FIELDS                                               \
 +  UV_LOOP_PRIVATE_PROCESS_FIELDS                                              \
++  UV_LOOP_PRIVATE_STREAM_FIELDS                                               \
 +  UV_LOOP_PRIVATE_PERFS_FIELDS                                                \
    UV_PLATFORM_LOOP_FIELDS                                                     \
  
  #define UV_REQ_TYPE_PRIVATE /* empty */
-@@ -290,7 +380,7 @@ typedef struct {
+@@ -289,10 +380,10 @@ typedef struct {
+   uv__io_t io_watcher;                                                        \
    void* write_queue[2];                                                       \
    void* write_completed_queue[2];                                             \
++  void* pending_queue[2];                                                     \
    uv_connection_cb connection_cb;                                             \
 -  int delayed_error;                                                          \
 +  /*int delayed_error;*/                                                      \
    int accepted_fd;                                                            \
-   void* queued_fds;                                                           \
+-  void* queued_fds;                                                           \
    UV_STREAM_PRIVATE_PLATFORM_FIELDS                                           \
-@@ -327,12 +417,20 @@ typedef struct {
+ 
+ #define UV_TCP_PRIVATE_FIELDS /* empty */
+@@ -327,12 +418,20 @@ typedef struct {
    void* queue[2];                                                             \
    int pending;                                                                \
  
@@ -526,6 +542,20 @@ index 3a131638f..294708654 100644
  
  #define UV_GETADDRINFO_PRIVATE_FIELDS                                         \
    struct uv__work work_req;                                                   \
+@@ -374,9 +473,13 @@ typedef struct {
+ #define UV_WORK_PRIVATE_FIELDS                                                \
+   struct uv__work work_req;
+ 
++#ifdef CONFIG_LIBUV_TTY
+ #define UV_TTY_PRIVATE_FIELDS                                                 \
+   struct termios orig_termios;                                                \
+   int mode;
++#else /* CONFIG_LIBUV_TTY */
++  #define UV_TTY_PRIVATE_FIELDS
++#endif /* CONFIG_LIBUV_TTY */
+ 
+ #define UV_SIGNAL_PRIVATE_FIELDS                                              \
+   /* RB_ENTRY(uv_signal_s) tree_entry; */                                     \
 diff --git a/src/inet.c b/src/inet.c
 index 698ab232e..63aa2b81b 100644
 --- a/src/inet.c
@@ -656,7 +686,7 @@ index 698ab232e..63aa2b81b 100644
  }
 +#endif
 diff --git a/src/queue.h b/src/queue.h
-index ff3540a0a..1e3e92904 100644
+index ff3540a0a..6fa87975f 100644
 --- a/src/queue.h
 +++ b/src/queue.h
 @@ -74,8 +74,8 @@ typedef void *QUEUE[2];
@@ -665,13 +695,13 @@ index ff3540a0a..1e3e92904 100644
      else {                                                                    \
 -      QUEUE* q = QUEUE_HEAD(h);                                               \
 -      QUEUE_SPLIT(h, q, n);                                                   \
-+      QUEUE* _q = QUEUE_HEAD(h);                                               \
-+      QUEUE_SPLIT(h, _q, n);                                                   \
++      QUEUE* _q = QUEUE_HEAD(h);                                              \
++      QUEUE_SPLIT(h, _q, n);                                                  \
      }                                                                         \
    }                                                                           \
    while (0)
 diff --git a/src/random.c b/src/random.c
-index 491bf7033..6b2280f02 100644
+index 491bf7033..26e45b334 100644
 --- a/src/random.c
 +++ b/src/random.c
 @@ -31,6 +31,9 @@
@@ -684,7 +714,7 @@ index 491bf7033..6b2280f02 100644
  #if defined(__PASE__)
    rc = uv__random_readpath("/dev/urandom", buf, buflen);
  #elif defined(_AIX)
-@@ -65,6 +68,7 @@ static int uv__random(void* buf, size_t buflen) {
+@@ -65,11 +68,12 @@ static int uv__random(void* buf, size_t buflen) {
  #else
    rc = uv__random_devurandom(buf, buflen);
  #endif
@@ -692,6 +722,61 @@ index 491bf7033..6b2280f02 100644
  
    return rc;
  }
+ 
+-
++#ifdef CONFIG_LIBUV_WQ
+ static void uv__random_work(struct uv__work* w) {
+   uv_random_t* req;
+ 
+@@ -89,7 +93,7 @@ static void uv__random_done(struct uv__work* w, int status) {
+ 
+   req->cb(req, status, req->buf, req->buflen);
+ }
+-
++#endif
+ 
+ int uv_random(uv_loop_t* loop,
+               uv_random_t* req,
+@@ -103,21 +107,23 @@ int uv_random(uv_loop_t* loop,
+   if (flags != 0)
+     return UV_EINVAL;
+ 
+-  if (cb == NULL)
+-    return uv__random(buf, buflen);
+-
+-  uv__req_init(loop, req, UV_RANDOM);
+-  req->loop = loop;
+-  req->status = 0;
+-  req->cb = cb;
+-  req->buf = buf;
+-  req->buflen = buflen;
+-
+-  uv__work_submit(loop,
+-                  &req->work_req,
+-                  UV__WORK_CPU,
+-                  uv__random_work,
+-                  uv__random_done);
++#ifdef CONFIG_LIBUV_WQ
++  if (cb != NULL) {
++    uv__req_init(loop, req, UV_RANDOM);
++    req->loop = loop;
++    req->status = 0;
++    req->cb = cb;
++    req->buf = buf;
++    req->buflen = buflen;
++
++    uv__work_submit(loop,
++                    &req->work_req,
++                    UV__WORK_CPU,
++                    uv__random_work,
++                    uv__random_done);
++    return 0;
++  }
++#endif
+ 
+-  return 0;
++  return uv__random(buf, buflen);
+ }
 diff --git a/src/unix/async.c b/src/unix/async.c
 index 5f58fb88d..00b6a858c 100644
 --- a/src/unix/async.c
@@ -879,7 +964,7 @@ index 5f58fb88d..00b6a858c 100644
    uv__io_stop(loop, &loop->async_io_watcher, POLLIN);
    uv__close(loop->async_io_watcher.fd);
 diff --git a/src/unix/core.c b/src/unix/core.c
-index 5b0b64dd4..2438614f0 100644
+index 5b0b64dd4..237a6b1bb 100644
 --- a/src/unix/core.c
 +++ b/src/unix/core.c
 @@ -1,3 +1,23 @@
@@ -921,23 +1006,29 @@ index 5b0b64dd4..2438614f0 100644
  #if defined(__DragonFly__)      || \
      defined(__FreeBSD__)        || \
      defined(__FreeBSD_kernel__) || \
-@@ -89,6 +112,7 @@ extern char** environ;
+@@ -87,8 +110,11 @@ extern char** environ;
+ # include <sys/syscall.h>
+ # define uv__accept4 accept4
  #endif
++#endif
  
++#ifdef CONFIG_LIBUV_STREAM
  static int uv__run_pending(uv_loop_t* loop);
 +#endif
  
  /* Verify that uv_buf_t is ABI-compatible with struct iovec. */
  STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec));
-@@ -112,6 +136,7 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
+@@ -112,22 +138,31 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
    handle->close_cb = close_cb;
  
    switch (handle->type) {
-+#if 0
++#ifdef CONFIG_LIBUV_PIPE
    case UV_NAMED_PIPE:
      uv__pipe_close((uv_pipe_t*)handle);
      break;
-@@ -119,15 +144,21 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
++#endif
+ 
++#if 0
    case UV_TTY:
      uv__stream_close((uv_stream_t*)handle);
      break;
@@ -959,7 +1050,7 @@ index 5b0b64dd4..2438614f0 100644
    case UV_PREPARE:
      uv__prepare_close((uv_prepare_t*)handle);
      break;
-@@ -139,15 +170,20 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
+@@ -139,15 +174,20 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
    case UV_IDLE:
      uv__idle_close((uv_idle_t*)handle);
      break;
@@ -981,7 +1072,7 @@ index 5b0b64dd4..2438614f0 100644
    case UV_PROCESS:
      uv__process_close((uv_process_t*)handle);
      break;
-@@ -155,21 +191,24 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
+@@ -155,21 +195,24 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
    case UV_FS_EVENT:
      uv__fs_event_close((uv_fs_event_t*)handle);
      break;
@@ -1008,7 +1099,7 @@ index 5b0b64dd4..2438614f0 100644
    default:
      assert(0);
    }
-@@ -177,6 +216,7 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
+@@ -177,6 +220,7 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
    uv__make_close_pending(handle);
  }
  
@@ -1016,7 +1107,7 @@ index 5b0b64dd4..2438614f0 100644
  int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
    int r;
    int fd;
-@@ -204,6 +244,7 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
+@@ -204,6 +248,7 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
  
    return 0;
  }
@@ -1024,7 +1115,7 @@ index 5b0b64dd4..2438614f0 100644
  
  void uv__make_close_pending(uv_handle_t* handle) {
    assert(handle->flags & UV_HANDLE_CLOSING);
-@@ -241,7 +282,9 @@ int uv__getiovmax(void) {
+@@ -241,7 +286,9 @@ int uv__getiovmax(void) {
  
  
  static void uv__finish_close(uv_handle_t* handle) {
@@ -1034,7 +1125,7 @@ index 5b0b64dd4..2438614f0 100644
  
    /* Note: while the handle is in the UV_HANDLE_CLOSING state now, it's still
     * possible for it to be active in the sense that uv__is_active() returns
-@@ -256,17 +299,28 @@ static void uv__finish_close(uv_handle_t* handle) {
+@@ -256,17 +303,28 @@ static void uv__finish_close(uv_handle_t* handle) {
    handle->flags |= UV_HANDLE_CLOSED;
  
    switch (handle->type) {
@@ -1064,23 +1155,27 @@ index 5b0b64dd4..2438614f0 100644
      case UV_SIGNAL:
        /* If there are any caught signals "trapped" in the signal pipe,
         * we can't call the close callback yet. Reinserting the handle
-@@ -280,17 +334,21 @@ static void uv__finish_close(uv_handle_t* handle) {
+@@ -280,17 +338,26 @@ static void uv__finish_close(uv_handle_t* handle) {
          return;
        }
        break;
--
 +#endif
-+#if 0
+ 
++#ifdef CONFIG_LIBUV_STREAM
++#ifdef CONFIG_LIBUV_PIPE
      case UV_NAMED_PIPE:
 -    case UV_TCP:
++#endif
++#if 0
      case UV_TTY:
 +#endif
 +#ifdef CONFIG_LIBUV_TCP
 +    case UV_TCP:
++#endif
        uv__stream_destroy((uv_stream_t*)handle);
        break;
 -
-+#endif
++#endif /* CONFIG_LIBUV_STREAM */
 +#ifdef CONFIG_LIBUV_UDP
      case UV_UDP:
        uv__udp_finish_close((uv_udp_t*)handle);
@@ -1090,7 +1185,7 @@ index 5b0b64dd4..2438614f0 100644
      default:
        assert(0);
        break;
-@@ -324,10 +382,11 @@ int uv_is_closing(const uv_handle_t* handle) {
+@@ -324,10 +391,11 @@ int uv_is_closing(const uv_handle_t* handle) {
    return uv__is_closing(handle);
  }
  
@@ -1103,7 +1198,7 @@ index 5b0b64dd4..2438614f0 100644
  
  
  int uv_backend_timeout(const uv_loop_t* loop) {
-@@ -337,16 +396,24 @@ int uv_backend_timeout(const uv_loop_t* loop) {
+@@ -337,16 +405,24 @@ int uv_backend_timeout(const uv_loop_t* loop) {
    if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
      return 0;
  
@@ -1112,7 +1207,7 @@ index 5b0b64dd4..2438614f0 100644
      return 0;
 +#endif
  
-+#if 0
++#ifdef CONFIG_LIBUV_STREAM
    if (!QUEUE_EMPTY(&loop->pending_queue))
      return 0;
 +#endif
@@ -1128,7 +1223,7 @@ index 5b0b64dd4..2438614f0 100644
  }
  
  
-@@ -373,17 +440,30 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
+@@ -373,17 +449,30 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
  
    while (r != 0 && loop->stop_flag == 0) {
      uv__update_time(loop);
@@ -1137,7 +1232,7 @@ index 5b0b64dd4..2438614f0 100644
      uv__run_timers(loop);
 +#endif
 +
-+#if 0
++#ifdef CONFIG_LIBUV_STREAM
      ran_pending = uv__run_pending(loop);
 +#else
 +    ran_pending = 0;
@@ -1159,7 +1254,7 @@ index 5b0b64dd4..2438614f0 100644
      uv__run_closing_handles(loop);
  
      if (mode == UV_RUN_ONCE) {
-@@ -396,7 +476,10 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
+@@ -396,7 +485,10 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
         * the check.
         */
        uv__update_time(loop);
@@ -1170,7 +1265,7 @@ index 5b0b64dd4..2438614f0 100644
      }
  
      r = uv__loop_alive(loop);
-@@ -423,7 +506,7 @@ int uv_is_active(const uv_handle_t* handle) {
+@@ -423,7 +515,7 @@ int uv_is_active(const uv_handle_t* handle) {
    return uv__is_active(handle);
  }
  
@@ -1179,7 +1274,7 @@ index 5b0b64dd4..2438614f0 100644
  /* Open a socket in non-blocking close-on-exec mode, atomically if possible. */
  int uv__socket(int domain, int type, int protocol) {
    int sockfd;
-@@ -460,6 +543,7 @@ int uv__socket(int domain, int type, int protocol) {
+@@ -460,6 +552,7 @@ int uv__socket(int domain, int type, int protocol) {
  
    return sockfd;
  }
@@ -1187,16 +1282,16 @@ index 5b0b64dd4..2438614f0 100644
  
  /* get a file pointer to a file in read-only and close-on-exec mode */
  FILE* uv__open_file(const char* path) {
-@@ -477,7 +561,7 @@ FILE* uv__open_file(const char* path) {
+@@ -477,7 +570,7 @@ FILE* uv__open_file(const char* path) {
     return fp;
  }
  
 -
-+#ifdef CONFIG_LIBUV_STREAM
++#if defined(CONFIG_LIBUV_STREAM) && defined(CONFIG_LIBUV_NET)
  int uv__accept(int sockfd) {
    int peerfd;
    int err;
-@@ -509,7 +593,7 @@ int uv__accept(int sockfd) {
+@@ -509,7 +602,7 @@ int uv__accept(int sockfd) {
  
    return peerfd;
  }
@@ -1205,7 +1300,7 @@ index 5b0b64dd4..2438614f0 100644
  
  /* close() on macos has the "interesting" quirk that it fails with EINTR
   * without closing the file descriptor when a thread is in the cancel state.
-@@ -531,6 +615,8 @@ int uv__close_nocancel(int fd) {
+@@ -531,6 +624,8 @@ int uv__close_nocancel(int fd) {
    return close$NOCANCEL$UNIX2003(fd);
  #endif
  #pragma GCC diagnostic pop
@@ -1214,7 +1309,7 @@ index 5b0b64dd4..2438614f0 100644
  #elif defined(__linux__)
    return syscall(SYS_close, fd);
  #else
-@@ -559,11 +645,18 @@ int uv__close_nocheckstdio(int fd) {
+@@ -559,11 +654,18 @@ int uv__close_nocheckstdio(int fd) {
  
  
  int uv__close(int fd) {
@@ -1233,7 +1328,7 @@ index 5b0b64dd4..2438614f0 100644
  }
  
  
-@@ -581,7 +674,8 @@ int uv__nonblock_ioctl(int fd, int set) {
+@@ -581,7 +683,8 @@ int uv__nonblock_ioctl(int fd, int set) {
  }
  
  
@@ -1243,7 +1338,7 @@ index 5b0b64dd4..2438614f0 100644
  int uv__cloexec_ioctl(int fd, int set) {
    int r;
  
-@@ -658,7 +752,7 @@ int uv__cloexec_fcntl(int fd, int set) {
+@@ -658,7 +761,7 @@ int uv__cloexec_fcntl(int fd, int set) {
    return 0;
  }
  
@@ -1252,7 +1347,7 @@ index 5b0b64dd4..2438614f0 100644
  ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
    struct cmsghdr* cmsg;
    ssize_t rc;
-@@ -695,7 +789,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
+@@ -695,7 +798,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
          uv__cloexec(*pfd, 1);
    return rc;
  }
@@ -1261,7 +1356,7 @@ index 5b0b64dd4..2438614f0 100644
  
  int uv_cwd(char* buffer, size_t* size) {
    char scratch[1 + UV__PATH_MAX];
-@@ -743,7 +837,7 @@ int uv_chdir(const char* dir) {
+@@ -743,7 +846,7 @@ int uv_chdir(const char* dir) {
    return 0;
  }
  
@@ -1270,7 +1365,7 @@ index 5b0b64dd4..2438614f0 100644
  void uv_disable_stdio_inheritance(void) {
    int fd;
  
-@@ -754,7 +848,7 @@ void uv_disable_stdio_inheritance(void) {
+@@ -754,21 +857,31 @@ void uv_disable_stdio_inheritance(void) {
      if (uv__cloexec(fd, 1) && fd > 15)
        break;
  }
@@ -1279,16 +1374,53 @@ index 5b0b64dd4..2438614f0 100644
  
  int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
    int fd_out;
-@@ -785,7 +879,7 @@ int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
+ 
+   switch (handle->type) {
++#ifdef CONFIG_LIBUV_TCP
+   case UV_TCP:
++#endif
++#ifdef CONFIG_LIBUV_PIPE
+   case UV_NAMED_PIPE:
++#endif
++#if 0
+   case UV_TTY:
++#endif
++#if defined(CONFIG_LIBUV_PIPE) || defined(CONFIG_LIBUV_TCP)
+     fd_out = uv__stream_fd((uv_stream_t*) handle);
+     break;
++#endif
+ 
++#ifdef CONFIG_LIBUV_UDP
+   case UV_UDP:
+     fd_out = ((uv_udp_t *) handle)->io_watcher.fd;
+     break;
++#endif
+ 
+   case UV_POLL:
+     fd_out = ((uv_poll_t *) handle)->io_watcher.fd;
+@@ -785,11 +898,11 @@ int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
    return 0;
  }
  
 -
-+#if 0
++#ifdef CONFIG_LIBUV_STREAM
  static int uv__run_pending(uv_loop_t* loop) {
    QUEUE* q;
    QUEUE pq;
-@@ -806,8 +900,9 @@ static int uv__run_pending(uv_loop_t* loop) {
+-  uv__io_t* w;
++  uv_stream_t* handle;
+ 
+   if (QUEUE_EMPTY(&loop->pending_queue))
+     return 0;
+@@ -800,14 +913,15 @@ static int uv__run_pending(uv_loop_t* loop) {
+     q = QUEUE_HEAD(&pq);
+     QUEUE_REMOVE(q);
+     QUEUE_INIT(q);
+-    w = QUEUE_DATA(q, uv__io_t, pending_queue);
+-    w->cb(loop, w, POLLOUT);
++    handle = QUEUE_DATA(q, uv_stream_t, pending_queue);
++    handle->io_watcher.cb(loop, &handle->io_watcher, POLLOUT);
+   }
  
    return 1;
  }
@@ -1299,7 +1431,7 @@ index 5b0b64dd4..2438614f0 100644
  static unsigned int next_power_of_two(unsigned int val) {
    val -= 1;
    val |= val >> 1;
-@@ -852,12 +947,14 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) {
+@@ -852,12 +966,14 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) {
    loop->watchers = watchers;
    loop->nwatchers = nwatchers;
  }
@@ -1315,7 +1447,7 @@ index 5b0b64dd4..2438614f0 100644
    QUEUE_INIT(&w->watcher_queue);
    w->cb = cb;
    w->fd = fd;
-@@ -878,7 +975,9 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+@@ -878,7 +994,9 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
    assert(w->fd < INT_MAX);
  
    w->pevents |= events;
@@ -1325,7 +1457,7 @@ index 5b0b64dd4..2438614f0 100644
  
  #if !defined(__sun)
    /* The event ports backend needs to rearm all file descriptors on each and
-@@ -892,10 +991,12 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+@@ -892,10 +1010,12 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
    if (QUEUE_EMPTY(&w->watcher_queue))
      QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
  
@@ -1338,7 +1470,7 @@ index 5b0b64dd4..2438614f0 100644
  }
  
  
-@@ -909,8 +1010,10 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+@@ -909,8 +1029,10 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
    assert(w->fd >= 0);
  
    /* Happens when uv__io_stop() is called on a handle that was never started. */
@@ -1349,7 +1481,7 @@ index 5b0b64dd4..2438614f0 100644
  
    w->pevents &= ~events;
  
-@@ -918,6 +1021,7 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+@@ -918,6 +1040,7 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
      QUEUE_REMOVE(&w->watcher_queue);
      QUEUE_INIT(&w->watcher_queue);
  
@@ -1357,7 +1489,7 @@ index 5b0b64dd4..2438614f0 100644
      if (loop->watchers[w->fd] != NULL) {
        assert(loop->watchers[w->fd] == w);
        assert(loop->nfds > 0);
-@@ -925,6 +1029,9 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+@@ -925,6 +1048,9 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
        loop->nfds--;
        w->events = 0;
      }
@@ -1367,29 +1499,34 @@ index 5b0b64dd4..2438614f0 100644
    }
    else if (QUEUE_EMPTY(&w->watcher_queue))
      QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
-@@ -933,7 +1040,7 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+@@ -933,19 +1059,21 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
  
  void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
    uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
--  QUEUE_REMOVE(&w->pending_queue);
-+  // QUEUE_REMOVE(&w->pending_queue);
++#if 0
+   QUEUE_REMOVE(&w->pending_queue);
++#endif
  
    /* Remove stale events for this file descriptor */
    if (w->fd != -1)
-@@ -941,10 +1048,12 @@ void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
+     uv__platform_invalidate_fd(loop, w->fd);
  }
  
- 
-+#if 0
- void uv__io_feed(uv_loop_t* loop, uv__io_t* w) {
-   if (QUEUE_EMPTY(&w->pending_queue))
-     QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue);
+-
+-void uv__io_feed(uv_loop_t* loop, uv__io_t* w) {
+-  if (QUEUE_EMPTY(&w->pending_queue))
+-    QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue);
++#ifdef CONFIG_LIBUV_STREAM
++void uv__stream_feed(uv_loop_t* loop, uv_stream_t* s) {
++  if (QUEUE_EMPTY(&s->pending_queue))
++    QUEUE_INSERT_TAIL(&loop->pending_queue, &s->pending_queue);
  }
+-
 +#endif
  
- 
  int uv__io_active(const uv__io_t* w, unsigned int events) {
-@@ -955,10 +1064,22 @@ int uv__io_active(const uv__io_t* w, unsigned int events) {
+   assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
+@@ -955,10 +1083,22 @@ int uv__io_active(const uv__io_t* w, unsigned int events) {
  
  
  int uv__fd_exists(uv_loop_t* loop, int fd) {
@@ -1413,7 +1550,7 @@ index 5b0b64dd4..2438614f0 100644
  int uv_getrusage(uv_rusage_t* rusage) {
    struct rusage usage;
  
-@@ -990,7 +1111,7 @@ int uv_getrusage(uv_rusage_t* rusage) {
+@@ -990,7 +1130,7 @@ int uv_getrusage(uv_rusage_t* rusage) {
  
    return 0;
  }
@@ -1422,7 +1559,7 @@ index 5b0b64dd4..2438614f0 100644
  
  int uv__open_cloexec(const char* path, int flags) {
  #if defined(O_CLOEXEC)
-@@ -1019,7 +1140,7 @@ int uv__open_cloexec(const char* path, int flags) {
+@@ -1019,7 +1159,7 @@ int uv__open_cloexec(const char* path, int flags) {
  #endif  /* O_CLOEXEC */
  }
  
@@ -1431,7 +1568,7 @@ index 5b0b64dd4..2438614f0 100644
  int uv__dup2_cloexec(int oldfd, int newfd) {
  #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__linux__)
    int r;
-@@ -1046,7 +1167,7 @@ int uv__dup2_cloexec(int oldfd, int newfd) {
+@@ -1046,7 +1186,7 @@ int uv__dup2_cloexec(int oldfd, int newfd) {
    return r;
  #endif
  }
@@ -1440,7 +1577,7 @@ index 5b0b64dd4..2438614f0 100644
  
  int uv_os_homedir(char* buffer, size_t* size) {
    uv_passwd_t pwd;
-@@ -1390,12 +1511,13 @@ uv_pid_t uv_os_getpid(void) {
+@@ -1390,12 +1530,13 @@ uv_pid_t uv_os_getpid(void) {
    return getpid();
  }
  
@@ -1456,7 +1593,7 @@ index 5b0b64dd4..2438614f0 100644
  int uv_os_getpriority(uv_pid_t pid, int* priority) {
    int r;
  
-@@ -1422,7 +1544,7 @@ int uv_os_setpriority(uv_pid_t pid, int priority) {
+@@ -1422,7 +1563,7 @@ int uv_os_setpriority(uv_pid_t pid, int priority) {
  
    return 0;
  }
@@ -1466,7 +1603,7 @@ index 5b0b64dd4..2438614f0 100644
  int uv_os_uname(uv_utsname_t* buffer) {
    struct utsname buf;
 diff --git a/src/unix/fs.c b/src/unix/fs.c
-index dd08ea541..4e32d0783 100644
+index dd08ea541..302d4f0c6 100644
 --- a/src/unix/fs.c
 +++ b/src/unix/fs.c
 @@ -56,6 +56,12 @@
@@ -1591,35 +1728,21 @@ index dd08ea541..4e32d0783 100644
      return -1;
    }
  #elif defined(__APPLE__)           || \
-@@ -970,7 +982,12 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
- 
- 
- static ssize_t uv__fs_utime(uv_fs_t* req) {
--#if defined(__linux__)                                                         \
-+#if defined(__NUTTX__)
-+  struct timeval tv[2];
-+  tv[0] = uv__fs_to_timeval(req->atime);
-+  tv[1] = uv__fs_to_timeval(req->mtime);
-+  return utimes(req->path, tv);
-+#elif defined(__linux__)                                                         \
-     || defined(_AIX71)                                                         \
-     || defined(__sun)                                                          \
-     || defined(__HAIKU__)
-@@ -1011,7 +1028,7 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
+@@ -968,7 +980,7 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
  #endif
  }
  
 -
 +#ifndef __NUTTX__
- static ssize_t uv__fs_lutime(uv_fs_t* req) {
- #if defined(__linux__)            ||                                           \
-     defined(_AIX71)               ||                                           \
-@@ -1035,10 +1052,10 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) {
+ static ssize_t uv__fs_utime(uv_fs_t* req) {
+ #if defined(__linux__)                                                         \
+     || defined(_AIX71)                                                         \
+@@ -1035,10 +1047,10 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) {
    return -1;
  #endif
  }
 -
-+#endif
++#endif /* !__NUTTX__ */
  
  static ssize_t uv__fs_write(uv_fs_t* req) {
 -#if defined(__linux__)
@@ -1627,7 +1750,7 @@ index dd08ea541..4e32d0783 100644
    static int no_pwritev;
  #endif
    ssize_t r;
-@@ -1067,13 +1084,13 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
+@@ -1067,13 +1079,13 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
  #if HAVE_PREADV
      r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
  #else
@@ -1643,7 +1766,7 @@ index dd08ea541..4e32d0783 100644
      else {
        r = uv__pwritev(req->file,
                        (struct iovec*) req->bufs,
-@@ -1102,7 +1119,9 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
+@@ -1102,7 +1114,9 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
    uv_file srcfd;
    uv_file dstfd;
    struct stat src_statsbuf;
@@ -1653,7 +1776,7 @@ index dd08ea541..4e32d0783 100644
    int dst_flags;
    int result;
    int err;
-@@ -1146,6 +1165,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
+@@ -1146,6 +1160,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
      goto out;
    }
  
@@ -1661,7 +1784,7 @@ index dd08ea541..4e32d0783 100644
    /* Get the destination file's mode. */
    if (fstat(dstfd, &dst_statsbuf)) {
      err = UV__ERR(errno);
-@@ -1157,9 +1177,12 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
+@@ -1157,9 +1172,12 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
        src_statsbuf.st_ino == dst_statsbuf.st_ino) {
      goto out;
    }
@@ -1674,7 +1797,7 @@ index dd08ea541..4e32d0783 100644
  #ifdef __linux__
      if (err != UV_EPERM)
        goto out;
-@@ -1183,6 +1206,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
+@@ -1183,6 +1201,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
      goto out;
  #endif  /* !__linux__ */
    }
@@ -1682,7 +1805,7 @@ index dd08ea541..4e32d0783 100644
  
  #ifdef FICLONE
    if (req->flags & UV_FS_COPYFILE_FICLONE ||
-@@ -1343,7 +1367,7 @@ static int uv__fs_statx(int fd,
+@@ -1343,7 +1362,7 @@ static int uv__fs_statx(int fd,
                          int is_lstat,
                          uv_stat_t* buf) {
    STATIC_ASSERT(UV_ENOSYS != -1);
@@ -1691,17 +1814,18 @@ index dd08ea541..4e32d0783 100644
    static int no_statx;
    struct uv__statx statxbuf;
    int dirfd;
-@@ -1543,30 +1567,40 @@ static void uv__fs_work(struct uv__work* w) {
+@@ -1542,40 +1561,56 @@ static void uv__fs_work(struct uv__work* w) {
+ 
      switch (req->fs_type) {
      X(ACCESS, access(req->path, req->flags));
-     X(CHMOD, chmod(req->path, req->mode));
 +#ifndef __NUTTX__
+     X(CHMOD, chmod(req->path, req->mode));
      X(CHOWN, chown(req->path, req->uid, req->gid));
 +#endif
      X(CLOSE, uv__fs_close(req->file));
      X(COPYFILE, uv__fs_copyfile(req));
-     X(FCHMOD, fchmod(req->file, req->mode));
 +#ifndef __NUTTX__
+     X(FCHMOD, fchmod(req->file, req->mode));
      X(FCHOWN, fchown(req->file, req->uid, req->gid));
      X(LCHOWN, lchown(req->path, req->uid, req->gid));
 +#endif
@@ -1714,7 +1838,9 @@ index dd08ea541..4e32d0783 100644
      X(LUTIME, uv__fs_lutime(req));
 +#endif
      X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));
++#ifdef CONFIG_PSEUDOFS_SOFTLINKS
      X(LINK, link(req->path, req->new_path));
++#endif
      X(MKDIR, mkdir(req->path, req->mode));
 +#ifndef __NUTTX__
      X(MKDTEMP, uv__fs_mkdtemp(req));
@@ -1732,8 +1858,93 @@ index dd08ea541..4e32d0783 100644
      X(REALPATH, uv__fs_realpath(req));
      X(RENAME, rename(req->path, req->new_path));
      X(RMDIR, rmdir(req->path));
+     X(SENDFILE, uv__fs_sendfile(req));
+     X(STAT, uv__fs_stat(req->path, &req->statbuf));
+     X(STATFS, uv__fs_statfs(req));
++#ifdef CONFIG_PSEUDOFS_SOFTLINKS
+     X(SYMLINK, symlink(req->path, req->new_path));
++#endif
+     X(UNLINK, unlink(req->path));
++#ifndef __NUTTX__
+     X(UTIME, uv__fs_utime(req));
++#endif
+     X(WRITE, uv__fs_write_all(req));
+     default: abort();
+     }
+@@ -1621,7 +1656,7 @@ int uv_fs_access(uv_loop_t* loop,
+   POST;
+ }
+ 
+-
++#ifndef __NUTTX__
+ int uv_fs_chmod(uv_loop_t* loop,
+                 uv_fs_t* req,
+                 const char* path,
+@@ -1646,7 +1681,7 @@ int uv_fs_chown(uv_loop_t* loop,
+   req->gid = gid;
+   POST;
+ }
+-
++#endif
+ 
+ int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+   INIT(CLOSE);
+@@ -1654,7 +1689,7 @@ int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+   POST;
+ }
+ 
+-
++#ifndef __NUTTX__
+ int uv_fs_fchmod(uv_loop_t* loop,
+                  uv_fs_t* req,
+                  uv_file file,
+@@ -1693,7 +1728,7 @@ int uv_fs_lchown(uv_loop_t* loop,
+   req->gid = gid;
+   POST;
+ }
+-
++#endif
+ 
+ int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+   INIT(FDATASYNC);
+@@ -1957,7 +1992,7 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+   POST;
+ }
+ 
+-
++#ifdef CONFIG_PSEUDOFS_SOFTLINKS
+ int uv_fs_symlink(uv_loop_t* loop,
+                   uv_fs_t* req,
+                   const char* path,
+@@ -1969,7 +2004,7 @@ int uv_fs_symlink(uv_loop_t* loop,
+   req->flags = flags;
+   POST;
+ }
+-
++#endif
+ 
+ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+   INIT(UNLINK);
+@@ -1977,7 +2012,7 @@ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+   POST;
+ }
+ 
+-
++#ifndef __NUTTX__
+ int uv_fs_utime(uv_loop_t* loop,
+                 uv_fs_t* req,
+                 const char* path,
+@@ -1990,7 +2025,7 @@ int uv_fs_utime(uv_loop_t* loop,
+   req->mtime = mtime;
+   POST;
+ }
+-
++#endif
+ 
+ int uv_fs_write(uv_loop_t* loop,
+                 uv_fs_t* req,
 diff --git a/src/unix/internal.h b/src/unix/internal.h
-index 402ee877d..9f828a223 100644
+index 402ee877d..107565e4c 100644
 --- a/src/unix/internal.h
 +++ b/src/unix/internal.h
 @@ -1,3 +1,23 @@
@@ -1778,6 +1989,15 @@ index 402ee877d..9f828a223 100644
  #define uv__cloexec uv__cloexec_ioctl
  #define uv__nonblock uv__nonblock_ioctl
  #else
+@@ -201,7 +222,7 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd);
+ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+ void uv__io_close(uv_loop_t* loop, uv__io_t* w);
+-void uv__io_feed(uv_loop_t* loop, uv__io_t* w);
++void uv__stream_feed(uv_loop_t* loop, uv_stream_t *s);
+ int uv__io_active(const uv__io_t* w, unsigned int events);
+ int uv__io_check_fd(uv_loop_t* loop, int fd);
+ void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */
 @@ -247,6 +268,7 @@ int uv__signal_loop_fork(uv_loop_t* loop);
  
  /* platform specific */
@@ -1799,7 +2019,7 @@ index 402ee877d..9f828a223 100644
  
  UV_UNUSED(static char* uv__basename_r(const char* path)) {
 diff --git a/src/unix/loop.c b/src/unix/loop.c
-index e5b288956..de5d5aa80 100644
+index e5b288956..bb100390a 100644
 --- a/src/unix/loop.c
 +++ b/src/unix/loop.c
 @@ -1,3 +1,23 @@
@@ -1875,7 +2095,7 @@ index e5b288956..de5d5aa80 100644
    loop->watchers = NULL;
    loop->nwatchers = 0;
 +#endif
-+#if 0
++#ifdef CONFIG_LIBUV_STREAM
    QUEUE_INIT(&loop->pending_queue);
 +#endif
    QUEUE_INIT(&loop->watcher_queue);
@@ -2334,10 +2554,10 @@ index 000000000..4549e48eb
 +}
 diff --git a/src/unix/nuttx_stream.c b/src/unix/nuttx_stream.c
 new file mode 100644
-index 000000000..891a872dd
+index 000000000..0642d057c
 --- /dev/null
 +++ b/src/unix/nuttx_stream.c
-@@ -0,0 +1,1077 @@
+@@ -0,0 +1,1016 @@
 +/****************************************************************************
 + * libuv/src/unix/nuttx_stream.c
 + *
@@ -2395,7 +2615,10 @@ index 000000000..891a872dd
 +#include <unistd.h>
 +#include <limits.h> /* IOV_MAX */
 +
++#ifdef CONFIG_LIBUV_NET
 +static void uv__stream_connect(uv_stream_t*);
++#endif
++
 +static void uv__write(uv_stream_t* stream);
 +static void uv__read(uv_stream_t* stream);
 +static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
@@ -2412,11 +2635,13 @@ index 000000000..891a872dd
 +  stream->close_cb = NULL;
 +  stream->connection_cb = NULL;
 +  stream->connect_req = NULL;
++  /* shutdown() not supported by NuttX */
 +  stream->shutdown_req = NULL;
 +  stream->accepted_fd = -1;
-+  stream->queued_fds = NULL;
 +  QUEUE_INIT(&stream->write_queue);
 +  QUEUE_INIT(&stream->write_completed_queue);
++  /* FIXME move back to uv__io_t if needed */
++  QUEUE_INIT(&stream->pending_queue);
 +  stream->write_queue_size = 0;
 +
 +  uv__io_init(&stream->io_watcher, uv__stream_io, -1);
@@ -2490,49 +2715,13 @@ index 000000000..891a872dd
 +  assert(stream->write_queue_size == 0);
 +}
 +
-+#ifndef CONFIG_LIBUV_LOW_FOOTPRINT
-+/* Implements a best effort approach to mitigating accept() EMFILE errors.
-+ * We have a spare file descriptor stashed away that we close to get below
-+ * the EMFILE limit. Next, we accept all pending connections and close them
-+ * immediately to signal the clients that we're overloaded - and we are, but
-+ * we still keep on trucking.
-+ *
-+ * There is one caveat: it's not reliable in a multi-threaded environment.
-+ * The file descriptor limit is per process. Our party trick fails if another
-+ * thread opens a file or creates a socket in the time window between us
-+ * calling close() and accept().
-+ */
-+static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
-+  int err;
-+  int emfile_fd;
-+
-+  if (loop->emfile_fd == -1)
-+    return UV_EMFILE;
-+
-+  uv__close(loop->emfile_fd);
-+  loop->emfile_fd = -1;
-+
-+  do {
-+    err = uv__accept(accept_fd);
-+    if (err >= 0)
-+      uv__close(err);
-+  } while (err >= 0 || err == UV_EINTR);
-+
-+  emfile_fd = uv__open_cloexec("/", O_RDONLY);
-+  if (emfile_fd >= 0)
-+    loop->emfile_fd = emfile_fd;
-+
-+  return err;
-+}
-+#endif
-+
 +#if defined(UV_HAVE_KQUEUE)
 +# define UV_DEC_BACKLOG(w) w->rcount--;
 +#else
 +# define UV_DEC_BACKLOG(w) /* no-op */
 +#endif /* defined(UV_HAVE_KQUEUE) */
 +
-+
++#ifdef CONFIG_LIBUV_NET
 +void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
 +  uv_stream_t* stream;
 +  int err;
@@ -2542,8 +2731,6 @@ index 000000000..891a872dd
 +  assert(stream->accepted_fd == -1);
 +  assert(!(stream->flags & UV_HANDLE_CLOSING));
 +
-+  uv__io_start(stream->loop, &stream->io_watcher, POLLIN);
-+
 +  /* connection_cb can close the server socket while we're
 +   * in the loop so check it on each iteration.
 +   */
@@ -2555,17 +2742,9 @@ index 000000000..891a872dd
 +      if (err == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK))
 +        return;  /* Not an error. */
 +
-+      if (err == UV_ECONNABORTED)
++      if (err == UV__ERR(ENOTCONN))
 +        continue;  /* Ignore. Nothing we can do about that. */
 +
-+#ifndef CONFIG_LIBUV_LOW_FOOTPRINT
-+      if (err == UV_EMFILE || err == UV_ENFILE) {
-+        err = uv__emfile_trick(loop, uv__stream_fd(stream));
-+        if (err == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK))
-+          break;
-+      }
-+#endif
-+
 +      stream->connection_cb(stream, err);
 +      continue;
 +    }
@@ -2590,7 +2769,7 @@ index 000000000..891a872dd
 +#endif
 +  }
 +}
-+
++#endif
 +
 +#undef UV_DEC_BACKLOG
 +
@@ -2604,11 +2783,13 @@ index 000000000..891a872dd
 +    return UV_EAGAIN;
 +
 +  switch (client->type) {
-+#if 0
++#ifdef CONFIG_LIBUV_PIPE
 +    case UV_NAMED_PIPE:
 +#endif
 +#ifdef CONFIG_LIBUV_TCP
 +    case UV_TCP:
++#endif
++#if defined(CONFIG_LIBUV_PIPE) || defined(CONFIG_LIBUV_TCP)
 +      err = uv__stream_open(client,
 +                            server->accepted_fd,
 +                            UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
@@ -2636,36 +2817,14 @@ index 000000000..891a872dd
 +  client->flags |= UV_HANDLE_BOUND;
 +
 +done:
-+  /* Process queued fds */
-+  if (server->queued_fds != NULL) {
-+    uv__stream_queued_fds_t* queued_fds;
-+
-+    queued_fds = server->queued_fds;
 +
-+    /* Read first */
-+    server->accepted_fd = queued_fds->fds[0];
-+
-+    /* All read, free */
-+    assert(queued_fds->offset > 0);
-+    if (--queued_fds->offset == 0) {
-+      uv__free(queued_fds);
-+      server->queued_fds = NULL;
-+    } else {
-+      /* Shift rest */
-+      memmove(queued_fds->fds,
-+              queued_fds->fds + 1,
-+              queued_fds->offset * sizeof(*queued_fds->fds));
-+    }
-+  } else {
-+    server->accepted_fd = -1;
++  server->accepted_fd = -1;
++  uv__io_start(server->loop, &server->io_watcher, POLLIN);
 +
-+    if (err == 0)
-+      uv__io_start(server->loop, &server->io_watcher, POLLIN);
-+  }
 +  return err;
 +}
 +
-+
++#ifdef CONFIG_LIBUV_NET
 +int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
 +  int err;
 +
@@ -2675,11 +2834,14 @@ index 000000000..891a872dd
 +    err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
 +    break;
 +#endif
-+#if 0
++#ifndef __NUTTX__
++  /* TODO Revist uv_pipe_listen() port */
++#ifdef CONFIG_LIBUV_PIPE
 +  case UV_NAMED_PIPE:
 +    err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
 +    break;
 +#endif
++#endif /* !__NUTTX__ */
 +
 +  default:
 +    err = UV_EINVAL;
@@ -2690,7 +2852,7 @@ index 000000000..891a872dd
 +
 +  return err;
 +}
-+
++#endif
 +
 +static void uv__drain(uv_stream_t* stream) {
 +  uv_shutdown_t* req;
@@ -2711,8 +2873,13 @@ index 000000000..891a872dd
 +    uv__req_unregister(stream->loop, req);
 +
 +    err = 0;
++
++#ifndef __NUTTX__
++    /* shutdown not implemented in NuttX */
++
 +    if (shutdown(uv__stream_fd(stream), SHUT_WR))
 +      err = UV__ERR(errno);
++#endif
 +
 +    if (err == 0)
 +      stream->flags |= UV_HANDLE_SHUT;
@@ -2792,16 +2959,11 @@ index 000000000..891a872dd
 +    req->bufs = NULL;
 +  }
 +
-+#if 0
 +  /* Add it to the write_completed_queue where it will have its
 +   * callback called in the near future.
 +   */
 +  QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
-+  uv__io_feed(stream->loop, &stream->io_watcher);
-+#else
-+  QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
-+  stream->io_watcher.cb(stream->loop, &stream->io_watcher, POLLOUT);
-+#endif
++  uv__stream_feed(stream->loop, stream);
 +}
 +
 +#if 0
@@ -2829,59 +2991,61 @@ index 000000000..891a872dd
 +  ssize_t n;
 +  int err;
 +
-+start:
-+
 +  assert(uv__stream_fd(stream) >= 0);
 +
-+  if (QUEUE_EMPTY(&stream->write_queue))
-+    return;
++  while (!QUEUE_EMPTY(&stream->write_queue)) {
 +
-+  q = QUEUE_HEAD(&stream->write_queue);
-+  req = QUEUE_DATA(q, uv_write_t, queue);
-+  assert(req->handle == stream);
++    q = QUEUE_HEAD(&stream->write_queue);
++    req = QUEUE_DATA(q, uv_write_t, queue);
++    assert(req->handle == stream);
 +
-+  /*
-+   * Cast to iovec. We had to have our own uv_buf_t instead of iovec
-+   * because Windows's WSABUF is not an iovec.
-+   */
-+  assert(sizeof(uv_buf_t) == sizeof(struct iovec));
-+  iov = (struct iovec*) &(req->bufs[req->write_index]);
-+  iovcnt = req->nbufs - req->write_index;
++    /*
++     * Cast to iovec. We had to have our own uv_buf_t instead of iovec
++     * because Windows's WSABUF is not an iovec.
++     */
++    assert(sizeof(uv_buf_t) == sizeof(struct iovec));
++    iov = (struct iovec*) &(req->bufs[req->write_index]);
++    iovcnt = req->nbufs - req->write_index;
 +
-+  iovmax = uv__getiovmax();
++    iovmax = uv__getiovmax();
 +
-+  /* Limit iov count to avoid EINVALs from writev() */
-+  if (iovcnt > iovmax)
-+    iovcnt = iovmax;
++    /* Limit iov count to avoid EINVALs from writev() */
++    if (iovcnt > iovmax)
++      iovcnt = iovmax;
 +
-+  /*
-+   * Now do the actual writev. Note that we've been updating the pointers
-+   * inside the iov each time we write. So there is no need to offset it.
-+   */
++    /*
++     * Now do the actual writev. Note that we've been updating the pointers
++     * inside the iov each time we write. So there is no need to offset it.
++     */
 +
-+  do {
-+    n = uv__writev(uv__stream_fd(stream), iov, iovcnt);
-+  } while (n == -1 && errno == EINTR);
-+
-+  if (n == -1 &&
-+    errno != EAGAIN &&
-+    errno != EWOULDBLOCK &&
-+    errno != ENOBUFS) {
-+    err = UV__ERR(errno);
-+    goto error;
-+  }
++    do {
++      n = uv__writev(uv__stream_fd(stream), iov, iovcnt);
++    } while (n == -1 && errno == EINTR);
 +
-+  if (n >= 0 && uv__write_req_update(stream, req, n)) {
-+    uv__write_req_finish(req);
-+    return;  /* TODO(bnoordhuis) Start trying to write the next request. */
-+  }
++    if (n == -1 &&
++      errno != EAGAIN &&
++      errno != EWOULDBLOCK &&
++      errno != ENOBUFS) {
++      err = UV__ERR(errno);
++      goto error;
++    }
 +
-+  /* If this is a blocking stream, try again. */
-+  if (stream->flags & UV_HANDLE_BLOCKING_WRITES)
-+    goto start;
++    if (n >= 0 && uv__write_req_update(stream, req, n)) {
++      uv__write_req_finish(req);
++      continue;  /* TODO(bnoordhuis) Start trying to write the next request. */
++    }
 +
-+  /* We're not done. */
-+  uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
++    /* If this is a blocking stream, try again. */
++    if (stream->flags & UV_HANDLE_BLOCKING_WRITES)
++      continue;
++
++    /* Wait for next POLLOUT to continue writing.
++     * FIXME: what if user called uv_read_stop() before ?
++     * stream handle may be in invalid state.
++     */
++    uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
++    return;
++  }
 +
 +  return;
 +
@@ -2924,7 +3088,7 @@ index 000000000..891a872dd
 +  }
 +}
 +
-+
++#ifdef CONFIG_LIBUV_NET
 +uv_handle_type uv__handle_type(int fd) {
 +  struct sockaddr_storage ss;
 +  socklen_t sslen;
@@ -2966,7 +3130,7 @@ index 000000000..891a872dd
 +
 +  return UV_UNKNOWN_HANDLE;
 +}
-+
++#endif
 +
 +static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
 +  stream->flags |= UV_HANDLE_READ_EOF;
@@ -3084,24 +3248,30 @@ index 000000000..891a872dd
 +
 +  stream = container_of(w, uv_stream_t, io_watcher);
 +
-+  assert(stream->type == UV_TCP ||
-+         stream->type == UV_NAMED_PIPE ||
-+         stream->type == UV_TTY);
++  assert(
++#ifdef CONFIG_LIBUV_NET
++    stream->type == UV_TCP ||
++#endif
++    stream->type == UV_NAMED_PIPE
++    // || stream->type == UV_TTY
++    );
 +  assert(!(stream->flags & UV_HANDLE_CLOSING));
 +
++#ifdef CONFIG_LIBUV_NET
 +  if (stream->connect_req) {
 +    uv__stream_connect(stream);
 +    return;
 +  }
++#endif
 +
 +  assert(uv__stream_fd(stream) >= 0);
 +
 +  /* Ignore POLLHUP here. Even if it's set, there may still be data to read. */
-+  if (events & (POLLIN | POLLERR | POLLHUP))
++  if (events & (POLLIN | POLLERR | POLLHUP)) {
 +    uv__read(stream);
-+
-+  if (uv__stream_fd(stream) == -1)
-+    return;  /* read_cb closed stream. */
++    if (uv__stream_fd(stream) == -1)
++      return;  /* read_cb closed stream. */
++  }
 +
 +  /* Short-circuit iff POLLHUP is set, the user is still interested in read
 +   * events and uv__read() reported a partial read but not EOF. If the EOF
@@ -3115,12 +3285,12 @@ index 000000000..891a872dd
 +      !(stream->flags & UV_HANDLE_READ_EOF)) {
 +    uv_buf_t buf = { NULL, 0 };
 +    uv__stream_eof(stream, &buf);
++    if (uv__stream_fd(stream) == -1)
++      return;  /* read_cb closed stream. */
 +  }
 +
-+  if (uv__stream_fd(stream) == -1)
-+    return;  /* read_cb closed stream. */
-+
 +  if (events & (POLLOUT | POLLERR | POLLHUP)) {
++    /* Called by either real poll event or stream_feed */
 +    uv__write(stream);
 +    uv__write_callbacks(stream);
 +
@@ -3130,7 +3300,7 @@ index 000000000..891a872dd
 +  }
 +}
 +
-+
++#ifdef CONFIG_LIBUV_NET
 +/**
 + * We get called here from directly following a call to connect(2).
 + * In order to determine if we've errored out or succeeded must call
@@ -3174,7 +3344,7 @@ index 000000000..891a872dd
 +    uv__write_callbacks(stream);
 +  }
 +}
-+
++#endif
 +
 +int uv_write2(uv_write_t* req,
 +              uv_stream_t* stream,
@@ -3244,7 +3414,6 @@ index 000000000..891a872dd
 +     * sufficiently flushed in uv__write.
 +     */
 +    assert(!(stream->flags & UV_HANDLE_BLOCKING_WRITES));
-+    uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
 +  }
 +
 +  return 0;
@@ -3376,8 +3545,7 @@ index 000000000..891a872dd
 +
 +
 +void uv__stream_close(uv_stream_t* handle) {
-+  unsigned int i;
-+  uv__stream_queued_fds_t* queued_fds;
++  QUEUE_REMOVE(&handle->pending_queue);
 +
 +  uv__io_close(handle->loop, &handle->io_watcher);
 +  uv_read_stop(handle);
@@ -3396,15 +3564,6 @@ index 000000000..891a872dd
 +    handle->accepted_fd = -1;
 +  }
 +
-+  /* Close all queued fds */
-+  if (handle->queued_fds != NULL) {
-+    queued_fds = handle->queued_fds;
-+    for (i = 0; i < queued_fds->offset; i++)
-+      uv__close(queued_fds->fds[i]);
-+    uv__free(handle->queued_fds);
-+    handle->queued_fds = NULL;
-+  }
-+
 +  assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT));
 +}
 +
@@ -4304,6 +4463,90 @@ index 000000000..d56fdc287
 +void uv__timer_close(uv_timer_t* handle) {
 +  uv_timer_stop(handle);
 +}
+diff --git a/src/unix/pipe.c b/src/unix/pipe.c
+index 040d57817..7d6105083 100644
+--- a/src/unix/pipe.c
++++ b/src/unix/pipe.c
+@@ -39,7 +39,8 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
+   return 0;
+ }
+ 
+-
++// #ifdef CONFIG_LIBUV_NET
++#if 0
+ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
+   struct sockaddr_un saddr;
+   const char* pipe_fname;
+@@ -115,7 +116,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
+   uv__io_start(handle->loop, &handle->io_watcher, POLLIN);
+   return 0;
+ }
+-
++#endif
+ 
+ void uv__pipe_close(uv_pipe_t* handle) {
+   if (handle->pipe_fname) {
+@@ -169,7 +170,8 @@ int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
+   return uv__stream_open((uv_stream_t*)handle, fd, flags);
+ }
+ 
+-
++// #ifdef CONFIG_LIBUV_NET
++#if 0
+ void uv_pipe_connect(uv_connect_t* req,
+                     uv_pipe_t* handle,
+                     const char* name,
+@@ -198,6 +200,10 @@ void uv_pipe_connect(uv_connect_t* req,
+   }
+   while (r == -1 && errno == EINTR);
+ 
++  /* FIXME NuttX does not support NONBLOCKING connect,
++   * no need to check for EINPROGRESS.
++   */
++
+   if (r == -1 && errno != EINPROGRESS) {
+     err = UV__ERR(errno);
+ #if defined(__CYGWIN__) || defined(__MSYS__)
+@@ -230,10 +236,13 @@ out:
+   req->cb = cb;
+   QUEUE_INIT(&req->queue);
+ 
++#ifdef __NUTTX__
++  return 0;
++#else
+   /* Force callback to run on next tick in case of error. */
+   if (err)
+-    uv__io_feed(handle->loop, &handle->io_watcher);
+-
++    uv__stream_feed(handle->loop, (uv_stream_t*)handle);
++#endif
+ }
+ 
+ 
+@@ -280,7 +289,6 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
+   return 0;
+ }
+ 
+-
+ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
+   return uv__pipe_getsockpeername(handle, getsockname, buffer, size);
+ }
+@@ -289,8 +297,9 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
+   return uv__pipe_getsockpeername(handle, getpeername, buffer, size);
+ }
++#endif
+ 
+-
++#if 0
+ void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
+ }
+ 
+@@ -379,3 +388,4 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
+ 
+   return r != -1 ? 0 : UV__ERR(errno);
+ }
++#endif
 diff --git a/src/unix/poll.c b/src/unix/poll.c
 index 3d5022b22..d2f442132 100644
 --- a/src/unix/poll.c
@@ -5403,7 +5646,7 @@ index 6801564f9..15619088d 100644
  /* Wait for all `n` processes in `vec` to terminate. Time out after `timeout`
   * msec, or never if timeout == -1. Return 0 if all processes are terminated,
 diff --git a/test/task.h b/test/task.h
-index e95e3bde5..29a20afbc 100644
+index e95e3bde5..3b4556d86 100644
 --- a/test/task.h
 +++ b/test/task.h
 @@ -1,3 +1,23 @@
@@ -5466,7 +5709,7 @@ index e95e3bde5..29a20afbc 100644
    do {                                              \
 -    close_loop(uv_default_loop());                  \
 -    ASSERT(0 == uv_loop_close(uv_default_loop()));  \
-+    if (loop != NULL) {                             \
++    if ((uv_loop_t*)(loop) != NULL) {               \
 +      uv_context_t *tmp_ctx =                       \
 +        ((uv_loop_t*)(loop))->context;              \
 +      close_loop(loop);                             \
@@ -5625,10 +5868,20 @@ index 6f5351bf1..fb29059e2 100644
    return 0;
  }
 diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c
-index 3335c8810..a70e6304c 100644
+index 3335c8810..51d0b26b8 100644
 --- a/test/test-fs-copyfile.c
 +++ b/test/test-fs-copyfile.c
-@@ -33,8 +33,8 @@
+@@ -22,7 +22,8 @@
+ #include "uv.h"
+ #include "task.h"
+ 
+-#if defined(__unix__) || defined(__POSIX__) || \
++#if defined(__NUTTX__) || \
++    defined(__unix__) || defined(__POSIX__) || \
+     defined(__APPLE__) || defined(__sun) || \
+     defined(_AIX) || defined(__MVS__) || \
+     defined(__HAIKU__)
+@@ -33,8 +34,8 @@
  # define unlink _unlink
  #endif
  
@@ -5639,7 +5892,7 @@ index 3335c8810..a70e6304c 100644
  static int result_check_count;
  
  
-@@ -96,12 +96,19 @@ static void touch_file(const char* name, unsigned int size) {
+@@ -96,12 +97,19 @@ static void touch_file(const char* name, unsigned int size) {
  
  
  TEST_IMPL(fs_copyfile) {
@@ -5661,7 +5914,7 @@ index 3335c8810..a70e6304c 100644
  
    /* Fails with EINVAL if bad flags are passed. */
    r = uv_fs_copyfile(NULL, &req, src, dst, -1, NULL);
-@@ -121,10 +128,14 @@ TEST_IMPL(fs_copyfile) {
+@@ -121,10 +129,14 @@ TEST_IMPL(fs_copyfile) {
    uv_fs_req_cleanup(&req);
  
    /* Succeeds if src and dst files are identical. */
@@ -5676,7 +5929,7 @@ index 3335c8810..a70e6304c 100644
    unlink(src);
  
    /* Copies file synchronously. Creates new file. */
-@@ -193,10 +204,9 @@ TEST_IMPL(fs_copyfile) {
+@@ -193,10 +205,9 @@ TEST_IMPL(fs_copyfile) {
    if (r == 0)
      handle_result(&req);
  
@@ -5688,7 +5941,7 @@ index 3335c8810..a70e6304c 100644
    chmod(dst, S_IRUSR|S_IRGRP|S_IROTH); /* Sets file mode to 444 (read-only). */
    r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL);
    /* On IBMi PASE, qsecofr users can overwrite read-only files */
-@@ -207,6 +217,9 @@ TEST_IMPL(fs_copyfile) {
+@@ -207,6 +218,9 @@ TEST_IMPL(fs_copyfile) {
    uv_fs_req_cleanup(&req);
  #endif
  
@@ -6043,7 +6296,7 @@ index dfefb0f91..1cd9cd33f 100644
    return 0;
  }
 diff --git a/test/test-list.h b/test/test-list.h
-index 58e174d1d..ec5ac09c9 100644
+index 58e174d1d..edf5077cd 100644
 --- a/test/test-list.h
 +++ b/test/test-list.h
 @@ -21,17 +21,20 @@
@@ -6067,7 +6320,17 @@ index 58e174d1d..ec5ac09c9 100644
  TEST_DECLARE   (loop_configure)
  TEST_DECLARE   (default_loop_close)
  TEST_DECLARE   (barrier_1)
-@@ -102,9 +105,11 @@ TEST_DECLARE   (pipe_ping_pong)
+@@ -94,17 +97,21 @@ TEST_DECLARE   (ipc_send_zero)
+ TEST_DECLARE   (ipc_closed_handle)
+ #endif
+ TEST_DECLARE   (tcp_alloc_cb_fail)
++#endif
+ TEST_DECLARE   (tcp_ping_pong)
+ TEST_DECLARE   (tcp_ping_pong_vec)
++#if 0
+ TEST_DECLARE   (tcp6_ping_pong)
+ TEST_DECLARE   (tcp6_ping_pong_vec)
+ TEST_DECLARE   (pipe_ping_pong)
  TEST_DECLARE   (pipe_ping_pong_vec)
  TEST_DECLARE   (delayed_accept)
  TEST_DECLARE   (multiple_listen)
@@ -6079,7 +6342,7 @@ index 58e174d1d..ec5ac09c9 100644
  TEST_DECLARE   (tcp_writealot)
  TEST_DECLARE   (tcp_write_fail)
  TEST_DECLARE   (tcp_try_write)
-@@ -144,7 +149,9 @@ TEST_DECLARE   (tcp_oob)
+@@ -144,7 +151,9 @@ TEST_DECLARE   (tcp_oob)
  TEST_DECLARE   (tcp_flags)
  TEST_DECLARE   (tcp_write_to_half_open_connection)
  TEST_DECLARE   (tcp_unexpected_read)
@@ -6089,7 +6352,7 @@ index 58e174d1d..ec5ac09c9 100644
  TEST_DECLARE   (tcp_bind6_error_addrinuse)
  TEST_DECLARE   (tcp_bind6_error_addrnotavail)
  TEST_DECLARE   (tcp_bind6_error_fault)
-@@ -206,6 +213,7 @@ TEST_DECLARE   (callback_stack)
+@@ -206,6 +215,7 @@ TEST_DECLARE   (callback_stack)
  TEST_DECLARE   (env_vars)
  TEST_DECLARE   (error_message)
  TEST_DECLARE   (sys_error)
@@ -6097,7 +6360,7 @@ index 58e174d1d..ec5ac09c9 100644
  TEST_DECLARE   (timer)
  TEST_DECLARE   (timer_init)
  TEST_DECLARE   (timer_again)
-@@ -218,10 +226,14 @@ TEST_DECLARE   (timer_from_check)
+@@ -218,10 +228,14 @@ TEST_DECLARE   (timer_from_check)
  TEST_DECLARE   (timer_is_closing)
  TEST_DECLARE   (timer_null_callback)
  TEST_DECLARE   (timer_early_check)
@@ -6112,7 +6375,7 @@ index 58e174d1d..ec5ac09c9 100644
  TEST_DECLARE   (watcher_cross_stop)
  TEST_DECLARE   (ref)
  TEST_DECLARE   (idle_ref)
-@@ -253,9 +265,13 @@ TEST_DECLARE   (pipe_set_chmod)
+@@ -253,9 +267,13 @@ TEST_DECLARE   (pipe_set_chmod)
  TEST_DECLARE   (process_ref)
  TEST_DECLARE   (process_priority)
  TEST_DECLARE   (has_ref)
@@ -6126,7 +6389,7 @@ index 58e174d1d..ec5ac09c9 100644
  TEST_DECLARE   (async_null_cb)
  TEST_DECLARE   (eintr_handling)
  TEST_DECLARE   (get_currentexe)
-@@ -311,12 +327,14 @@ TEST_DECLARE   (spawn_reads_child_path)
+@@ -311,12 +329,14 @@ TEST_DECLARE   (spawn_reads_child_path)
  TEST_DECLARE   (spawn_inherit_streams)
  TEST_DECLARE   (spawn_quoted_path)
  TEST_DECLARE   (spawn_tcp_server)
@@ -6141,7 +6404,7 @@ index 58e174d1d..ec5ac09c9 100644
  TEST_DECLARE   (kill)
  TEST_DECLARE   (kill_invalid_signum)
  TEST_DECLARE   (fs_file_noent)
-@@ -333,7 +351,9 @@ TEST_DECLARE   (fs_mkstemp)
+@@ -333,7 +353,9 @@ TEST_DECLARE   (fs_mkstemp)
  TEST_DECLARE   (fs_fstat)
  TEST_DECLARE   (fs_access)
  TEST_DECLARE   (fs_chmod)
@@ -6151,7 +6414,7 @@ index 58e174d1d..ec5ac09c9 100644
  TEST_DECLARE   (fs_unlink_readonly)
  #ifdef _WIN32
  TEST_DECLARE   (fs_unlink_archive_readonly)
-@@ -413,8 +433,10 @@ TEST_DECLARE   (fs_invalid_mkdir_name)
+@@ -413,8 +435,10 @@ TEST_DECLARE   (fs_invalid_mkdir_name)
  #endif
  TEST_DECLARE   (fs_get_system_error)
  TEST_DECLARE   (strscpy)
@@ -6162,7 +6425,7 @@ index 58e174d1d..ec5ac09c9 100644
  TEST_DECLARE   (threadpool_multiple_event_loops)
  TEST_DECLARE   (threadpool_cancel_getaddrinfo)
  TEST_DECLARE   (threadpool_cancel_getnameinfo)
-@@ -438,7 +460,9 @@ TEST_DECLARE   (poll_oob)
+@@ -438,7 +462,9 @@ TEST_DECLARE   (poll_oob)
  #endif
  TEST_DECLARE   (poll_duplex)
  TEST_DECLARE   (poll_unidirectional)
@@ -6172,7 +6435,7 @@ index 58e174d1d..ec5ac09c9 100644
  TEST_DECLARE   (poll_bad_fdtype)
  #ifdef __linux__
  TEST_DECLARE   (poll_nested_epoll)
-@@ -447,7 +471,9 @@ TEST_DECLARE   (poll_nested_epoll)
+@@ -447,7 +473,9 @@ TEST_DECLARE   (poll_nested_epoll)
  TEST_DECLARE   (poll_nested_kqueue)
  #endif
  
@@ -6182,7 +6445,7 @@ index 58e174d1d..ec5ac09c9 100644
  TEST_DECLARE   (ip6_addr_link_local)
  
  TEST_DECLARE   (poll_close_doesnt_corrupt_stack)
-@@ -482,16 +508,18 @@ TEST_DECLARE   (closed_fd_events)
+@@ -482,16 +510,20 @@ TEST_DECLARE   (closed_fd_events)
  TEST_DECLARE   (osx_select)
  TEST_DECLARE   (osx_select_many_fds)
  #endif
@@ -6196,14 +6459,16 @@ index 58e174d1d..ec5ac09c9 100644
  TEST_DECLARE   (queue_foreach_delete)
 -
 +#endif
++#ifdef CONFIG_DEV_URANDOM
  TEST_DECLARE   (random_async)
  TEST_DECLARE   (random_sync)
 -
++#endif
 +#if 0
  TEST_DECLARE   (handle_type_name)
  TEST_DECLARE   (req_type_name)
  TEST_DECLARE   (getters_setters)
-@@ -517,22 +545,27 @@ TEST_DECLARE  (fork_threadpool_queue_work_simple)
+@@ -517,22 +549,27 @@ TEST_DECLARE  (fork_threadpool_queue_work_simple)
  TEST_DECLARE  (idna_toascii)
  TEST_DECLARE  (utf8_decode1)
  TEST_DECLARE  (uname)
@@ -6232,7 +6497,23 @@ index 58e174d1d..ec5ac09c9 100644
    TEST_ENTRY  (loop_configure)
    TEST_ENTRY  (default_loop_close)
    TEST_ENTRY  (barrier_1)
-@@ -628,11 +661,11 @@ TASK_LIST_START
+@@ -607,13 +644,13 @@ TASK_LIST_START
+ #endif
+ 
+   TEST_ENTRY  (tcp_alloc_cb_fail)
+-
++#endif
+   TEST_ENTRY  (tcp_ping_pong)
+   TEST_HELPER (tcp_ping_pong, tcp4_echo_server)
+ 
+   TEST_ENTRY  (tcp_ping_pong_vec)
+   TEST_HELPER (tcp_ping_pong_vec, tcp4_echo_server)
+-
++#if 0
+   TEST_ENTRY  (tcp6_ping_pong)
+   TEST_HELPER (tcp6_ping_pong, tcp6_echo_server)
+ 
+@@ -628,11 +665,11 @@ TASK_LIST_START
  
    TEST_ENTRY  (delayed_accept)
    TEST_ENTRY  (multiple_listen)
@@ -6246,7 +6527,7 @@ index 58e174d1d..ec5ac09c9 100644
  #ifdef __MVS__
    TEST_ENTRY_CUSTOM (tcp_writealot, 0, 0, 20000)
  #else
-@@ -689,10 +722,10 @@ TASK_LIST_START
+@@ -689,10 +726,10 @@ TASK_LIST_START
    TEST_ENTRY  (tcp_flags)
    TEST_ENTRY  (tcp_write_to_half_open_connection)
    TEST_ENTRY  (tcp_unexpected_read)
@@ -6259,7 +6540,7 @@ index 58e174d1d..ec5ac09c9 100644
    TEST_ENTRY  (tcp_bind6_error_addrinuse)
    TEST_ENTRY  (tcp_bind6_error_addrnotavail)
    TEST_ENTRY  (tcp_bind6_error_fault)
-@@ -764,7 +797,7 @@ TASK_LIST_START
+@@ -764,7 +801,7 @@ TASK_LIST_START
  
    TEST_ENTRY  (error_message)
    TEST_ENTRY  (sys_error)
@@ -6268,7 +6549,7 @@ index 58e174d1d..ec5ac09c9 100644
    TEST_ENTRY  (timer)
    TEST_ENTRY  (timer_init)
    TEST_ENTRY  (timer_again)
-@@ -779,7 +812,7 @@ TASK_LIST_START
+@@ -779,7 +816,7 @@ TASK_LIST_START
    TEST_ENTRY  (timer_early_check)
  
    TEST_ENTRY  (idle_starvation)
@@ -6277,7 +6558,7 @@ index 58e174d1d..ec5ac09c9 100644
    TEST_ENTRY  (ref)
    TEST_ENTRY  (idle_ref)
    TEST_ENTRY  (fs_poll_ref)
-@@ -812,15 +845,18 @@ TASK_LIST_START
+@@ -812,15 +849,18 @@ TASK_LIST_START
    TEST_ENTRY  (has_ref)
  
    TEST_ENTRY  (loop_handles)
@@ -6299,7 +6580,7 @@ index 58e174d1d..ec5ac09c9 100644
    TEST_ENTRY  (async_null_cb)
    TEST_ENTRY  (eintr_handling)
  
-@@ -866,7 +902,9 @@ TASK_LIST_START
+@@ -866,7 +906,9 @@ TASK_LIST_START
  
    TEST_ENTRY  (poll_duplex)
    TEST_ENTRY  (poll_unidirectional)
@@ -6309,7 +6590,7 @@ index 58e174d1d..ec5ac09c9 100644
    TEST_ENTRY  (poll_bad_fdtype)
  #if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \
      !defined(__sun)
-@@ -909,12 +947,14 @@ TASK_LIST_START
+@@ -909,12 +951,14 @@ TASK_LIST_START
    TEST_ENTRY  (spawn_inherit_streams)
    TEST_ENTRY  (spawn_quoted_path)
    TEST_ENTRY  (spawn_tcp_server)
@@ -6324,7 +6605,7 @@ index 58e174d1d..ec5ac09c9 100644
    TEST_ENTRY  (kill)
    TEST_ENTRY  (kill_invalid_signum)
  
-@@ -966,7 +1006,9 @@ TASK_LIST_START
+@@ -966,7 +1010,9 @@ TASK_LIST_START
    TEST_ENTRY  (fs_fstat)
    TEST_ENTRY  (fs_access)
    TEST_ENTRY  (fs_chmod)
@@ -6334,7 +6615,7 @@ index 58e174d1d..ec5ac09c9 100644
    TEST_ENTRY  (fs_unlink_readonly)
  #ifdef _WIN32
    TEST_ENTRY  (fs_unlink_archive_readonly)
-@@ -1045,8 +1087,10 @@ TASK_LIST_START
+@@ -1045,8 +1091,10 @@ TASK_LIST_START
    TEST_ENTRY  (get_osfhandle_valid_handle)
    TEST_ENTRY  (open_osfhandle_valid_handle)
    TEST_ENTRY  (strscpy)
@@ -6345,7 +6626,7 @@ index 58e174d1d..ec5ac09c9 100644
    TEST_ENTRY_CUSTOM (threadpool_multiple_event_loops, 0, 0, 60000)
    TEST_ENTRY  (threadpool_cancel_getaddrinfo)
    TEST_ENTRY  (threadpool_cancel_getnameinfo)
-@@ -1064,14 +1108,16 @@ TASK_LIST_START
+@@ -1064,14 +1112,18 @@ TASK_LIST_START
    TEST_ENTRY  (thread_create)
    TEST_ENTRY  (thread_equal)
    TEST_ENTRY  (dlerror)
@@ -6357,14 +6638,16 @@ index 58e174d1d..ec5ac09c9 100644
    TEST_ENTRY  (queue_foreach_delete)
 -
 +#endif
++#ifdef CONFIG_DEV_URANDOM
    TEST_ENTRY  (random_async)
    TEST_ENTRY  (random_sync)
 -
++#endif
 +#if 0
    TEST_ENTRY  (handle_type_name)
    TEST_ENTRY  (req_type_name)
    TEST_ENTRY  (getters_setters)
-@@ -1105,4 +1151,5 @@ TASK_LIST_START
+@@ -1105,4 +1157,5 @@ TASK_LIST_START
    TEST_ENTRY  (fail_always)
    TEST_ENTRY  (pass_always)
  #endif
@@ -6543,8 +6826,204 @@ index a2db42cce..581f31b9e 100644
 +  MAKE_VALGRIND_HAPPY(loop);
    return 0;
  }
+diff --git a/test/test-ping-pong.c b/test/test-ping-pong.c
+index c86a3f4a6..50e47d6a3 100644
+--- a/test/test-ping-pong.c
++++ b/test/test-ping-pong.c
+@@ -49,7 +49,7 @@ typedef struct {
+     uv_pipe_t pipe;
+   } stream;
+   uv_connect_t connect_req;
+-  char read_buffer[BUFSIZE];
++  // char read_buffer[BUFSIZE];
+ } pinger_t;
+ 
+ 
+@@ -102,7 +102,34 @@ static void pinger_write_ping(pinger_t* pinger) {
+     FATAL("uv_write failed");
+   }
+ 
+-  puts("PING");
++  // puts("PING");
++}
++
++
++static void pinger_after_stop_write(uv_write_t *req, int status) {
++  ASSERT(status == 0);
++  pinger_t* pinger = (pinger_t*)req->data;
++  uv_close((uv_handle_t*)(&pinger->stream.tcp), pinger_on_close);
++  free(req);
++}
++
++
++static void pinger_write_stop(pinger_t* pinger) {
++  uv_write_t *req;
++  uv_buf_t bufs;
++
++  bufs.base = "QQS";
++  bufs.len = 3;
++
++  req = malloc(sizeof(*req));
++  req->data = pinger;
++  if (uv_write(req,
++               (uv_stream_t*) &pinger->stream.tcp,
++               &bufs,
++               1,
++               pinger_after_stop_write)) {
++    FATAL("uv_write failed");
++  }
+ }
+ 
+ 
+@@ -133,13 +160,13 @@ static void pinger_read_cb(uv_stream_t* stream,
+     if (pinger->state != 0)
+       continue;
+ 
+-    printf("PONG %d\n", pinger->pongs);
++    // printf("PONG %d\n", pinger->pongs);
+     pinger->pongs++;
+ 
+     if (pinger->pongs < NUM_PINGS) {
+       pinger_write_ping(pinger);
+     } else {
+-      uv_close((uv_handle_t*)(&pinger->stream.tcp), pinger_on_close);
++      pinger_write_stop(pinger);
+       break;
+     }
+   }
+@@ -164,7 +191,7 @@ static void pinger_on_connect(uv_connect_t *req, int status) {
+   uv_read_start((uv_stream_t*)(req->handle), alloc_cb, pinger_read_cb);
+ }
+ 
+-
++#if 0
+ /* same ping-pong test, but using IPv6 connection */
+ static void tcp_pinger_v6_new(int vectored_writes) {
+   int r;
+@@ -195,13 +222,16 @@ static void tcp_pinger_v6_new(int vectored_writes) {
+   /* Synchronous connect callbacks are not allowed. */
+   ASSERT(pinger_on_connect_count == 0);
+ }
++#endif
+ 
+-
+-static void tcp_pinger_new(int vectored_writes) {
++static void tcp_pinger_new(uv_context_t *ctx, int vectored_writes) {
+   int r;
+   struct sockaddr_in server_addr;
+   pinger_t *pinger;
+ 
++  pinger_on_connect_count = 0;
++  completed_pingers = 0;
++
+   ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
+   pinger = malloc(sizeof(*pinger));
+   ASSERT(pinger != NULL);
+@@ -210,7 +240,7 @@ static void tcp_pinger_new(int vectored_writes) {
+   pinger->pongs = 0;
+ 
+   /* Try to connect to the server and do NUM_PINGS ping-pongs. */
+-  r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp);
++  r = uv_tcp_init(uv_default_loop(ctx), &pinger->stream.tcp);
+   pinger->stream.tcp.data = pinger;
+   ASSERT(!r);
+ 
+@@ -226,11 +256,14 @@ static void tcp_pinger_new(int vectored_writes) {
+   ASSERT(pinger_on_connect_count == 0);
+ }
+ 
+-
+-static void pipe_pinger_new(int vectored_writes) {
++#if 0
++static void pipe_pinger_new(uv_context_t *ctx, int vectored_writes) {
+   int r;
+   pinger_t *pinger;
+ 
++  pinger_on_connect_count = 0;
++  completed_pingers = 0;
++
+   pinger = (pinger_t*)malloc(sizeof(*pinger));
+   ASSERT(pinger != NULL);
+   pinger->vectored_writes = vectored_writes;
+@@ -238,7 +271,7 @@ static void pipe_pinger_new(int vectored_writes) {
+   pinger->pongs = 0;
+ 
+   /* Try to connect to the server and do NUM_PINGS ping-pongs. */
+-  r = uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0);
++  r = uv_pipe_init(uv_default_loop(ctx), &pinger->stream.pipe, 0);
+   pinger->stream.pipe.data = pinger;
+   ASSERT(!r);
+ 
+@@ -250,29 +283,34 @@ static void pipe_pinger_new(int vectored_writes) {
+   /* Synchronous connect callbacks are not allowed. */
+   ASSERT(pinger_on_connect_count == 0);
+ }
++#endif
+ 
+-
+-static int run_ping_pong_test(void) {
+-  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
++static int run_ping_pong_test(uv_context_t *ctx) {
++  uv_loop_t *loop = uv_default_loop(ctx);
++  uv_run(loop, UV_RUN_DEFAULT);
+   ASSERT(completed_pingers == 1);
+ 
+-  MAKE_VALGRIND_HAPPY();
++  MAKE_VALGRIND_HAPPY(loop);
+   return 0;
+ }
+ 
+ 
+ TEST_IMPL(tcp_ping_pong) {
+-  tcp_pinger_new(0);
+-  return run_ping_pong_test();
++  uv_context_t context;
++  uv_library_init(&context);
++  tcp_pinger_new(&context, 0);
++  return run_ping_pong_test(&context);
+ }
+ 
+ 
+ TEST_IMPL(tcp_ping_pong_vec) {
+-  tcp_pinger_new(1);
+-  return run_ping_pong_test();
++  uv_context_t context;
++  uv_library_init(&context);
++  tcp_pinger_new(&context, 1);
++  return run_ping_pong_test(&context);
+ }
+ 
+-
++#if 0
+ TEST_IMPL(tcp6_ping_pong) {
+   if (!can_ipv6())
+     RETURN_SKIP("IPv6 not supported");
+@@ -288,14 +326,18 @@ TEST_IMPL(tcp6_ping_pong_vec) {
+   return run_ping_pong_test();
+ }
+ 
+-
+ TEST_IMPL(pipe_ping_pong) {
+-  pipe_pinger_new(0);
+-  return run_ping_pong_test();
++  uv_context_t context;
++  uv_library_init(&context);
++  pipe_pinger_new(&context, 0);
++  return run_ping_pong_test(&context);
+ }
+ 
+ 
+ TEST_IMPL(pipe_ping_pong_vec) {
+-  pipe_pinger_new(1);
+-  return run_ping_pong_test();
++  uv_context_t context;
++  uv_library_init(&context);
++  pipe_pinger_new(&context, 1);
++  return run_ping_pong_test(&context);
+ }
++#endif
 diff --git a/test/test-poll-close.c b/test/test-poll-close.c
-index 2eccddf5b..050316428 100644
+index 2eccddf5b..c5b059d03 100644
 --- a/test/test-poll-close.c
 +++ b/test/test-poll-close.c
 @@ -30,7 +30,7 @@
@@ -6574,7 +7053,7 @@ index 2eccddf5b..050316428 100644
  #ifdef _WIN32
    {
      struct WSAData wsa_data;
-@@ -56,7 +63,7 @@ TEST_IMPL(poll_close) {
+@@ -56,18 +63,19 @@ TEST_IMPL(poll_close) {
  
    for (i = 0; i < NUM_SOCKETS; i++) {
      sockets[i] = socket(AF_INET, SOCK_STREAM, 0);
@@ -6583,8 +7062,9 @@ index 2eccddf5b..050316428 100644
      uv_poll_start(&poll_handles[i], UV_READABLE | UV_WRITABLE, NULL);
    }
  
-@@ -64,10 +71,10 @@ TEST_IMPL(poll_close) {
+   for (i = 0; i < NUM_SOCKETS; i++) {
      uv_close((uv_handle_t*) &poll_handles[i], close_cb);
++    close(sockets[i]);
    }
  
 -  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
diff --git a/system/libuv/libuv/Kconfig b/system/libuv/libuv/Kconfig
index 41c0102..22cb439 100644
--- a/system/libuv/libuv/Kconfig
+++ b/system/libuv/libuv/Kconfig
@@ -54,6 +54,13 @@ config LIBUV_STREAM_READ_SIZE
 	---help---
 		Defines the size of buffer used for stream reads.
 
+config LIBUV_PIPE
+	bool "libuv pipe support"
+	default n
+	depends on LIBUV_STREAM
+	---help---
+		Enable libuv pipe support.
+
 config LIBUV_FS
 	bool "libuv FS support"
 	default n
diff --git a/system/libuv/libuv/Makefile b/system/libuv/libuv/Makefile
index 558ec61..4556fdd 100644
--- a/system/libuv/libuv/Makefile
+++ b/system/libuv/libuv/Makefile
@@ -86,6 +86,10 @@ ifeq ($(CONFIG_LIBUV_ASYNC),y)
 CSRCS += $(LIBUV_UNPACKDIR)/src/unix/async.c
 endif
 
+ifeq ($(CONFIG_LIBUV_PIPE),y)
+CSRCS += $(LIBUV_UNPACKDIR)/src/unix/pipe.c
+endif
+
 ifeq ($(CONFIG_LIBUV_FS),y)
 CSRCS += $(LIBUV_UNPACKDIR)/src/unix/fs.c
 endif
diff --git a/system/libuv/tests/Makefile b/system/libuv/tests/Makefile
index 26728c5..d567f6b 100644
--- a/system/libuv/tests/Makefile
+++ b/system/libuv/tests/Makefile
@@ -49,11 +49,13 @@ CSRCS += $(LIBUV_UNPACKDIR)/test/test-poll-close.c
 CSRCS += $(LIBUV_UNPACKDIR)/test/test-loop-close.c
 CSRCS += $(LIBUV_UNPACKDIR)/test/test-loop-stop.c
 CSRCS += $(LIBUV_UNPACKDIR)/test/test-tcp-read-stop.c
+CSRCS += $(LIBUV_UNPACKDIR)/test/test-ping-pong.c
 CSRCS += $(LIBUV_UNPACKDIR)/test/test-tcp-write-after-connect.c
 CSRCS += $(LIBUV_UNPACKDIR)/test/test-fs-copyfile.c
 CSRCS += $(LIBUV_UNPACKDIR)/test/test-fs-poll.c
+ifeq ($(CONFIG_DEV_URANDOM),y)
 CSRCS += $(LIBUV_UNPACKDIR)/test/test-random.c
-
+endif
 # Test helpers
 
 CSRCS += $(LIBUV_UNPACKDIR)/test/echo-server.c