Home | History | Annotate | Download | only in tests
      1 /* GLIB - Library of useful routines for C programming
      2  * Copyright (C) 2005 Matthias Clasen
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Lesser General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Lesser General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Lesser General Public
     15  * License along with this library; if not, write to the
     16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     17  * Boston, MA 02111-1307, USA.
     18  */
     19 #include "config.h"
     20 
     21 #include <stdlib.h>
     22 #include <string.h>
     23 #ifdef HAVE_UNISTD_H
     24 #include <unistd.h>
     25 #endif
     26 #include <sys/types.h>
     27 #include <signal.h>
     28 
     29 #include "glib.h"
     30 #include "gstdio.h"
     31 
     32 static gchar *dir, *filename, *displayname, *childname;
     33 
     34 static gboolean stop = FALSE;
     35 
     36 #ifndef G_OS_WIN32
     37 
     38 static void
     39 handle_usr1 (int signum)
     40 {
     41   stop = TRUE;
     42 }
     43 
     44 #endif
     45 
     46 static gboolean
     47 check_stop (gpointer data)
     48 {
     49   GMainLoop *loop = data;
     50 
     51 #ifdef G_OS_WIN32
     52   stop = g_file_test ("STOP", G_FILE_TEST_EXISTS);
     53 #endif
     54 
     55   if (stop)
     56     g_main_loop_quit (loop);
     57 
     58   return TRUE;
     59 }
     60 
     61 static void
     62 write_or_die (const gchar *filename,
     63 	      const gchar *contents,
     64 	      gssize       length)
     65 {
     66   GError *error = NULL;
     67   gchar *displayname;
     68 
     69   if (!g_file_set_contents (filename, contents, length, &error))
     70     {
     71       displayname = g_filename_display_name (childname);
     72       g_print ("failed to write '%s': %s\n",
     73 	       displayname, error->message);
     74       exit (1);
     75     }
     76 }
     77 
     78 static GMappedFile *
     79 map_or_die (const gchar *filename,
     80 	    gboolean     writable)
     81 {
     82   GError *error = NULL;
     83   GMappedFile *map;
     84   gchar *displayname;
     85 
     86   map = g_mapped_file_new (filename, writable, &error);
     87   if (!map)
     88     {
     89       displayname = g_filename_display_name (childname);
     90       g_print ("failed to map '%s' non-writable, shared: %s\n",
     91 	       displayname, error->message);
     92       exit (1);
     93     }
     94 
     95   return map;
     96 }
     97 
     98 static int
     99 child_main (int argc, char *argv[])
    100 {
    101   GMappedFile *map;
    102   GMainLoop *loop;
    103 
    104   map = map_or_die (filename, FALSE);
    105 
    106   loop = g_main_loop_new (NULL, FALSE);
    107 
    108 #ifndef G_OS_WIN32
    109   signal (SIGUSR1, handle_usr1);
    110 #endif
    111   g_idle_add (check_stop, loop);
    112   g_main_loop_run (loop);
    113 
    114   write_or_die (childname,
    115 		g_mapped_file_get_contents (map),
    116 		g_mapped_file_get_length (map));
    117 
    118   return 0;
    119 }
    120 
    121 static void
    122 test_mapping (void)
    123 {
    124   GMappedFile *map;
    125 
    126   write_or_die (filename, "ABC", -1);
    127 
    128   map = map_or_die (filename, FALSE);
    129   g_assert (g_mapped_file_get_length (map) == 3);
    130   g_mapped_file_free (map);
    131 
    132   map = map_or_die (filename, TRUE);
    133   g_assert (g_mapped_file_get_length (map) == 3);
    134   g_mapped_file_free (map);
    135 }
    136 
    137 static void
    138 test_private (void)
    139 {
    140   GError *error = NULL;
    141   GMappedFile *map;
    142   gchar *buffer;
    143   gsize len;
    144 
    145   write_or_die (filename, "ABC", -1);
    146   map = map_or_die (filename, TRUE);
    147 
    148   buffer = (gchar *)g_mapped_file_get_contents (map);
    149   buffer[0] = '1';
    150   buffer[1] = '2';
    151   buffer[2] = '3';
    152   g_mapped_file_free (map);
    153 
    154   if (!g_file_get_contents (filename, &buffer, &len, &error))
    155     {
    156       g_print ("failed to read '%s': %s\n",
    157 	       displayname, error->message);
    158       exit (1);
    159 
    160     }
    161   g_assert (len == 3);
    162   g_assert (strcmp (buffer, "ABC") == 0);
    163   g_free (buffer);
    164 
    165 }
    166 
    167 static void
    168 test_child_private (gchar *argv0)
    169 {
    170   GError *error = NULL;
    171   GMappedFile *map;
    172   gchar *buffer;
    173   gsize len;
    174   gchar *child_argv[3];
    175   GPid  child_pid;
    176 
    177 #ifdef G_OS_WIN32
    178   g_remove ("STOP");
    179   g_assert (!g_file_test ("STOP", G_FILE_TEST_EXISTS));
    180 #endif
    181 
    182   write_or_die (filename, "ABC", -1);
    183   map = map_or_die (filename, TRUE);
    184 
    185   child_argv[0] = argv0;
    186   child_argv[1] = "mapchild";
    187   child_argv[2] = NULL;
    188   if (!g_spawn_async (dir, child_argv, NULL,
    189 		      0, NULL, NULL, &child_pid, &error))
    190     {
    191       g_print ("failed to spawn child: %s\n",
    192 	       error->message);
    193       exit (1);
    194     }
    195 
    196   /* give the child some time to set up its mapping */
    197   g_usleep (2000000);
    198 
    199   buffer = (gchar *)g_mapped_file_get_contents (map);
    200   buffer[0] = '1';
    201   buffer[1] = '2';
    202   buffer[2] = '3';
    203   g_mapped_file_free (map);
    204 
    205 #ifndef G_OS_WIN32
    206   kill (child_pid, SIGUSR1);
    207 #else
    208   g_file_set_contents ("STOP", "Hey there\n", -1, NULL);
    209 #endif
    210 
    211   /* give the child some time to write the file */
    212   g_usleep (2000000);
    213 
    214   if (!g_file_get_contents (childname, &buffer, &len, &error))
    215     {
    216       gchar *name;
    217 
    218       name = g_filename_display_name (childname);
    219       g_print ("failed to read '%s': %s\n", name, error->message);
    220       exit (1);
    221     }
    222   g_assert (len == 3);
    223   g_assert (strcmp (buffer, "ABC") == 0);
    224   g_free (buffer);
    225 }
    226 
    227 static int
    228 parent_main (int   argc,
    229 	     char *argv[])
    230 {
    231   /* test mapping with various flag combinations */
    232   test_mapping ();
    233 
    234   /* test private modification */
    235   test_private ();
    236 
    237   /* test multiple clients, non-shared */
    238   test_child_private (argv[0]);
    239 
    240   return 0;
    241 }
    242 
    243 int
    244 main (int argc,
    245       char *argv[])
    246 {
    247   dir = g_get_current_dir ();
    248   filename = g_build_filename (dir, "maptest", NULL);
    249   displayname = g_filename_display_name (filename);
    250   childname = g_build_filename (dir, "mapchild", NULL);
    251 
    252   if (argc > 1)
    253     return child_main (argc, argv);
    254   else
    255     return parent_main (argc, argv);
    256 }
    257