[glib: 5/15] Implement GOutputStream::writev() and GPollableOutputStream::writev_nonblocking() GUnixOutputStream
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib: 5/15] Implement GOutputStream::writev() and GPollableOutputStream::writev_nonblocking() GUnixOutputStream
- Date: Thu, 24 Jan 2019 14:43:29 +0000 (UTC)
commit 90d9e4ab721be7b9034bbdf463226bd78421388d
Author: Sebastian Dröge <sebastian centricular com>
Date: Thu Sep 13 21:23:56 2018 +0300
Implement GOutputStream::writev() and GPollableOutputStream::writev_nonblocking() GUnixOutputStream
gio/gunixoutputstream.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 191 insertions(+)
---
diff --git a/gio/gunixoutputstream.c b/gio/gunixoutputstream.c
index 3cf96cf19..3a2350009 100644
--- a/gio/gunixoutputstream.c
+++ b/gio/gunixoutputstream.c
@@ -26,6 +26,7 @@
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
+#include <sys/uio.h>
#include <glib.h>
#include <glib/gstdio.h>
@@ -91,6 +92,12 @@ static gssize g_unix_output_stream_write (GOutputStream *stream,
gsize count,
GCancellable *cancellable,
GError **error);
+static gboolean g_unix_output_stream_writev (GOutputStream *stream,
+ const GOutputVector *vectors,
+ gsize n_vectors,
+ gsize *bytes_written,
+ GCancellable *cancellable,
+ GError **error);
static gboolean g_unix_output_stream_close (GOutputStream *stream,
GCancellable *cancellable,
GError **error);
@@ -107,6 +114,11 @@ static gboolean g_unix_output_stream_pollable_can_poll (GPollableOutputStre
static gboolean g_unix_output_stream_pollable_is_writable (GPollableOutputStream *stream);
static GSource *g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream,
GCancellable *cancellable);
+static GPollableReturn g_unix_output_stream_pollable_writev_nonblocking (GPollableOutputStream *stream,
+ const GOutputVector *vectors,
+ gsize n_vectors,
+ gsize
*bytes_written,
+ GError **error);
static void
g_unix_output_stream_class_init (GUnixOutputStreamClass *klass)
@@ -118,6 +130,7 @@ g_unix_output_stream_class_init (GUnixOutputStreamClass *klass)
gobject_class->set_property = g_unix_output_stream_set_property;
stream_class->write_fn = g_unix_output_stream_write;
+ stream_class->writev_fn = g_unix_output_stream_writev;
stream_class->close_fn = g_unix_output_stream_close;
stream_class->close_async = g_unix_output_stream_close_async;
stream_class->close_finish = g_unix_output_stream_close_finish;
@@ -159,6 +172,7 @@ g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface)
iface->can_poll = g_unix_output_stream_pollable_can_poll;
iface->is_writable = g_unix_output_stream_pollable_is_writable;
iface->create_source = g_unix_output_stream_pollable_create_source;
+ iface->writev_nonblocking = g_unix_output_stream_pollable_writev_nonblocking;
}
static void
@@ -387,6 +401,116 @@ g_unix_output_stream_write (GOutputStream *stream,
return res;
}
+/* Macro to check if struct iovec and GOutputVector have the same ABI */
+#define G_OUTPUT_VECTOR_IS_IOVEC (sizeof (struct iovec) == sizeof (GOutputVector) && \
+ sizeof ((struct iovec *) 0)->iov_base == sizeof ((GOutputVector *) 0)->buffer && \
+ G_STRUCT_OFFSET (struct iovec, iov_base) == G_STRUCT_OFFSET (GOutputVector, buffer) && \
+ sizeof ((struct iovec *) 0)->iov_len == sizeof((GOutputVector *) 0)->size && \
+ G_STRUCT_OFFSET (struct iovec, iov_len) == G_STRUCT_OFFSET (GOutputVector, size))
+
+static gboolean
+g_unix_output_stream_writev (GOutputStream *stream,
+ const GOutputVector *vectors,
+ gsize n_vectors,
+ gsize *bytes_written,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GUnixOutputStream *unix_stream;
+ gssize res = -1;
+ GPollFD poll_fds[2];
+ int nfds = 0;
+ int poll_ret;
+ struct iovec *iov;
+
+ if (bytes_written)
+ *bytes_written = 0;
+
+ /* Clamp to G_MAXINT as writev() takes an integer for the number of vectors.
+ * We handle this like a short write in this case
+ */
+ if (n_vectors > G_MAXINT)
+ n_vectors = G_MAXINT;
+
+ unix_stream = G_UNIX_OUTPUT_STREAM (stream);
+
+ if (G_OUTPUT_VECTOR_IS_IOVEC)
+ {
+ /* ABI is compatible */
+ iov = (struct iovec *) vectors;
+ }
+ else
+ {
+ gsize i;
+
+ /* ABI is incompatible */
+ iov = g_newa (struct iovec, n_vectors);
+ for (i = 0; i < n_vectors; i++)
+ {
+ iov[i].iov_base = (void *)vectors[i].buffer;
+ iov[i].iov_len = vectors[i].size;
+ }
+ }
+
+ poll_fds[0].fd = unix_stream->priv->fd;
+ poll_fds[0].events = G_IO_OUT;
+ nfds++;
+
+ if (unix_stream->priv->is_pipe_or_socket &&
+ g_cancellable_make_pollfd (cancellable, &poll_fds[1]))
+ nfds++;
+
+ while (1)
+ {
+ int errsv;
+
+ poll_fds[0].revents = poll_fds[1].revents = 0;
+ do
+ {
+ poll_ret = g_poll (poll_fds, nfds, -1);
+ errsv = errno;
+ }
+ while (poll_ret == -1 && errsv == EINTR);
+
+ if (poll_ret == -1)
+ {
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (errsv),
+ _("Error writing to file descriptor: %s"),
+ g_strerror (errsv));
+ break;
+ }
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ break;
+
+ if (!poll_fds[0].revents)
+ continue;
+
+ res = writev (unix_stream->priv->fd, iov, n_vectors);
+ errsv = errno;
+ if (res == -1)
+ {
+ if (errsv == EINTR || errsv == EAGAIN)
+ continue;
+
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (errsv),
+ _("Error writing to file descriptor: %s"),
+ g_strerror (errsv));
+ }
+
+ if (bytes_written)
+ *bytes_written = res;
+
+ break;
+ }
+
+ if (nfds == 2)
+ g_cancellable_release_fd (cancellable);
+ return res != -1;
+}
+
static gboolean
g_unix_output_stream_close (GOutputStream *stream,
GCancellable *cancellable,
@@ -494,3 +618,70 @@ g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream,
return pollable_source;
}
+
+static GPollableReturn
+g_unix_output_stream_pollable_writev_nonblocking (GPollableOutputStream *stream,
+ const GOutputVector *vectors,
+ gsize n_vectors,
+ gsize *bytes_written,
+ GError **error)
+{
+ GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
+ struct iovec *iov;
+ gssize res = -1;
+
+ if (!g_pollable_output_stream_is_writable (stream))
+ {
+ *bytes_written = 0;
+ return G_POLLABLE_RETURN_WOULD_BLOCK;
+ }
+
+ /* Clamp to G_MAXINT as writev() takes an integer for the number of vectors.
+ * We handle this like a short write in this case
+ */
+ if (n_vectors > G_MAXINT)
+ n_vectors = G_MAXINT;
+
+ if (G_OUTPUT_VECTOR_IS_IOVEC)
+ {
+ /* ABI is compatible */
+ iov = (struct iovec *) vectors;
+ }
+ else
+ {
+ gsize i;
+
+ /* ABI is incompatible */
+ iov = g_newa (struct iovec, n_vectors);
+ for (i = 0; i < n_vectors; i++)
+ {
+ iov[i].iov_base = (void *)vectors[i].buffer;
+ iov[i].iov_len = vectors[i].size;
+ }
+ }
+
+ while (1)
+ {
+ int errsv;
+
+ res = writev (unix_stream->priv->fd, iov, n_vectors);
+ errsv = errno;
+ if (res == -1)
+ {
+ if (errsv == EINTR)
+ continue;
+
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (errsv),
+ _("Error writing to file descriptor: %s"),
+ g_strerror (errsv));
+ }
+
+ if (bytes_written)
+ *bytes_written = res;
+
+ break;
+ }
+
+ return res != -1 ? G_POLLABLE_RETURN_OK : G_POLLABLE_RETURN_FAILED;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]