[glib/th/gspawn-no-safe-close: 2/4] gutilsprivate: add safe_close() and safe_close_with_error() helper




commit 152995a6b02866e1e7e2267439270df3987a5e74
Author: Thomas Haller <thaller redhat com>
Date:   Tue Oct 18 08:42:08 2022 +0200

    gutilsprivate: add safe_close() and safe_close_with_error() helper

 glib/gutils.c        | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 glib/gutilsprivate.h |  4 +++
 2 files changed, 96 insertions(+)
---
diff --git a/glib/gutils.c b/glib/gutils.c
index 78ccd61214..a2c09986ab 100644
--- a/glib/gutils.c
+++ b/glib/gutils.c
@@ -3246,3 +3246,95 @@ g_abort (void)
   ExitProcess (127);
 }
 #endif
+
+/**
+ * _g_safe_close_with_error:
+ * fd: the file descriptor to close.
+ *
+ * This function is async-signal-safe (except assertion failures), so it can be used from a
+ * signal handler or between fork and exec.
+ *
+ * While this function returns an error result, in most cases there isn't
+ * much you want to do about it. See `man 3 close`. Probably you should use
+ * _g_safe_close() wrapper instead.
+ *
+ * This handles EINTR internally (currently by ignoring it and signaling success).
+ *
+ * It asserts against EBADF (which itself is not async-signal-safe, but in case
+ * of an assertion failure, all bets are already off).
+ *
+ * The function may change errno.
+ *
+ * Returns: zero on success, or a negative errno.
+ */
+int
+_g_safe_close_with_error (int fd)
+{
+  int errsv;
+  int r;
+
+  r = close (fd);
+
+  if (r == 0)
+    return 0;
+
+  errsv = errno;
+
+  if (errsv == EINTR)
+    {
+      /* Just ignore EINTR for now; a retry loop is the wrong thing to do
+       * on Linux at least.  Anyone who wants to add a conditional check
+       * for e.g. HP-UX is welcome to do so later...
+       *
+       * https://lwn.net/Articles/576478/
+       * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
+       * https://bugzilla.gnome.org/show_bug.cgi?id=682819
+       * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
+       * 
https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
+       */
+      return 0;
+    }
+
+  if (errsv == EBADF)
+    {
+      /* There is a bug. Fail and assertion. Note that this function is supposed to be
+       * async-signal-safe, but in case an assertion fails, that is not the case! */
+      if (fd >= 0)
+        {
+          /* Closing an non-negative, invalid file descriptor is a bug. The bug is
+           * not necessarily in the caller of g_close(), but somebody else
+           * might have wrongly closed fd. In any case, there is a serious bug
+           * somewhere. */
+          g_critical ("g_close(fd:%d) failed with EBADF. The tracking of file descriptors got messed up", 
fd);
+        }
+      else
+        {
+          g_critical ("g_close(fd:%d) failed with EBADF. This is not a valid file descriptor", fd);
+        }
+    }
+
+  return -errsv;
+}
+
+/**
+ * _g_safe_close:
+ * fd: the file descriptor to close.
+ *
+ * This wraps _g_safe_close_with_error(), so everything said there applies.
+ * Additionally:
+ *
+ * This function returns no error. In most cases, there is nothing to handle about
+ * failures of close (see `man 3 close`). In most cases, use _g_safe_close() instead
+ * of _g_safe_close_with_error().
+ *
+ * The function promises not to change errno.
+ */
+void
+_g_safe_close (int fd)
+{
+  int errsv;
+
+  errsv = errno;
+  _g_safe_close_with_error (fd);
+  errno = errsv;
+}
diff --git a/glib/gutilsprivate.h b/glib/gutilsprivate.h
index 77bed4e87b..a0ae28dfd4 100644
--- a/glib/gutilsprivate.h
+++ b/glib/gutilsprivate.h
@@ -54,6 +54,10 @@ g_nearest_pow (gsize num)
   return n + 1;
 }
 
+int _g_safe_close_with_error (int fd);
+
+void _g_safe_close (int fd);
+
 G_END_DECLS
 
 #endif /* __G_UTILS_PRIVATE_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]