X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fglib-unix.c;h=b768e0b4749454ee696796a9df3900daf5840913;hb=ea4f9ce8a060d53cbc299e4c384089f6cc926caa;hp=4006a0d4a0e561c2123849a4a0e3e9f7ea1a2198;hpb=0ff211f520c18550454289e7265061d7e8ac41c0;p=platform%2Fupstream%2Fglib.git diff --git a/glib/glib-unix.c b/glib/glib-unix.c index 4006a0d..b768e0b 100644 --- a/glib/glib-unix.c +++ b/glib/glib-unix.c @@ -1,7 +1,7 @@ /* GLIB - Library of useful routines for C programming * Copyright (C) 2011 Red Hat, Inc. * - * glib-unix.c: Unix specific API wrappers and convenience functions + * 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 @@ -10,91 +10,110 @@ * * 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 + * 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. + * License along with this library; if not, see . * * Authors: Colin Walters */ #include "config.h" +/* To make bionic export pipe2() */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + #include "glib-unix.h" +#include "gmain-internal.h" #include +#include +#include +#include + +#ifdef __linux__ + +/* We want to support these features of Linux even when building GLib + * against older versions of system headers. This will allow us to + * 'automatically' start supporting a particular feature when GLib is + * used with a newer kernel, without recompile. + * + * This means that we're not changing functionality of GLib simply based + * on the set of headers we happen to compile against... + */ + +#ifndef F_LINUX_SPECIFIC_BASE +#define F_LINUX_SPECIFIC_BASE 1024 +#endif + +#ifndef F_ADD_SEALS +#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) +#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) + +#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ +#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ +#define F_SEAL_GROW 0x0004 /* prevent file from growing */ +#define F_SEAL_WRITE 0x0008 /* prevent writes */ +#endif + +#endif + /** * SECTION:gunix - * @short_description: Unix-specific utilities and integration + * @title: UNIX-specific utilities and integration + * @short_description: pipes, signal handling * @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 + * Most of GLib is intended to be portable; in contrast, 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; -} +G_DEFINE_QUARK (g-unix-error-quark, g_unix_error) static gboolean -g_unix_set_error_from_errno_saved (GError **error, - int saved_errno) +g_unix_set_error_from_errno (GError **error, + gint saved_errno) { g_set_error_literal (error, - G_UNIX_ERROR, - 0, - g_strerror (saved_errno)); + G_UNIX_ERROR, + 0, + g_strerror (saved_errno)); errno = saved_errno; return FALSE; } /** - * g_unix_pipe_flags: + * g_unix_open_pipe: * @fds: Array of two integers - * @flags: Bitfield of file descriptor flags, see "man 2 fcntl" + * @flags: Bitfield of file descriptor flags, as for 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(). + * 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. + * 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) +g_unix_open_pipe (int *fds, + int flags, + GError **error) { int ecode; @@ -109,27 +128,386 @@ g_unix_pipe_flags (int *fds, /* Atomic */ ecode = pipe2 (fds, pipe2_flags); if (ecode == -1 && errno != ENOSYS) - return g_unix_set_error_from_errno (error); + return g_unix_set_error_from_errno (error, errno); + else if (ecode == 0) + return TRUE; /* 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); + return g_unix_set_error_from_errno (error, errno); + + if (flags == 0) + return TRUE; + + ecode = fcntl (fds[0], F_SETFD, flags); if (ecode == -1) { int saved_errno = errno; close (fds[0]); - return g_unix_set_error_from_errno_saved (error, saved_errno); + close (fds[1]); + return g_unix_set_error_from_errno (error, saved_errno); } - ecode = fcntl (fds[0], flags); + ecode = fcntl (fds[1], F_SETFD, 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 g_unix_set_error_from_errno (error, saved_errno); + } + return TRUE; +} + +/** + * g_unix_set_fd_nonblocking: + * @fd: A file descriptor + * @nonblock: If %TRUE, set the descriptor to be non-blocking + * @error: a #GError + * + * Control the non-blocking state of the given file descriptor, + * according to @nonblock. On most systems this uses %O_NONBLOCK, but + * on some older ones may use %O_NDELAY. + * + * Returns: %TRUE if successful + * + * Since: 2.30 + */ +gboolean +g_unix_set_fd_nonblocking (gint fd, + gboolean nonblock, + GError **error) +{ +#ifdef F_GETFL + glong fcntl_flags; + fcntl_flags = fcntl (fd, F_GETFL); + + if (fcntl_flags == -1) + return g_unix_set_error_from_errno (error, errno); + + if (nonblock) + { +#ifdef O_NONBLOCK + fcntl_flags |= O_NONBLOCK; +#else + fcntl_flags |= O_NDELAY; +#endif + } + else + { +#ifdef O_NONBLOCK + fcntl_flags &= ~O_NONBLOCK; +#else + fcntl_flags &= ~O_NDELAY; +#endif + } + + if (fcntl (fd, F_SETFL, fcntl_flags) == -1) + return g_unix_set_error_from_errno (error, errno); + return TRUE; +#else + return g_unix_set_error_from_errno (error, EINVAL); +#endif +} + +/** + * g_unix_signal_source_new: + * @signum: A signal number + * + * Create a #GSource that will be dispatched upon delivery of the UNIX + * signal @signum. In GLib versions before 2.36, only `SIGHUP`, `SIGINT`, + * `SIGTERM` can be monitored. In GLib 2.36, `SIGUSR1` and `SIGUSR2` + * were added. + * + * Note that unlike the UNIX default, all sources which have created a + * watch will be dispatched, regardless of which underlying thread + * invoked g_unix_signal_source_new(). + * + * For example, an effective use of this function is to handle `SIGTERM` + * cleanly; flushing any outstanding files, and then calling + * g_main_loop_quit (). It is not safe to do any of this a regular + * UNIX signal handler; your handler may be invoked while malloc() or + * another library function is running, causing reentrancy if you + * attempt to use it from the handler. None of the GLib/GObject API + * is safe against this kind of reentrancy. + * + * The interaction of this source when combined with native UNIX + * functions like sigprocmask() is not defined. + * + * The source will not initially be associated with any #GMainContext + * and must be added to one with g_source_attach() before it will be + * executed. + * + * Returns: A newly created #GSource + * + * Since: 2.30 + */ +GSource * +g_unix_signal_source_new (int signum) +{ + g_return_val_if_fail (signum == SIGHUP || signum == SIGINT || signum == SIGTERM || + signum == SIGUSR1 || signum == SIGUSR2, NULL); + + return _g_main_create_unix_signal_watch (signum); +} + +/** + * g_unix_signal_add_full: + * @priority: the priority of the signal source. Typically this will be in + * the range between #G_PRIORITY_DEFAULT and #G_PRIORITY_HIGH. + * @signum: Signal number + * @handler: Callback + * @user_data: Data for @handler + * @notify: #GDestroyNotify for @handler + * + * A convenience function for g_unix_signal_source_new(), which + * attaches to the default #GMainContext. You can remove the watch + * using g_source_remove(). + * + * Returns: An ID (greater than 0) for the event source + * + * Rename to: g_unix_signal_add + * Since: 2.30 + */ +guint +g_unix_signal_add_full (int priority, + int signum, + GSourceFunc handler, + gpointer user_data, + GDestroyNotify notify) +{ + guint id; + GSource *source; + + source = g_unix_signal_source_new (signum); + + if (priority != G_PRIORITY_DEFAULT) + g_source_set_priority (source, priority); + + g_source_set_callback (source, handler, user_data, notify); + id = g_source_attach (source, NULL); + g_source_unref (source); + + return id; +} + +/** + * g_unix_signal_add: + * @signum: Signal number + * @handler: Callback + * @user_data: Data for @handler + * + * A convenience function for g_unix_signal_source_new(), which + * attaches to the default #GMainContext. You can remove the watch + * using g_source_remove(). + * + * Returns: An ID (greater than 0) for the event source + * + * Since: 2.30 + */ +guint +g_unix_signal_add (int signum, + GSourceFunc handler, + gpointer user_data) +{ + return g_unix_signal_add_full (G_PRIORITY_DEFAULT, signum, handler, user_data, NULL); +} + +typedef struct +{ + GSource source; + + gint fd; + gpointer tag; +} GUnixFDSource; + +static gboolean +g_unix_fd_source_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + GUnixFDSource *fd_source = (GUnixFDSource *) source; + GUnixFDSourceFunc func = (GUnixFDSourceFunc) callback; + + if (!callback) + { + g_warning ("GUnixFDSource dispatched without callback\n" + "You must call g_source_set_callback()."); + return FALSE; + } + + return (* func) (fd_source->fd, g_source_query_unix_fd (source, fd_source->tag), user_data); +} + +GSourceFuncs g_unix_fd_source_funcs = { + NULL, NULL, g_unix_fd_source_dispatch, NULL +}; + +/** + * g_unix_fd_source_new: + * @fd: a file descriptor + * @condition: IO conditions to watch for on @fd + * + * Creates a #GSource to watch for a particular IO condition on a file + * descriptor. + * + * The source will never close the fd -- you must do it yourself. + * + * Returns: the newly created #GSource + * + * Since: 2.36 + **/ +GSource * +g_unix_fd_source_new (gint fd, + GIOCondition condition) +{ + GUnixFDSource *fd_source; + GSource *source; + + source = g_source_new (&g_unix_fd_source_funcs, sizeof (GUnixFDSource)); + fd_source = (GUnixFDSource *) source; + + fd_source->fd = fd; + fd_source->tag = g_source_add_unix_fd (source, fd, condition); + + return source; +} + +/** + * g_unix_fd_add_full: + * @priority: the priority of the source + * @fd: a file descriptor + * @condition: IO conditions to watch for on @fd + * @function: a #GUnixFDSourceFunc + * @user_data: data to pass to @function + * @notify: function to call when the idle is removed, or %NULL + * + * Sets a function to be called when the IO condition, as specified by + * @condition becomes true for @fd. + * + * This is the same as g_unix_fd_add(), except that it allows you to + * specify a non-default priority and a provide a #GDestroyNotify for + * @user_data. + * + * Returns: the ID (greater than 0) of the event source + * + * Since: 2.36 + **/ +guint +g_unix_fd_add_full (gint priority, + gint fd, + GIOCondition condition, + GUnixFDSourceFunc function, + gpointer user_data, + GDestroyNotify notify) +{ + GSource *source; + guint id; + + g_return_val_if_fail (function != NULL, 0); + + source = g_unix_fd_source_new (fd, condition); + + if (priority != G_PRIORITY_DEFAULT) + g_source_set_priority (source, priority); + + g_source_set_callback (source, (GSourceFunc) function, user_data, notify); + id = g_source_attach (source, NULL); + g_source_unref (source); + + return id; +} + +/** + * g_unix_fd_add: + * @fd: a file descriptor + * @condition: IO conditions to watch for on @fd + * @function: a #GPollFDFunc + * @user_data: data to pass to @function + * + * Sets a function to be called when the IO condition, as specified by + * @condition becomes true for @fd. + * + * @function will be called when the specified IO condition becomes + * %TRUE. The function is expected to clear whatever event caused the + * IO condition to become true and return %TRUE in order to be notified + * when it happens again. If @function returns %FALSE then the watch + * will be cancelled. + * + * The return value of this function can be passed to g_source_remove() + * to cancel the watch at any time that it exists. + * + * The source will never close the fd -- you must do it yourself. + * + * Returns: the ID (greater than 0) of the event source + * + * Since: 2.36 + **/ +guint +g_unix_fd_add (gint fd, + GIOCondition condition, + GUnixFDSourceFunc function, + gpointer user_data) +{ + return g_unix_fd_add_full (G_PRIORITY_DEFAULT, fd, condition, function, user_data, NULL); +} + +/** + * g_unix_fd_ensure_zero_copy_safe: + * @fd: a file descriptor + * + * Checks whether @fd can be use in zero-copy mode. On Linux, this checks that + * the descriptor is a memfd, created with memfd_create(), and tries to apply + * seals to it so that it can be safely consumed by another process. On other + * Unix systems, this function will fail. + * + * Returns: whether the fd is safe to use in zero-copy mode. Sealing of memfds + * is required for the @fd to be considered safe. If sealing fails, or + * memfds are not available, or the @fd is not a memfd, returns %FALSE + * + * Since: 2.44 + **/ +gboolean +g_unix_fd_ensure_zero_copy_safe (gint fd) +{ +#ifdef F_GET_SEALS + gint seals; + const gint IMMUTABLE_SEALS = F_SEAL_WRITE | + F_SEAL_SHRINK | + F_SEAL_GROW | + F_SEAL_SEAL; + + g_return_val_if_fail (fd >= 0, FALSE); + + /* Seal the fd if possible (only on Linux 3.17+, and if the fd was created + * with memfd_create()). */ + seals = fcntl (fd, F_GET_SEALS); + if (seals == -1) + { + g_debug ("Retrieving fd seals failed: %s", g_strerror (errno)); + return FALSE; } + + /* Seal the fd, if it is not already. */ + if ((seals & (IMMUTABLE_SEALS)) >= IMMUTABLE_SEALS) + { + g_debug ("%s", "fd already sealed"); + } + else + { + gint error; + + error = fcntl (fd, F_ADD_SEALS, IMMUTABLE_SEALS); + if (error == -1) + { + g_debug ("fd sealing failed: %s", g_strerror (errno)); + return FALSE; + } + } + return TRUE; +#else + return FALSE; +#endif }