You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2019/12/31 15:17:01 UTC

[incubator-nuttx] branch dev updated: Net cleanup (#17)

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

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


The following commit(s) were added to refs/heads/dev by this push:
     new c8739e9  Net cleanup (#17)
c8739e9 is described below

commit c8739e926bd29c7dfbf53c0bd8ac87476427e0d0
Author: Xiang Xiao <xi...@xiaomi.com>
AuthorDate: Tue Dec 31 09:16:52 2019 -0600

    Net cleanup (#17)
    
    * Fix the semaphore usage issue found in tcp/udp
    
    1. The count semaphore need disable priority inheritance
    2. Loop again if net_lockedwait return -EINTR
    3. Call nxsem_trywait to avoid the race condition
    4. Call nxsem_post instead of sem_post
    
    * Put the work notifier into free list to avoid the heap fragment in the long run.  Since the allocation strategy is encapsulated internally, we can even refine the implementation later.
    
    * Network stack shouldn't allocate memory in the poll implementation to avoid the heap fragment in the long run, other modification include:
    
    1. Select MM_IOB automatically since ICMP[v6] socket can't work without the read ahead buffer
    2. Remove the net lock since xxx_callback_free already do the same thing
    3. TCP/UDP poll should work even the read ahead buffer isn't enabled at all
    
    * Add NET_ prefix for UDP_NOTIFIER and TCP_NOTIFIER option to align with other UDP/TCP option convention
    
    * Remove the unused _SF_[IDLE|ACCEPT|SEND|RECV|MASK] flags since there are code to set/clear these flags, but nobody check them.
---
 .../lpc4088-devkit/configs/nsh/defconfig           |  2 +-
 include/nuttx/wqueue.h                             | 30 ---------
 net/bluetooth/bluetooth_recvfrom.c                 |  7 --
 net/bluetooth/bluetooth_sendto.c                   |  8 ---
 net/icmp/Kconfig                                   |  6 +-
 net/icmp/Make.defs                                 |  5 +-
 net/icmp/icmp.h                                    | 25 ++++++--
 net/icmp/icmp_netpoll.c                            | 48 ++++----------
 net/icmp/icmp_sockif.c                             |  4 --
 net/icmpv6/Kconfig                                 |  6 +-
 net/icmpv6/Make.defs                               |  5 +-
 net/icmpv6/icmpv6.h                                | 29 ++++++---
 net/icmpv6/icmpv6_netpoll.c                        | 48 +++++---------
 net/icmpv6/icmpv6_sockif.c                         |  4 --
 net/ieee802154/ieee802154_recvfrom.c               |  7 --
 net/ieee802154/ieee802154_sendto.c                 |  8 ---
 net/inet/inet_sockif.c                             | 28 ++++----
 net/local/local.h                                  |  7 +-
 net/local/local_netpoll.c                          | 32 +++++----
 net/pkt/pkt_recvfrom.c                             |  8 ---
 net/pkt/pkt_send.c                                 |  8 ---
 net/sixlowpan/sixlowpan_tcpsend.c                  |  9 ---
 net/sixlowpan/sixlowpan_udpsend.c                  |  7 --
 net/socket/Kconfig                                 |  4 +-
 net/socket/recvfrom.c                              | 13 +---
 net/socket/socket.h                                | 11 ----
 net/tcp/Kconfig                                    |  6 +-
 net/tcp/Make.defs                                  |  7 +-
 net/tcp/tcp.h                                      | 56 +++++++++-------
 net/tcp/tcp_accept.c                               |  8 ---
 net/tcp/tcp_callback.c                             |  6 +-
 net/tcp/tcp_netpoll.c                              | 75 ++++++----------------
 net/tcp/tcp_notifier.c                             |  4 +-
 net/tcp/tcp_send_buffered.c                        | 10 +--
 net/tcp/tcp_send_unbuffered.c                      |  8 ---
 net/tcp/tcp_sendfile.c                             |  8 ---
 net/tcp/tcp_txdrain.c                              | 27 ++------
 net/tcp/tcp_wrbuffer.c                             |  9 +--
 net/udp/Kconfig                                    | 10 ++-
 net/udp/Make.defs                                  |  7 +-
 net/udp/udp.h                                      | 53 ++++++++-------
 net/udp/udp_callback.c                             |  2 +-
 net/udp/udp_netpoll.c                              | 72 ++++++---------------
 net/udp/udp_notifier.c                             |  4 +-
 net/udp/udp_psock_sendto_buffered.c                | 10 +--
 net/udp/udp_psock_sendto_unbuffered.c              |  8 ---
 net/udp/udp_txdrain.c                              | 27 ++------
 net/udp/udp_wrbuffer.c                             |  3 +-
 net/usrsock/Kconfig                                |  4 ++
 net/usrsock/usrsock.h                              | 13 ++++
 net/usrsock/usrsock_poll.c                         | 34 ++++------
 sched/wqueue/kwork_notifier.c                      | 75 ++++++++++++++++++++--
 52 files changed, 363 insertions(+), 552 deletions(-)

diff --git a/boards/arm/lpc17xx_40xx/lpc4088-devkit/configs/nsh/defconfig b/boards/arm/lpc17xx_40xx/lpc4088-devkit/configs/nsh/defconfig
index f57a24c..01b2c0d 100644
--- a/boards/arm/lpc17xx_40xx/lpc4088-devkit/configs/nsh/defconfig
+++ b/boards/arm/lpc17xx_40xx/lpc4088-devkit/configs/nsh/defconfig
@@ -57,6 +57,7 @@ CONFIG_NET_BROADCAST=y
 CONFIG_NET_ICMP=y
 CONFIG_NET_SOCKOPTS=y
 CONFIG_NET_TCP=y
+CONFIG_NET_TCP_NOTIFIER=y
 CONFIG_NET_TCP_WRITE_BUFFERS=y
 CONFIG_NET_UDP=y
 CONFIG_NFILE_DESCRIPTORS=8
@@ -90,7 +91,6 @@ CONFIG_SYMTAB_ORDEREDBYNAME=y
 CONFIG_SYSTEM_MDIO=y
 CONFIG_SYSTEM_NSH=y
 CONFIG_TASK_NAME_SIZE=0
-CONFIG_TCP_NOTIFIER=y
 CONFIG_UART0_SERIAL_CONSOLE=y
 CONFIG_USERMAIN_STACKSIZE=4096
 CONFIG_USER_ENTRYPOINT="nsh_main"
diff --git a/include/nuttx/wqueue.h b/include/nuttx/wqueue.h
index 31867ad..42d73f7 100644
--- a/include/nuttx/wqueue.h
+++ b/include/nuttx/wqueue.h
@@ -309,36 +309,6 @@ struct work_notifier_s
   worker_t worker;     /* The worker function to schedule */
 };
 
-/* This structure describes one notification list entry.  It is cast-
- * compatible with struct work_notifier_s.  This structure is an allocated
- * container for the user notification data.   It is allocated because it
- * must persist until the work is executed and must be freed using
- * kmm_free() by the work.
- *
- * With the work notification is scheduled, the work function will receive
- * the allocated instance of struct work_notifier_entry_s as its input
- * argument.  When it completes the notification operation, the work function
- * is responsible for freeing that instance.
- */
-
-struct work_notifier_entry_s
-{
-  /* This must appear at the beginning of the structure.  A reference to
-   * the struct work_notifier_entry_s instance must be cast-compatible with
-   * struct dq_entry_s.
-   */
-
-  struct work_s work;           /* Used for scheduling the work */
-
-  /* User notification information */
-
-  struct work_notifier_s info;  /* The notification info */
-
-  /* Additional payload needed to manage the notification */
-
-  int16_t key;                  /* Unique ID for the notification */
-};
-
 /****************************************************************************
  * Public Data
  ****************************************************************************/
diff --git a/net/bluetooth/bluetooth_recvfrom.c b/net/bluetooth/bluetooth_recvfrom.c
index 9de4764..cb781e3 100644
--- a/net/bluetooth/bluetooth_recvfrom.c
+++ b/net/bluetooth/bluetooth_recvfrom.c
@@ -387,10 +387,6 @@ ssize_t bluetooth_recvfrom(FAR struct socket *psock, FAR void *buf,
   (void)nxsem_init(&state.ir_sem, 0, 0); /* Doesn't really fail */
   (void)nxsem_setprotocol(&state.ir_sem, SEM_PRIO_NONE);
 
-  /* Set the socket state to receiving */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_RECV);
-
   /* Set up the callback in the connection */
 
   state.ir_cb = bluetooth_callback_alloc(&radio->r_dev, conn);
@@ -418,9 +414,6 @@ ssize_t bluetooth_recvfrom(FAR struct socket *psock, FAR void *buf,
       ret = -EBUSY;
     }
 
-  /* Set the socket state to idle */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
   nxsem_destroy(&state.ir_sem);
 
 errout_with_lock:
diff --git a/net/bluetooth/bluetooth_sendto.c b/net/bluetooth/bluetooth_sendto.c
index bdfa90a..03ec6a2 100644
--- a/net/bluetooth/bluetooth_sendto.c
+++ b/net/bluetooth/bluetooth_sendto.c
@@ -283,10 +283,6 @@ ssize_t psock_bluetooth_sendto(FAR struct socket *psock, FAR const void *buf,
       return -ENODEV;
     }
 
-  /* Set the socket state to sending */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
-
   /* Perform the send operation */
 
   /* Initialize the state structure. This is done with the network locked
@@ -345,10 +341,6 @@ ssize_t psock_bluetooth_sendto(FAR struct socket *psock, FAR const void *buf,
   nxsem_destroy(&state.is_sem);
   net_unlock();
 
-  /* Set the socket state to idle */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
-
   /* Check for a errors, Errors are signaled by negative errno values
    * for the send length
    */
diff --git a/net/icmp/Kconfig b/net/icmp/Kconfig
index f691a56..04d7b3f 100644
--- a/net/icmp/Kconfig
+++ b/net/icmp/Kconfig
@@ -25,6 +25,7 @@ if NET_ICMP && !NET_ICMP_NO_STACK
 config NET_ICMP_SOCKET
 	bool "IPPROTO_ICMP socket support"
 	default n
+	select MM_IOB
 	---help---
 		Enable support for IPPROTO_ICMP sockets.  These sockets are needed
 		for application level support for sending ECHO (ping) requests and
@@ -35,7 +36,10 @@ if NET_ICMP_SOCKET
 config NET_ICMP_NCONNS
 	int "Max ICMP packet sockets"
 	default 4
-	depends on MM_IOB
+
+config NET_ICMP_NPOLLWAITERS
+	int "Number of ICMP poll waiters"
+	default 1
 
 endif # NET_ICMP_SOCKET
 endif # NET_ICMP && !NET_ICMP_NO_STACK
diff --git a/net/icmp/Make.defs b/net/icmp/Make.defs
index f714c40..31dbf4d 100644
--- a/net/icmp/Make.defs
+++ b/net/icmp/Make.defs
@@ -42,10 +42,7 @@ NET_CSRCS += icmp_input.c
 
 ifeq ($(CONFIG_NET_ICMP_SOCKET),y)
 SOCK_CSRCS += icmp_sockif.c icmp_poll.c icmp_conn.c icmp_sendto.c
-SOCK_CSRCS += icmp_recvfrom.c
-ifeq ($(CONFIG_MM_IOB),y)
-SOCK_CSRCS += icmp_netpoll.c
-endif
+SOCK_CSRCS += icmp_recvfrom.c icmp_netpoll.c
 endif
 
 # Include ICMP build support
diff --git a/net/icmp/icmp.h b/net/icmp/icmp.h
index 024ced2..13690fc 100644
--- a/net/icmp/icmp.h
+++ b/net/icmp/icmp.h
@@ -70,11 +70,24 @@
  * Public types
  ****************************************************************************/
 
+struct socket;    /* Forward reference */
+struct sockaddr;  /* Forward reference */
+struct pollfd;    /* Forward reference */
+
 #ifdef CONFIG_NET_ICMP_SOCKET
 /* Representation of a IPPROTO_ICMP socket connection */
 
 struct devif_callback_s;         /* Forward reference */
 
+/* This is a container that holds the poll-related information */
+
+struct icmp_poll_s
+{
+  FAR struct socket *psock;        /* IPPROTO_ICMP socket structure */
+  FAR struct pollfd *fds;          /* Needed to handle poll events */
+  FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
+};
+
 struct icmp_conn_s
 {
   /* Common prologue of all connection structures. */
@@ -97,14 +110,18 @@ struct icmp_conn_s
 
   FAR struct net_driver_s *dev;  /* Needed to free the callback structure */
 
-#ifdef CONFIG_MM_IOB
   /* ICMP response read-ahead list.  A singly linked list of type struct
    * iob_qentry_s where the ICMP read-ahead data for the current ID is
    * retained.
    */
 
   struct iob_queue_s readahead;  /* Read-ahead buffering */
-#endif
+
+  /* The following is a list of poll structures of threads waiting for
+   * socket events.
+   */
+
+  struct icmp_poll_s pollinfo[CONFIG_NET_ICMP_NPOLLWAITERS];
 };
 #endif
 
@@ -130,10 +147,6 @@ EXTERN const struct sock_intf_s g_icmp_sockif;
  * Public Function Prototypes
  ****************************************************************************/
 
-struct socket;    /* Forward reference */
-struct sockaddr;  /* Forward reference */
-struct pollfd;    /* Forward reference */
-
 /****************************************************************************
  * Name: icmp_input
  *
diff --git a/net/icmp/icmp_netpoll.c b/net/icmp/icmp_netpoll.c
index 1052259..99b299d 100644
--- a/net/icmp/icmp_netpoll.c
+++ b/net/icmp/icmp_netpoll.c
@@ -43,28 +43,12 @@
 #include <poll.h>
 #include <debug.h>
 
-#include <nuttx/kmalloc.h>
 #include <nuttx/net/net.h>
 
-#include <devif/devif.h>
+#include "devif/devif.h"
 #include "netdev/netdev.h"
 #include "icmp/icmp.h"
 
-#ifdef CONFIG_MM_IOB
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/* This is an allocated container that holds the poll-related information */
-
-struct icmp_poll_s
-{
-  FAR struct socket *psock;        /* IPPROTO_ICMP socket structure */
-  FAR struct pollfd *fds;          /* Needed to handle poll events */
-  FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
-};
-
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -178,18 +162,22 @@ int icmp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
 
   DEBUGASSERT(conn != NULL && fds != NULL);
 
-  /* Allocate a container to hold the poll information */
-
-  info = (FAR struct icmp_poll_s *)kmm_malloc(sizeof(struct icmp_poll_s));
-  if (!info)
-    {
-      return -ENOMEM;
-    }
-
   /* Some of the  following must be atomic */
 
   net_lock();
 
+  /* Find a container to hold the poll information */
+
+  info = conn->pollinfo;
+  while (info->psock != NULL)
+    {
+      if (++info >= &conn->pollinfo[CONFIG_NET_ICMP_NPOLLWAITERS])
+        {
+          ret = -ENOMEM;
+          goto errout_with_lock;
+        }
+    }
+
   /* Allocate a ICMP callback structure */
 
   cb = icmp_callback_alloc(conn->dev, conn);
@@ -249,11 +237,7 @@ int icmp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
       nxsem_post(fds->sem);
     }
 
-  net_unlock();
-  return OK;
-
 errout_with_lock:
-  kmm_free(info);
   net_unlock();
   return ret;
 }
