Add `patient_writev()` function
authorFrancis Deslauriers <francis.deslauriers@efficios.com>
Mon, 30 Mar 2020 21:45:15 +0000 (17:45 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 26 Nov 2020 18:27:49 +0000 (13:27 -0500)
This function wraps the `writev()` function to make it EINTR-aware.

We are going to use this function to send multiple structs in a single
call when dealing with event notifier captures.

This function also supports partial writes even though this should never
happen with event notifier notification. We assert that the data sent is less
then PIPE_BUF in size so to take advantage of the POSIX guarantee for
write atomicity as explained in pipe(7).

The implementation was inspired by this stackoverflow.com post:
https://stackoverflow.com/questions/5853675/techniques-for-handling-short-reads-writes-with-scatter-gather

Signed-off-by: Francis Deslauriers <francis.deslauriers@efficios.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: Ifd1def23f38ab95411fd4550858466451d0468ea

include/share.h
snprintf/patient_write.c

index 20315b26bc932d1eac77efa32bf4c7129e17f02f..9df61772451accfa0a2e8b09c64a820363019b90 100644 (file)
  */
 
 #include <stdlib.h>
+#include <sys/uio.h>
 
 ssize_t patient_write(int fd, const void *buf, size_t count);
+ssize_t patient_writev(int fd, struct iovec *iov, int iovcnt);
 ssize_t patient_send(int fd, const void *buf, size_t count, int flags);
 
 #endif /* _LTTNG_SHARE_H */
index 9bd2913f58ecbed3a9e56f4e6b5481d974f1d9d6..aa59ba1457d92ece99df4ac4daa7acc001d31e12 100644 (file)
@@ -22,6 +22,9 @@
 /* write() */
 #include <unistd.h>
 
+/* writev() */
+#include <sys/uio.h>
+
 /* send() */
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -58,6 +61,52 @@ ssize_t patient_write(int fd, const void *buf, size_t count)
        return bufc-(const char *)buf;
 }
 
+/*
+ * The `struct iovec *iov` is not `const` because we modify it to support
+ * partial writes.
+ */
+ssize_t patient_writev(int fd, struct iovec *iov, int iovcnt)
+{
+       ssize_t written, total_written = 0;
+       int curr_element_idx = 0;
+
+       for(;;) {
+               written = writev(fd, iov + curr_element_idx,
+                               iovcnt - curr_element_idx);
+               if (written == -1 && errno == EINTR) {
+                       continue;
+               }
+               if (written <= 0) {
+                       return written;
+               }
+
+               total_written += written;
+
+               /*
+                * If it's not the last element in the vector and we have
+                * written more than the current element size, then increment
+                * the current element index until we reach the element that
+                * was partially written.
+                */
+               while (curr_element_idx < iovcnt &&
+                               written >= iov[curr_element_idx].iov_len) {
+                       written -= iov[curr_element_idx].iov_len;
+                       curr_element_idx++;
+               }
+
+               /* Maybe we are done. */
+               if (curr_element_idx >= iovcnt) {
+                       break;
+               }
+
+               /* Update the current element base and size. */
+               iov[curr_element_idx].iov_base += written;
+               iov[curr_element_idx].iov_len -= written;
+       }
+
+       return total_written;
+}
+
 ssize_t patient_send(int fd, const void *buf, size_t count, int flags)
 {
        const char *bufc = (const char *) buf;
This page took 0.02705 seconds and 4 git commands to generate.