2005-06-24 Matthias Clasen <mclasen@redhat.com>
+ Add an mmap() wrapper called GMappedFile. (#148218,
+ David Schleef, Behdad Esfahbod)
+
+ * glib/gmappedfile.[hc]: New files.
+
+ * configure.in: Check for mmap.
+
+ * glib/Makefile.am: Add new files.
+
+ * glib/glib.symbols: Add new functions.
+
+ * glib/glib.h: Include gmappedfile.h
+
+ * tests/mapping-test.c: Tests for GMappedFile.
+
+ * tests/Makefile.am: Add new file.
+
* Makefile.am (DISTCHECK_CONFIGURE_FLAGS): Add --enable-man.
2005-06-24 Tor Lillqvist <tml@novell.com>
2005-06-24 Matthias Clasen <mclasen@redhat.com>
+ Add an mmap() wrapper called GMappedFile. (#148218,
+ David Schleef, Behdad Esfahbod)
+
+ * glib/gmappedfile.[hc]: New files.
+
+ * configure.in: Check for mmap.
+
+ * glib/Makefile.am: Add new files.
+
+ * glib/glib.symbols: Add new functions.
+
+ * glib/glib.h: Include gmappedfile.h
+
+ * tests/mapping-test.c: Tests for GMappedFile.
+
+ * tests/Makefile.am: Add new file.
+
* Makefile.am (DISTCHECK_CONFIGURE_FLAGS): Add --enable-man.
2005-06-24 Tor Lillqvist <tml@novell.com>
2005-06-24 Matthias Clasen <mclasen@redhat.com>
+ Add an mmap() wrapper called GMappedFile. (#148218,
+ David Schleef, Behdad Esfahbod)
+
+ * glib/gmappedfile.[hc]: New files.
+
+ * configure.in: Check for mmap.
+
+ * glib/Makefile.am: Add new files.
+
+ * glib/glib.symbols: Add new functions.
+
+ * glib/glib.h: Include gmappedfile.h
+
+ * tests/mapping-test.c: Tests for GMappedFile.
+
+ * tests/Makefile.am: Add new file.
+
* Makefile.am (DISTCHECK_CONFIGURE_FLAGS): Add --enable-man.
2005-06-24 Tor Lillqvist <tml@novell.com>
2005-06-24 Matthias Clasen <mclasen@redhat.com>
+ Add an mmap() wrapper called GMappedFile. (#148218,
+ David Schleef, Behdad Esfahbod)
+
+ * glib/gmappedfile.[hc]: New files.
+
+ * configure.in: Check for mmap.
+
+ * glib/Makefile.am: Add new files.
+
+ * glib/glib.symbols: Add new functions.
+
+ * glib/glib.h: Include gmappedfile.h
+
+ * tests/mapping-test.c: Tests for GMappedFile.
+
+ * tests/Makefile.am: Add new file.
+
* Makefile.am (DISTCHECK_CONFIGURE_FLAGS): Add --enable-man.
2005-06-24 Tor Lillqvist <tml@novell.com>
# Checks for library functions.
AC_FUNC_VPRINTF
-
+AC_FUNC_MMAP
AC_FUNC_ALLOCA
AC_CHECK_FUNCS(atexit on_exit)
+2005-06-24 Matthias Clasen <mclasen@redhat.com>
+
+ * glib/glib-sections.txt: Add GMappedFile functions.
+
2005-06-18 Matthias Clasen <mclasen@redhat.com>
* glib/tmpl/option.sgml (GOptionFlags): document
g_dir_close
<SUBSECTION>
+GMappedFile
+g_mapped_file_new
+g_mapped_file_free
+g_mapped_file_get_length
+g_mapped_file_get_contents
+
+<SUBSECTION>
g_open
g_rename
g_mkdir
g_access
g_creat
g_chdir
+
<SUBSECTION Private>
g_file_error_quark
</SECTION>
glibintl.h \
glist.c \
gmain.c \
+ gmappedfile.c \
gmarkup.c \
gmem.c \
gmessages.c \
glist.h \
gmacros.h \
gmain.h \
+ gmappedfile.h \
gmarkup.h \
gmem.h \
gmessages.h \
#include <glib/glist.h>
#include <glib/gmacros.h>
#include <glib/gmain.h>
+#include <glib/gmappedfile.h>
#include <glib/gmarkup.h>
#include <glib/gmem.h>
#include <glib/gmessages.h>
#endif
#endif
+#if IN_HEADER(__G_MAPPED_FILE_H__)
+#if IN_FILE(__G_MAPPED_FILE_C__)
+g_mapped_file_new G_GNUC_MALLOC
+g_mapped_file_get_length
+g_mapped_file_get_contents
+g_mapped_file_free
+#endif
+#endif
+
#if IN_HEADER(__G_MARKUP_H__)
#if IN_FILE(__G_MARKUP_C__)
g_markup_error_quark
--- /dev/null
+/* GLIB - Library of useful routines for C programming
+ * gmappedfile.c: Simplified wrapper around the mmap() function.
+ *
+ * Copyright 2005 Matthias Clasen
+ *
+ * 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.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#endif
+
+
+#include "gconvert.h"
+#include "gerror.h"
+#include "gfileutils.h"
+#include "gmappedfile.h"
+#include "gmem.h"
+#include "gmessages.h"
+#include "gstdio.h"
+#include "gstrfuncs.h"
+
+#include "glibintl.h"
+
+#include "galias.h"
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *) -1)
+#endif
+
+struct _GMappedFile
+{
+ gsize length;
+ gchar *contents;
+};
+
+/**
+ * g_mapped_file_new:
+ * @filename: The path of the file to load, in the GLib filename encoding
+ * @writable: wether the mapping should be writable
+ * @error: return location for a #GError, or %NULL
+ *
+ * Maps a file into memory. On UNIX, this is using the mmap() function.
+ *
+ * If @writable is %TRUE, the mapped buffer may be modified, otherwise
+ * it is an error to modify the mapped buffer. Modifications to the buffer
+ * are not visible to other processes mapping the same file, and are not
+ * written back to the file.
+ *
+ * Note that modifications of the underlying file might affect the contents
+ * of the #GMappedFile. Therefore, mapping should only be used if the file
+ * will not be modified, or if all modifications of the file are done
+ * atomically (e.g. using g_file_set_contents()).
+ *
+ * Return value: a newly allocated #GMappedFile which must be freed
+ * with g_mapped_file_free(), or %NULL if the mapping failed.
+ *
+ * Since: 2.8
+ */
+GMappedFile *
+g_mapped_file_new (const gchar *filename,
+ gboolean writable,
+ GError **error)
+{
+ GMappedFile *file;
+ int fd;
+ struct stat st;
+
+ g_return_val_if_fail (filename != NULL, NULL);
+ g_return_val_if_fail (!error || *error == NULL, NULL);
+
+ fd = g_open (filename, writable ? O_RDWR : O_RDONLY);
+ if (fd == -1)
+ {
+ int save_errno = errno;
+ gchar *display_filename = g_filename_display_name (filename);
+
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (save_errno),
+ _("Failed to open file '%s': open() failed: %s"),
+ display_filename,
+ g_strerror (save_errno));
+ g_free (display_filename);
+ return NULL;
+ }
+
+ file = g_new0 (GMappedFile, 1);
+
+ if (fstat (fd, &st) == -1)
+ {
+ int save_errno = errno;
+ gchar *display_filename = g_filename_display_name (filename);
+
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (save_errno),
+ _("Failed to get attributes of file '%s': fstat() failed: %s"),
+ display_filename,
+ g_strerror (save_errno));
+ g_free (display_filename);
+ goto out;
+ }
+
+ file->contents = MAP_FAILED;
+
+#ifdef HAVE_MMAP
+ file->length = st.st_size;
+ file->contents = (gchar *) mmap (NULL, st.st_size,
+ writable ? PROT_READ|PROT_WRITE : PROT_READ,
+ MAP_PRIVATE, fd, 0);
+#endif
+
+ if (file->contents == MAP_FAILED)
+ {
+ int save_errno = errno;
+ gchar *display_filename = g_filename_display_name (filename);
+
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (save_errno),
+ _("Failed to map file '%s': mmap() failed: %s"),
+ display_filename,
+ g_strerror (save_errno));
+ g_free (display_filename);
+ goto out;
+ }
+
+ close (fd);
+ return file;
+
+ out:
+ close (fd);
+ g_free (file);
+
+ return NULL;
+}
+
+/**
+ * g_mapped_file_get_length:
+ * @file: a #GMappedFile
+ *
+ * Returns the length of the contents of a #GMappedFile.
+ *
+ * Returns: the length of the contents of @file.
+ *
+ * Since: 2.8
+ */
+gsize
+g_mapped_file_get_length (GMappedFile *file)
+{
+ g_return_val_if_fail (file != NULL, 0);
+
+ return file->length;
+}
+
+/**
+ * g_mapped_file_get_contents:
+ * @file: a #GMappedFile
+ *
+ * Returns the contents of a #GMappedFile.
+ *
+ * Note that the contents may not be zero-terminated,
+ * even if the #GMappedFile is backed by a text file.
+ *
+ * Returns: the contents of @file.
+ *
+ * Since: 2.8
+ */
+gchar *
+g_mapped_file_get_contents (GMappedFile *file)
+{
+ g_return_val_if_fail (file != NULL, NULL);
+
+ return file->contents;
+}
+
+/**
+ * g_mapped_file_free:
+ * @file: a #GMappedFile
+ *
+ * Unmaps the buffer of @file and frees it.
+ *
+ * For writable, shared mappings, the contents
+ * will be written back to the file at this point.
+ *
+ * Since: 2.8
+ */
+void
+g_mapped_file_free (GMappedFile *file)
+{
+ g_return_if_fail (file != NULL);
+
+#ifdef HAVE_MMAP
+ munmap (file->contents, file->length);
+#endif
+}
+
+
+#define __G_MAPPED_FILE_C__
+#include "galiasdef.c"
--- /dev/null
+/* GLIB - Library of useful routines for C programming
+ * gmappedfile.h: Simplified wrapper around the mmap function
+ *
+ * Copyright 2005 Matthias Clasen
+ *
+ * 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.
+ */
+#ifndef __G_MAPPED_FILE_H__
+#define __G_MAPPED_FILE_H__
+
+#include <glib/gerror.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GMappedFile GMappedFile;
+
+GMappedFile *g_mapped_file_new (const gchar *filename,
+ gboolean writable,
+ GError **error) G_GNUC_MALLOC;
+gsize g_mapped_file_get_length (GMappedFile *file);
+gchar *g_mapped_file_get_contents (GMappedFile *file);
+void g_mapped_file_free (GMappedFile *file);
+
+G_END_DECLS
+
+#endif /* __G_MAPPED_FILE_H__ */
+2005-06-24 Matthias Clasen <mclasen@redhat.com>
+
+ * POTFILES.in: Add gmappedfile.c
+
2005-06-22 Abel Cheung <maddog@linuxhall.org>
* zh_TW.po: Fix language team reference.
glib/gfileutils.c
glib/giochannel.c
glib/giowin32.c
+glib/gmappedfile.c
glib/gmarkup.c
glib/gshell.c
glib/gspawn-win32.c
keyfile-test \
list-test \
mainloop-test \
+ mapping-test \
markup-escape-test \
module-test \
node-test \
list_test_LDADD = $(progs_ldadd)
mainloop_test_LDADD = $(thread_ldadd)
markup_test_LDADD = $(progs_ldadd)
+mapping_test_LDADD = $(progs_ldadd)
markup_escape_test_LDADD = $(progs_ldadd)
module_test_LDADD = $(module_ldadd) $(module_test_exp)
module_test_LDFLAGS = $(G_MODULE_LDFLAGS)
--- /dev/null
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include "glib.h"
+
+static gchar *dir, *filename, *displayname, *childname;
+
+static gboolean stop = FALSE;
+
+static void
+handle_usr1 (int signum)
+{
+ stop = TRUE;
+}
+
+static gboolean
+check_stop (gpointer data)
+{
+ GMainLoop *loop = data;
+
+ if (stop)
+ g_main_loop_quit (loop);
+
+ return TRUE;
+}
+
+static void
+write_or_die (const gchar *filename,
+ const gchar *contents,
+ gssize length)
+{
+ GError *error = NULL;
+ gchar *displayname;
+
+ if (!g_file_set_contents (filename, contents, length, &error))
+ {
+ displayname = g_filename_display_name (childname);
+ g_print ("failed to write '%s': %s\n",
+ displayname, error->message);
+ exit (1);
+ }
+}
+
+static GMappedFile *
+map_or_die (const gchar *filename,
+ gboolean writable)
+{
+ GError *error = NULL;
+ GMappedFile *map;
+ gchar *displayname;
+
+ map = g_mapped_file_new (filename, writable, &error);
+ if (!map)
+ {
+ displayname = g_filename_display_name (childname);
+ g_print ("failed to map '%s' non-writable, shared: %s\n",
+ displayname, error->message);
+ exit (1);
+ }
+
+ return map;
+}
+
+static int
+child_main (int argc, char *argv[])
+{
+ GMappedFile *map;
+ GMainLoop *loop;
+
+ map = map_or_die (filename, FALSE);
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ signal (SIGUSR1, handle_usr1);
+ g_idle_add (check_stop, loop);
+ g_main_loop_run (loop);
+
+ write_or_die (childname,
+ g_mapped_file_get_contents (map),
+ g_mapped_file_get_length (map));
+
+ return 0;
+}
+
+static void
+test_mapping (void)
+{
+ GMappedFile *map;
+
+ write_or_die (filename, "ABC", -1);
+
+ map = map_or_die (filename, FALSE);
+ g_assert (g_mapped_file_get_length (map) == 3);
+ g_mapped_file_free (map);
+
+ map = map_or_die (filename, TRUE);
+ g_assert (g_mapped_file_get_length (map) == 3);
+ g_mapped_file_free (map);
+}
+
+static void
+test_private (void)
+{
+ GError *error = NULL;
+ GMappedFile *map;
+ gchar *buffer;
+ gsize len;
+
+ write_or_die (filename, "ABC", -1);
+ map = map_or_die (filename, TRUE);
+
+ buffer = (gchar *)g_mapped_file_get_contents (map);
+ buffer[0] = '1';
+ buffer[1] = '2';
+ buffer[2] = '3';
+ g_mapped_file_free (map);
+
+ if (!g_file_get_contents (filename, &buffer, &len, &error))
+ {
+ g_print ("failed to read '%s': %s\n",
+ displayname, error->message);
+ exit (1);
+
+ }
+ g_assert (len == 3);
+ g_assert (strcmp (buffer, "ABC") == 0);
+ g_free (buffer);
+
+}
+
+static void
+test_child_private (gchar *argv0)
+{
+ GError *error = NULL;
+ GMappedFile *map;
+ gchar *buffer;
+ gsize len;
+ gchar *child_argv[3];
+ GPid child_pid;
+
+ write_or_die (filename, "ABC", -1);
+ map = map_or_die (filename, TRUE);
+
+ child_argv[0] = argv0;
+ child_argv[1] = "mapchild";
+ child_argv[2] = NULL;
+ if (!g_spawn_async (dir, child_argv, NULL,
+ 0, NULL, NULL, &child_pid, &error))
+ {
+ g_print ("failed to spawn child: %s\n",
+ error->message);
+ exit (1);
+ }
+
+ /* give the child some time to set up its mapping */
+ sleep (2);
+
+ buffer = (gchar *)g_mapped_file_get_contents (map);
+ buffer[0] = '1';
+ buffer[1] = '2';
+ buffer[2] = '3';
+ g_mapped_file_free (map);
+
+ kill (child_pid, SIGUSR1);
+
+ /* give the child some time to write the file */
+ sleep (2);
+
+ if (!g_file_get_contents (childname, &buffer, &len, &error))
+ {
+ gchar *name;
+
+ name = g_filename_display_name (childname);
+ g_print ("failed to read '%s': %s\n", name, error->message);
+ exit (1);
+ }
+ g_assert (len == 3);
+ g_assert (strcmp (buffer, "ABC") == 0);
+ g_free (buffer);
+}
+
+static int
+parent_main (int argc,
+ char *argv[])
+{
+ /* test mapping with various flag combinations */
+ test_mapping ();
+
+ /* test private modification */
+ test_private ();
+
+ /* test multiple clients, non-shared */
+ test_child_private (argv[0]);
+
+ return 0;
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ dir = g_get_current_dir ();
+ filename = g_build_filename (dir, "maptest", NULL);
+ displayname = g_filename_display_name (filename);
+ childname = g_build_filename (dir, "mapchild", NULL);
+
+ if (argc > 1)
+ return child_main (argc, argv);
+ else
+ return parent_main (argc, argv);
+}