@@ -293,9 +277,7 @@ int icmp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
     {
       /* Release the callback */
 
-      net_lock();
       icmp_callback_free(conn->dev, conn, info->cb);
-      net_unlock();
 
       /* Release the poll/select data slot */
 
@@ -303,10 +285,8 @@ int icmp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
 
       /* Then free the poll info container */
 
-      kmm_free(info);
+      info->psock = NULL;
     }
 
   return OK;
 }
-
-#endif /* !CONFIG_MM_IOB */
diff --git a/net/icmp/icmp_sockif.c b/net/icmp/icmp_sockif.c
index 47c1d4d..80277b4 100644
--- a/net/icmp/icmp_sockif.c
+++ b/net/icmp/icmp_sockif.c
@@ -445,7 +445,6 @@ int icmp_listen(FAR struct socket *psock, int backlog)
 static int icmp_netpoll(FAR struct socket *psock, FAR struct pollfd *fds,
                         bool setup)
 {
-#ifdef CONFIG_MM_IOB
   /* Check if we are setting up or tearing down the poll */
 
   if (setup)
@@ -460,9 +459,6 @@ static int icmp_netpoll(FAR struct socket *psock, FAR struct pollfd *fds,
 
       return icmp_pollteardown(psock, fds);
     }
-#else
-  return -ENOSYS;
-#endif /* CONFIG_MM_IOB */
 }
 
 /****************************************************************************
diff --git a/net/icmpv6/Kconfig b/net/icmpv6/Kconfig
index 3c7afc3..1ef9e0a 100644
--- a/net/icmpv6/Kconfig
+++ b/net/icmpv6/Kconfig
@@ -26,6 +26,7 @@ if NET_ICMPv6 && !NET_ICMPv6_NO_STACK
 config NET_ICMPv6_SOCKET
 	bool "IPPROTO_ICMP6 socket support"
 	default n
+	select MM_IOB
 	---help---
 		Enable support for IPPROTO_ICMP6 sockets.  These sockets are needed
 		for application level support for sending ICMPv7 ECHO requests and
@@ -203,7 +204,10 @@ if NET_ICMPv6_SOCKET
 config NET_ICMPv6_NCONNS
 	int "Max ICMPv6 packet sockets"
 	default 4
-	depends on MM_IOB
+
+config NET_ICMPv6_NPOLLWAITERS
+	int "Number of ICMPv6 poll waiters"
+	default 1
 
 endif # NET_ICMPv6_SOCKET
 
diff --git a/net/icmpv6/Make.defs b/net/icmpv6/Make.defs
index 9ecec70..d273447 100644
--- a/net/icmpv6/Make.defs
+++ b/net/icmpv6/Make.defs
@@ -43,10 +43,7 @@ NET_CSRCS += icmpv6_linkipaddr.c
 
 ifeq ($(CONFIG_NET_ICMPv6_SOCKET),y)
 SOCK_CSRCS += icmpv6_sockif.c icmpv6_conn.c icmpv6_sendto.c
-SOCK_CSRCS += icmpv6_recvfrom.c
-ifeq ($(CONFIG_MM_IOB),y)
-SOCK_CSRCS += icmpv6_netpoll.c
-endif
+SOCK_CSRCS += icmpv6_recvfrom.c icmpv6_netpoll.c
 endif
 
 ifeq ($(CONFIG_NET_ICMPv6_NEIGHBOR),y)
diff --git a/net/icmpv6/icmpv6.h b/net/icmpv6/icmpv6.h
index 189249c..f5f2ab5 100644
--- a/net/icmpv6/icmpv6.h
+++ b/net/icmpv6/icmpv6.h
@@ -71,11 +71,26 @@
  * Public Type Definitions
  ****************************************************************************/
 
+struct timespec;     /* Forward reference */
+struct net_driver_s; /* Forward reference */
+struct socket;       /* Forward reference */
+struct sockaddr;     /* Forward reference */
+struct pollfd;       /* Forward reference */
+
 #ifdef CONFIG_NET_ICMPv6_SOCKET
 /* Representation of a IPPROTO_ICMP socket connection */
 
 struct devif_callback_s; /* Forward reference */
 
+/* This is a container that holds the poll-related information */
+
+struct icmpv6_poll_s
+{
+  FAR struct socket *psock;        /* IPPROTO_ICMP6 socket structure */
+  FAR struct pollfd *fds;          /* Needed to handle poll events */
+  FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
+};
+
 struct icmpv6_conn_s
 {
   /* Common prologue of all connection structures. */
@@ -98,14 +113,18 @@ struct icmpv6_conn_s
 
   FAR struct net_driver_s *dev;  /* Needed to free the callback structure */
 
-#ifdef CONFIG_MM_IOB
   /* ICMPv6 response read-ahead list.  A singly linked list of type struct
    * iob_qentry_s where the ICMPv6 read-ahead data for the current ID is
    * retained.
    */
 
   struct iob_queue_s readahead;  /* Read-ahead buffering */
-#endif
+
+  /* The following is a list of poll structures of threads waiting for
+   * socket events.
+   */
+
+  struct icmpv6_poll_s pollinfo[CONFIG_NET_ICMPv6_NPOLLWAITERS];
 };
 #endif
 
@@ -155,12 +174,6 @@ EXTERN const struct sock_intf_s g_icmpv6_sockif;
  * Public Function Prototypes
  ****************************************************************************/
 
-struct timespec;     /* Forward reference */
-struct net_driver_s; /* Forward reference */
-struct socket;       /* Forward reference */
-struct sockaddr;     /* Forward reference */
-struct pollfd;       /* Forward reference */
-
 /****************************************************************************
  * Name: icmpv6_input
  *
diff --git a/net/icmpv6/icmpv6_netpoll.c b/net/icmpv6/icmpv6_netpoll.c
index 1fbf964..82f6dda 100644
--- a/net/icmpv6/icmpv6_netpoll.c
+++ b/net/icmpv6/icmpv6_netpoll.c
@@ -43,28 +43,12 @@
 #include <poll.h>
 #include <debug.h>
 
-#include <nuttx/kmalloc.h>
 #include <nuttx/net/net.h>
 
-#include <devif/devif.h>
+#include "devif/devif.h"
 #include "netdev/netdev.h"
 #include "icmpv6/icmpv6.h"
 
-#ifdef CONFIG_MM_IOB
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/* This is an allocated container that holds the poll-related information */
-
-struct icmpv6_poll_s
-{
-  FAR struct socket *psock;        /* IPPROTO_ICMP6 socket structure */
-  FAR struct pollfd *fds;          /* Needed to handle poll events */
-  FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
-};
-
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -178,17 +162,23 @@ int icmpv6_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
 
   DEBUGASSERT(conn != NULL && fds != NULL);
 
-  /* Allocate a container to hold the poll information */
+  /* Some of the following must be atomic */
+
+  net_lock();
+
+  /* Find a container to hold the poll information */
 
-  info = (FAR struct icmpv6_poll_s *)kmm_malloc(sizeof(struct icmpv6_poll_s));
-  if (!info)
+  info = conn->pollinfo;
+  while (info->psock != NULL)
     {
-      return -ENOMEM;
+      if (++info >= &conn->pollinfo[CONFIG_NET_ICMPv6_NPOLLWAITERS])
+        {
+          ret = -ENOMEM;
+          goto errout_with_lock;
+        }
     }
 
