Merge remote-tracking branch 'gvdb/master'
[platform/upstream/glib.git] / tests / mapping-test.c
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 }