[gnome-builder/wip/gtk4-port] libide/threading: add IdeUnixFDMap
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/gtk4-port] libide/threading: add IdeUnixFDMap
- Date: Thu, 16 Jun 2022 23:29:05 +0000 (UTC)
commit 1c2ee3f95e8c078680f8429c803f6472740cd605
Author: Christian Hergert <chergert redhat com>
Date: Thu Jun 16 14:33:31 2022 -0700
libide/threading: add IdeUnixFDMap
This object is somewhat like GUnixFDList but meant to be for mapping a FD
in the current process into a FD number in a destination process. It can
be used by various subsystems (once ported off their private
implementations) by having it in libide-threading.
It includes a number of helpful features to make implementing things in
various dark corners of Builder easier. In particular it can handle all
the forms of get/steal/peek we need, opening files, and checking for
isatty() on various FDs.
src/libide/threading/ide-unix-fd-map.c | 384 ++++++++++++++++++++++++++++++++
src/libide/threading/ide-unix-fd-map.h | 84 +++++++
src/libide/threading/libide-threading.h | 1 +
src/libide/threading/meson.build | 2 +
4 files changed, 471 insertions(+)
---
diff --git a/src/libide/threading/ide-unix-fd-map.c b/src/libide/threading/ide-unix-fd-map.c
new file mode 100644
index 000000000..75946f4b7
--- /dev/null
+++ b/src/libide/threading/ide-unix-fd-map.c
@@ -0,0 +1,384 @@
+/* ide-unix-fd-map.c
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-unix-fd-map"
+
+#include "config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "ide-unix-fd-map.h"
+
+typedef struct
+{
+ int source_fd;
+ int dest_fd;
+} IdeUnixFDMapItem;
+
+struct _IdeUnixFDMap
+{
+ GObject parent_instance;
+ GArray *map;
+};
+
+G_DEFINE_FINAL_TYPE (IdeUnixFDMap, ide_unix_fd_map, G_TYPE_OBJECT)
+
+static void
+item_clear (gpointer data)
+{
+ IdeUnixFDMapItem *item = data;
+
+ item->dest_fd = -1;
+
+ if (item->source_fd != -1)
+ {
+ close (item->source_fd);
+ item->source_fd = -1;
+ }
+}
+
+static void
+ide_unix_fd_map_dispose (GObject *object)
+{
+ IdeUnixFDMap *self = (IdeUnixFDMap *)object;
+
+ if (self->map->len > 0)
+ g_array_remove_range (self->map, 0, self->map->len);
+
+ G_OBJECT_CLASS (ide_unix_fd_map_parent_class)->dispose (object);
+}
+
+static void
+ide_unix_fd_map_finalize (GObject *object)
+{
+ IdeUnixFDMap *self = (IdeUnixFDMap *)object;
+
+ g_clear_pointer (&self->map, g_array_unref);
+
+ G_OBJECT_CLASS (ide_unix_fd_map_parent_class)->finalize (object);
+}
+
+static void
+ide_unix_fd_map_class_init (IdeUnixFDMapClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = ide_unix_fd_map_dispose;
+ object_class->finalize = ide_unix_fd_map_finalize;
+}
+
+static void
+ide_unix_fd_map_init (IdeUnixFDMap *self)
+{
+ self->map = g_array_new (FALSE, FALSE, sizeof (IdeUnixFDMapItem));
+ g_array_set_clear_func (self->map, item_clear);
+}
+
+IdeUnixFDMap *
+ide_unix_fd_map_new (void)
+{
+ return g_object_new (IDE_TYPE_UNIX_FD_MAP, NULL);
+}
+
+guint
+ide_unix_fd_map_get_length (IdeUnixFDMap *self)
+{
+ g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (self), 0);
+
+ return self->map->len;
+}
+
+void
+ide_unix_fd_map_take (IdeUnixFDMap *self,
+ int source_fd,
+ int dest_fd)
+{
+ IdeUnixFDMapItem insert;
+
+ g_return_if_fail (IDE_IS_UNIX_FD_MAP (self));
+ g_return_if_fail (source_fd > -1);
+ g_return_if_fail (dest_fd > -1);
+
+ for (guint i = 0; i < self->map->len; i++)
+ {
+ IdeUnixFDMapItem *item = &g_array_index (self->map, IdeUnixFDMapItem, i);
+
+ if (item->dest_fd == dest_fd)
+ {
+ if (item->source_fd != -1)
+ close (item->source_fd);
+ item->source_fd = source_fd;
+ return;
+ }
+ }
+
+ insert.source_fd = source_fd;
+ insert.dest_fd = dest_fd;
+ g_array_append_val (self->map, insert);
+}
+
+int
+ide_unix_fd_map_steal (IdeUnixFDMap *self,
+ guint index,
+ int *dest_fd)
+{
+ IdeUnixFDMapItem *steal;
+
+ g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (self), -1);
+ g_return_val_if_fail (index < self->map->len, -1);
+
+ steal = &g_array_index (self->map, IdeUnixFDMapItem, index);
+
+ if (dest_fd != NULL)
+ *dest_fd = steal->dest_fd;
+
+ return ide_steal_fd (&steal->source_fd);
+}
+
+int
+ide_unix_fd_map_get (IdeUnixFDMap *self,
+ guint index,
+ int *dest_fd,
+ GError **error)
+{
+ IdeUnixFDMapItem *item;
+ int ret = -1;
+
+ g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (self), -1);
+ g_return_val_if_fail (index < self->map->len, -1);
+
+ item = &g_array_index (self->map, IdeUnixFDMapItem, index);
+
+ if (item->source_fd == -1)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_CLOSED,
+ "File-descriptor at index %u already stolen",
+ index);
+ return -1;
+ }
+
+ ret = dup (item->source_fd);
+
+ if (ret == -1)
+ {
+ int errsv = errno;
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (errsv),
+ g_strerror (errsv));
+ return -1;
+ }
+
+ return ret;
+}
+
+int
+ide_unix_fd_map_peek (IdeUnixFDMap *self,
+ guint index,
+ int *dest_fd)
+{
+ const IdeUnixFDMapItem *item;
+
+ g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (self), -1);
+ g_return_val_if_fail (index < self->map->len, -1);
+
+ item = &g_array_index (self->map, IdeUnixFDMapItem, index);
+
+ if (dest_fd != NULL)
+ *dest_fd = item->dest_fd;
+
+ return item->source_fd;
+}
+
+static int
+ide_unix_fd_map_peek_for_dest_fd (IdeUnixFDMap *self,
+ int dest_fd)
+{
+ g_assert (IDE_IS_UNIX_FD_MAP (self));
+ g_assert (dest_fd != -1);
+
+ for (guint i = 0; i < self->map->len; i++)
+ {
+ const IdeUnixFDMapItem *item = &g_array_index (self->map, IdeUnixFDMapItem, i);
+
+ if (item->dest_fd == dest_fd)
+ return item->source_fd;
+ }
+
+ return -1;
+}
+
+int
+ide_unix_fd_map_peek_stdin (IdeUnixFDMap *self)
+{
+ g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (self), -1);
+
+ return ide_unix_fd_map_peek_for_dest_fd (self, STDIN_FILENO);
+}
+
+int
+ide_unix_fd_map_peek_stdout (IdeUnixFDMap *self)
+{
+ g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (self), -1);
+
+ return ide_unix_fd_map_peek_for_dest_fd (self, STDOUT_FILENO);
+}
+
+int
+ide_unix_fd_map_peek_stderr (IdeUnixFDMap *self)
+{
+ g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (self), -1);
+
+ return ide_unix_fd_map_peek_for_dest_fd (self, STDERR_FILENO);
+}
+
+static int
+ide_unix_fd_map_steal_for_dest_fd (IdeUnixFDMap *self,
+ int dest_fd)
+{
+ g_assert (IDE_IS_UNIX_FD_MAP (self));
+ g_assert (dest_fd != -1);
+
+ for (guint i = 0; i < self->map->len; i++)
+ {
+ IdeUnixFDMapItem *item = &g_array_index (self->map, IdeUnixFDMapItem, i);
+
+ if (item->dest_fd == dest_fd)
+ return ide_steal_fd (&item->source_fd);
+ }
+
+ return -1;
+}
+
+int
+ide_unix_fd_map_steal_stdin (IdeUnixFDMap *self)
+{
+ g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (self), -1);
+
+ return ide_unix_fd_map_steal_for_dest_fd (self, STDIN_FILENO);
+}
+
+int
+ide_unix_fd_map_steal_stdout (IdeUnixFDMap *self)
+{
+ g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (self), -1);
+
+ return ide_unix_fd_map_steal_for_dest_fd (self, STDOUT_FILENO);
+}
+
+int
+ide_unix_fd_map_steal_stderr (IdeUnixFDMap *self)
+{
+ g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (self), -1);
+
+ return ide_unix_fd_map_steal_for_dest_fd (self, STDERR_FILENO);
+}
+
+static gboolean
+ide_unix_fd_map_isatty (IdeUnixFDMap *self,
+ int dest_fd)
+{
+ g_assert (IDE_IS_UNIX_FD_MAP (self));
+ g_assert (dest_fd != -1);
+
+ for (guint i = 0; i < self->map->len; i++)
+ {
+ const IdeUnixFDMapItem *item = &g_array_index (self->map, IdeUnixFDMapItem, i);
+
+ if (item->dest_fd == dest_fd)
+ return item->source_fd != -1 && isatty (item->source_fd);
+ }
+
+ return FALSE;
+}
+
+gboolean
+ide_unix_fd_map_stdin_isatty (IdeUnixFDMap *self)
+{
+ g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (self), FALSE);
+
+ return ide_unix_fd_map_isatty (self, STDIN_FILENO);
+}
+
+gboolean
+ide_unix_fd_map_stdout_isatty (IdeUnixFDMap *self)
+{
+ g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (self), FALSE);
+
+ return ide_unix_fd_map_isatty (self, STDOUT_FILENO);
+}
+
+gboolean
+ide_unix_fd_map_stderr_isatty (IdeUnixFDMap *self)
+{
+ g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (self), FALSE);
+
+ return ide_unix_fd_map_isatty (self, STDERR_FILENO);
+}
+
+int
+ide_unix_fd_map_get_max_dest_fd (IdeUnixFDMap *self)
+{
+ int max_dest_fd = 2;
+
+ g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (self), -1);
+
+ for (guint i = 0; i < self->map->len; i++)
+ {
+ const IdeUnixFDMapItem *item = &g_array_index (self->map, IdeUnixFDMapItem, i);
+
+ if (item->dest_fd > max_dest_fd)
+ max_dest_fd = item->dest_fd;
+ }
+
+ return max_dest_fd;
+}
+
+gboolean
+ide_unix_fd_map_open_file (IdeUnixFDMap *self,
+ const char *filename,
+ int dest_fd,
+ int mode,
+ GError **error)
+{
+ int fd;
+
+ g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (self), FALSE);
+ g_return_val_if_fail (filename != NULL, FALSE);
+ g_return_val_if_fail (dest_fd > -1, FALSE);
+
+ if (-1 == (fd = open (filename, mode)))
+ {
+ int errsv = errno;
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (errsv),
+ g_strerror (errsv));
+ return FALSE;
+ }
+
+ ide_unix_fd_map_take (self, fd, dest_fd);
+
+ return TRUE;
+}
diff --git a/src/libide/threading/ide-unix-fd-map.h b/src/libide/threading/ide-unix-fd-map.h
new file mode 100644
index 000000000..1c13bdc07
--- /dev/null
+++ b/src/libide/threading/ide-unix-fd-map.h
@@ -0,0 +1,84 @@
+/* ide-unix-fd-map.h
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#if !defined (IDE_THREADING_INSIDE) && !defined (IDE_THREADING_COMPILATION)
+# error "Only <libide-threading.h> can be included directly."
+#endif
+
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_UNIX_FD_MAP (ide_unix_fd_map_get_type())
+
+IDE_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (IdeUnixFDMap, ide_unix_fd_map, IDE, UNIX_FD_MAP, GObject)
+
+IDE_AVAILABLE_IN_ALL
+IdeUnixFDMap *ide_unix_fd_map_new (void);
+IDE_AVAILABLE_IN_ALL
+guint ide_unix_fd_map_get_length (IdeUnixFDMap *self);
+IDE_AVAILABLE_IN_ALL
+int ide_unix_fd_map_peek_stdin (IdeUnixFDMap *self);
+IDE_AVAILABLE_IN_ALL
+int ide_unix_fd_map_peek_stdout (IdeUnixFDMap *self);
+IDE_AVAILABLE_IN_ALL
+int ide_unix_fd_map_peek_stderr (IdeUnixFDMap *self);
+IDE_AVAILABLE_IN_ALL
+int ide_unix_fd_map_steal_stdin (IdeUnixFDMap *self);
+IDE_AVAILABLE_IN_ALL
+int ide_unix_fd_map_steal_stdout (IdeUnixFDMap *self);
+IDE_AVAILABLE_IN_ALL
+int ide_unix_fd_map_steal_stderr (IdeUnixFDMap *self);
+IDE_AVAILABLE_IN_ALL
+int ide_unix_fd_map_peek (IdeUnixFDMap *self,
+ guint index,
+ int *dest_fd);
+IDE_AVAILABLE_IN_ALL
+int ide_unix_fd_map_get (IdeUnixFDMap *self,
+ guint index,
+ int *dest_fd,
+ GError **error);
+IDE_AVAILABLE_IN_ALL
+int ide_unix_fd_map_steal (IdeUnixFDMap *self,
+ guint index,
+ int *dest_fd);
+IDE_AVAILABLE_IN_ALL
+void ide_unix_fd_map_take (IdeUnixFDMap *self,
+ int source_fd,
+ int dest_fd);
+IDE_AVAILABLE_IN_ALL
+gboolean ide_unix_fd_map_open_file (IdeUnixFDMap *self,
+ const char *filename,
+ int mode,
+ int dest_fd,
+ GError **error);
+IDE_AVAILABLE_IN_ALL
+int ide_unix_fd_map_get_max_dest_fd (IdeUnixFDMap *self);
+IDE_AVAILABLE_IN_ALL
+gboolean ide_unix_fd_map_stdin_isatty (IdeUnixFDMap *self);
+IDE_AVAILABLE_IN_ALL
+gboolean ide_unix_fd_map_stdout_isatty (IdeUnixFDMap *self);
+IDE_AVAILABLE_IN_ALL
+gboolean ide_unix_fd_map_stderr_isatty (IdeUnixFDMap *self);
+
+G_END_DECLS
diff --git a/src/libide/threading/libide-threading.h b/src/libide/threading/libide-threading.h
index c085137f6..55a0f2fe5 100644
--- a/src/libide/threading/libide-threading.h
+++ b/src/libide/threading/libide-threading.h
@@ -32,5 +32,6 @@
#include "ide-subprocess.h"
#include "ide-task.h"
#include "ide-thread-pool.h"
+#include "ide-unix-fd-map.h"
#undef IDE_THREADING_INSIDE
diff --git a/src/libide/threading/meson.build b/src/libide/threading/meson.build
index c9e9e99cd..01a7a33a9 100644
--- a/src/libide/threading/meson.build
+++ b/src/libide/threading/meson.build
@@ -14,6 +14,7 @@ libide_threading_public_headers = [
'ide-subprocess-supervisor.h',
'ide-task.h',
'ide-thread-pool.h',
+ 'ide-unix-fd-map.h',
'libide-threading.h',
]
@@ -45,6 +46,7 @@ libide_threading_public_sources = [
'ide-subprocess.c',
'ide-task.c',
'ide-thread-pool.c',
+ 'ide-unix-fd-map.c',
]
libide_threading_sources = libide_threading_public_sources + libide_threading_private_sources
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]