-  /* Some of the following must be atomic */
-
-  net_lock();
+  /* Allocate a ICMP callback structure */
 
   cb = icmpv6_callback_alloc(conn->dev, conn);
   if (cb == NULL)
@@ -247,11 +237,7 @@ int icmpv6_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
       nxsem_post(fds->sem);
     }
 
-  net_unlock();
-  return OK;
-
 errout_with_lock:
-  kmm_free(info);
   net_unlock();
   return ret;
 }
@@ -291,9 +277,7 @@ int icmpv6_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
     {
       /* Release the callback */
 
-      net_lock();
       icmpv6_callback_free(conn->dev, conn, info->cb);
-      net_unlock();
 
       /* Release the poll/select data slot */
 
@@ -301,10 +285,8 @@ int icmpv6_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
 
       /* Then free the poll info container */
 
-      kmm_free(info);
+      info->psock = NULL;
     }
 
   return OK;
 }
-
-#endif /* !CONFIG_MM_IOB */
diff --git a/net/icmpv6/icmpv6_sockif.c b/net/icmpv6/icmpv6_sockif.c
index 1a21749..f229320 100644
--- a/net/icmpv6/icmpv6_sockif.c
+++ b/net/icmpv6/icmpv6_sockif.c
@@ -445,7 +445,6 @@ int icmpv6_listen(FAR struct socket *psock, int backlog)
 static int icmpv6_netpoll(FAR struct socket *psock, FAR struct pollfd *fds,
                         bool setup)
 {
-#ifdef CONFIG_MM_IOB
   /* Check if we are setting up or tearing down the poll */
 
   if (setup)
@@ -460,9 +459,6 @@ static int icmpv6_netpoll(FAR struct socket *psock, FAR struct pollfd *fds,
 
       return icmpv6_pollteardown(psock, fds);
     }
-#else
-  return -ENOSYS;
-#endif /* CONFIG_MM_IOB */
 }
 
 /****************************************************************************
diff --git a/net/ieee802154/ieee802154_recvfrom.c b/net/ieee802154/ieee802154_recvfrom.c
index bdb50a5..2ab12fb 100644
--- a/net/ieee802154/ieee802154_recvfrom.c
+++ b/net/ieee802154/ieee802154_recvfrom.c
@@ -385,10 +385,6 @@ ssize_t ieee802154_recvfrom(FAR struct socket *psock, FAR void *buf,
   (void)nxsem_init(&state.ir_sem, 0, 0); /* Doesn't really fail */
   (void)nxsem_setprotocol(&state.ir_sem, SEM_PRIO_NONE);
 
-  /* Set the socket state to receiving */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_RECV);
-
   /* Set up the callback in the connection */
 
   state.ir_cb = ieee802154_callback_alloc(&radio->r_dev, conn);
@@ -416,9 +412,6 @@ ssize_t ieee802154_recvfrom(FAR struct socket *psock, FAR void *buf,
       ret = -EBUSY;
     }
 
-  /* Set the socket state to idle */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
   nxsem_destroy(&state.ir_sem);
 
 errout_with_lock:
diff --git a/net/ieee802154/ieee802154_sendto.c b/net/ieee802154/ieee802154_sendto.c
index 7556f23..66c35d7 100644
--- a/net/ieee802154/ieee802154_sendto.c
+++ b/net/ieee802154/ieee802154_sendto.c
@@ -471,10 +471,6 @@ ssize_t psock_ieee802154_sendto(FAR struct socket *psock, FAR const void *buf,
       return -ENODEV;
     }
 
-  /* Set the socket state to sending */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
-
   /* Perform the send operation */
 
   /* Initialize the state structure. This is done with the network
@@ -534,10 +530,6 @@ ssize_t psock_ieee802154_sendto(FAR struct socket *psock, FAR const void *buf,
   nxsem_destroy(&state.is_sem);
   net_unlock();
 
-  /* Set the socket state to idle */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
-
   /* Check for a errors, Errors are signaled by negative errno values
    * for the send length
    */
diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c
index b327398..2f03075 100644
--- a/net/inet/inet_sockif.c
+++ b/net/inet/inet_sockif.c
@@ -956,29 +956,29 @@ static int inet_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
  *
  ****************************************************************************/
 
-#if defined(HAVE_TCP_POLL) || defined(HAVE_UDP_POLL)
+#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK)
 static inline int inet_pollsetup(FAR struct socket *psock,
                                  FAR struct pollfd *fds)
 {
-#ifdef HAVE_TCP_POLL
+#ifdef NET_TCP_HAVE_STACK
   if (psock->s_type == SOCK_STREAM)
     {
       return tcp_pollsetup(psock, fds);
     }
   else
-#endif /* HAVE_TCP_POLL */
-#ifdef HAVE_UDP_POLL
+#endif /* NET_TCP_HAVE_STACK */
+#ifdef NET_UDP_HAVE_STACK
   if (psock->s_type != SOCK_STREAM)
     {
       return udp_pollsetup(psock, fds);
     }
   else
-#endif /* HAVE_UDP_POLL */
+#endif /* NET_UDP_HAVE_STACK */
     {
       return -ENOSYS;
     }
 }
-#endif /* HAVE_TCP_POLL || HAVE_UDP_POLL */
+#endif /* NET_TCP_HAVE_STACK || NET_UDP_HAVE_STACK */
 
 /****************************************************************************
  * Name: inet_pollteardown
@@ -996,29 +996,29 @@ static inline int inet_pollsetup(FAR struct socket *psock,
  *
  ****************************************************************************/
 
-#if defined(HAVE_TCP_POLL) || defined(HAVE_UDP_POLL)
+#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK)
 static inline int inet_pollteardown(FAR struct socket *psock,
                                     FAR struct pollfd *fds)
 {
-#ifdef HAVE_TCP_POLL
+#ifdef NET_TCP_HAVE_STACK
   if (psock->s_type == SOCK_STREAM)
     {
       return tcp_pollteardown(psock, fds);
     }
   else
-#endif /* HAVE_TCP_POLL */
-#ifdef HAVE_UDP_POLL
+#endif /* NET_TCP_HAVE_STACK */
+#ifdef NET_UDP_HAVE_STACK
   if (psock->s_type == SOCK_DGRAM)
     {
       return udp_pollteardown(psock, fds);
     }
   else
-#endif /* HAVE_UDP_POLL */
+#endif /* NET_UDP_HAVE_STACK */
     {
       return -ENOSYS;
     }
 }
-#endif /* HAVE_TCP_POLL || HAVE_UDP_POLL */
+#endif /* NET_TCP_HAVE_STACK || NET_UDP_HAVE_STACK */
 
 /****************************************************************************
  * Name: inet_poll
@@ -1041,7 +1041,7 @@ static inline int inet_pollteardown(FAR struct socket *psock,
 static int inet_poll(FAR struct socket *psock, FAR struct pollfd *fds,
                      bool setup)
 {
-#if defined(HAVE_TCP_POLL) || defined(HAVE_UDP_POLL)
+#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK)
 
   /* Check if we are setting up or tearing down the poll */
 
@@ -1061,7 +1061,7 @@ static int inet_poll(FAR struct socket *psock, FAR struct pollfd *fds,
     {
       return -ENOSYS;
     }
-#endif /* HAVE_TCP_POLL || !HAVE_UDP_POLL */
+#endif /* NET_TCP_HAVE_STACK || !NET_UDP_HAVE_STACK */
 }
 
 /****************************************************************************
diff --git a/net/local/local.h b/net/local/local.h
index 944f02f..4eb0aaa 100644
--- a/net/local/local.h
+++ b/net/local/local.h
@@ -61,7 +61,7 @@
  ****************************************************************************/
 
 #define HAVE_LOCAL_POLL 1
-#define LOCAL_ACCEPT_NPOLLWAITERS 2
+#define LOCAL_NPOLLWAITERS 2
 
 /* Packet format in FIFO:
  *
@@ -168,10 +168,11 @@ struct local_conn_s
 
 #ifdef HAVE_LOCAL_POLL
   /* The following is a list if poll structures of threads waiting for
-   * socket accept events.
+   * socket events.
    */
 
-  struct pollfd *lc_accept_fds[LOCAL_ACCEPT_NPOLLWAITERS];
+  struct pollfd *lc_accept_fds[LOCAL_NPOLLWAITERS];
+  struct pollfd lc_inout_fds[2*LOCAL_NPOLLWAITERS];
 #endif
 
   /* Union of fields unique to SOCK_STREAM client, server, and connected
diff --git a/net/local/local_netpoll.c b/net/local/local_netpoll.c
index 81aff7c..ebcd978 100644
--- a/net/local/local_netpoll.c
+++ b/net/local/local_netpoll.c
@@ -44,7 +44,6 @@
 #include <errno.h>
 #include <debug.h>
 
-#include <nuttx/kmalloc.h>
 #include <nuttx/net/net.h>
 #include <nuttx/fs/fs.h>
 
@@ -73,7 +72,7 @@ static int local_accept_pollsetup(FAR struct local_conn_s *conn,
        * slot for the poll structure reference
        */
 
-      for (i = 0; i < LOCAL_ACCEPT_NPOLLWAITERS; i++)
+      for (i = 0; i < LOCAL_NPOLLWAITERS; i++)
         {
           /* Find an available slot */
 
@@ -87,7 +86,7 @@ static int local_accept_pollsetup(FAR struct local_conn_s *conn,
             }
         }
 
-      if (i >= LOCAL_ACCEPT_NPOLLWAITERS)
+      if (i >= LOCAL_NPOLLWAITERS)
         {
           fds->priv = NULL;
           ret = -EBUSY;
@@ -143,7 +142,7 @@ void local_accept_pollnotify(FAR struct local_conn_s *conn,
 #ifdef CONFIG_NET_LOCAL_STREAM
   int i;
 
-  for (i = 0; i < LOCAL_ACCEPT_NPOLLWAITERS; i++)
+  for (i = 0; i < LOCAL_NPOLLWAITERS; i++)
     {
       struct pollfd *fds = conn->lc_accept_fds[i];
       if (fds)
@@ -215,22 +214,31 @@ int local_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
               goto pollerr;
             }
 
-          /* Allocate shadow pollfds. */
+          /* Find shadow pollfds. */
 
-          shadowfds = kmm_zalloc(2 * sizeof(struct pollfd));
-          if (!shadowfds)
+          net_lock();
+
+          shadowfds = conn->lc_inout_fds;
+          while (shadowfds->fd != 0)
             {
-              return -ENOMEM;
+              shadowfds += 2;
+              if (shadowfds >= &conn->lc_inout_fds[2*LOCAL_NPOLLWAITERS])
+                {
+                  net_unlock();
+                  return -ENOMEM;
+                }
             }
 
-          shadowfds[0].fd     = 0; /* Does not matter */
+          shadowfds[0].fd     = 1; /* Does not matter */
           shadowfds[0].sem    = fds->sem;
           shadowfds[0].events = fds->events & ~POLLOUT;
 
-          shadowfds[1].fd     = 1; /* Does not matter */
+          shadowfds[1].fd     = 0; /* Does not matter */
           shadowfds[1].sem    = fds->sem;
           shadowfds[1].events = fds->events & ~POLLIN;
 
+          net_unlock();
+
           /* Setup poll for both shadow pollfds. */
 
           ret = file_poll(&conn->lc_infile, &shadowfds[0], true);
@@ -245,7 +253,7 @@ int local_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
 
           if (ret < 0)
             {
-              kmm_free(shadowfds);
+              shadowfds[0].fd = 0;
               fds->priv = NULL;
               goto pollerr;
             }
@@ -367,7 +375,7 @@ int local_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
 
           fds->revents |= shadowfds[0].revents | shadowfds[1].revents;
           fds->priv = NULL;
-          kmm_free(shadowfds);
+          shadowfds[0].fd = 0;
         }
         break;
 
diff --git a/net/pkt/pkt_recvfrom.c b/net/pkt/pkt_recvfrom.c
index a859083..8b8a510 100644
--- a/net/pkt/pkt_recvfrom.c
+++ b/net/pkt/pkt_recvfrom.c
@@ -410,10 +410,6 @@ ssize_t pkt_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
     }
 #endif
 
