From 28f73bd928754519cf2893d29334dccc9bde5543 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 9 Sep 2018 09:21:39 -0600 Subject: [PATCH] net/tcp and udp: Add logic to signal events when TCP or UDP read-ahead data is buffered. Squashed commit of the following: net/tcp: Add signal notification for the case when UDP read-ahead data is buffered. This is basically of clone of the TCP notification logic with naming adapted for UDP. net/tcp: Add signal notification for the case when TCP read-ahead data is buffered. --- mm/iob/Kconfig | 2 +- net/tcp/Kconfig | 13 +++- net/tcp/Make.defs | 3 + net/tcp/tcp.h | 79 +++++++++++++++++++++ net/tcp/tcp_callback.c | 8 +++ net/tcp/tcp_notifier.c | 152 +++++++++++++++++++++++++++++++++++++++++ net/udp/Kconfig | 12 ++++ net/udp/Make.defs | 3 + net/udp/udp.h | 79 +++++++++++++++++++++ net/udp/udp_callback.c | 8 +++ net/udp/udp_notifier.c | 152 +++++++++++++++++++++++++++++++++++++++++ 11 files changed, 508 insertions(+), 3 deletions(-) create mode 100644 net/tcp/tcp_notifier.c create mode 100644 net/udp/udp_notifier.c diff --git a/mm/iob/Kconfig b/mm/iob/Kconfig index 1689c6178f..3bb1a8648b 100644 --- a/mm/iob/Kconfig +++ b/mm/iob/Kconfig @@ -64,7 +64,7 @@ config IOB_NOTIFIER default n select SIG_NOTIFIER ---help--- - Enable building of IOB notifier logic that will send a signla to + Enable building of IOB notifier logic that will send a signal to a kernel thread when an IOB is available. This is is a general purpose notifier, but was developed specifically to support poll() logic where the poll must wait for an IOB to become available. diff --git a/net/tcp/Kconfig b/net/tcp/Kconfig index f291991343..045e6a7f6f 100644 --- a/net/tcp/Kconfig +++ b/net/tcp/Kconfig @@ -66,8 +66,17 @@ config NET_TCP_READAHEAD These settings are critical to the reasonable operation of read- ahead buffering. -if NET_TCP_READAHEAD -endif # NET_TCP_READAHEAD +config TCP_READAHEAD_NOTIFIER + bool "Support TCP read-ahead notifications" + default n + select SIG_NOTIFIER + depends on NET_TCP_READAHEAD && !DISABLE_POLL + ---help--- + Enable building of TCP read-ahead notifier logic that will send a + signal to a kernel thread when an TCP read-ahead data has been + buffered. This is is a general purpose notifier, but was developed + specifically to support TCP poll() logic where the poll must wait + for incoming TCP data to be buffered. config NET_TCP_WRITE_BUFFERS bool "Enable TCP/IP write buffering" diff --git a/net/tcp/Make.defs b/net/tcp/Make.defs index 48e8ab29e9..a59e758ff3 100644 --- a/net/tcp/Make.defs +++ b/net/tcp/Make.defs @@ -55,6 +55,9 @@ endif ifneq ($(CONFIG_DISABLE_POLL),y) ifeq ($(CONFIG_NET_TCP_READAHEAD),y) SOCK_CSRCS += tcp_netpoll.c +ifeq ($(CONFIG_TCP_READAHEAD_NOTIFIER),y) +SOCK_CSRCS += tcp_notifier.c +endif endif endif diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index 72e3aefda7..e7539ecc22 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -1542,6 +1542,85 @@ int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds); int tcp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds); #endif +/**************************************************************************** + * Name: tcp_notifier_setup + * + * Description: + * Set up to notify the specified PID with the provided signal number. + * + * NOTE: To avoid race conditions, the caller should set the sigprocmask + * to block signal delivery. The signal will be delivered once the + * signal is removed from the sigprocmask. + * + * Input Parameters: + * pid - The PID to be notified. If a zero value is provided, then the + * PID of the calling thread will be used. + * signo - The signal number to use with the notification. + * conn - The TCP connection where read-ahead data is needed. + * + * Returned Value: + * > 0 - The signal notification is in place. The returned value is a + * key that may be used later in a call to + * tcp_notifier_teardown(). + * == 0 - There is already buffered read-ahead data. No signal + * notification will be provided. + * < 0 - An unexpected error occurred and no signal will be sent. The + * returned value is a negated errno value that indicates the + * nature of the failure. + * + ****************************************************************************/ + +#ifdef CONFIG_TCP_READAHEAD_NOTIFIER +int tcp_notifier_setup(int pid, int signo, FAR struct tcp_conn_s *conn); +#endif + +/**************************************************************************** + * Name: tcp_notifier_teardown + * + * Description: + * Eliminate a TCP read-ahead notification previously setup by + * tcp_notifier_setup(). This function should only be called if the + * notification should be aborted prior to the notification. The + * notification will automatically be torn down after the signal is sent. + * + * Input Parameters: + * key - The key value returned from a previous call to + * tcp_notifier_setup(). + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_TCP_READAHEAD_NOTIFIER +int tcp_notifier_teardown(int key); +#endif + +/**************************************************************************** + * Name: tcp_notifier_signal + * + * Description: + * Read-ahead data has been buffered. Signal all threads waiting for + * read-ahead data to become available. + * + * When the read-ahead data becomes available, *all* of the waiters in + * this thread will be signaled. If there are multiple waiters then only + * the highest priority thread will get the data. Lower priority threads + * will need to call tcp_notifier_setup() once again. + * + * Input Parameters: + * conn - The TCP connection where read-ahead data was just buffered. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_TCP_READAHEAD_NOTIFIER +void tcp_notifier_signal(FAR struct tcp_conn_s *conn); +#endif + #undef EXTERN #ifdef __cplusplus } diff --git a/net/tcp/tcp_callback.c b/net/tcp/tcp_callback.c index 7aca15a281..857963ba69 100644 --- a/net/tcp/tcp_callback.c +++ b/net/tcp/tcp_callback.c @@ -273,6 +273,14 @@ uint16_t tcp_datahandler(FAR struct tcp_conn_s *conn, FAR uint8_t *buffer, return 0; } +#ifdef CONFIG_TCP_READAHEAD_NOTIFIER + /* Provided notification(s) that additional TCP read-ahead data is + * available. + */ + + tcp_notifier_signal(conn); +#endif + ninfo("Buffered %d bytes\n", buflen); return buflen; } diff --git a/net/tcp/tcp_notifier.c b/net/tcp/tcp_notifier.c new file mode 100644 index 0000000000..905eb07f05 --- /dev/null +++ b/net/tcp/tcp_notifier.c @@ -0,0 +1,152 @@ +/**************************************************************************** + * net/tcp/tcp_notifier.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include + +#include "tcp/tcp.h" + +#ifdef CONFIG_TCP_READAHEAD_NOTIFIER + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tcp_notifier_setup + * + * Description: + * Set up to notify the specified PID with the provided signal number. + * + * NOTE: To avoid race conditions, the caller should set the sigprocmask + * to block signal delivery. The signal will be delivered once the + * signal is removed from the sigprocmask. + * + * Input Parameters: + * pid - The PID to be notified. If a zero value is provided, then the + * PID of the calling thread will be used. + * signo - The signal number to use with the notification. + * conn - The TCP connection where read-ahead data is needed. + * + * Returned Value: + * > 0 - The signal notification is in place. The returned value is a + * key that may be used later in a call to + * tcp_notifier_teardown(). + * == 0 - There is already buffered read-ahead data. No signal + * notification will be provided. + * < 0 - An unexpected error occurred and no signal will be sent. The + * returned value is a negated errno value that indicates the + * nature of the failure. + * + ****************************************************************************/ + +int tcp_notifier_setup(int pid, int signo, FAR struct tcp_conn_s *conn) +{ + /* If there is already buffered read-ahead data, then return zero without + * setting up the notification. + */ + + if (conn->readahead.qh_head != NULL) + { + return 0; + } + + /* Otherwise, this is just a simple wrapper around nxsig_notifer_setup(). */ + + return nxsig_notifier_setup(pid, signo, NXSIG_TCP_READAHEAD, conn); +} + +/**************************************************************************** + * Name: tcp_notifier_teardown + * + * Description: + * Eliminate a TCP read-ahead notification previously setup by + * tcp_notifier_setup(). This function should only be called if the + * notification should be aborted prior to the notification. The + * notification will automatically be torn down after the signal is sent. + * + * Input Parameters: + * key - The key value returned from a previous call to + * tcp_notifier_setup(). + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +int tcp_notifier_teardown(int key) +{ + /* This is just a simple wrapper around nxsig_notifier_teardown(). */ + + return nxsig_notifier_teardown(key); +} + +/**************************************************************************** + * Name: tcp_notifier_signal + * + * Description: + * Read-ahead data has been buffered. Signal all threads waiting for + * read-ahead data to become available. + * + * When the read-ahead data becomes available, *all* of the waiters in + * this thread will be signaled. If there are multiple waiters then only + * the highest priority thread will get the data. Lower priority threads + * will need to call tcp_notifier_setup() once again. + * + * Input Parameters: + * conn - The TCP connection where read-ahead data was just buffered. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void tcp_notifier_signal(FAR struct tcp_conn_s *conn) +{ + /* This is just a simple wrapper around nxsig_notifier_signal(). */ + + return nxsig_notifier_signal(NXSIG_TCP_READAHEAD, conn); +} + +#endif /* CONFIG_TCP_READAHEAD_NOTIFIER */ diff --git a/net/udp/Kconfig b/net/udp/Kconfig index 848c8abb96..9f1aad0868 100644 --- a/net/udp/Kconfig +++ b/net/udp/Kconfig @@ -57,6 +57,18 @@ config NET_UDP_READAHEAD select NET_READAHEAD select MM_IOB +config UDP_READAHEAD_NOTIFIER + bool "Support UDP read-ahead notifications" + default n + select SIG_NOTIFIER + depends on NET_UDP_READAHEAD && !DISABLE_POLL + ---help--- + Enable building of UDP read-ahead notifier logic that will send a + signal to a kernel thread when an UDP read-ahead data has been + buffered. This is is a general purpose notifier, but was developed + specifically to support UDP poll() logic where the poll must wait + for incoming UDP data to be buffered. + config NET_UDP_WRITE_BUFFERS bool "Enable UDP/IP write buffering" default n diff --git a/net/udp/Make.defs b/net/udp/Make.defs index 8b5650c3f4..1a7e98810c 100644 --- a/net/udp/Make.defs +++ b/net/udp/Make.defs @@ -55,6 +55,9 @@ endif ifneq ($(CONFIG_DISABLE_POLL),y) ifeq ($(CONFIG_NET_UDP_READAHEAD),y) SOCK_CSRCS += udp_netpoll.c +ifeq ($(CONFIG_UDP_READAHEAD_NOTIFIER),y) +SOCK_CSRCS += udp_notifier.c +endif endif endif diff --git a/net/udp/udp.h b/net/udp/udp.h index 956d7822e5..24132eaeb7 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -643,6 +643,85 @@ int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds); int udp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds); #endif +/**************************************************************************** + * Name: udp_notifier_setup + * + * Description: + * Set up to notify the specified PID with the provided signal number. + * + * NOTE: To avoid race conditions, the caller should set the sigprocmask + * to block signal delivery. The signal will be delivered once the + * signal is removed from the sigprocmask. + * + * Input Parameters: + * pid - The PID to be notified. If a zero value is provided, then the + * PID of the calling thread will be used. + * signo - The signal number to use with the notification. + * conn - The UDP connection where read-ahead data is needed. + * + * Returned Value: + * > 0 - The signal notification is in place. The returned value is a + * key that may be used later in a call to + * udp_notifier_teardown(). + * == 0 - There is already buffered read-ahead data. No signal + * notification will be provided. + * < 0 - An unexpected error occurred and no signal will be sent. The + * returned value is a negated errno value that indicates the + * nature of the failure. + * + ****************************************************************************/ + +#ifdef CONFIG_UDP_READAHEAD_NOTIFIER +int udp_notifier_setup(int pid, int signo, FAR struct udp_conn_s *conn); +#endif + +/**************************************************************************** + * Name: udp_notifier_teardown + * + * Description: + * Eliminate a UDP read-ahead notification previously setup by + * udp_notifier_setup(). This function should only be called if the + * notification should be aborted prior to the notification. The + * notification will automatically be torn down after the signal is sent. + * + * Input Parameters: + * key - The key value returned from a previous call to + * udp_notifier_setup(). + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_UDP_READAHEAD_NOTIFIER +int udp_notifier_teardown(int key); +#endif + +/**************************************************************************** + * Name: udp_notifier_signal + * + * Description: + * Read-ahead data has been buffered. Signal all threads waiting for + * read-ahead data to become available. + * + * When the read-ahead data becomes available, *all* of the waiters in + * this thread will be signaled. If there are multiple waiters then only + * the highest priority thread will get the data. Lower priority threads + * will need to call udp_notifier_setup() once again. + * + * Input Parameters: + * conn - The UDP connection where read-ahead data was just buffered. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_UDP_READAHEAD_NOTIFIER +void udp_notifier_signal(FAR struct udp_conn_s *conn); +#endif + #undef EXTERN #ifdef __cplusplus } diff --git a/net/udp/udp_callback.c b/net/udp/udp_callback.c index c35db56bdd..e1bd6bc542 100644 --- a/net/udp/udp_callback.c +++ b/net/udp/udp_callback.c @@ -224,6 +224,14 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev, FAR struct udp_con return 0; } +#ifdef CONFIG_UDP_READAHEAD_NOTIFIER + /* Provided notification(s) that additional UDP read-ahead data is + * available. + */ + + udp_notifier_signal(conn); +#endif + ninfo("Buffered %d bytes\n", buflen); return buflen; } diff --git a/net/udp/udp_notifier.c b/net/udp/udp_notifier.c new file mode 100644 index 0000000000..f2a2af1cd8 --- /dev/null +++ b/net/udp/udp_notifier.c @@ -0,0 +1,152 @@ +/**************************************************************************** + * net/udp/udp_notifier.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include + +#include "udp/udp.h" + +#ifdef CONFIG_UDP_READAHEAD_NOTIFIER + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: udp_notifier_setup + * + * Description: + * Set up to notify the specified PID with the provided signal number. + * + * NOTE: To avoid race conditions, the caller should set the sigprocmask + * to block signal delivery. The signal will be delivered once the + * signal is removed from the sigprocmask. + * + * Input Parameters: + * pid - The PID to be notified. If a zero value is provided, then the + * PID of the calling thread will be used. + * signo - The signal number to use with the notification. + * conn - The UDP connection where read-ahead data is needed. + * + * Returned Value: + * > 0 - The signal notification is in place. The returned value is a + * key that may be used later in a call to + * udp_notifier_teardown(). + * == 0 - There is already buffered read-ahead data. No signal + * notification will be provided. + * < 0 - An unexpected error occurred and no signal will be sent. The + * returned value is a negated errno value that indicates the + * nature of the failure. + * + ****************************************************************************/ + +int udp_notifier_setup(int pid, int signo, FAR struct udp_conn_s *conn) +{ + /* If there is already buffered read-ahead data, then return zero without + * setting up the notification. + */ + + if (conn->readahead.qh_head != NULL) + { + return 0; + } + + /* Otherwise, this is just a simple wrapper around nxsig_notifer_setup(). */ + + return nxsig_notifier_setup(pid, signo, NXSIG_UDP_READAHEAD, conn); +} + +/**************************************************************************** + * Name: udp_notifier_teardown + * + * Description: + * Eliminate a UDP read-ahead notification previously setup by + * udp_notifier_setup(). This function should only be called if the + * notification should be aborted prior to the notification. The + * notification will automatically be torn down after the signal is sent. + * + * Input Parameters: + * key - The key value returned from a previous call to + * udp_notifier_setup(). + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +int udp_notifier_teardown(int key) +{ + /* This is just a simple wrapper around nxsig_notifier_teardown(). */ + + return nxsig_notifier_teardown(key); +} + +/**************************************************************************** + * Name: udp_notifier_signal + * + * Description: + * Read-ahead data has been buffered. Signal all threads waiting for + * read-ahead data to become available. + * + * When the read-ahead data becomes available, *all* of the waiters in + * this thread will be signaled. If there are multiple waiters then only + * the highest priority thread will get the data. Lower priority threads + * will need to call udp_notifier_setup() once again. + * + * Input Parameters: + * conn - The UDP connection where read-ahead data was just buffered. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void udp_notifier_signal(FAR struct udp_conn_s *conn) +{ + /* This is just a simple wrapper around nxsig_notifier_signal(). */ + + return nxsig_notifier_signal(NXSIG_UDP_READAHEAD, conn); +} + +#endif /* CONFIG_UDP_READAHEAD_NOTIFIER */