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