-  /* Set the socket state to receiving */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_RECV);
-
   /* Set up the callback in the connection */
 
   state.pr_cb = pkt_callback_alloc(dev, conn);
@@ -441,10 +437,6 @@ ssize_t pkt_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
       ret = -EBUSY;
     }
 
-  /* Set the socket state to idle */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
-
 errout_with_state:
   net_unlock();
   pkt_recvfrom_uninitialize(&state);
diff --git a/net/pkt/pkt_send.c b/net/pkt/pkt_send.c
index cd0ec8e..aec0e72 100644
--- a/net/pkt/pkt_send.c
+++ b/net/pkt/pkt_send.c
@@ -191,10 +191,6 @@ ssize_t psock_pkt_send(FAR struct socket *psock, FAR const void *buf,
       return -ENODEV;
     }
 
-  /* Set the socket state to sending */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
-
   /* Perform the send operation */
 
   /* Initialize the state structure. This is done with the network locked
@@ -249,10 +245,6 @@ ssize_t psock_pkt_send(FAR struct socket *psock, FAR const void *buf,
   nxsem_destroy(&state.snd_sem);
   net_unlock();
 
-  /* Set the socket state to idle */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
-
   /* Check for a errors, Errors are signalled by negative errno values
    * for the send length
    */
diff --git a/net/sixlowpan/sixlowpan_tcpsend.c b/net/sixlowpan/sixlowpan_tcpsend.c
index 8a86a7b..67d83e4 100644
--- a/net/sixlowpan/sixlowpan_tcpsend.c
+++ b/net/sixlowpan/sixlowpan_tcpsend.c
@@ -854,10 +854,6 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
       return (ssize_t)ret;
     }
 
-  /* Set the socket state to sending */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
-
   /* Send the TCP packets, breaking down the potential large user buffer
    * into smaller packets that can be reassembled in the allocated MTU
    * packet buffer.
@@ -874,14 +870,9 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
   if (ret < 0)
     {
       nerr("ERROR: sixlowpan_send_packet() failed: %d\n", ret);
-
-      psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
       return (ssize_t)ret;
     }
 
-  /* Set the socket state to idle */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
   return (ssize_t)buflen;
 }
 
diff --git a/net/sixlowpan/sixlowpan_udpsend.c b/net/sixlowpan/sixlowpan_udpsend.c
index 56684d7..ffb62bd 100644
--- a/net/sixlowpan/sixlowpan_udpsend.c
+++ b/net/sixlowpan/sixlowpan_udpsend.c
@@ -302,10 +302,6 @@ ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock,
       return (ssize_t)ret;
     }
 
-  /* Set the socket state to sending */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
-
   /* If routable, then call sixlowpan_send() to format and send the 6LoWPAN
    * packet.
    */
@@ -324,9 +320,6 @@ ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock,
       nerr("ERROR: sixlowpan_send() failed: %d\n", ret);
     }
 
-  /* Set the socket state to idle */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
   return (ssize_t)ret;
 }
 
diff --git a/net/socket/Kconfig b/net/socket/Kconfig
index a22948b..c627ea5 100644
--- a/net/socket/Kconfig
+++ b/net/socket/Kconfig
@@ -43,8 +43,8 @@ config NET_SOLINGER
 	bool "SO_LINGER socket option"
 	default n
 	depends on NET_TCP_WRITE_BUFFERS || NET_UDP_WRITE_BUFFERS
-	select TCP_NOTIFIER if NET_TCP
-	select UDP_NOTIFIER if NET_UDP
+	select NET_TCP_NOTIFIER if NET_TCP
+	select NET_UDP_NOTIFIER if NET_UDP
 	---help---
 		Enable or disable support for the SO_LINGER socket option.  Requires
 		write buffer support.
diff --git a/net/socket/recvfrom.c b/net/socket/recvfrom.c
index 79944c2..60a9535 100644
--- a/net/socket/recvfrom.c
+++ b/net/socket/recvfrom.c
@@ -88,8 +88,6 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
                        int flags, FAR struct sockaddr *from,
                        FAR socklen_t *fromlen)
 {
-  ssize_t ret;
-
   /* Verify that non-NULL pointers were passed */
 
 #ifdef CONFIG_DEBUG_FEATURES
@@ -111,10 +109,6 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
       return -EBADF;
     }
 
-  /* Set the socket state to receiving */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_RECV);
-
   /* Let logic specific to this address family handle the recvfrom()
    * operation.
    */
@@ -122,12 +116,7 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
   DEBUGASSERT(psock->s_sockif != NULL &&
              psock->s_sockif->si_recvfrom != NULL);
 
-  ret = psock->s_sockif->si_recvfrom(psock, buf, len, flags, from, fromlen);
-
-  /* Set the socket state to idle */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
-  return ret;
+  return psock->s_sockif->si_recvfrom(psock, buf, len, flags, from, fromlen);
 }
 
 /****************************************************************************
diff --git a/net/socket/socket.h b/net/socket/socket.h
index f826337..7f7abe9 100644
--- a/net/socket/socket.h
+++ b/net/socket/socket.h
@@ -56,13 +56,6 @@
 
 /* Definitions of 8-bit socket flags */
 
-                                  /* Bits 0-2: Socket state */
-#define _SF_IDLE            0x00  /* - There is no socket activity */
-#define _SF_ACCEPT          0x01  /* - Socket is waiting to accept a connection */
-#define _SF_RECV            0x02  /* - Waiting for recv action to complete */
-#define _SF_SEND            0x03  /* - Waiting for send action to complete */
-#define _SF_MASK            0x03  /* - Mask to isolate the above actions */
-
 #define _SF_NONBLOCK        0x08  /* Bit 3: Don't block if no data (TCP/READ only) */
 #define _SF_LISTENING       0x10  /* Bit 4: SOCK_STREAM is listening */
 #define _SF_BOUND           0x20  /* Bit 5: SOCK_STREAM is bound to an address */
@@ -79,10 +72,6 @@
 
 /* Macro to manage the socket state and flags */
 
-#define _SS_SETSTATE(s,f)   (((s) & ~_SF_MASK) | (f))
-#define _SS_GETSTATE(s)     ((s) & _SF_MASK)
-#define _SS_ISBUSY(s)       (_SS_GETSTATE(s) != _SF_IDLE)
-
 #define _SS_ISNONBLOCK(s)   (((s) & _SF_NONBLOCK)  != 0)
 #define _SS_ISLISTENING(s)  (((s) & _SF_LISTENING) != 0)
 #define _SS_ISBOUND(s)      (((s) & _SF_BOUND)     != 0)
diff --git a/net/tcp/Kconfig b/net/tcp/Kconfig
index 239a53e..9319c62 100644
--- a/net/tcp/Kconfig
+++ b/net/tcp/Kconfig
@@ -55,6 +55,10 @@ config NET_TCP_CONNS
 	---help---
 		Maximum number of TCP/IP connections (all tasks)
 
+config NET_TCP_NPOLLWAITERS
+	int "Number of TCP poll waiters"
+	default 1
+
 config NET_TCP_RTO
 	int "RTO of TCP/IP connections"
 	default 3
@@ -74,7 +78,7 @@ config NET_MAX_LISTENPORTS
 	---help---
 		Maximum number of listening TCP/IP ports (all tasks).  Default: 20
 
-config TCP_NOTIFIER
+config NET_TCP_NOTIFIER
 	bool "Support TCP notifications"
 	default n
 	depends on SCHED_WORKQUEUE
diff --git a/net/tcp/Make.defs b/net/tcp/Make.defs
index 6d67b02..4cc27db 100644
--- a/net/tcp/Make.defs
+++ b/net/tcp/Make.defs
@@ -52,15 +52,12 @@ ifeq ($(CONFIG_NET_SENDFILE),y)
 SOCK_CSRCS += tcp_sendfile.c
 endif
 
-ifeq ($(CONFIG_NET_TCP_READAHEAD),y)
-SOCK_CSRCS += tcp_netpoll.c
-ifeq ($(CONFIG_TCP_NOTIFIER),y)
+ifeq ($(CONFIG_NET_TCP_NOTIFIER),y)
 SOCK_CSRCS += tcp_notifier.c
 ifeq ($(CONFIG_NET_TCP_WRITE_BUFFERS),y)
 SOCK_CSRCS += tcp_txdrain.c
 endif
 endif
-endif
 
 ifeq ($(CONFIG_NET_TCPPROTO_OPTIONS),y)
 SOCK_CSRCS += tcp_setsockopt.c tcp_getsockopt.c
@@ -71,7 +68,7 @@ endif
 NET_CSRCS += tcp_conn.c tcp_seqno.c tcp_devpoll.c tcp_finddev.c tcp_timer.c
 NET_CSRCS += tcp_send.c tcp_input.c tcp_appsend.c tcp_listen.c
 NET_CSRCS += tcp_monitor.c tcp_callback.c tcp_backlog.c tcp_ipselect.c
-NET_CSRCS += tcp_recvwindow.c
+NET_CSRCS += tcp_recvwindow.c tcp_netpoll.c
 
 # TCP write buffering
 
diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h
index 53135f8..f786d3d 100644
--- a/net/tcp/tcp.h
+++ b/net/tcp/tcp.h
@@ -49,7 +49,7 @@
 #include <nuttx/mm/iob.h>
 #include <nuttx/net/ip.h>
 
-#ifdef CONFIG_TCP_NOTIFIER
+#ifdef CONFIG_NET_TCP_NOTIFIER
 #  include <nuttx/wqueue.h>
 #endif
 
@@ -61,12 +61,6 @@
 
 #define NET_TCP_HAVE_STACK 1
 
-/* Conditions for support TCP poll/select operations */
-
-#ifdef CONFIG_NET_TCP_READAHEAD
-#  define HAVE_TCP_POLL
-#endif
-
 /* Allocate a new TCP data callback */
 
 /* These macros allocate and free callback structures used for receiving
@@ -110,6 +104,11 @@
  * Public Type Definitions
  ****************************************************************************/
 
+struct file;      /* Forward reference */
+struct sockaddr;  /* Forward reference */
+struct socket;    /* Forward reference */
+struct pollfd;    /* Forward reference */
+
 /* Representation of a TCP connection.
  *
  * The tcp_conn_s structure is used for identifying a connection. All
@@ -124,6 +123,18 @@ struct devif_callback_s;  /* Forward reference */
 struct tcp_backlog_s;     /* Forward reference */
 struct tcp_hdr_s;         /* Forward reference */
 
