source: trunk/third/glib2/tests/gio-test.c @ 18159

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