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

casaroli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 05095b69601 drivers/serial: batch pty_write output post-processing
05095b69601 is described below

commit 05095b696010f33d01cd445b66bd321561b2eac8
Author: yangsong8 <[email protected]>
AuthorDate: Tue Aug 25 21:56:04 2026 +0800

    drivers/serial: batch pty_write output post-processing
    
    pty_write() performed OPOST output one byte at a time, issuing a
    separate file_write() to the sink pipe for every character.  Use
    memchr to locate the next byte that needs translation (CR under
    OCRNL, NL under ONLCR/ONLRET) or that is a tty control character
    (c_cc[VINTR]/c_cc[VSUSP], unless _POSIX_VDISABLE), then write the run
    of ordinary bytes before it to the sink in a single call.
    
    When a control character raises SIGINT/SIGTSTP, return the number of
    bytes actually consumed instead of always returning 1, and when a sink
    write fails after some bytes were written, return that partial count
    instead of the error.
    
    Generate the signals only when ISIG is set in the terminal settings of
    the pair, which are kept in the slave also when set through the master,
    and set ISIG in the default c_lflag of the slave so the default
    behavior does not change.
    
    Signed-off-by: yangsong8 <[email protected]>
---
 drivers/serial/pty.c | 136 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 117 insertions(+), 19 deletions(-)

