glib/tests/gio-test.c
changeset 18 47c74d1534e1
equal deleted inserted replaced
0:e4d67989cc36 18:47c74d1534e1
       
     1 /* GLIB - Library of useful routines for C programming
       
     2  * Copyright (C) 2000  Tor Lillqvist
       
     3  * Portion Copyright © 2008-09 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
       
     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 __SYMBIAN32__
       
    37 //  #define VERBOSE
       
    38   #include <pthread.h>
       
    39   #include "mrt2_glib2_test.h"
       
    40   void *child_function(void*);
       
    41   gboolean child_terminated = FALSE;
       
    42   int from_descriptor, to_descriptor;
       
    43 #endif /*__SYMBIAN32__*/
       
    44 #ifdef G_OS_WIN32
       
    45   #include <io.h>
       
    46   #include <fcntl.h>
       
    47   #include <process.h>
       
    48   #define STRICT
       
    49   #include <windows.h>
       
    50   #define pipe(fds) _pipe(fds, 4096, _O_BINARY)
       
    51 #else
       
    52   #ifdef HAVE_UNISTD_H
       
    53     #include <unistd.h>
       
    54   #endif
       
    55 #endif
       
    56 
       
    57 static int nrunning;
       
    58 static GMainLoop *main_loop;
       
    59 
       
    60 #define BUFSIZE 5000		/* Larger than the circular buffer in
       
    61 				 * giowin32.c on purpose.
       
    62 				 */
       
    63 
       
    64 static int nkiddies;
       
    65 
       
    66 static struct {
       
    67   int fd;
       
    68   int seq;
       
    69 } *seqtab;
       
    70 
       
    71 static GIOError
       
    72 read_all (int         fd,
       
    73 	  GIOChannel *channel,
       
    74 	  char       *buffer,
       
    75 	  guint       nbytes,
       
    76 	  guint      *bytes_read)
       
    77 {
       
    78   guint left = nbytes;
       
    79   gsize nb;
       
    80   GIOError error = G_IO_ERROR_NONE;
       
    81   char *bufp = buffer;
       
    82 #ifdef VERBOSE
       
    83       g_print ("gio-test: ...entering read_all()");
       
    84 #endif  
       
    85 
       
    86   /* g_io_channel_read() doesn't necessarily return all the
       
    87    * data we want at once.
       
    88    */
       
    89   *bytes_read = 0;
       
    90   while (left)
       
    91     {
       
    92       error = g_io_channel_read (channel, bufp, left, &nb);
       
    93       
       
    94       if (error != G_IO_ERROR_NONE)
       
    95 	{
       
    96 	  g_print ("gio-test: ...from %d: G_IO_ERROR_%s\n", fd,
       
    97 		   (error == G_IO_ERROR_AGAIN ? "AGAIN" :
       
    98 		    (error == G_IO_ERROR_INVAL ? "INVAL" :
       
    99 		     (error == G_IO_ERROR_UNKNOWN ? "UNKNOWN" : "???"))));
       
   100 	  if (error == G_IO_ERROR_AGAIN)
       
   101 	    continue;
       
   102 	  break;
       
   103 	}
       
   104       if (nb == 0)
       
   105 	return error;
       
   106       left -= nb;
       
   107       bufp += nb;
       
   108       *bytes_read += nb;
       
   109     }
       
   110   return error;
       
   111 }
       
   112 
       
   113 static void
       
   114 shutdown_source (gpointer data)
       
   115 {
       
   116 #ifdef VERBOSE
       
   117       g_print ("gio-test: ...entering shutdown_source()");
       
   118 #endif  
       
   119 
       
   120   if (g_source_remove (*(guint *) data))
       
   121     {
       
   122       nrunning--;
       
   123       if (nrunning == 0)
       
   124 	g_main_loop_quit (main_loop);
       
   125     }
       
   126 }
       
   127 
       
   128 static gboolean
       
   129 recv_message (GIOChannel  *channel,
       
   130 	      GIOCondition cond,
       
   131 	      gpointer    data)
       
   132 {
       
   133   gint fd = g_io_channel_unix_get_fd (channel);
       
   134   gboolean retval = TRUE;
       
   135 
       
   136 #ifdef VERBOSE
       
   137   g_print ("gio-test: ...entering recv_message()");
       
   138   g_print ("gio-test: ...from %d:%s%s%s%s\n", fd,
       
   139 	   (cond & G_IO_ERR) ? " ERR" : "",
       
   140 	   (cond & G_IO_HUP) ? " HUP" : "",
       
   141 	   (cond & G_IO_IN)  ? " IN"  : "",
       
   142 	   (cond & G_IO_PRI) ? " PRI" : "");
       
   143 #endif
       
   144 
       
   145   if (cond & (G_IO_ERR | G_IO_HUP))
       
   146     {
       
   147       shutdown_source (data);
       
   148       retval = FALSE;
       
   149     }
       
   150 
       
   151   if (cond & G_IO_IN)
       
   152     {
       
   153       char buf[BUFSIZE];
       
   154       guint nbytes;
       
   155       guint nb;
       
   156       int i, j, seq;
       
   157       GIOError error;
       
   158       
       
   159       error = read_all (fd, channel, (gchar *) &seq, sizeof (seq), &nb);
       
   160       if (error == G_IO_ERROR_NONE)
       
   161 	{
       
   162 	  if (nb == 0)
       
   163 	    {
       
   164 #ifdef VERBOSE
       
   165 	      g_print ("gio-test: ...from %d: EOF\n", fd);
       
   166 #endif
       
   167 	      shutdown_source (data);
       
   168 	      return FALSE;
       
   169 	    }
       
   170 	  
       
   171 	  g_assert (nb == sizeof (nbytes));
       
   172 
       
   173 	  for (i = 0; i < nkiddies; i++)
       
   174 	    if (seqtab[i].fd == fd)
       
   175 	      {
       
   176 		if (seq != seqtab[i].seq)
       
   177 		  {
       
   178 		    g_print ("gio-test: ...from %d: invalid sequence number %d, expected %d\n",
       
   179 			     fd, seq, seqtab[i].seq);
       
   180 		    g_assert_not_reached ();
       
   181 		    
       
   182 		    g_assert(FALSE && "gio-test failed");
       
   183 		  }
       
   184 		seqtab[i].seq++;
       
   185 		break;
       
   186 	      }
       
   187 
       
   188 	  error = read_all (fd, channel, (gchar *) &nbytes, sizeof (nbytes), &nb);
       
   189 	}
       
   190 
       
   191       if (error != G_IO_ERROR_NONE)
       
   192 	return FALSE;
       
   193       
       
   194       if (nb == 0)
       
   195 	{
       
   196 #ifdef VERBOSE
       
   197 	  g_print ("gio-test: ...from %d: EOF\n", fd);
       
   198 #endif
       
   199 	  shutdown_source (data);
       
   200 	  return FALSE;
       
   201 	}
       
   202       
       
   203       g_assert (nb == sizeof (nbytes));
       
   204 
       
   205       if (nbytes >= BUFSIZE)
       
   206 	{
       
   207 	  g_print ("gio-test: ...from %d: nbytes = %d (%#x)!\n", fd, nbytes, nbytes);
       
   208 	  g_assert_not_reached ();
       
   209 	  g_assert(FALSE && "gio-test failed");
       
   210 	}
       
   211       g_assert (nbytes >= 0 && nbytes < BUFSIZE);
       
   212 #ifdef VERBOSE      
       
   213       g_print ("gio-test: ...from %d: %d bytes\n", fd, nbytes);
       
   214 #endif      
       
   215       if (nbytes > 0)
       
   216 	{
       
   217 	  error = read_all (fd, channel, buf, nbytes, &nb);
       
   218 	  if(child_terminated)
       
   219 	  	shutdown_source (data);
       
   220 	  	
       
   221 
       
   222 	  if (error != G_IO_ERROR_NONE)
       
   223 	    return FALSE;
       
   224 
       
   225 	  if (nb == 0)
       
   226 	    {
       
   227 #ifdef VERBOSE
       
   228 	      g_print ("gio-test: ...from %d: EOF\n", fd);
       
   229 #endif
       
   230 	      shutdown_source (data);
       
   231 	      return FALSE;
       
   232 	    }
       
   233       
       
   234 	  for (j = 0; j < nbytes; j++)
       
   235 	    if (buf[j] != ' ' + ((nbytes + j) % 95))
       
   236 	      {
       
   237 		g_print ("gio-test: ...from %d: buf[%d] == '%c', should be '%c'\n",
       
   238 			 fd, j, buf[j], 'a' + ((nbytes + j) % 32));
       
   239 		g_assert_not_reached ();
       
   240 		g_assert(FALSE && "gio-test failed");
       
   241 	      }
       
   242 #ifdef VERBOSE
       
   243 	  g_print ("gio-test: ...from %d: OK\n", fd);
       
   244 #endif
       
   245 	}
       
   246     }
       
   247   return retval;
       
   248 }
       
   249 
       
   250 #ifdef G_OS_WIN32
       
   251 
       
   252 static gboolean
       
   253 recv_windows_message (GIOChannel  *channel,
       
   254 		      GIOCondition cond,
       
   255 		      gpointer    data)
       
   256 {
       
   257   GIOError error;
       
   258   MSG msg;
       
   259   guint nb;
       
   260   
       
   261   while (1)
       
   262     {
       
   263       error = g_io_channel_read (channel, &msg, sizeof (MSG), &nb);
       
   264       
       
   265       if (error != G_IO_ERROR_NONE)
       
   266 	{
       
   267 	  g_print ("gio-test: ...reading Windows message: G_IO_ERROR_%s\n",
       
   268 		   (error == G_IO_ERROR_AGAIN ? "AGAIN" :
       
   269 		    (error == G_IO_ERROR_INVAL ? "INVAL" :
       
   270 		     (error == G_IO_ERROR_UNKNOWN ? "UNKNOWN" : "???"))));
       
   271 	  if (error == G_IO_ERROR_AGAIN)
       
   272 	    continue;
       
   273 	}
       
   274       break;
       
   275     }
       
   276 
       
   277   g_print ("gio-test: ...Windows message for %#x: %d,%d,%d\n",
       
   278 	   msg.hwnd, msg.message, msg.wParam, msg.lParam);
       
   279 
       
   280   return TRUE;
       
   281 }
       
   282 
       
   283 LRESULT CALLBACK 
       
   284 window_procedure (HWND hwnd,
       
   285 		  UINT message,
       
   286 		  WPARAM wparam,
       
   287 		  LPARAM lparam)
       
   288 {
       
   289   g_print ("gio-test: window_procedure for %#x: %d,%d,%d\n",
       
   290 	   hwnd, message, wparam, lparam);
       
   291   return DefWindowProc (hwnd, message, wparam, lparam);
       
   292 }
       
   293 
       
   294 #endif
       
   295 
       
   296 int
       
   297 main (int    argc,
       
   298       char **argv)
       
   299 {
       
   300    
       
   301   #ifdef __SYMBIAN32__
       
   302   /*GLIB_INIT();*/
       
   303   pthread_t thread_child;
       
   304   int rc,t;
       
   305   g_log_set_handler (NULL,  G_LOG_FLAG_FATAL| G_LOG_FLAG_RECURSION | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG, &mrtLogHandler, NULL);
       
   306   g_set_print_handler(mrtPrintHandler);
       
   307   #endif /*__SYMBIAN32__*/
       
   308  
       
   309   #ifdef VERBOSE
       
   310 printf("started tests\n");
       
   311 #endif
       
   312   if (argc < 3)
       
   313     {
       
   314       /* Parent */
       
   315       
       
   316       GIOChannel *my_read_channel;
       
   317       gchar *cmdline;
       
   318       guint *id;
       
   319       int i;
       
   320 #ifdef G_OS_WIN32
       
   321       GTimeVal start, end;
       
   322       GPollFD pollfd;
       
   323       int pollresult;
       
   324       ATOM klass;
       
   325       static WNDCLASS wcl;
       
   326       HWND hwnd;
       
   327       GIOChannel *windows_messages_channel;
       
   328 #endif
       
   329 
       
   330       nkiddies = (argc == 1 ? 1 : atoi(argv[1]));
       
   331       seqtab = g_malloc (nkiddies * 2 * sizeof (int));
       
   332 
       
   333 #ifdef G_OS_WIN32
       
   334       wcl.style = 0;
       
   335       wcl.lpfnWndProc = window_procedure;
       
   336       wcl.cbClsExtra = 0;
       
   337       wcl.cbWndExtra = 0;
       
   338       wcl.hInstance = GetModuleHandle (NULL);
       
   339       wcl.hIcon = NULL;
       
   340       wcl.hCursor = NULL;
       
   341       wcl.hbrBackground = NULL;
       
   342       wcl.lpszMenuName = NULL;
       
   343       wcl.lpszClassName = "gio-test";
       
   344 
       
   345       klass = RegisterClass (&wcl);
       
   346 
       
   347       if (!klass)
       
   348 	{
       
   349 	  g_print ("gio-test: RegisterClass failed\n");
       
   350 	  exit (1);
       
   351 	}
       
   352 
       
   353       hwnd = CreateWindow (MAKEINTATOM(klass), "gio-test", 0, 0, 0, 10, 10,
       
   354 			   NULL, NULL, wcl.hInstance, NULL);
       
   355       if (!hwnd)
       
   356 	{
       
   357 	  g_print ("gio-test: CreateWindow failed\n");
       
   358 	  exit (1);
       
   359 	}
       
   360 
       
   361       windows_messages_channel = g_io_channel_win32_new_messages ((guint)hwnd);
       
   362       g_io_add_watch (windows_messages_channel, G_IO_IN, recv_windows_message, 0);
       
   363 #endif
       
   364 
       
   365       for (i = 0; i < nkiddies; i++)
       
   366 	{
       
   367 	  int pipe_to_sub[2], pipe_from_sub[2];
       
   368 	  
       
   369 	  if (pipe (pipe_to_sub) == -1 ||
       
   370 	      pipe (pipe_from_sub) == -1)
       
   371 	    perror ("pipe"), exit (1);
       
   372 	  
       
   373 	  seqtab[i].fd = pipe_from_sub[0];
       
   374 	  seqtab[i].seq = 0;
       
   375 
       
   376 	  my_read_channel = g_io_channel_unix_new (pipe_from_sub[0]);
       
   377 	  
       
   378 	  id = g_new (guint, 1);
       
   379 	  *id =
       
   380 	    g_io_add_watch (my_read_channel,
       
   381 			    G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
       
   382 			    recv_message,
       
   383 			    id);
       
   384 	  
       
   385 	  nrunning++;
       
   386 	  
       
   387 #ifdef G_OS_WIN32
       
   388 	  cmdline = g_strdup_printf ("%d:%d:%d",
       
   389 				     pipe_to_sub[0],
       
   390 				     pipe_from_sub[1],
       
   391 				     hwnd);
       
   392 	  _spawnl (_P_NOWAIT, argv[0], argv[0], "--child", cmdline, NULL);
       
   393 #else
       
   394 	  cmdline = g_strdup_printf ("%s --child %d:%d &", argv[0],
       
   395 				     pipe_to_sub[0], pipe_from_sub[1]);
       
   396 	  
       
   397 #ifndef __SYMBIAN32__
       
   398 	  system (cmdline);
       
   399 #else
       
   400 	 from_descriptor = pipe_to_sub[0];
       
   401      to_descriptor = pipe_from_sub[1]; 
       
   402 	  rc = pthread_create(&thread_child,NULL,child_function,NULL);
       
   403      
       
   404 
       
   405 	  if(rc)
       
   406 	  {
       
   407 	  	g_print("Failed to create thread.\n");
       
   408 	  	exit(1);
       
   409 	  }
       
   410 #endif /*__SYMBIAN32__*/	  
       
   411 	  
       
   412 #endif
       
   413 
       
   414 #ifndef __SYMBIAN32__
       
   415 	  close (pipe_to_sub[0]);
       
   416 	  close (pipe_from_sub [1]);
       
   417 #endif	  
       
   418 
       
   419 #ifdef G_OS_WIN32
       
   420 	  g_get_current_time (&start);
       
   421 	  g_io_channel_win32_make_pollfd (my_read_channel, G_IO_IN, &pollfd);
       
   422 	  pollresult = g_io_channel_win32_poll (&pollfd, 1, 100);
       
   423 	  g_get_current_time (&end);
       
   424 	  if (end.tv_usec < start.tv_usec)
       
   425 	    end.tv_sec--, end.tv_usec += 1000000;
       
   426 	  g_print ("gio-test: had to wait %ld.%03ld s, result:%d\n",
       
   427 		   end.tv_sec - start.tv_sec,
       
   428 		   (end.tv_usec - start.tv_usec) / 1000,
       
   429 		   pollresult);
       
   430 #endif
       
   431 	}
       
   432       
       
   433       main_loop = g_main_loop_new (NULL, FALSE);
       
   434       
       
   435       g_main_loop_run (main_loop);
       
   436     }
       
   437   else if (argc == 3)
       
   438     {
       
   439       /* Child */
       
   440       
       
   441       int readfd, writefd;
       
   442 #ifdef G_OS_WIN32
       
   443       HWND hwnd;
       
   444 #endif
       
   445       int i, j;
       
   446       char buf[BUFSIZE];
       
   447       int buflen;
       
   448       GTimeVal tv;
       
   449       int n;
       
   450   
       
   451       g_get_current_time (&tv);
       
   452       
       
   453       sscanf (argv[2], "%d:%d%n", &readfd, &writefd, &n);
       
   454 
       
   455 #ifdef G_OS_WIN32
       
   456       sscanf (argv[2] + n, ":%d", &hwnd);
       
   457 #endif
       
   458       
       
   459       srand (tv.tv_sec ^ (tv.tv_usec / 1000) ^ readfd ^ (writefd << 4));
       
   460   
       
   461       for (i = 0; i < 20 + rand() % 20; i++)
       
   462 	{
       
   463 	  g_usleep (100 + (rand() % 10) * 5000);
       
   464 	  buflen = rand() % BUFSIZE;
       
   465 	  for (j = 0; j < buflen; j++)
       
   466 	    buf[j] = ' ' + ((buflen + j) % 95);
       
   467 #ifdef VERBOSE
       
   468 	  g_print ("gio-test: child writing %d+%d bytes to %d\n",
       
   469 		   (int)(sizeof(i) + sizeof(buflen)), buflen, writefd);
       
   470 #endif
       
   471 	  write (writefd, &i, sizeof (i));
       
   472 	  write (writefd, &buflen, sizeof (buflen));
       
   473 	  write (writefd, buf, buflen);
       
   474 
       
   475 #ifdef G_OS_WIN32
       
   476 	  if (rand() % 100 < 5)
       
   477 	    {
       
   478 	      int msg = WM_USER + (rand() % 100);
       
   479 	      WPARAM wparam = rand ();
       
   480 	      LPARAM lparam = rand ();
       
   481 	      g_print ("gio-test: child posting message %d,%d,%d to %#x\n",
       
   482 		       msg, wparam, lparam, hwnd);
       
   483 	      PostMessage (hwnd, msg, wparam, lparam);
       
   484 	    }
       
   485 #endif
       
   486 	}
       
   487 #ifdef VERBOSE
       
   488       g_print ("gio-test: child exiting, closing %d\n", writefd);
       
   489 #endif
       
   490       close (writefd);
       
   491     }
       
   492   else
       
   493     g_print ("Huh?\n");
       
   494   
       
   495 
       
   496 #ifdef __SYMBIAN32__
       
   497   close(from_descriptor);
       
   498   close(to_descriptor);
       
   499 #endif
       
   500 
       
   501   #if __SYMBIAN32__
       
   502   testResultXml("gio-test");
       
   503   #endif /* EMULATOR */
       
   504   
       
   505 #ifdef VERBOSE
       
   506 printf("Completed tests\n");
       
   507 #endif
       
   508   
       
   509   return 0;
       
   510 }
       
   511 
       
   512 #ifdef __SYMBIAN32__
       
   513 void *child_function(void* t)
       
   514 {
       
   515       int readfd, writefd;
       
   516 
       
   517       int i, j;
       
   518       char buf[BUFSIZE];
       
   519       int buflen;
       
   520       GTimeVal tv;
       
   521       int n;
       
   522 #ifdef VERBOSE
       
   523       g_print ("gio-test: ...entering child_function()");
       
   524 #endif  
       
   525       g_get_current_time (&tv);
       
   526 
       
   527 
       
   528       readfd=from_descriptor;
       
   529       writefd=to_descriptor;
       
   530 
       
   531       srand (tv.tv_sec ^ (tv.tv_usec / 1000) ^ readfd ^ (writefd << 4));
       
   532   
       
   533       for (i = 0; i < 5; i++)
       
   534 	  {
       
   535 	    if(i==4)
       
   536 	    	child_terminated = TRUE;
       
   537 	    g_usleep (100 + (rand() % 10) * 5000);
       
   538 	    buflen = rand() % BUFSIZE;
       
   539 	    for (j = 0; j < buflen; j++)
       
   540 	      buf[j] = ' ' + ((buflen + j) % 95);
       
   541 #ifdef VERBOSE
       
   542 	    g_print ("gio-test: child writing %d+%d bytes to %d\n",
       
   543 		   (int)(sizeof(i) + sizeof(buflen)), buflen, writefd);
       
   544 #endif
       
   545 	    write (writefd, &i, sizeof (i));
       
   546 	    write (writefd, &buflen, sizeof (buflen));
       
   547 	    write (writefd, buf, buflen);
       
   548 	  }
       
   549 #ifdef VERBOSE
       
   550       g_print ("gio-test: child exiting, closing %d\n", writefd);
       
   551 #endif
       
   552       close (writefd);
       
   553       
       
   554 }
       
   555 #endif