X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fglib-unix.c;h=b768e0b4749454ee696796a9df3900daf5840913;hb=ea4f9ce8a060d53cbc299e4c384089f6cc926caa;hp=14a2ef3101936683b527d43cc2eead34f74518fa;hpb=d35e83d3372ca484a765dfca2ded8ed5adb61e5a;p=platform%2Fupstream%2Fglib.git diff --git a/glib/glib-unix.c b/glib/glib-unix.c index 14a2ef3..b768e0b 100644 --- a/glib/glib-unix.c +++ b/glib/glib-unix.c @@ -14,56 +14,74 @@ * 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 * @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"); -} +G_DEFINE_QUARK (g-unix-error-quark, g_unix_error) 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_unix_set_error_from_errno (GError **error, + gint saved_errno) { g_set_error_literal (error, G_UNIX_ERROR, @@ -76,18 +94,17 @@ g_unix_set_error_from_errno_saved (GError **error, /** * 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(). + * 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(). * - * 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). * @@ -111,7 +128,7 @@ g_unix_open_pipe (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 */ @@ -119,21 +136,26 @@ g_unix_open_pipe (int *fds, #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; } @@ -145,7 +167,7 @@ g_unix_open_pipe (int *fds, * @error: a #GError * * Control the non-blocking state of the given file descriptor, - * according to @nonblock. On most systems this uses %O_NONBLOCK, but + * according to @nonblock. On most systems this uses %O_NONBLOCK, but * on some older ones may use %O_NDELAY. * * Returns: %TRUE if successful @@ -162,7 +184,7 @@ g_unix_set_fd_nonblocking (gint fd, fcntl_flags = fcntl (fd, F_GETFL); if (fcntl_flags == -1) - return g_unix_set_error_from_errno (error); + return g_unix_set_error_from_errno (error, errno); if (nonblock) { @@ -182,25 +204,27 @@ g_unix_set_fd_nonblocking (gint fd, } if (fcntl (fd, F_SETFL, fcntl_flags) == -1) - return g_unix_set_error_from_errno (error); + return g_unix_set_error_from_errno (error, errno); return TRUE; #else - return g_unix_set_error_from_errno_saved (error, EINVAL); + 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. Currently only %SIGHUP, %SIGINT, and %SIGTERM can - * be monitored. 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_create_watch(). + * signal @signum. In GLib versions before 2.36, only `SIGHUP`, `SIGINT`, + * `SIGTERM` can be monitored. In GLib 2.36, `SIGUSR1` and `SIGUSR2` + * were added. * - * For example, an effective use of this function is to handle SIGTERM + * 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 @@ -211,12 +235,6 @@ g_unix_set_fd_nonblocking (gint fd, * The interaction of this source when combined with native UNIX * functions like sigprocmask() is not defined. * - * For reliable behavior, if your program links to gthread - * (either directly or indirectly via GObject, GIO, or a higher level - * library), you should ensure g_thread_init() is called before using - * this function. For example, if your program uses GObject, call - * g_type_init(). - * * 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. @@ -228,16 +246,17 @@ g_unix_set_fd_nonblocking (gint fd, GSource * g_unix_signal_source_new (int signum) { - g_return_val_if_fail (signum == SIGHUP || signum == SIGINT || signum == SIGTERM, NULL); + 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_watch_full: - * @signum: Signal number + * 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 @@ -248,14 +267,15 @@ g_unix_signal_source_new (int signum) * * Returns: An ID (greater than 0) for the event source * + * Rename to: g_unix_signal_add * Since: 2.30 */ guint -g_unix_signal_add_watch_full (int signum, - int priority, - GSourceFunc handler, - gpointer user_data, - GDestroyNotify notify) +g_unix_signal_add_full (int priority, + int signum, + GSourceFunc handler, + gpointer user_data, + GDestroyNotify notify) { guint id; GSource *source; @@ -271,3 +291,223 @@ g_unix_signal_add_watch_full (int signum, 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 +}