diff --git a/drivers/serial/pty.c b/drivers/serial/pty.c
index 009588659f3..85d5cfc2d3a 100644
--- a/drivers/serial/pty.c
+++ b/drivers/serial/pty.c
@@ -600,12 +600,18 @@ static ssize_t pty_write(FAR struct file *filep,
 {
   FAR struct inode *inode;
   FAR struct pty_dev_s *dev;
-  ssize_t ntotal;
+  ssize_t ntotal = 0;
   ssize_t nwritten;
 #if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGTSTP)
   pid_t pid;
+  bool isig;
+#endif
+#ifdef CONFIG_TTY_SIGINT
+  cc_t vintr;
+#endif
+#ifdef CONFIG_TTY_SIGTSTP
+  cc_t vsusp;
 #endif
-  size_t i;
   char ch;
 
   inode = filep->f_inode;
@@ -618,6 +624,19 @@ static ssize_t pty_write(FAR struct file *filep,
     {
       pid = dev->pd_devpair->pp_slave.pd_pid;
     }
+
+  /* The terminal settings of the pair are kept in the slave (TCSETS sets
+   * them there also through the master), so ISIG is taken from the slave
+   * for both ends.
+   */
+
+  isig = pid > 0 && (dev->pd_devpair->pp_slave.pd_lflag & ISIG) != 0;
+#endif
+#ifdef CONFIG_TTY_SIGINT
+  vintr = dev->pd_devpair->pp_vintr;
+#endif
+#ifdef CONFIG_TTY_SIGTSTP
+  vsusp = dev->pd_devpair->pp_vsusp;
 #endif
 
   /* Do output post-processing */
@@ -633,10 +652,86 @@ static ssize_t pty_write(FAR struct file *filep,
        *   ONOCR  - low-speed interactive optimisation
        */
 
-      ntotal = 0;
-      for (i = 0; i < len; i++)
+      FAR const char *special;
+      size_t nbulk;
+
+      while (ntotal < len)
         {
-          ch = *buffer++;
+          special = NULL;
+
+          if ((dev->pd_oflag & OCRNL) != 0)
+            {
+              special = memchr(&buffer[ntotal], '\r', len - ntotal);
+            }
+
+          if ((dev->pd_oflag & (ONLCR | ONLRET)) != 0)
+            {
+              FAR const char *nl;
+
+              nl = memchr(&buffer[ntotal], '\n', len - ntotal);
+              if (nl != NULL && (special == NULL || nl < special))
+                {
+                  special = nl;
+                }
+            }
+
+#if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGTSTP)
+          if (isig)
+            {
+              FAR const char *si;
+
+#ifdef CONFIG_TTY_SIGINT
+              if (vintr != _POSIX_VDISABLE)
+                {
+                  si = memchr(&buffer[ntotal], vintr, len - ntotal);
+                  if (si != NULL && (special == NULL || si < special))
+                    {
+                      special = si;
+                    }
+                }
+#endif
+
+#ifdef CONFIG_TTY_SIGTSTP
+              if (vsusp != _POSIX_VDISABLE)
+                {
+                  si = memchr(&buffer[ntotal], vsusp, len - ntotal);
+                  if (si != NULL && (special == NULL || si < special))
+                    {
+                      special = si;
+                    }
+                }
+#endif
+            }
+#endif
+
+          /* Write the run of ordinary bytes before the special byte (or the
+           * rest of the buffer when there is none).  The sink pipe write
+           * blocks until all bytes have been written.
+           */
+
+          nbulk = special != NULL ? special - &buffer[ntotal] : len - ntotal;
+          if (nbulk > 0)
+            {
+              nwritten = file_write(&dev->pd_sink, &buffer[ntotal], nbulk);
+              if (nwritten < 0)
+                {
+                  ntotal = ntotal ? ntotal : nwritten;
+                  break;
+                }
+
+              ntotal += nwritten;
+              if (nwritten < nbulk)
+                {
+                  continue;
+                }
+            }
+
+          if (special == NULL)
+            {
+              break;
+            }
+
+          ch = buffer[ntotal];
 
           /* Mapping CR to NL? */
 
@@ -667,26 +762,29 @@ static ssize_t pty_write(FAR struct file *filep,
               nwritten = file_write(&dev->pd_sink, &cr, 1);
               if (nwritten < 0)
                 {
-                  ntotal = nwritten;
+                  ntotal = ntotal ? ntotal : nwritten;
                   break;
                 }
             }
 
-#ifdef CONFIG_TTY_SIGINT
-          if (pid > 0 && dev->pd_devpair->pp_vintr != _POSIX_VDISABLE &&
-              (cc_t)ch == dev->pd_devpair->pp_vintr)
+#if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGTSTP)
+          if (isig)
             {
-              nxsig_kill(pid, SIGINT);
-              return 1;
-            }
+#ifdef CONFIG_TTY_SIGINT
+              if (vintr != _POSIX_VDISABLE && (cc_t)ch == vintr)
+                {
+                  nxsig_kill(pid, SIGINT);
+                  return ntotal + 1;
+                }
 #endif
 
 #ifdef CONFIG_TTY_SIGTSTP
-          if (pid > 0 && dev->pd_devpair->pp_vsusp != _POSIX_VDISABLE &&
-              (cc_t)ch == dev->pd_devpair->pp_vsusp)
-            {
-              nxsig_kill(pid, SIGTSTP);
-              return 1;
+              if (vsusp != _POSIX_VDISABLE && (cc_t)ch == vsusp)
+                {
+                  nxsig_kill(pid, SIGTSTP);
+                  return ntotal + 1;
+                }
+#endif
             }
 #endif
 
@@ -702,7 +800,7 @@ static ssize_t pty_write(FAR struct file *filep,
           nwritten = file_write(&dev->pd_sink, &ch, 1);
           if (nwritten < 0)
             {
-              ntotal = nwritten;
+              ntotal = ntotal ? ntotal : nwritten;
               break;
             }
 
@@ -1207,7 +1305,7 @@ int pty_register2(int minor, bool susv1)
   devpair->pp_master.pd_oflag   = OPOST | OCRNL;
   devpair->pp_slave.pd_devpair  = devpair;
   devpair->pp_slave.pd_oflag    = OPOST | ONLCR;
-  devpair->pp_slave.pd_lflag    = ECHO | ICANON;
+  devpair->pp_slave.pd_lflag    = ECHO | ICANON | ISIG;
 #if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGTSTP)
   /* Initialize  of the task that will receive SIGINT signals. */
 

Reply via email to