From 9fe043d73a3e2112f859ce1fa489021a96efecc9 Mon Sep 17 00:00:00 2001 From: Francis Deslauriers Date: Mon, 30 Mar 2020 17:45:15 -0400 Subject: [PATCH] Add `patient_writev()` function 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 Signed-off-by: Mathieu Desnoyers Change-Id: Ifd1def23f38ab95411fd4550858466451d0468ea --- include/share.h | 2 ++ snprintf/patient_write.c | 49 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/include/share.h b/include/share.h index 20315b26..9df61772 100644 --- a/include/share.h +++ b/include/share.h @@ -24,8 +24,10 @@ */ #include +#include 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 */ diff --git a/snprintf/patient_write.c b/snprintf/patient_write.c index 9bd2913f..aa59ba14 100644 --- a/snprintf/patient_write.c +++ b/snprintf/patient_write.c @@ -22,6 +22,9 @@ /* write() */ #include +/* writev() */ +#include + /* send() */ #include #include @@ -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; -- 2.34.1