Add a check for the Darwin dynamic linker. Use AC_TRY_LINK when checking
[platform/upstream/glib.git] / tests / gio-test.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 2000  Tor Lillqvist
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
20 /* A test program for the main loop and IO channel code.
21  * Just run it. Optional parameter is number of sub-processes.
22  */
23
24 #include "config.h"
25
26 #include <glib.h>
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <math.h>
31 #include <time.h>
32
33 #ifdef G_OS_WIN32
34   #include <io.h>
35   #include <fcntl.h>
36   #include <process.h>
37   #define STRICT
38   #include <windows.h>
39 #else
40   #ifdef HAVE_UNISTD_H
41     #include <unistd.h>
42   #endif
43 #endif
44
45 static int nrunning;
46 static GMainLoop *main_loop;
47
48 #define BUFSIZE 5000            /* Larger than the circular buffer in
49                                  * giowin32.c on purpose.
50                                  */
51
52 static int nkiddies;
53
54 static struct {
55   int fd;
56   int seq;
57 } *seqtab;
58
59 static GIOError
60 read_all (int         fd,
61           GIOChannel *channel,
62           char       *buffer,
63           guint       nbytes,
64           guint      *bytes_read)
65 {
66   guint left = nbytes;
67   guint nb;
68   GIOError error = G_IO_ERROR_NONE;
69   char *bufp = buffer;
70
71   /* g_io_channel_read() doesn't necessarily return all the
72    * data we want at once.
73    */
74   *bytes_read = 0;
75   while (left)
76     {
77       error = g_io_channel_read (channel, bufp, left, &nb);
78       
79       if (error != G_IO_ERROR_NONE)
80         {
81           g_print ("gio-test: ...from %d: G_IO_ERROR_%s\n", fd,
82                    (error == G_IO_ERROR_AGAIN ? "AGAIN" :
83                     (error == G_IO_ERROR_INVAL ? "INVAL" :
84                      (error == G_IO_ERROR_UNKNOWN ? "UNKNOWN" : "???"))));
85           if (error == G_IO_ERROR_AGAIN)
86             continue;
87           break;
88         }
89       if (nb == 0)
90         return error;
91       left -= nb;
92       bufp += nb;
93       *bytes_read += nb;
94     }
95   return error;
96 }
97
98 static void
99 shutdown_source (gpointer data)
100 {
101   if (g_source_remove (*(guint *) data))
102     {
103       nrunning--;
104       if (nrunning == 0)
105         g_main_quit (main_loop);
106     }
107 }
108
109 static gboolean
110 recv_message (GIOChannel  *channel,
111               GIOCondition cond,
112               gpointer    data)
113 {
114   gint fd = g_io_channel_unix_get_fd (channel);
115   gboolean retval = TRUE;
116
117   g_print ("gio-test: ...from %d:%s%s%s%s\n", fd,
118            (cond & G_IO_ERR) ? " ERR" : "",
119            (cond & G_IO_HUP) ? " HUP" : "",
120            (cond & G_IO_IN)  ? " IN"  : "",
121            (cond & G_IO_PRI) ? " PRI" : "");
122
123   if (cond & (G_IO_ERR | G_IO_HUP))
124     {
125       shutdown_source (data);
126       retval = FALSE;
127     }
128
129   if (cond & G_IO_IN)
130     {
131       char buf[BUFSIZE];
132       guint nbytes;
133       guint nb;
134       int i, j, seq;
135       GIOError error;
136       
137       error = read_all (fd, channel, (gchar *) &seq, sizeof (seq), &nb);
138       if (error == G_IO_ERROR_NONE)
139         {
140           if (nb == 0)
141             {
142               g_print ("gio-test: ...from %d: EOF\n", fd);
143               shutdown_source (data);
144               return FALSE;
145             }
146           
147           g_assert (nb == sizeof (nbytes));
148
149           for (i = 0; i < nkiddies; i++)
150             if (seqtab[i].fd == fd)
151               {
152                 if (seq != seqtab[i].seq)
153                   {
154                     g_print ("gio-test: ...from %d: invalid sequence number %d, expected %d\n",
155                              fd, seq, seqtab[i].seq);
156                     g_assert_not_reached ();
157                   }
158                 seqtab[i].seq++;
159                 break;
160               }
161
162           error = read_all (fd, channel, (gchar *) &nbytes, sizeof (nbytes), &nb);
163         }
164
165       if (error != G_IO_ERROR_NONE)
166         return FALSE;
167       
168       if (nb == 0)
169         {
170           g_print ("gio-test: ...from %d: EOF\n", fd);
171           shutdown_source (data);
172           return FALSE;
173         }
174       
175       g_assert (nb == sizeof (nbytes));
176
177       if (nbytes >= BUFSIZE)
178         {
179           g_print ("gio-test: ...from %d: nbytes = %d (%#x)!\n", fd, nbytes, nbytes);
180           g_assert_not_reached ();
181         }
182       g_assert (nbytes >= 0 && nbytes < BUFSIZE);
183       
184       g_print ("gio-test: ...from %d: %d bytes\n", fd, nbytes);
185       
186       if (nbytes > 0)
187         {
188           error = read_all (fd, channel, buf, nbytes, &nb);
189
190           if (error != G_IO_ERROR_NONE)
191             return FALSE;
192
193           if (nb == 0)
194             {
195               g_print ("gio-test: ...from %d: EOF\n", fd);
196               shutdown_source (data);
197               return FALSE;
198             }
199       
200           for (j = 0; j < nbytes; j++)
201             if (buf[j] != ' ' + ((nbytes + j) % 95))
202               {
203                 g_print ("gio-test: ...from %d: buf[%d] == '%c', should be '%c'\n",
204                          fd, j, buf[j], 'a' + ((nbytes + j) % 32));
205                 g_assert_not_reached ();
206               }
207           g_print ("gio-test: ...from %d: OK\n", fd);
208         }
209     }
210   return retval;
211 }
212
213 #ifdef G_OS_WIN32
214
215 static gboolean
216 recv_windows_message (GIOChannel  *channel,
217                       GIOCondition cond,
218                       gpointer    data)
219 {
220   GIOError error;
221   MSG msg;
222   guint nb;
223   
224   while (1)
225     {
226       error = g_io_channel_read (channel, &msg, sizeof (MSG), &nb);
227       
228       if (error != G_IO_ERROR_NONE)
229         {
230           g_print ("gio-test: ...reading Windows message: G_IO_ERROR_%s\n",
231                    (error == G_IO_ERROR_AGAIN ? "AGAIN" :
232                     (error == G_IO_ERROR_INVAL ? "INVAL" :
233                      (error == G_IO_ERROR_UNKNOWN ? "UNKNOWN" : "???"))));
234           if (error == G_IO_ERROR_AGAIN)
235             continue;
236         }
237       break;
238     }
239
240   g_print ("gio-test: ...Windows message for %#x: %d,%d,%d\n",
241            msg.hwnd, msg.message, msg.wParam, msg.lParam);
242
243   return TRUE;
244 }
245
246 LRESULT CALLBACK 
247 window_procedure (HWND hwnd,
248                   UINT message,
249                   WPARAM wparam,
250                   LPARAM lparam)
251 {
252   g_print ("gio-test: window_procedure for %#x: %d,%d,%d\n",
253            hwnd, message, wparam, lparam);
254   return DefWindowProc (hwnd, message, wparam, lparam);
255 }
256
257 #endif
258
259 int
260 main (int    argc,
261       char **argv)
262 {
263   if (argc < 3)
264     {
265       /* Parent */
266       
267       GIOChannel *my_read_channel;
268       gchar *cmdline;
269       guint *id;
270       int i;
271 #ifdef G_OS_WIN32
272       GTimeVal start, end;
273       GPollFD pollfd;
274       int pollresult;
275       ATOM klass;
276       static WNDCLASS wcl;
277       HWND hwnd;
278       GIOChannel *windows_messages_channel;
279 #endif
280
281       nkiddies = (argc == 1 ? 1 : atoi(argv[1]));
282       seqtab = g_malloc (nkiddies * 2 * sizeof (int));
283
284 #ifdef G_OS_WIN32
285       wcl.style = 0;
286       wcl.lpfnWndProc = window_procedure;
287       wcl.cbClsExtra = 0;
288       wcl.cbWndExtra = 0;
289       wcl.hInstance = GetModuleHandle (NULL);
290       wcl.hIcon = NULL;
291       wcl.hCursor = NULL;
292       wcl.hbrBackground = NULL;
293       wcl.lpszMenuName = NULL;
294       wcl.lpszClassName = "gio-test";
295
296       klass = RegisterClass (&wcl);
297
298       if (!klass)
299         {
300           g_print ("gio-test: RegisterClass failed\n");
301           exit (1);
302         }
303
304       hwnd = CreateWindow (klass, "gio-test", 0, 0, 0, 10, 10,
305                            NULL, NULL, wcl.hInstance, NULL);
306       if (!hwnd)
307         {
308           g_print ("gio-test: CreateWindow failed\n");
309           exit (1);
310         }
311
312       windows_messages_channel = g_io_channel_win32_new_messages (hwnd);
313       g_io_add_watch (windows_messages_channel, G_IO_IN, recv_windows_message, 0);
314 #endif
315
316       for (i = 0; i < nkiddies; i++)
317         {
318           int pipe_to_sub[2], pipe_from_sub[2];
319           
320           if (pipe (pipe_to_sub) == -1 ||
321               pipe (pipe_from_sub) == -1)
322             perror ("pipe"), exit (1);
323           
324           seqtab[i].fd = pipe_from_sub[0];
325           seqtab[i].seq = 0;
326
327           my_read_channel = g_io_channel_unix_new (pipe_from_sub[0]);
328           
329           id = g_new (guint, 1);
330           *id =
331             g_io_add_watch (my_read_channel,
332                             G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
333                             recv_message,
334                             id);
335           
336           nrunning++;
337           
338 #ifdef G_OS_WIN32
339           cmdline = g_strdup_printf ("%d:%d:%d",
340                                      pipe_to_sub[0],
341                                      pipe_from_sub[1],
342                                      hwnd);
343           _spawnl (_P_NOWAIT, argv[0], argv[0], "--child", cmdline, NULL);
344 #else
345           cmdline = g_strdup_printf ("%s --child %d:%d &", argv[0],
346                                      pipe_to_sub[0], pipe_from_sub[1]);
347           
348           system (cmdline);
349 #endif
350           close (pipe_to_sub[0]);
351           close (pipe_from_sub [1]);
352
353 #ifdef G_OS_WIN32
354           g_get_current_time (&start);
355           g_io_channel_win32_make_pollfd (my_read_channel, G_IO_IN, &pollfd);
356           pollresult = g_io_channel_win32_poll (&pollfd, 1, 100);
357           g_get_current_time (&end);
358           if (end.tv_usec < start.tv_usec)
359             end.tv_sec--, end.tv_usec += 1000000;
360           g_print ("gio-test: had to wait %ld.%03ld s, result:%d\n",
361                    end.tv_sec - start.tv_sec,
362                    (end.tv_usec - start.tv_usec) / 1000,
363                    pollresult);
364 #endif
365         }
366       
367       main_loop = g_main_new (FALSE);
368       
369       g_main_run (main_loop);
370     }
371   else if (argc == 3)
372     {
373       /* Child */
374       
375       int readfd, writefd;
376 #ifdef G_OS_WIN32
377       HWND hwnd;
378 #endif
379       int i, j;
380       char buf[BUFSIZE];
381       int buflen;
382       GTimeVal tv;
383       int n;
384   
385       g_get_current_time (&tv);
386       
387       sscanf (argv[2], "%d:%d%n", &readfd, &writefd, &n);
388
389 #ifdef G_OS_WIN32
390       sscanf (argv[2] + n, ":%d", &hwnd);
391 #endif
392       
393       srand (tv.tv_sec ^ (tv.tv_usec / 1000) ^ readfd ^ (writefd << 4));
394   
395       for (i = 0; i < 20 + rand() % 20; i++)
396         {
397           g_usleep (100 + (rand() % 10) * 5000);
398           buflen = rand() % BUFSIZE;
399           for (j = 0; j < buflen; j++)
400             buf[j] = ' ' + ((buflen + j) % 95);
401           g_print ("gio-test: child writing %d+%d bytes to %d\n",
402                    (int)(sizeof(i) + sizeof(buflen)), buflen, writefd);
403           write (writefd, &i, sizeof (i));
404           write (writefd, &buflen, sizeof (buflen));
405           write (writefd, buf, buflen);
406
407 #ifdef G_OS_WIN32
408           if (rand() % 100 < 5)
409             {
410               int msg = WM_USER + (rand() % 100);
411               WPARAM wparam = rand ();
412               LPARAM lparam = rand ();
413               g_print ("gio-test: child posting message %d,%d,%d to %#x\n",
414                        msg, wparam, lparam, hwnd);
415               PostMessage (hwnd, msg, wparam, lparam);
416             }
417 #endif
418         }
419       g_print ("gio-test: child exiting, closing %d\n", writefd);
420       close (writefd);
421     }
422   else
423     g_print ("Huh?\n");
424   
425   return 0;
426 }
427