+/* This is a container that holds the poll-related information */
+
+struct tcp_poll_s
+{
+  FAR struct socket *psock;        /* Needed to handle loss of connection */
+  struct pollfd *fds;              /* Needed to handle poll events */
+  FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
+#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
+  int16_t key;                     /* Needed to cancel pending notification */
+#endif
+};
+
 struct tcp_conn_s
 {
   /* Common prologue of all connection structures. */
@@ -274,6 +285,12 @@ struct tcp_conn_s
 
   FAR void *accept_private;
   int (*accept)(FAR struct tcp_conn_s *listener, FAR struct tcp_conn_s *conn);
+
+  /* The following is a list of poll structures of threads waiting for
+   * socket events.
+   */
+
+  struct tcp_poll_s pollinfo[CONFIG_NET_TCP_NPOLLWAITERS];
 };
 
 /* This structure supports TCP write buffering */
@@ -335,11 +352,6 @@ EXTERN struct net_driver_s *g_netdevices;
  * Public Function Prototypes
  ****************************************************************************/
 
-struct file;      /* Forward reference */
-struct sockaddr;  /* Forward reference */
-struct socket;    /* Forward reference */
-struct pollfd;    /* Forward reference */
-
 /****************************************************************************
  * Name: tcp_initialize
  *
@@ -1535,9 +1547,7 @@ void tcp_wrbuffer_dump(FAR const char *msg, FAR struct tcp_wrbuffer_s *wrb,
  *
  ****************************************************************************/
 
-#ifdef HAVE_TCP_POLL
 int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds);
-#endif
 
 /****************************************************************************
  * Name: tcp_pollteardown
@@ -1555,9 +1565,7 @@ int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds);
  *
  ****************************************************************************/
 
-#ifdef HAVE_TCP_POLL
 int tcp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds);
-#endif
 
 /****************************************************************************
  * Name: tcp_readahead_notifier_setup
@@ -1586,7 +1594,7 @@ int tcp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds);
  *
  ****************************************************************************/
 
-#ifdef CONFIG_TCP_NOTIFIER
+#ifdef CONFIG_NET_TCP_NOTIFIER
 int tcp_readahead_notifier_setup(worker_t worker,
                                  FAR struct tcp_conn_s *conn,
                                  FAR void *arg);
@@ -1619,7 +1627,7 @@ int tcp_readahead_notifier_setup(worker_t worker,
  *
  ****************************************************************************/
 
-#ifdef CONFIG_TCP_NOTIFIER
+#ifdef CONFIG_NET_TCP_NOTIFIER
 int tcp_writebuffer_notifier_setup(worker_t worker,
                                    FAR struct tcp_conn_s *conn,
                                    FAR void *arg);
@@ -1650,7 +1658,7 @@ int tcp_writebuffer_notifier_setup(worker_t worker,
  *
  ****************************************************************************/
 
-#ifdef CONFIG_TCP_NOTIFIER
+#ifdef CONFIG_NET_TCP_NOTIFIER
 int tcp_disconnect_notifier_setup(worker_t worker,
                                   FAR struct tcp_conn_s *conn,
                                   FAR void *arg);
@@ -1675,7 +1683,7 @@ int tcp_disconnect_notifier_setup(worker_t worker,
  *
  ****************************************************************************/
 
-#ifdef CONFIG_TCP_NOTIFIER
+#ifdef CONFIG_NET_TCP_NOTIFIER
 int tcp_notifier_teardown(int key);
 #endif
 
@@ -1700,7 +1708,7 @@ int tcp_notifier_teardown(int key);
  *
  ****************************************************************************/
 
-#if defined(CONFIG_NET_TCP_READAHEAD) && defined(CONFIG_TCP_NOTIFIER)
+#if defined(CONFIG_NET_TCP_READAHEAD) && defined(CONFIG_NET_TCP_NOTIFIER)
 void tcp_readahead_signal(FAR struct tcp_conn_s *conn);
 #endif
 
@@ -1725,7 +1733,7 @@ void tcp_readahead_signal(FAR struct tcp_conn_s *conn);
  *
  ****************************************************************************/
 
-#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_TCP_NOTIFIER)
+#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_NET_TCP_NOTIFIER)
 void tcp_writebuffer_signal(FAR struct tcp_conn_s *conn);
 #endif
 
@@ -1744,7 +1752,7 @@ void tcp_writebuffer_signal(FAR struct tcp_conn_s *conn);
  *
  ****************************************************************************/
 
-#ifdef CONFIG_TCP_NOTIFIER
+#ifdef CONFIG_NET_TCP_NOTIFIER
 void tcp_disconnect_signal(FAR struct tcp_conn_s *conn);
 #endif
 
@@ -1764,7 +1772,7 @@ void tcp_disconnect_signal(FAR struct tcp_conn_s *conn);
  *
  ****************************************************************************/
 
-#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_TCP_NOTIFIER)
+#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_NET_TCP_NOTIFIER)
 struct timespec;
 int tcp_txdrain(FAR struct socket *psock,
                 FAR const struct timespec *abstime);
diff --git a/net/tcp/tcp_accept.c b/net/tcp/tcp_accept.c
index 602375b..1b74d8e 100644
--- a/net/tcp/tcp_accept.c
+++ b/net/tcp/tcp_accept.c
@@ -264,10 +264,6 @@ int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
   else
 #endif
     {
-      /* Set the socket state to accepting */
-
-      psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_ACCEPT);
-
       /* Perform the TCP accept operation */
 
       /* Initialize the state structure.  This is done with the network
@@ -306,10 +302,6 @@ int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
 
       nxsem_destroy(&state. acpt_sem);
 
-      /* Set the socket state to idle */
-
-      psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
-
       /* Check for a errors.  Errors are signalled by negative errno values
        * for the send length.
        */
diff --git a/net/tcp/tcp_callback.c b/net/tcp/tcp_callback.c
index d04a2c9..c9f8c55 100644
--- a/net/tcp/tcp_callback.c
+++ b/net/tcp/tcp_callback.c
@@ -145,7 +145,7 @@ tcp_data_event(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
 uint16_t tcp_callback(FAR struct net_driver_s *dev,
                       FAR struct tcp_conn_s *conn, uint16_t flags)
 {
-#ifdef CONFIG_TCP_NOTIFIER
+#ifdef CONFIG_NET_TCP_NOTIFIER
   uint16_t orig = flags;
 #endif
 
@@ -203,7 +203,7 @@ uint16_t tcp_callback(FAR struct net_driver_s *dev,
       flags = devif_conn_event(dev, conn, flags, conn->connevents);
     }
 
-#ifdef CONFIG_TCP_NOTIFIER
+#ifdef CONFIG_NET_TCP_NOTIFIER
   /* Provide notification(s) if the TCP connection has been lost. */
 
   if ((orig & TCP_DISCONN_EVENTS) != 0)
@@ -287,7 +287,7 @@ uint16_t tcp_datahandler(FAR struct tcp_conn_s *conn, FAR uint8_t *buffer,
       return 0;
     }
 
-#ifdef CONFIG_TCP_NOTIFIER
+#ifdef CONFIG_NET_TCP_NOTIFIER
   /* Provide notification(s) that additional TCP read-ahead data is
    * available.
    */
diff --git a/net/tcp/tcp_netpoll.c b/net/tcp/tcp_netpoll.c
index eea06ee..3890d06 100644
--- a/net/tcp/tcp_netpoll.c
+++ b/net/tcp/tcp_netpoll.c
@@ -41,13 +41,12 @@
 #include <nuttx/config.h>
 
 #include <stdint.h>
+#include <assert.h>
 #include <poll.h>
 #include <debug.h>
 
-#include <nuttx/kmalloc.h>
-#include <nuttx/wqueue.h>
-#include <nuttx/mm/iob.h>
 #include <nuttx/net/net.h>
+#include <nuttx/semaphore.h>
 
 #include "devif/devif.h"
 #include "netdev/netdev.h"
@@ -55,24 +54,6 @@
 #include "inet/inet.h"
 #include "tcp/tcp.h"
 
-#ifdef HAVE_TCP_POLL
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/* This is an allocated container that holds the poll-related information */
-
-struct tcp_poll_s
-{
-  FAR struct socket *psock;        /* Needed to handle loss of connection */
-  struct pollfd *fds;              /* Needed to handle poll events */
-  FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
-#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
-  int16_t key;                     /* Needed to cancel pending notification */
-#endif
-};
-
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -172,19 +153,11 @@ static uint16_t tcp_poll_eventhandler(FAR struct net_driver_s *dev,
 #if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
 static inline void tcp_iob_work(FAR void *arg)
 {
-  FAR struct work_notifier_entry_s *entry;
-  FAR struct work_notifier_s *ninfo;
   FAR struct tcp_poll_s *pinfo;
   FAR struct socket *psock;
   FAR struct pollfd *fds;
 
-  entry = (FAR struct work_notifier_entry_s *)arg;
-  DEBUGASSERT(entry != NULL);
-
-  ninfo = &entry->info;
-  DEBUGASSERT(ninfo->arg != NULL);
-
-  pinfo = (FAR struct tcp_poll_s *)ninfo->arg;
+  pinfo = (FAR struct tcp_poll_s *)arg;
   DEBUGASSERT(pinfo->psock != NULL && pinfo->fds != NULL);
 
   psock = pinfo->psock;
@@ -231,12 +204,6 @@ static inline void tcp_iob_work(FAR void *arg)
           pinfo->key = iob_notifier_setup(LPWORK, tcp_iob_work, pinfo);
         }
     }
-
-  /* Protocol for the use of the IOB notifier is that we free the argument
-   * after the notification has been processed.
-   */
-
-  kmm_free(arg);
 }
 #endif
 
@@ -276,18 +243,22 @@ int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
     }
 #endif
 
-  /* Allocate a container to hold the poll information */
-
-  info = (FAR struct tcp_poll_s *)kmm_malloc(sizeof(struct tcp_poll_s));
-  if (!info)
-    {
-      return -ENOMEM;
-    }
-
   /* Some of the  following must be atomic */
 
   net_lock();
 
+  /* Find a container to hold the poll information */
+
+  info = conn->pollinfo;
+  while (info->psock != NULL)
+    {
+      if (++info >= &conn->pollinfo[CONFIG_NET_TCP_NPOLLWAITERS])
+        {
+          ret = -ENOMEM;
+          goto errout_with_lock;
+        }
+    }
+
   /* Allocate a TCP/IP callback structure */
 
   cb = tcp_callback_alloc(conn);
@@ -331,14 +302,14 @@ int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
 
   fds->priv    = (FAR void *)info;
 
-#ifdef CONFIG_NET_TCPBACKLOG
+#ifdef CONFIG_NET_TCP_READAHEAD
   /* Check for read data or backlogged connection availability now */
 
   if (!IOB_QEMPTY(&conn->readahead) || tcp_backlogavailable(conn))
 #else
-  /* Check for read data availability now */
+  /* Check for backlogged connection now */
 
-  if (!IOB_QEMPTY(&conn->readahead))
+  if (tcp_backlogavailable(conn))
 #endif
     {
       /* Normal data may be read without blocking. */
@@ -423,11 +394,7 @@ int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
     }
 #endif
 
-  net_unlock();
-  return OK;
-
 errout_with_lock:
-  kmm_free(info);
   net_unlock();
   return ret;
 }
@@ -481,9 +448,7 @@ int tcp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
 
       /* Release the callback */
 
-      net_lock();
       tcp_callback_free(conn, info->cb);
-      net_unlock();
 
       /* Release the poll/select data slot */
 
@@ -491,10 +456,8 @@ int tcp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
 
       /* Then free the poll info container */
 
-      kmm_free(info);
+      info->psock = NULL;
     }
 
   return OK;
 }
