commit c850aa60f945079f5a486cd9ca2a6ab723f6e094
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
Date:   Wed Mar 5 00:21:22 2025 +0100

    libpipe: Do not optimize reading pipe->write_limit
    
    It may have changed while sleeping.

diff --git a/libpipe/pipe.h b/libpipe/pipe.h
index 1b1ef82f..f724e98b 100644
--- a/libpipe/pipe.h
+++ b/libpipe/pipe.h
@@ -208,10 +208,9 @@ pipe_select_readable (struct pipe *pipe, struct timespec *tsp, int data_only)
 PIPE_EI error_t
 pipe_wait_writable (struct pipe *pipe, int noblock)
 {
-  size_t limit = pipe->write_limit;
   if (pipe->flags & PIPE_BROKEN)
     return EPIPE;
-  while (pipe_readable (pipe, 1) >= limit)
+  while (pipe_readable (pipe, 1) >= pipe->write_limit)
     {
       if (noblock)
 	return EWOULDBLOCK;
@@ -229,9 +228,9 @@ pipe_wait_writable (struct pipe *pipe, int noblock)
 PIPE_EI error_t
 pipe_select_writable (struct pipe *pipe, struct timespec *tsp)
 {
-  size_t limit = pipe->write_limit;
   error_t err = 0;
-  while (! (pipe->flags & PIPE_BROKEN) && pipe_readable (pipe, 1) >= limit)
+  while (! (pipe->flags & PIPE_BROKEN)
+	 && pipe_readable (pipe, 1) >= pipe->write_limit)
     {
       err = pthread_hurd_cond_timedwait_np (&pipe->pending_writes,
 					    &pipe->lock, tsp);
commit 2eda7f5a540226f55ef3f0298290a0b0cbe298a8
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
Date:   Wed Mar 5 00:23:05 2025 +0100

    libpipe: Introduce pipe_wait_writable_amount

diff --git a/libpipe/pipe.h b/libpipe/pipe.h
index f724e98b..f4985de3 100644
--- a/libpipe/pipe.h
+++ b/libpipe/pipe.h
@@ -129,6 +129,8 @@ extern error_t pipe_wait_readable (struct pipe *pipe, int noblock, int data_only
 extern error_t pipe_select_readable (struct pipe *pipe, struct timespec *tsp,
 				     int data_only);
 
+extern error_t pipe_wait_writable_amount (struct pipe *pipe, int noblock, size_t amount);
+
 extern error_t pipe_wait_writable (struct pipe *pipe, int noblock);
 
 extern error_t pipe_select_writable (struct pipe *pipe, struct timespec *tsp);
@@ -202,15 +204,15 @@ pipe_select_readable (struct pipe *pipe, struct timespec *tsp, int data_only)
   return err;
 }
 
-/* Block until data can be written to PIPE.  If NOBLOCK is true, then
-   EWOULDBLOCK is returned instead of blocking if this can't be done
+/* Block until at least AMOUNT data can be written to PIPE.  If NOBLOCK is true,
+   then EWOULDBLOCK is returned instead of blocking if this can't be done
    immediately.  */
 PIPE_EI error_t
-pipe_wait_writable (struct pipe *pipe, int noblock)
+pipe_wait_writable_amount (struct pipe *pipe, int noblock, size_t amount)
 {
   if (pipe->flags & PIPE_BROKEN)
     return EPIPE;
-  while (pipe_readable (pipe, 1) >= pipe->write_limit)
+  while (pipe_readable (pipe, 1) + amount >= pipe->write_limit)
     {
       if (noblock)
 	return EWOULDBLOCK;
@@ -222,6 +224,15 @@ pipe_wait_writable (struct pipe *pipe, int noblock)
   return 0;
 }
 
+/* Block until data can be written to PIPE.  If NOBLOCK is true, then
+   EWOULDBLOCK is returned instead of blocking if this can't be done
+   immediately.  */
+PIPE_EI error_t
+pipe_wait_writable (struct pipe *pipe, int noblock)
+{
+  return pipe_wait_writable_amount (pipe, noblock, 1);
+}
+
 /* Block until some data can be written to PIPE.  This call only returns once
    threads waiting using pipe_wait_writable have been woken and given a
    chance to write, and if there is still space available thereafter.  */
commit 76f469369b91a4417a67557da55003f79c1def83
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
Date:   Wed Mar 5 00:23:43 2025 +0100

    libpipe: Do not split writes on dgrem and seqpack pipes
    
    They really should not be split for the application, and really should
    not be queued several times because otherwise we would record the source
    several times and get a reference miscount.

diff --git a/libpipe/pipe.c b/libpipe/pipe.c
index 53b761d2..55ef773f 100644
--- a/libpipe/pipe.c
+++ b/libpipe/pipe.c
@@ -21,6 +21,7 @@
 #include <string.h>		/* For memset() */
 #include <assert-backtrace.h>
 #include <stdlib.h>
+#include <sys/socket.h>
 
 #include <mach/time_value.h>
 #include <mach/mach_host.h>
@@ -352,7 +353,8 @@ pipe_send (struct pipe *pipe, int noblock, void *source,
       size_t left = pipe->write_limit - pipe_readable (pipe, 1);
       if (left < data_len)
 	{
-	  if (data_len <= pipe->write_atomic)
+	  if (pipe->class->sock_type != SOCK_STREAM
+              || data_len <= pipe->write_atomic)
 	    return EWOULDBLOCK;
 	  else
 	    data_len = left;
@@ -389,19 +391,52 @@ pipe_send (struct pipe *pipe, int noblock, void *source,
   done = 0;
   do
     {
-      size_t todo = data_len - done;
-      size_t left = pipe->write_limit - pipe_readable (pipe, 1);
+      size_t todo = data_len - done, piece;
       size_t partial_amount;
 
-      if (todo > left)
-	todo = left;
+      while(1)
+	{
+	  size_t left = pipe->write_limit - pipe_readable (pipe, 1);
+
+	  piece = todo;
 
-      err = (*pipe->class->write)(pipe->queue, source, data + done, todo,
+	  if (piece > left)
+	    {
+	      if (pipe->class->sock_type == SOCK_STREAM)
+		/* Can't write it all, split.  */
+		piece = left;
+	      else
+		/* Can't write it in a single packet, wait.  */
+		piece = 0;
+	    }
+	  if (piece)
+	    /* Ok, can progress.  */
+	    break;
+
+	  if (!noblock)
+	    {
+	      /* No room, wait for people to consume enough.  */
+	      size_t amount = pipe->class->sock_type == SOCK_STREAM ? 1 : todo;
+	      err = pipe_wait_writable_amount (pipe, 0, amount);
+	      if (err)
+		break;
+	    }
+	}
+      if (err)
+	break;
+
+      err = (*pipe->class->write)(pipe->queue, source, data + done, piece,
 				  &partial_amount);
 
       if (!err)
 	{
 	  done += partial_amount;
+	  if (done < data_len)
+	    /* We are not supposed to record source in a split case, otherwise
+               we would record it several times and get spurious reference
+               releases.  */
+	    assert_backtrace (!source);
+
 	  timestamp (&pipe->write_time);
 
 	  /* And wakeup anyone that might be interested in it.  */
@@ -415,10 +450,6 @@ pipe_send (struct pipe *pipe, int noblock, void *source,
 	      pthread_cond_broadcast (&pipe->pending_read_selects);
 	      pipe_select_cond_broadcast (pipe);
 	    }
-
-	  if (!noblock && done < data_len)
-	    /* And wait for them to consume.  */
-	    err = pipe_wait_writable (pipe, 0);
 	}
     }
   while (!noblock && !err && done < data_len);
