[glib] glib-unix: New Unix-specific API
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] glib-unix: New Unix-specific API
- Date: Wed, 27 Apr 2011 20:01:53 +0000 (UTC)
commit 0ff211f520c18550454289e7265061d7e8ac41c0
Author: Colin Walters <walters verbum org>
Date: Wed Mar 16 13:54:28 2011 -0400
glib-unix: New Unix-specific API
GLib historically has been designed to be "mostly" portable; there
are some functions only available on Unix like g_io_channel_unix_new(),
but these are typically paired with obvious counterparts for Win32.
However, as GLib is used not only by portable software, but components
targeting Unix (or even just Linux), there are a few cases where it
would be very convenient if GLib shipped built-in functionality.
This initial patch is a basic wrapper around pipe2(), including
fallbacks for older kernels. This pairs well with the
existing g_spawn_*() API and its child_setup functionality.
However, in the future, I want to add a signal() wrapper here,
complete with proxying the signal to a mainloop. I have initial code
for this, but doing it sanely (including factoring out gmain.c's
private worker thread), is a complex task, and I don't want to block
on that.
See also gwin32.h for Win32 specific functionality.
https://bugzilla.gnome.org/show_bug.cgi?id=644941
docs/reference/glib/glib-sections.txt | 8 ++
glib/Makefile.am | 7 ++
glib/glib-unix.c | 135 +++++++++++++++++++++++++++++++++
glib/glib-unix.h | 70 +++++++++++++++++
glib/glib.symbols | 9 ++
glib/gmain.c | 30 +++-----
glib/tests/Makefile.am | 3 +
glib/tests/unix.c | 60 +++++++++++++++
8 files changed, 302 insertions(+), 20 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 037f577..9873393 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -1924,6 +1924,14 @@ g_win32_ftruncate
</SECTION>
+<SECTION>
+<TITLE>UNIX Compatibility Functions</TITLE>
+<FILE>gunix</FILE>
+G_UNIX_ERROR
+g_unix_pipe_flags
+
+</SECTION>
+
# Data Structures
<SECTION>
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 6c53e17..ba76729 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -206,6 +206,9 @@ libglib_2_0_la_SOURCES = \
gprintf.c \
gprintfint.h
+if OS_UNIX
+libglib_2_0_la_SOURCES += glib-unix.c
+endif
EXTRA_libglib_2_0_la_SOURCES = \
giounix.c \
@@ -219,6 +222,10 @@ glibinclude_HEADERS = \
glib-object.h \
glib.h
+if OS_UNIX
+glibinclude_HEADERS += glib-unix.h
+endif
+
glibsubincludedir=$(includedir)/glib-2.0/glib
glibsubinclude_HEADERS = \
galloca.h \
diff --git a/glib/glib-unix.c b/glib/glib-unix.c
new file mode 100644
index 0000000..4006a0d
--- /dev/null
+++ b/glib/glib-unix.c
@@ -0,0 +1,135 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * glib-unix.c: Unix specific API wrappers and convenience functions
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Colin Walters <walters verbum org>
+ */
+
+#include "config.h"
+
+#include "glib-unix.h"
+
+#include <string.h>
+
+/**
+ * SECTION:gunix
+ * @short_description: Unix-specific utilities and integration
+ * @include: glib-unix.h
+ *
+ * Most of GLib is intended to be portable; in constrast, this set of
+ * functions is designed for programs which explicitly target UNIX, or
+ * are using it to build higher level abstractions which would be
+ * conditionally compiled if the platform matches G_OS_UNIX.
+ *
+ * To use these functions, you must explicitly include the
+ * "glib-unix.h" header.
+ */
+
+GQuark
+g_unix_error_quark (void)
+{
+ return g_quark_from_static_string ("g-unix-error-quark");
+}
+
+static gboolean
+g_unix_set_error_from_errno (GError **error)
+{
+ int saved_errno = errno;
+ g_set_error_literal (error,
+ G_UNIX_ERROR,
+ 0,
+ g_strerror (errno));
+ errno = saved_errno;
+ return FALSE;
+}
+
+static gboolean
+g_unix_set_error_from_errno_saved (GError **error,
+ int saved_errno)
+{
+ g_set_error_literal (error,
+ G_UNIX_ERROR,
+ 0,
+ g_strerror (saved_errno));
+ errno = saved_errno;
+ return FALSE;
+}
+
+/**
+ * g_unix_pipe_flags:
+ * @fds: Array of two integers
+ * @flags: Bitfield of file descriptor flags, see "man 2 fcntl"
+ * @error: a #GError
+ *
+ * Similar to the Unix pipe() call, but on modern systems like
+ * Linux uses the pipe2 system call, which atomically creates
+ * a pipe with the configured flags. The only supported flag
+ * currently is FD_CLOEXEC. If for example you want to configure
+ * O_NONBLOCK, that must still be done separately with fcntl().
+ *
+ * Note in particular this function does *not* take O_CLOEXEC, it
+ * takes FD_CLOEXEC as if for fcntl(); these are different on
+ * Linux/glibc.
+ *
+ * Returns: %TRUE on success, %FALSE if not (and errno will be set).
+ *
+ * Since: 2.30
+ */
+gboolean
+g_unix_pipe_flags (int *fds,
+ int flags,
+ GError **error)
+{
+ int ecode;
+
+ /* We only support FD_CLOEXEC */
+ g_return_val_if_fail ((flags & (FD_CLOEXEC)) == flags, FALSE);
+
+#ifdef HAVE_PIPE2
+ {
+ int pipe2_flags = 0;
+ if (flags & FD_CLOEXEC)
+ pipe2_flags |= O_CLOEXEC;
+ /* Atomic */
+ ecode = pipe2 (fds, pipe2_flags);
+ if (ecode == -1 && errno != ENOSYS)
+ return g_unix_set_error_from_errno (error);
+ /* Fall through on -ENOSYS, we must be running on an old kernel */
+ }
+#endif
+ ecode = pipe (fds);
+ if (ecode == -1)
+ return g_unix_set_error_from_errno (error);
+ ecode = fcntl (fds[0], flags);
+ if (ecode == -1)
+ {
+ int saved_errno = errno;
+ close (fds[0]);
+ return g_unix_set_error_from_errno_saved (error, saved_errno);
+ }
+ ecode = fcntl (fds[0], flags);
+ if (ecode == -1)
+ {
+ int saved_errno = errno;
+ close (fds[0]);
+ close (fds[1]);
+ return g_unix_set_error_from_errno_saved (error, saved_errno);
+ }
+ return TRUE;
+}
diff --git a/glib/glib-unix.h b/glib/glib-unix.h
new file mode 100644
index 0000000..f2f784d
--- /dev/null
+++ b/glib/glib-unix.h
@@ -0,0 +1,70 @@
+/* glib-unix.h - Unix specific integration
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __G_UNIX_H__
+#define __G_UNIX_H__
+
+/* We need to include the UNIX headers needed to use the APIs below,
+ * but we also take this opportunity to include a wide selection of
+ * other UNIX headers. If one of the headers below is broken on some
+ * system, work around it here (or better, fix the system or tell
+ * people to use a better one).
+ */
+#ifndef _GNU_SOURCE
+#define _G_GNU_SOURCE_TEMPORARILY_DEFINED
+#define _GNU_SOURCE
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#ifdef _G_GNU_SOURCE_TEMPORARILY_DEFINED
+#undef _GNU_SOURCE
+#undef _G_GNU_SOURCE_TEMPORARILY_DEFINED
+#endif
+
+#include <glib.h>
+
+/**
+ * G_UNIX_ERROR:
+ *
+ * Error domain for API in the "g_unix_" namespace. Note that there
+ * is no exported enumeration mapping "errno". Instead, all functions
+ * ensure that "errno" is relevant. The code for all G_UNIX_ERROR is
+ * always 0, and the error message is always generated via
+ * g_strerror().
+ *
+ * It is expected that most code will not look at "errno" from these
+ * APIs. Important cases where one would want to differentiate between
+ * errors are already covered by existing cross-platform GLib API,
+ * such as e.g. GFile wrapping "ENOENT". However, it is provided for
+ * completeness, at least.
+ */
+#define G_UNIX_ERROR (g_unix_error_quark())
+
+GQuark g_unix_error_quark (void);
+
+gboolean g_unix_pipe_flags (int *fds,
+ int flags,
+ GError **error);
+
+#endif
diff --git a/glib/glib.symbols b/glib/glib.symbols
index 6c86667..be3acfa 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -1978,6 +1978,15 @@ g_hostname_to_unicode
#endif
#endif
+#if IN_HEADER(__G_UNIX_H__)
+#if IN_FILE(__G_UNIX_C__)
+#ifdef G_OS_UNIX
+g_unix_pipe_flags
+g_unix_error_quark
+#endif
+#endif
+#endif
+
#ifdef INCLUDE_VARIABLES
g_ascii_table
g_utf8_skip
diff --git a/glib/gmain.c b/glib/gmain.c
index 718c36c..c045e1c 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -62,6 +62,10 @@
#define G_MAIN_POLL_DEBUG
#endif
+#ifdef G_OS_UNIX
+#include "glib-unix.h"
+#endif
+
#include <signal.h>
#include <sys/types.h>
#include <time.h>
@@ -84,11 +88,6 @@
#include <sys/wait.h>
#endif /* G_OS_BEOS */
-#ifdef G_OS_UNIX
-#include <fcntl.h>
-#include <sys/wait.h>
-#endif
-
#include "gmain.h"
#include "garray.h"
@@ -515,23 +514,14 @@ g_main_context_unref (GMainContext *context)
static void
g_main_context_init_pipe (GMainContext *context)
{
+ GError *error = NULL;
+
# ifndef G_OS_WIN32
if (context->wake_up_pipe[0] != -1)
return;
-#ifdef HAVE_PIPE2
- /* if this fails, we fall through and try pipe */
- pipe2 (context->wake_up_pipe, O_CLOEXEC);
-#endif
- if (context->wake_up_pipe[0] == -1)
- {
- if (pipe (context->wake_up_pipe) < 0)
- g_error ("Cannot create pipe main loop wake-up: %s\n",
- g_strerror (errno));
-
- fcntl (context->wake_up_pipe[0], F_SETFD, FD_CLOEXEC);
- fcntl (context->wake_up_pipe[1], F_SETFD, FD_CLOEXEC);
- }
+ if (!g_unix_pipe_flags (context->wake_up_pipe, FD_CLOEXEC, &error))
+ g_error ("Cannot create pipe main loop wake-up: %s", error->message);
context->wake_up_rec.fd = context->wake_up_pipe[0];
context->wake_up_rec.events = G_IO_IN;
@@ -4334,8 +4324,8 @@ g_child_watch_source_init_multi_threaded (void)
g_assert (g_thread_supported());
- if (pipe (child_watch_wake_up_pipe) < 0)
- g_error ("Cannot create wake up pipe: %s\n", g_strerror (errno));
+ if (!g_unix_pipe_flags (child_watch_wake_up_pipe, FD_CLOEXEC, &error))
+ g_error ("Cannot create wake up pipe: %s\n", error->message);
fcntl (child_watch_wake_up_pipe[1], F_SETFL, O_NONBLOCK | fcntl (child_watch_wake_up_pipe[1], F_GETFL));
/* We create a helper thread that polls on the wakeup pipe indefinitely */
diff --git a/glib/tests/Makefile.am b/glib/tests/Makefile.am
index ea7da1f..ca42eb4 100644
--- a/glib/tests/Makefile.am
+++ b/glib/tests/Makefile.am
@@ -170,6 +170,9 @@ sort_LDADD = $(progs_ldadd)
if OS_UNIX
+TEST_PROGS += unix
+unix_LDADD = $(progs_ldadd)
+
# some testing of gtester funcitonality
XMLLINT=xmllint
gtester-xmllint-check: # check testreport xml with xmllint if present
diff --git a/glib/tests/unix.c b/glib/tests/unix.c
new file mode 100644
index 0000000..2dc2364
--- /dev/null
+++ b/glib/tests/unix.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This work is provided "as is"; redistribution and modification
+ * in whole or in part, in any medium, physical or electronic is
+ * permitted without restriction.
+ *
+ * This work 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.
+ *
+ * In no event shall the authors or contributors be liable for any
+ * direct, indirect, incidental, special, exemplary, or consequential
+ * damages (including, but not limited to, procurement of substitute
+ * goods or services; loss of use, data, or profits; or business
+ * interruption) however caused and on any theory of liability, whether
+ * in contract, strict liability, or tort (including negligence or
+ * otherwise) arising in any way out of the use of this software, even
+ * if advised of the possibility of such damage.
+ *
+ * Author: Colin Walters <walters verbum org>
+ */
+
+#include "config.h"
+
+#include "glib-unix.h"
+#include <string.h>
+
+static void
+test_pipe (void)
+{
+ GError *error = NULL;
+ int pipefd[2];
+ char buf[1024];
+ ssize_t bytes_read;
+
+ g_unix_pipe_flags (pipefd, FD_CLOEXEC, NULL);
+ g_assert_no_error (error);
+
+ write (pipefd[1], "hello", sizeof ("hello"));
+ memset (buf, 0, sizeof (buf));
+ bytes_read = read (pipefd[0], buf, sizeof(buf) - 1);
+ g_assert_cmpint (bytes_read, >, 0);
+
+ close (pipefd[0]);
+ close (pipefd[1]);
+
+ g_assert (g_str_has_prefix (buf, "hello"));
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/glib-unix/pipe", test_pipe);
+
+ return g_test_run();
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]