-
-#endif /* HAVE_TCP_POLL */
diff --git a/net/tcp/tcp_notifier.c b/net/tcp/tcp_notifier.c
index d106b5a..23673cf 100644
--- a/net/tcp/tcp_notifier.c
+++ b/net/tcp/tcp_notifier.c
@@ -49,7 +49,7 @@
 
 #include "tcp/tcp.h"
 
-#ifdef CONFIG_TCP_NOTIFIER
+#ifdef CONFIG_NET_TCP_NOTIFIER
 
 /****************************************************************************
  * Public Functions
@@ -330,4 +330,4 @@ void tcp_disconnect_signal(FAR struct tcp_conn_s *conn)
   return work_notifier_signal(WORK_TCP_DISCONNECT, conn);
 }
 
-#endif /* CONFIG_TCP_NOTIFIER */
+#endif /* CONFIG_NET_TCP_NOTIFIER */
diff --git a/net/tcp/tcp_send_buffered.c b/net/tcp/tcp_send_buffered.c
index d6ca21b..601747f 100644
--- a/net/tcp/tcp_send_buffered.c
+++ b/net/tcp/tcp_send_buffered.c
@@ -173,7 +173,7 @@ static void psock_insert_segment(FAR struct tcp_wrbuffer_s *wrb,
  *
  ****************************************************************************/
 
-#ifdef CONFIG_TCP_NOTIFIER
+#ifdef CONFIG_NET_TCP_NOTIFIER
 static void psock_writebuffer_notify(FAR struct tcp_conn_s *conn)
 {
   /* Check if all write buffers have been sent and ACKed */
@@ -994,10 +994,6 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf,
 
   BUF_DUMP("psock_tcp_send", buf, len);
 
-  /* Set the socket state to sending */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
-
   if (len > 0)
     {
       /* Allocate a write buffer.  Careful, the network will be momentarily
@@ -1124,10 +1120,6 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf,
       net_unlock();
     }
 
-  /* Set the socket state to idle */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
-
   /* Check for errors.  Errors are signaled by negative errno values
    * for the send length
    */
diff --git a/net/tcp/tcp_send_unbuffered.c b/net/tcp/tcp_send_unbuffered.c
index 03b199a..df9d80b 100644
--- a/net/tcp/tcp_send_unbuffered.c
+++ b/net/tcp/tcp_send_unbuffered.c
@@ -707,10 +707,6 @@ ssize_t psock_tcp_send(FAR struct socket *psock,
     }
 #endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */
 
-  /* Set the socket state to sending */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
-
   /* Perform the TCP send operation */
 
   /* Initialize the state structure.  This is done with the network
@@ -780,10 +776,6 @@ ssize_t psock_tcp_send(FAR struct socket *psock,
   nxsem_destroy(&state.snd_sem);
   net_unlock();
 
-  /* Set the socket state to idle */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
-
   /* Check for a errors.  Errors are signalled by negative errno values
    * for the send length
    */
diff --git a/net/tcp/tcp_sendfile.c b/net/tcp/tcp_sendfile.c
index 6f2ec57..c7fcaed 100644
--- a/net/tcp/tcp_sendfile.c
+++ b/net/tcp/tcp_sendfile.c
@@ -562,10 +562,6 @@ ssize_t tcp_sendfile(FAR struct socket *psock, FAR struct file *infile,
     }
 #endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */
 
-  /* Set the socket state to sending */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
-
   /* Initialize the state structure.  This is done with the network
    * locked because we don't want anything to happen until we are
    * ready.
@@ -643,10 +639,6 @@ ssize_t tcp_sendfile(FAR struct socket *psock, FAR struct file *infile,
     }
   while (state.snd_sent >= 0 && state.snd_acked < state.snd_flen);
 
-  /* Set the socket state to idle */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
-
   tcp_callback_free(conn, state.snd_ackcb);
 
 errout_datacb:
diff --git a/net/tcp/tcp_txdrain.c b/net/tcp/tcp_txdrain.c
index 552c631..b3fd722 100644
--- a/net/tcp/tcp_txdrain.c
+++ b/net/tcp/tcp_txdrain.c
@@ -46,13 +46,9 @@
 #include <assert.h>
 #include <errno.h>
 
-#include <nuttx/kmalloc.h>
-#include <nuttx/wqueue.h>
-#include <nuttx/net/net.h>
-
 #include "tcp/tcp.h"
 
-#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_TCP_NOTIFIER)
+#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_NET_TCP_NOTIFIER)
 
 /****************************************************************************
  * Private Functions
@@ -74,25 +70,13 @@
 
 static void txdrain_worker(FAR void *arg)
 {
-  /* The entire notifier entry is passed to us.  That is because we are
-   * responsible for disposing of the entry via kmm_free() when we are
-   * finished with it.
-   */
-
-  FAR struct work_notifier_entry_s *notifier =
-    (FAR struct work_notifier_entry_s *)arg;
-  FAR sem_t *waitsem;
-
-  DEBUGASSERT(notifier != NULL && notifier->info.arg != NULL);
-  waitsem = (FAR sem_t *)notifier->info.arg;
-
-  /* Free the notifier entry */
+  FAR sem_t *waitsem = (FAR sem_t *)arg;
 
-  kmm_free(notifier);
+  DEBUGASSERT(waitsem != NULL);
 
   /* Then just post the semaphore, waking up tcp_txdrain() */
 
-  sem_post(waitsem);
+  nxsem_post(waitsem);
 }
 
 /****************************************************************************
@@ -130,6 +114,7 @@ int tcp_txdrain(FAR struct socket *psock,
   /* Initialize the wait semaphore */
 
   nxsem_init(&waitsem, 0, 0);
+  nxsem_setprotocol(&waitsem, SEM_PRIO_NONE);
 
   /* The following needs to be done with the network stable */
 
@@ -195,4 +180,4 @@ int tcp_txdrain(FAR struct socket *psock,
   return ret;
 }
 
-#endif /* CONFIG_NET_TCP_WRITE_BUFFERS && CONFIG_TCP_NOTIFIER */
+#endif /* CONFIG_NET_TCP_WRITE_BUFFERS && CONFIG_NET_TCP_NOTIFIER */
diff --git a/net/tcp/tcp_wrbuffer.c b/net/tcp/tcp_wrbuffer.c
index 285d13e..44dcad2 100644
--- a/net/tcp/tcp_wrbuffer.c
+++ b/net/tcp/tcp_wrbuffer.c
@@ -119,6 +119,7 @@ void tcp_wrbuffer_initialize(void)
     }
 
   nxsem_init(&g_wrbuffer.sem, 0, CONFIG_NET_TCP_NWRBCHAINS);
+  nxsem_setprotocol(&g_wrbuffer.sem, SEM_PRIO_NONE);
 }
 
 /****************************************************************************
@@ -149,7 +150,7 @@ FAR struct tcp_wrbuffer_s *tcp_wrbuffer_alloc(void)
    * buffer
    */
 
-  DEBUGVERIFY(net_lockedwait(&g_wrbuffer.sem)); /* TODO: Handle EINTR. */
+  while (net_lockedwait(&g_wrbuffer.sem) < 0);
 
   /* Now, we are guaranteed to have a write buffer structure reserved
    * for us in the free list.
@@ -207,11 +208,7 @@ FAR struct tcp_wrbuffer_s *tcp_wrbuffer_tryalloc(void)
    * buffer
    */
 
-  if (tcp_wrbuffer_test() == OK)
-    {
-      DEBUGVERIFY(net_lockedwait(&g_wrbuffer.sem));
-    }
-  else
+  if (nxsem_trywait(&g_wrbuffer.sem) != OK)
     {
       return NULL;
     }
diff --git a/net/udp/Kconfig b/net/udp/Kconfig
index ec9609c..095d86a 100644
--- a/net/udp/Kconfig
+++ b/net/udp/Kconfig
@@ -55,6 +55,10 @@ config NET_UDP_CONNS
 	---help---
 		The maximum amount of open concurrent UDP sockets
 
+config NET_UDP_NPOLLWAITERS
+	int "Number of UDP poll waiters"
+	default 1
+
 config NET_UDP_READAHEAD
 	bool "Enable UDP/IP read-ahead buffering"
 	default y
@@ -109,15 +113,15 @@ config NET_UDP_WRBUFFER_DUMP
 
 endif # NET_UDP_WRITE_BUFFERS
 
-config UDP_NOTIFIER
+config NET_UDP_NOTIFIER
 	bool "Support UDP read-ahead notifications"
 	default n
 	depends on SCHED_WORKQUEUE
 	select WQUEUE_NOTIFIER
 	---help---
 		Enable building of UDP read-ahead notifier logic that will execute a
-		worker function on the high priority work queue when read-ahead data
-		is available.  This is is a general purpose notifier, but was
+		worker function on the low priority work queue when read-ahead data
+		is available.  This is a general purpose notifier, but was
 		developed specifically to support poll() logic where the poll must
 		wait for read-ahead data to become available.
 
diff --git a/net/udp/Make.defs b/net/udp/Make.defs
index f7d09fc..edb0e31 100644
--- a/net/udp/Make.defs
+++ b/net/udp/Make.defs
@@ -52,11 +52,8 @@ else
 SOCK_CSRCS += udp_psock_sendto_unbuffered.c
 endif
 
-ifeq ($(CONFIG_NET_UDP_READAHEAD),y)
-SOCK_CSRCS += udp_netpoll.c
-ifeq ($(CONFIG_UDP_NOTIFIER),y)
+ifeq ($(CONFIG_NET_UDP_NOTIFIER),y)
 SOCK_CSRCS += udp_notifier.c
-endif
 ifeq ($(CONFIG_NET_UDP_WRITE_BUFFERS),y)
 SOCK_CSRCS += udp_txdrain.c
 endif
@@ -65,7 +62,7 @@ endif
 # Transport layer
 
 NET_CSRCS += udp_conn.c udp_devpoll.c udp_send.c udp_input.c udp_finddev.c
-NET_CSRCS += udp_callback.c udp_ipselect.c
+NET_CSRCS += udp_callback.c udp_ipselect.c udp_netpoll.c
 
 # UDP write buffering
 
diff --git a/net/udp/udp.h b/net/udp/udp.h
index 0dd327c..2c95052 100644
--- a/net/udp/udp.h
+++ b/net/udp/udp.h
@@ -53,7 +53,7 @@
 #  include <nuttx/mm/iob.h>
 #endif
 
-#ifdef CONFIG_UDP_NOTIFIER
+#ifdef CONFIG_NET_UDP_NOTIFIER
 #  include <nuttx/wqueue.h>
 #endif
 
@@ -65,12 +65,6 @@
 
 #define NET_UDP_HAVE_STACK 1
 
-/* Conditions for support UDP poll/select operations */
-
-#ifdef CONFIG_NET_UDP_READAHEAD
-#  define HAVE_UDP_POLL
-#endif
-
 #ifdef CONFIG_NET_UDP_WRITE_BUFFERS
 /* UDP write buffer dump macros */
 
@@ -99,11 +93,29 @@
  * Public Type Definitions
  ****************************************************************************/
 
+struct sockaddr;      /* Forward reference */
+struct socket;        /* Forward reference */
+struct net_driver_s;  /* Forward reference */
+struct pollfd;        /* Forward reference */
+
 /* Representation of a UDP connection */
 
 struct devif_callback_s;  /* Forward reference */
 struct udp_hdr_s;         /* Forward reference */
 
