LCOV - code coverage report
Current view: top level - glib/glib/tests - io-channel-basic.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 104 122 85.2 %
Date: 2024-03-26 05:16:46 Functions: 7 7 100.0 %
Branches: 39 56 69.6 %

           Branch data     Line data    Source code
       1                 :            : /* GLIB - Library of useful routines for C programming
       2                 :            :  * Copyright (C) 2000  Tor Lillqvist
       3                 :            :  *
       4                 :            :  * SPDX-License-Identifier: LGPL-2.1-or-later
       5                 :            :  *
       6                 :            :  * This library is free software; you can redistribute it and/or
       7                 :            :  * modify it under the terms of the GNU Lesser General Public
       8                 :            :  * License as published by the Free Software Foundation; either
       9                 :            :  * version 2.1 of the License, or (at your option) any later version.
      10                 :            :  *
      11                 :            :  * This library is distributed in the hope that it will be useful,
      12                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14                 :            :  * Lesser General Public License for more details.
      15                 :            :  *
      16                 :            :  * You should have received a copy of the GNU Lesser General Public
      17                 :            :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      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                 :            : /* We are using g_io_channel_read() which is deprecated */
      25                 :            : #ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
      26                 :            : #define GLIB_DISABLE_DEPRECATION_WARNINGS
      27                 :            : #endif
      28                 :            : 
      29                 :            : #include "config.h"
      30                 :            : 
      31                 :            : #include <glib.h>
      32                 :            : 
      33                 :            : #include <stdio.h>
      34                 :            : 
      35                 :            : #ifdef G_OS_WIN32
      36                 :            :   #include <io.h>
      37                 :            :   #include <fcntl.h>
      38                 :            :   #include <process.h>
      39                 :            :   #define STRICT
      40                 :            :   #include <windows.h>
      41                 :            :   #define pipe(fds) _pipe(fds, 4096, _O_BINARY)
      42                 :            : #endif
      43                 :            : 
      44                 :            : #ifdef G_OS_UNIX
      45                 :            :   #include <unistd.h>
      46                 :            : #endif
      47                 :            : 
      48                 :            : static int nrunning;
      49                 :            : static GMainLoop *main_loop;
      50                 :            : 
      51                 :            : /* Larger than the circular buffer in giowin32.c on purpose */
      52                 :            : #define BUFSIZE 5000
      53                 :            : 
      54                 :            : static int nkiddies;
      55                 :            : static char *exec_name;
      56                 :            : 
      57                 :            : static struct {
      58                 :            :   int fd;
      59                 :            :   int seq;
      60                 :            : } *seqtab;
      61                 :            : 
      62                 :            : static GIOError
      63                 :        399 : read_all (int         fd,
      64                 :            :           GIOChannel *channel,
      65                 :            :           char       *buffer,
      66                 :            :           guint       nbytes,
      67                 :            :           guint      *bytes_read)
      68                 :            : {
      69                 :        399 :   guint left = nbytes;
      70                 :            :   gsize nb;
      71                 :        399 :   GIOError error = G_IO_ERROR_NONE;
      72                 :        399 :   char *bufp = buffer;
      73                 :            : 
      74                 :            :   /* g_io_channel_read() doesn't necessarily return all the
      75                 :            :    * data we want at once.
      76                 :            :    */
      77                 :        399 :   *bytes_read = 0;
      78         [ +  + ]:        798 :   while (left)
      79                 :            :     {
      80                 :        399 :       error = g_io_channel_read (channel, bufp, left, &nb);
      81                 :            : 
      82         [ -  + ]:        399 :       if (error != G_IO_ERROR_NONE)
      83                 :            :         {
      84                 :          0 :           g_test_message ("io-channel-basic: ...from %d: %d", fd, error);
      85         [ #  # ]:          0 :           if (error == G_IO_ERROR_AGAIN)
      86                 :          0 :             continue;
      87                 :          0 :           break;
      88                 :            :         }
      89         [ -  + ]:        399 :       if (nb == 0)
      90                 :          0 :         return error;
      91                 :        399 :       left -= nb;
      92                 :        399 :       bufp += nb;
      93                 :        399 :       *bytes_read += nb;
      94                 :            :     }
      95                 :        399 :   return error;
      96                 :            : }
      97                 :            : 
      98                 :            : static void
      99                 :          6 : shutdown_source (gpointer data)
     100                 :            : {
     101                 :          6 :   guint *fd_ptr = data;
     102                 :            : 
     103         [ +  - ]:          6 :   if (*fd_ptr != 0)
     104                 :            :     {
     105                 :          6 :       g_source_remove (*fd_ptr);
     106                 :          6 :       *fd_ptr = 0;
     107                 :            : 
     108                 :          6 :       nrunning--;
     109         [ +  + ]:          6 :       if (nrunning == 0)
     110                 :          2 :         g_main_loop_quit (main_loop);
     111                 :            :     }
     112                 :          6 : }
     113                 :            : 
     114                 :            : static gboolean
     115                 :        137 : recv_message (GIOChannel  *channel,
     116                 :            :               GIOCondition cond,
     117                 :            :               gpointer    data)
     118                 :            : {
     119                 :        137 :   gint fd = g_io_channel_unix_get_fd (channel);
     120                 :        137 :   gboolean retval = TRUE;
     121                 :            : 
     122   [ -  +  +  +  :        137 :   g_debug ("io-channel-basic: ...from %d:%s%s%s%s", fd,
             +  +  -  + ]
     123                 :            :            (cond & G_IO_ERR) ? " ERR" : "",
     124                 :            :            (cond & G_IO_HUP) ? " HUP" : "",
     125                 :            :            (cond & G_IO_IN)  ? " IN"  : "",
     126                 :            :            (cond & G_IO_PRI) ? " PRI" : "");
     127                 :            : 
     128         [ +  + ]:        137 :   if (cond & (G_IO_ERR | G_IO_HUP))
     129                 :            :     {
     130                 :          6 :       shutdown_source (data);
     131                 :          6 :       retval = FALSE;
     132                 :            :     }
     133                 :            : 
     134         [ +  + ]:        137 :   if (cond & G_IO_IN)
     135                 :            :     {
     136                 :            :       char buf[BUFSIZE];
     137                 :        133 :       guint nbytes = 0;
     138                 :            :       guint nb;
     139                 :            :       guint j;
     140                 :            :       int i, seq;
     141                 :            :       GIOError error;
     142                 :            : 
     143                 :        133 :       error = read_all (fd, channel, (gchar *) &seq, sizeof (seq), &nb);
     144         [ +  - ]:        133 :       if (error == G_IO_ERROR_NONE)
     145                 :            :         {
     146         [ -  + ]:        133 :           if (nb == 0)
     147                 :            :             {
     148                 :          0 :               g_debug ("io-channel-basic: ...from %d: EOF", fd);
     149                 :          0 :               shutdown_source (data);
     150                 :          0 :               return FALSE;
     151                 :            :             }
     152                 :        133 :           g_assert_cmpuint (nb, ==, sizeof (nbytes));
     153                 :            : 
     154         [ +  - ]:        362 :           for (i = 0; i < nkiddies; i++)
     155         [ +  + ]:        362 :             if (seqtab[i].fd == fd)
     156                 :            :               {
     157                 :        133 :                 g_assert_cmpint (seq, ==, seqtab[i].seq);
     158                 :        133 :                 seqtab[i].seq++;
     159                 :        133 :                 break;
     160                 :            :               }
     161                 :            : 
     162                 :            :           error =
     163                 :        133 :             read_all (fd, channel, (gchar *) &nbytes, sizeof (nbytes), &nb);
     164                 :            :         }
     165                 :            : 
     166         [ -  + ]:        133 :       if (error != G_IO_ERROR_NONE)
     167                 :          0 :         return FALSE;
     168                 :            : 
     169         [ -  + ]:        133 :       if (nb == 0)
     170                 :            :         {
     171                 :          0 :           g_debug ("io-channel-basic: ...from %d: EOF", fd);
     172                 :          0 :           shutdown_source (data);
     173                 :          0 :           return FALSE;
     174                 :            :         }
     175                 :        133 :       g_assert_cmpuint (nb, ==, sizeof (nbytes));
     176                 :            : 
     177                 :        133 :       g_assert_cmpuint (nbytes, <, BUFSIZE);
     178                 :        133 :       g_debug ("io-channel-basic: ...from %d: %d bytes", fd, nbytes);
     179         [ +  - ]:        133 :       if (nbytes > 0)
     180                 :            :         {
     181                 :        133 :           error = read_all (fd, channel, buf, nbytes, &nb);
     182                 :            : 
     183         [ -  + ]:        133 :           if (error != G_IO_ERROR_NONE)
     184                 :          0 :             return FALSE;
     185                 :            : 
     186         [ -  + ]:        133 :           if (nb == 0)
     187                 :            :             {
     188                 :          0 :               g_debug ("io-channel-basic: ...from %d: EOF", fd);
     189                 :          0 :               shutdown_source (data);
     190                 :          0 :               return FALSE;
     191                 :            :             }
     192                 :            : 
     193         [ +  + ]:     316915 :           for (j = 0; j < nbytes; j++)
     194                 :     316782 :             g_assert_cmpint (buf[j], ==, ' ' + (char) ((nbytes + j) % 95));
     195                 :        133 :           g_debug ("io-channel-basic: ...from %d: OK", fd);
     196                 :            :         }
     197                 :            :     }
     198                 :        137 :   return retval;
     199                 :            : }
     200                 :            : 
     201                 :            : #ifdef G_OS_WIN32
     202                 :            : static gboolean
     203                 :            : recv_windows_message (GIOChannel  *channel,
     204                 :            :                       GIOCondition cond,
     205                 :            :                       gpointer    data)
     206                 :            : {
     207                 :            :   GIOError error;
     208                 :            :   MSG msg;
     209                 :            :   gsize nb;
     210                 :            : 
     211                 :            :   while (1)
     212                 :            :     {
     213                 :            :       error = g_io_channel_read (channel, (gchar *) &msg, sizeof (MSG), &nb);
     214                 :            : 
     215                 :            :       if (error != G_IO_ERROR_NONE)
     216                 :            :         {
     217                 :            :           g_test_message ("io-channel-basic: ...reading Windows message: G_IO_ERROR_%s",
     218                 :            :                           (error == G_IO_ERROR_AGAIN ? "AGAIN" : (error == G_IO_ERROR_INVAL ? "INVAL" : (error == G_IO_ERROR_UNKNOWN ? "UNKNOWN" : "???"))));
     219                 :            :           if (error == G_IO_ERROR_AGAIN)
     220                 :            :             continue;
     221                 :            :         }
     222                 :            :       break;
     223                 :            :     }
     224                 :            : 
     225                 :            :   g_test_message ("io-channel-basic: ...Windows message for 0x%p: %d,%" G_GUINTPTR_FORMAT ",%" G_GINTPTR_FORMAT,
     226                 :            :                   msg.hwnd, msg.message, msg.wParam, (gintptr) msg.lParam);
     227                 :            : 
     228                 :            :   return TRUE;
     229                 :            : }
     230                 :            : 
     231                 :            : LRESULT CALLBACK window_procedure (HWND   hwnd,
     232                 :            :                                    UINT   message,
     233                 :            :                                    WPARAM wparam,
     234                 :            :                                    LPARAM lparam);
     235                 :            : 
     236                 :            : LRESULT CALLBACK
     237                 :            : window_procedure (HWND hwnd,
     238                 :            :                   UINT message,
     239                 :            :                   WPARAM wparam,
     240                 :            :                   LPARAM lparam)
     241                 :            : {
     242                 :            :   g_test_message ("io-channel-basic: window_procedure for 0x%p: %d,%" G_GUINTPTR_FORMAT ",%" G_GINTPTR_FORMAT,
     243                 :            :                   hwnd, message, wparam, (gintptr) lparam);
     244                 :            :   return DefWindowProc (hwnd, message, wparam, lparam);
     245                 :            : }
     246                 :            : #endif
     247                 :            : 
     248                 :            : static void
     249                 :          2 : spawn_process (int children_nb)
     250                 :            : {
     251                 :            :   GIOChannel *my_read_channel;
     252                 :            :   gchar *cmdline;
     253                 :            :   int i;
     254                 :            : 
     255                 :            : #ifdef G_OS_WIN32
     256                 :            :   gint64 start, end;
     257                 :            :   GPollFD pollfd;
     258                 :            :   int pollresult;
     259                 :            :   ATOM klass;
     260                 :            :   static WNDCLASS wcl;
     261                 :            :   HWND hwnd;
     262                 :            :   GIOChannel *windows_messages_channel;
     263                 :            : 
     264                 :            :   wcl.style = 0;
     265                 :            :   wcl.lpfnWndProc = window_procedure;
     266                 :            :   wcl.cbClsExtra = 0;
     267                 :            :   wcl.cbWndExtra = 0;
     268                 :            :   wcl.hInstance = GetModuleHandle (NULL);
     269                 :            :   wcl.hIcon = NULL;
     270                 :            :   wcl.hCursor = NULL;
     271                 :            :   wcl.hbrBackground = NULL;
     272                 :            :   wcl.lpszMenuName = NULL;
     273                 :            :   wcl.lpszClassName = L"io-channel-basic";
     274                 :            : 
     275                 :            :   klass = RegisterClass (&wcl);
     276                 :            :   g_assert_cmpint (klass, !=, 0);
     277                 :            : 
     278                 :            :   hwnd = CreateWindow (MAKEINTATOM (klass), L"io-channel-basic", 0, 0, 0, 10, 10,
     279                 :            :                        NULL, NULL, wcl.hInstance, NULL);
     280                 :            :   g_assert_nonnull (hwnd);
     281                 :            : 
     282                 :            :   windows_messages_channel =
     283                 :            :     g_io_channel_win32_new_messages ((guint) (guintptr) hwnd);
     284                 :            :   g_io_add_watch (windows_messages_channel, G_IO_IN, recv_windows_message, 0);
     285                 :            : #endif
     286                 :            : 
     287                 :          2 :   nkiddies = (children_nb > 0 ? children_nb : 1);
     288                 :          2 :   seqtab = g_malloc (nkiddies * 2 * sizeof (int));
     289                 :            : 
     290         [ +  + ]:          8 :   for (i = 0; i < nkiddies; i++)
     291                 :            :     {
     292                 :            :       guint *id;
     293                 :            :       int pipe_to_sub[2], pipe_from_sub[2];
     294                 :            : 
     295   [ +  -  -  + ]:          6 :       if (pipe (pipe_to_sub) == -1 || pipe (pipe_from_sub) == -1)
     296                 :            :         {
     297                 :          0 :           perror ("pipe");
     298                 :          0 :           exit (1);
     299                 :            :         }
     300                 :            : 
     301                 :          6 :       seqtab[i].fd = pipe_from_sub[0];
     302                 :          6 :       seqtab[i].seq = 0;
     303                 :            : 
     304                 :          6 :       my_read_channel = g_io_channel_unix_new (pipe_from_sub[0]);
     305                 :            : 
     306                 :          6 :       id = g_new (guint, 1);
     307                 :          6 :       *id = g_io_add_watch_full (my_read_channel,
     308                 :            :                                  G_PRIORITY_DEFAULT,
     309                 :            :                                  G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
     310                 :            :                                  recv_message,
     311                 :            :                                  id, g_free);
     312                 :          6 :       nrunning++;
     313                 :            : 
     314                 :            : #ifdef G_OS_WIN32
     315                 :            :       /* Spawn new Win32 process */
     316                 :            :       cmdline =
     317                 :            :         g_strdup_printf ("%d:%d:0x%p", pipe_to_sub[0], pipe_from_sub[1], hwnd);
     318                 :            :       _spawnl (_P_NOWAIT, exec_name, exec_name, "--child", cmdline, NULL);
     319                 :            : #else
     320                 :            :       /* Spawn new Unix process */
     321                 :          6 :       cmdline = g_strdup_printf ("%s --child %d:%d &",
     322                 :            :                                  exec_name, pipe_to_sub[0], pipe_from_sub[1]);
     323                 :          6 :       g_assert_no_errno (system (cmdline));
     324                 :            : #endif
     325                 :          6 :       g_free (cmdline);
     326                 :            : 
     327                 :            :       /* Closing pipes */
     328                 :          6 :       close (pipe_to_sub[0]);
     329                 :          6 :       close (pipe_from_sub[1]);
     330                 :            : 
     331                 :            : #ifdef G_OS_WIN32
     332                 :            :       start = g_get_monotonic_time();
     333                 :            :       g_io_channel_win32_make_pollfd (my_read_channel, G_IO_IN, &pollfd);
     334                 :            :       pollresult = g_io_channel_win32_poll (&pollfd, 1, 100);
     335                 :            :       end = g_get_monotonic_time();
     336                 :            : 
     337                 :            :       g_test_message ("io-channel-basic: had to wait %" G_GINT64_FORMAT "s, result:%d",
     338                 :            :                       (end - start) / 1000000, pollresult);
     339                 :            : #endif
     340                 :          6 :       g_io_channel_unref (my_read_channel);
     341                 :            :     }
     342                 :            : 
     343                 :          2 :   main_loop = g_main_loop_new (NULL, FALSE);
     344                 :          2 :   g_main_loop_run (main_loop);
     345                 :            : 
     346                 :          2 :   g_main_loop_unref (main_loop);
     347                 :          2 :   g_free (seqtab);
     348                 :          2 : }
     349                 :            : 
     350                 :            : static void
     351                 :          6 : run_process (int argc, char *argv[])
     352                 :            : {
     353                 :            :   int readfd, writefd;
     354                 :            :   gint64 dt;
     355                 :            :   char buf[BUFSIZE];
     356                 :            :   int buflen, i, j, n;
     357                 :            : #ifdef G_OS_WIN32
     358                 :            :   HWND hwnd;
     359                 :            : #endif
     360                 :            : 
     361                 :            :   /* Extract parameters */
     362                 :          6 :   sscanf (argv[2], "%d:%d%n", &readfd, &writefd, &n);
     363                 :            : #ifdef G_OS_WIN32
     364                 :            :   sscanf (argv[2] + n, ":0x%p", &hwnd);
     365                 :            : #endif
     366                 :            : 
     367                 :          6 :   dt = g_get_monotonic_time();
     368                 :          6 :   srand (dt ^ (dt / 1000) ^ readfd ^ (writefd << 4));
     369                 :            : 
     370         [ +  + ]:        139 :   for (i = 0; i < 20 + rand () % 10; i++)
     371                 :            :     {
     372                 :        133 :       g_usleep ((100 + rand () % 10) * 2500);
     373                 :        133 :       buflen = rand () % BUFSIZE;
     374         [ +  + ]:     316915 :       for (j = 0; j < buflen; j++)
     375                 :     316782 :         buf[j] = ' ' + ((buflen + j) % 95);
     376                 :        133 :       g_debug ("io-channel-basic: child writing %d+%d bytes to %d",
     377                 :            :                (int) (sizeof (i) + sizeof (buflen)), buflen, writefd);
     378                 :        133 :       g_assert_cmpint (write (writefd, &i, sizeof (i)), ==, sizeof (i));
     379                 :        133 :       g_assert_cmpint (write (writefd, &buflen, sizeof (buflen)), ==, sizeof (buflen));
     380                 :        133 :       g_assert_cmpint (write (writefd, buf, buflen), ==, buflen);
     381                 :            : 
     382                 :            : #ifdef G_OS_WIN32
     383                 :            :       if (i % 10 == 0)
     384                 :            :         {
     385                 :            :           int msg = WM_USER + (rand () % 100);
     386                 :            :           WPARAM wparam = rand ();
     387                 :            :           LPARAM lparam = rand ();
     388                 :            :           g_test_message ("io-channel-basic: child posting message %d,%" G_GUINTPTR_FORMAT ",%" G_GINTPTR_FORMAT " to 0x%p",
     389                 :            :                           msg, wparam, (gintptr) lparam, hwnd);
     390                 :            :           PostMessage (hwnd, msg, wparam, lparam);
     391                 :            :         }
     392                 :            : #endif
     393                 :            :     }
     394                 :          6 :   g_debug ("io-channel-basic: child exiting, closing %d", writefd);
     395                 :          6 :   close (writefd);
     396                 :          6 : }
     397                 :            : 
     398                 :            : static void
     399                 :          1 : test_io_basics (void)
     400                 :            : {
     401                 :          1 :   spawn_process (1);
     402                 :            : #ifndef G_OS_WIN32
     403                 :          1 :   spawn_process (5);
     404                 :            : #endif
     405                 :          1 : }
     406                 :            : 
     407                 :            : int
     408                 :          7 : main (int argc, char *argv[])
     409                 :            : {
     410                 :            :   /* Get executable name */
     411                 :          7 :   exec_name = argv[0];
     412                 :            : 
     413                 :            :   /* Run the tests */
     414                 :          7 :   g_test_init (&argc, &argv, NULL);
     415                 :            : 
     416                 :            :   /* Run subprocess, if it is the case */
     417         [ +  + ]:          7 :   if (argc > 2)
     418                 :            :     {
     419                 :          6 :       run_process (argc, argv);
     420                 :          6 :       return 0;
     421                 :            :     }
     422                 :            : 
     423                 :          1 :   g_test_add_func ("/gio/io-basics", test_io_basics);
     424                 :            : 
     425                 :          1 :   return g_test_run ();
     426                 :            : }

Generated by: LCOV version 1.14