+/* This is a container that holds the poll-related information */
+
+struct udp_poll_s
+{
+  FAR struct socket *psock;        /* Needed to handle loss of connection */
+  FAR struct net_driver_s *dev;    /* Needed to free the callback structure */
+  struct pollfd *fds;              /* Needed to handle poll events */
+  FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
+#if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
+  int16_t key;                     /* Needed to cancel pending notification */
+#endif
+};
+
 struct udp_conn_s
 {
   /* Common prologue of all connection structures. */
@@ -151,6 +163,12 @@ struct udp_conn_s
   sq_queue_t write_q;             /* Write buffering for UDP packets */
   FAR struct net_driver_s *dev;   /* Last device */
 #endif
+
+  /* The following is a list of poll structures of threads waiting for
+   * socket events.
+   */
+
+  struct udp_poll_s pollinfo[CONFIG_NET_UDP_NPOLLWAITERS];
 };
 
 /* This structure supports UDP write buffering.  It is simply a container
@@ -185,11 +203,6 @@ extern "C"
  * Public Function Prototypes
  ****************************************************************************/
 
-struct sockaddr;      /* Forward reference */
-struct socket;        /* Forward reference */
-struct net_driver_s;  /* Forward reference */
-struct pollfd;        /* Forward reference */
-
 /****************************************************************************
  * Name: udp_initialize
  *
@@ -653,9 +666,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
  *
  ****************************************************************************/
 
-#ifdef HAVE_UDP_POLL
 int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds);
-#endif
 
 /****************************************************************************
  * Name: udp_pollteardown
@@ -673,9 +684,7 @@ int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds);
  *
  ****************************************************************************/
 
-#ifdef HAVE_UDP_POLL
 int udp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds);
-#endif
 
 /****************************************************************************
  * Name: udp_readahead_notifier_setup
@@ -703,7 +712,7 @@ int udp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds);
  *
  ****************************************************************************/
 
-#ifdef CONFIG_UDP_NOTIFIER
+#ifdef CONFIG_NET_UDP_NOTIFIER
 int udp_readahead_notifier_setup(worker_t worker,
                                  FAR struct udp_conn_s *conn,
                                  FAR void *arg);
@@ -735,7 +744,7 @@ int udp_readahead_notifier_setup(worker_t worker,
  *
  ****************************************************************************/
 
-#ifdef CONFIG_UDP_NOTIFIER
+#ifdef CONFIG_NET_UDP_NOTIFIER
 int udp_writebuffer_notifier_setup(worker_t worker,
                                    FAR struct udp_conn_s *conn,
                                    FAR void *arg);
@@ -760,7 +769,7 @@ int udp_writebuffer_notifier_setup(worker_t worker,
  *
  ****************************************************************************/
 
-#ifdef CONFIG_UDP_NOTIFIER
+#ifdef CONFIG_NET_UDP_NOTIFIER
 int udp_notifier_teardown(int key);
 #endif
 
@@ -784,7 +793,7 @@ int udp_notifier_teardown(int key);
  *
  ****************************************************************************/
 
-#if defined(CONFIG_NET_UDP_READAHEAD) && defined(CONFIG_UDP_NOTIFIER)
+#if defined(CONFIG_NET_UDP_READAHEAD) && defined(CONFIG_NET_UDP_NOTIFIER)
 void udp_readahead_signal(FAR struct udp_conn_s *conn);
 #endif
 
@@ -809,7 +818,7 @@ void udp_readahead_signal(FAR struct udp_conn_s *conn);
  *
  ****************************************************************************/
 
-#if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_UDP_NOTIFIER)
+#if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_NET_UDP_NOTIFIER)
 void udp_writebuffer_signal(FAR struct udp_conn_s *conn);
 #endif
 
@@ -829,7 +838,7 @@ void udp_writebuffer_signal(FAR struct udp_conn_s *conn);
  *
  ****************************************************************************/
 
-#if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_UDP_NOTIFIER)
+#if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_NET_UDP_NOTIFIER)
 struct timespec;
 int udp_txdrain(FAR struct socket *psock,
                 FAR const struct timespec *abstime);
diff --git a/net/udp/udp_callback.c b/net/udp/udp_callback.c
index e6b38b9..3343f40 100644
--- a/net/udp/udp_callback.c
+++ b/net/udp/udp_callback.c
@@ -234,7 +234,7 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev,
       return 0;
     }
 
-#ifdef CONFIG_UDP_NOTIFIER
+#ifdef CONFIG_NET_UDP_NOTIFIER
   /* Provided notification(s) that additional UDP read-ahead data is
    * available.
    */
diff --git a/net/udp/udp_netpoll.c b/net/udp/udp_netpoll.c
index b6fcc85..0bf042b 100644
--- a/net/udp/udp_netpoll.c
+++ b/net/udp/udp_netpoll.c
@@ -41,38 +41,18 @@
 #include <nuttx/config.h>
 
 #include <stdint.h>
+#include <assert.h>
 #include <poll.h>
 #include <debug.h>
 
-#include <nuttx/kmalloc.h>
-#include <nuttx/wqueue.h>
-#include <nuttx/mm/iob.h>
 #include <nuttx/net/net.h>
+#include <nuttx/semaphore.h>
 
 #include "devif/devif.h"
 #include "netdev/netdev.h"
 #include "socket/socket.h"
 #include "udp/udp.h"
 
-#ifdef HAVE_UDP_POLL
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/* This is an allocated container that holds the poll-related information */
-
-struct udp_poll_s
-{
-  FAR struct socket *psock;        /* Needed to handle loss of connection */
-  FAR struct net_driver_s *dev;    /* Needed to free the callback structure */
-  struct pollfd *fds;              /* Needed to handle poll events */
-  FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
-#if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
-  int16_t key;                     /* Needed to cancel pending notification */
-#endif
-};
-
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -163,19 +143,11 @@ static uint16_t udp_poll_eventhandler(FAR struct net_driver_s *dev,
 #if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
 static inline void udp_iob_work(FAR void *arg)
 {
-  FAR struct work_notifier_entry_s *entry;
-  FAR struct work_notifier_s *ninfo;
   FAR struct udp_poll_s *pinfo;
   FAR struct socket *psock;
   FAR struct pollfd *fds;
 
-  entry = (FAR struct work_notifier_entry_s *)arg;
-  DEBUGASSERT(entry != NULL);
-
-  ninfo = &entry->info;
-  DEBUGASSERT(ninfo->arg != NULL);
-
-  pinfo = (FAR struct udp_poll_s *)ninfo->arg;
+  pinfo = (FAR struct udp_poll_s *)arg;
   DEBUGASSERT(pinfo->psock != NULL && pinfo->fds != NULL);
 
   psock = pinfo->psock;
@@ -204,12 +176,6 @@ static inline void udp_iob_work(FAR void *arg)
           pinfo->key = iob_notifier_setup(LPWORK, udp_iob_work, pinfo);
         }
     }
-
-  /* Protocol for the use of the IOB notifier is that we free the argument
-   * after the notification has been processed.
-   */
-
-  kmm_free(arg);
 }
 #endif
 
@@ -249,18 +215,22 @@ int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
     }
 #endif
 
-  /* Allocate a container to hold the poll information */
-
-  info = (FAR struct udp_poll_s *)kmm_malloc(sizeof(struct udp_poll_s));
-  if (!info)
-    {
-      return -ENOMEM;
-    }
-
   /* Some of the  following must be atomic */
 
   net_lock();
 
+  /* Find a container to hold the poll information */
+
+  info = conn->pollinfo;
+  while (info->psock != NULL)
+    {
+      if (++info >= &conn->pollinfo[CONFIG_NET_UDP_NPOLLWAITERS])
+        {
+          ret = -ENOMEM;
+          goto errout_with_lock;
+        }
+    }
+
   /* Get the device that will provide the provide the NETDEV_DOWN event.
    * NOTE: in the event that the local socket is bound to INADDR_ANY, the
    * dev value will be zero and there will be no NETDEV_DOWN notifications.
@@ -311,6 +281,7 @@ int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
 
   fds->priv = (FAR void *)info;
 
+#ifdef CONFIG_NET_UDP_READAHEAD
   /* Check for read data availability now */
 
   if (!IOB_QEMPTY(&conn->readahead))
@@ -319,6 +290,7 @@ int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
 
       fds->revents |= (POLLRDNORM & fds->events);
     }
+#endif
 
   if (psock_udp_cansend(psock) >= 0)
     {
@@ -350,11 +322,7 @@ int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
     }
 #endif
 
-  net_unlock();
-  return OK;
-
 errout_with_lock:
-  kmm_free(info);
   net_unlock();
   return ret;
 }
@@ -408,9 +376,7 @@ int udp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
 
       /* Release the callback */
 
-      net_lock();
       udp_callback_free(info->dev, conn, info->cb);
-      net_unlock();
 
       /* Release the poll/select data slot */
 
@@ -418,10 +384,8 @@ int udp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
 
       /* Then free the poll info container */
 
-      kmm_free(info);
+      info->psock = NULL;
     }
 
   return OK;
 }
-
-#endif /* !HAVE_UDP_POLL */
diff --git a/net/udp/udp_notifier.c b/net/udp/udp_notifier.c
index a9919cf..e2c909a 100644
--- a/net/udp/udp_notifier.c
+++ b/net/udp/udp_notifier.c
@@ -47,7 +47,7 @@
 
 #include "udp/udp.h"
 
-#ifdef CONFIG_UDP_NOTIFIER
+#ifdef CONFIG_NET_UDP_NOTIFIER
 
 /****************************************************************************
  * Public Functions
@@ -254,4 +254,4 @@ void udp_writebuffer_signal(FAR struct udp_conn_s *conn)
 }
 #endif
 
-#endif /* CONFIG_UDP_NOTIFIER */
+#endif /* CONFIG_NET_UDP_NOTIFIER */
diff --git a/net/udp/udp_psock_sendto_buffered.c b/net/udp/udp_psock_sendto_buffered.c
index 73d8f44..45ef043 100644
--- a/net/udp/udp_psock_sendto_buffered.c
+++ b/net/udp/udp_psock_sendto_buffered.c
@@ -162,7 +162,7 @@ static void sendto_writebuffer_release(FAR struct socket *psock,
           psock->s_sndcb->event = NULL;
           wrb = NULL;
 
-#ifdef CONFIG_UDP_NOTIFIER
+#ifdef CONFIG_NET_UDP_NOTIFIER
           /* Notify any waiters that the write buffers have been drained. */
 
           udp_writebuffer_signal(conn);
@@ -694,10 +694,6 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
 
   BUF_DUMP("psock_udp_send", buf, len);
 
-  /* Set the socket state to sending */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
-
   if (len > 0)
     {
       /* Allocate a write buffer.  Careful, the network will be momentarily
@@ -825,10 +821,6 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
       net_unlock();
     }
 
-  /* Set the socket state to idle */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
-
   /* Return the number of bytes that will be sent */
 
   return len;
diff --git a/net/udp/udp_psock_sendto_unbuffered.c b/net/udp/udp_psock_sendto_unbuffered.c
index 25c74ce..1522d9d 100644
--- a/net/udp/udp_psock_sendto_unbuffered.c
+++ b/net/udp/udp_psock_sendto_unbuffered.c
@@ -458,10 +458,6 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
     }
 #endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */
 
-  /* Set the socket state to sending */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
-
   /* Initialize the state structure.  This is done with the network
    * locked because we don't want anything to happen until we are
    * ready.
@@ -566,10 +562,6 @@ errout_with_lock:
 
   nxsem_destroy(&state.st_sem);
 
-  /* Set the socket state back to idle */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
-
   /* Unlock the network and return the result of the sendto() operation */
 
   net_unlock();
diff --git a/net/udp/udp_txdrain.c b/net/udp/udp_txdrain.c
index df899f6..ed8f2e5 100644
--- a/net/udp/udp_txdrain.c
+++ b/net/udp/udp_txdrain.c
@@ -46,13 +46,9 @@
 #include <assert.h>
 #include <errno.h>
 
-#include <nuttx/wqueue.h>
-#include <nuttx/kmalloc.h>
-#include <nuttx/net/net.h>
-
 #include "udp/udp.h"
 
-#if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_UDP_NOTIFIER)
+#if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_NET_UDP_NOTIFIER)
 
 /****************************************************************************
  * Private Functions
@@ -74,25 +70,13 @@
 
 static void txdrain_worker(FAR void *arg)
 {
-  /* The entire notifier entry is passed to us.  That is because we are
-   * responsible for disposing of the entry via kmm_free() when we are
-   * finished with it.
-   */
-
-  FAR struct work_notifier_entry_s *notifier =
-    (FAR struct work_notifier_entry_s *)arg;
-  FAR sem_t *waitsem;
-
-  DEBUGASSERT(notifier != NULL && notifier->info.arg != NULL);
-  waitsem = (FAR sem_t *)notifier->info.arg;
-
-  /* Free the notifier entry */
+  FAR sem_t *waitsem = (FAR sem_t *)arg;
 
-  kmm_free(notifier);
+  DEBUGASSERT(waitsem != NULL);
 
   /* Then just post the semaphore, waking up tcp_txdrain() */
 
-  sem_post(waitsem);
+  nxsem_post(waitsem);
 }
 
 /****************************************************************************
@@ -130,6 +114,7 @@ int udp_txdrain(FAR struct socket *psock,
   /* Initialize the wait semaphore */
 
   nxsem_init(&waitsem, 0, 0);
+  nxsem_setprotocol(&waitsem, SEM_PRIO_NONE);
 
   /* The following needs to be done with the network stable */
 
@@ -160,4 +145,4 @@ int udp_txdrain(FAR struct socket *psock,
   return ret;
 }
 
-#endif /* CONFIG_NET_UDP_WRITE_BUFFERS && CONFIG_UDP_NOTIFIER */
+#endif /* CONFIG_NET_UDP_WRITE_BUFFERS && CONFIG_NET_UDP_NOTIFIER */
diff --git a/net/udp/udp_wrbuffer.c b/net/udp/udp_wrbuffer.c
index 399da0d..b380c59 100644
--- a/net/udp/udp_wrbuffer.c
+++ b/net/udp/udp_wrbuffer.c
@@ -116,6 +116,7 @@ void udp_wrbuffer_initialize(void)
     }
 
   nxsem_init(&g_wrbuffer.sem, 0, CONFIG_NET_UDP_NWRBCHAINS);
+  nxsem_setprotocol(&g_wrbuffer.sem, SEM_PRIO_NONE);
 }
 
 /****************************************************************************
@@ -146,7 +147,7 @@ FAR struct udp_wrbuffer_s *udp_wrbuffer_alloc(void)
    * buffer
    */
 
-  DEBUGVERIFY(net_lockedwait(&g_wrbuffer.sem)); /* TODO: Handle EINTR. */
+  while (net_lockedwait(&g_wrbuffer.sem) < 0);
 
   /* Now, we are guaranteed to have a write buffer structure reserved
    * for us in the free list.
diff --git a/net/usrsock/Kconfig b/net/usrsock/Kconfig
index 0d965da..a8b1a19 100644
--- a/net/usrsock/Kconfig
+++ b/net/usrsock/Kconfig
@@ -23,6 +23,10 @@ config NET_USRSOCK_CONNS
 		Note: Usrsock daemon can impose additional restrictions for
 		maximum number of concurrent connections supported.
 
+config NET_USRSOCK_NPOLLWAITERS
+	int "Number of usrsock poll waiters"
+	default 1
+
 config NET_USRSOCK_NO_INET
 	bool "Disable PF_INET for usrsock"
 	default n
diff --git a/net/usrsock/usrsock.h b/net/usrsock/usrsock.h
index b2f0722..1bacb9c 100644
--- a/net/usrsock/usrsock.h
+++ b/net/usrsock/usrsock.h
@@ -86,6 +86,13 @@ enum usrsock_conn_state_e
   USRSOCK_CONN_STATE_CONNECTING,
 };
 
+struct usrsock_poll_s
+{
+  FAR struct socket *psock;        /* Needed to handle loss of connection */
+  struct pollfd *fds;              /* Needed to handle poll events */
+  FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
+};
+
 struct usrsock_conn_s
 {
   /* Common prologue of all connection structures. */
@@ -126,6 +133,12 @@ struct usrsock_conn_s
       size_t pos;            /* Writer position on input buffer */
     } datain;
   } resp;
+
+  /* The following is a list of poll structures of threads waiting for
+   * socket events.
+   */
+
+  struct usrsock_poll_s pollinfo[CONFIG_NET_USRSOCK_NPOLLWAITERS];
 };
 
 struct usrsock_reqstate_s
diff --git a/net/usrsock/usrsock_poll.c b/net/usrsock/usrsock_poll.c
index e1b35c2..1e5e6cf 100644
--- a/net/usrsock/usrsock_poll.c
+++ b/net/usrsock/usrsock_poll.c
@@ -53,22 +53,10 @@
 #include <nuttx/semaphore.h>
 #include <nuttx/net/net.h>
 #include <nuttx/net/usrsock.h>
-#include <nuttx/kmalloc.h>
 
 #include "usrsock/usrsock.h"
 
 /****************************************************************************
- * Private Data
- ****************************************************************************/
-
-struct usrsock_poll_s
-{
-  FAR struct socket *psock;        /* Needed to handle loss of connection */
-  struct pollfd *fds;              /* Needed to handle poll events */
-  FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
-};
-
-/****************************************************************************
  * Private Functions
  ****************************************************************************/
 
@@ -182,24 +170,26 @@ static int usrsock_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
     }
 #endif
 
-  /* Allocate a container to hold the poll information */
+  net_lock();
 
-  info = (FAR struct usrsock_poll_s *)
-    kmm_malloc(sizeof(struct usrsock_poll_s));
-  if (!info)
+  /* Find a container to hold the poll information */
+
+  info = conn->pollinfo;
+  while (info->psock != NULL)
     {
-      return -ENOMEM;
+      if (++info >= &conn->pollinfo[CONFIG_NET_USRSOCK_NPOLLWAITERS])
+        {
+          ret = -ENOMEM;
+          goto errout_unlock;
+        }
     }
 
-  net_lock();
-
   /* Allocate a usrsock callback structure */
 
   cb = devif_callback_alloc(NULL, &conn->list);
   if (cb == NULL)
     {
       ret = -EBUSY;
-      kmm_free(info); /* fds->priv not set, so we need to free info here. */
       goto errout_unlock;
     }
 
@@ -338,9 +328,7 @@ static int usrsock_pollteardown(FAR struct socket *psock,
     {
       /* Release the callback */
 
-      net_lock();
       devif_conn_callback_free(NULL, info->cb, &conn->list);
-      net_unlock();
 
       /* Release the poll/select data slot */
 
@@ -348,7 +336,7 @@ static int usrsock_pollteardown(FAR struct socket *psock,
 
       /* Then free the poll info container */
 
-      kmm_free(info);
+      info->psock = NULL;
     }
 
   return OK;
diff --git a/sched/wqueue/kwork_notifier.c b/sched/wqueue/kwork_notifier.c
index 706aed4..66bc573 100644
--- a/sched/wqueue/kwork_notifier.c
+++ b/sched/wqueue/kwork_notifier.c
@@ -56,9 +56,41 @@
 #ifdef CONFIG_WQUEUE_NOTIFIER
 
 /****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure describes one notification list entry.  It is cast-
+ * compatible with struct work_notifier_s.  This structure is an allocated
+ * container for the user notification data.   It is allocated because it
+ * must persist until the work is executed.
+ */
+
+struct work_notifier_entry_s
+{
+  /* This must appear at the beginning of the structure.  A reference to
+   * the struct work_notifier_entry_s instance must be cast-compatible with
+   * struct dq_entry_s.
+   */
+
+  struct work_s work;           /* Used for scheduling the work */
+
+  /* User notification information */
+
+  struct work_notifier_s info;  /* The notification info */
+
+  /* Additional payload needed to manage the notification */
+
+  int16_t key;                  /* Unique ID for the notification */
+};
+
+/****************************************************************************
  * Private Data
  ****************************************************************************/
 
+/* This is a doubly linked list of free notifications. */
+
+static dq_queue_t g_notifier_free;
+
 /* This is a doubly linked list of pending notifications.  When an event
  * occurs available, *all* of the waiters for that event in this list will
  * be notified and the entry will be freed.  If there are multiple waiters
@@ -147,6 +179,30 @@ static int16_t work_notifier_key(void)
 }
 
 /****************************************************************************
+ * Name: work_notifier_worker
+ *
+ * Description:
+ *   Forward to the real worker and free the notification.
+ *
+ ****************************************************************************/
+
+static void work_notifier_worker(FAR void *arg)
+{
+  FAR struct work_notifier_entry_s *notifier =
+    (FAR struct work_notifier_entry_s *)arg;
+
+  /* Forward to the real worker */
+
+  notifier->info.worker(notifier->info.arg);
+
+  /* Put the notification to the free list */
+
+  while (nxsem_wait(&g_notifier_sem) < 0);
+  dq_addlast((FAR dq_entry_t *)notifier, &g_notifier_free);
+  nxsem_post(&g_notifier_sem);
+}
+
+/****************************************************************************
  * Public Functions
  ****************************************************************************/
 
@@ -185,9 +241,16 @@ int work_notifier_setup(FAR struct work_notifier_s *info)
       return ret;
     }
 
-  /* Allocate a new notification entry */
+  /* Try to get the entry from the free list */
+
+  notifier = (FAR struct work_notifier_entry_s *)dq_remfirst(&g_notifier_free);
+  if (notifier == NULL)
+    {
+      /* Allocate a new notification entry */
+
+      notifier = kmm_malloc(sizeof(struct work_notifier_entry_s));
+    }
 
-  notifier = kmm_malloc(sizeof(struct work_notifier_entry_s));
   if (notifier == NULL)
     {
       ret = -ENOMEM;
@@ -269,9 +332,9 @@ int work_notifier_teardown(int key)
 
       dq_rem((FAR dq_entry_t *)notifier, &g_notifier_pending);
 
-      /* Free the notification */
+      /* Put the notification to the free list */
 
-      kmm_free(notifier);
+      dq_addlast((FAR dq_entry_t *)notifier, &g_notifier_free);
       ret = OK;
     }
 
@@ -359,8 +422,8 @@ void work_notifier_signal(enum work_evtype_e evtype,
            * responsible for freeing the allocated memory.
            */
 
-          (void)work_queue(info->qid, &notifier->work, info->worker,
-                           entry, 0);
+          (void)work_queue(info->qid, &notifier->work,
+                           work_notifier_worker, entry, 0);
         }
     }