sl@0: /* GLIB - Library of useful routines for C programming sl@0: * Copyright (C) 2000 Tor Lillqvist sl@0: * Portion Copyright © 2008-09 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. sl@0: * This library is free software; you can redistribute it and/or sl@0: * modify it under the terms of the GNU Lesser General Public sl@0: * License as published by the Free Software Foundation; either sl@0: * version 2 of the License, or (at your option) any later version. sl@0: * sl@0: * This library is distributed in the hope that it will be useful, sl@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of sl@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU sl@0: * Lesser General Public License for more details. sl@0: * sl@0: * You should have received a copy of the GNU Lesser General Public sl@0: * License along with this library; if not, write to the sl@0: * Free Software Foundation, Inc., 59 Temple Place - Suite 330, sl@0: * Boston, MA 02111-1307, USA. sl@0: */ sl@0: sl@0: /* A test program for the main loop and IO channel code. sl@0: * Just run it. Optional parameter is number of sub-processes. sl@0: */ sl@0: sl@0: sl@0: #undef G_DISABLE_ASSERT sl@0: #undef G_LOG_DOMAIN sl@0: sl@0: #include "config.h" sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #ifdef SYMBIAN sl@0: //#define VERBOSE sl@0: #include sl@0: #include "mrt2_glib2_test.h" sl@0: void *child_function(void*); sl@0: gboolean child_terminated = FALSE; sl@0: int from_descriptor, to_descriptor; sl@0: #endif /*SYMBIAN*/ sl@0: sl@0: #ifdef G_OS_WIN32 sl@0: #include sl@0: #include sl@0: #include sl@0: #define STRICT sl@0: #include sl@0: #else sl@0: #ifdef HAVE_UNISTD_H sl@0: #include sl@0: #endif sl@0: #endif sl@0: sl@0: sl@0: static int nrunning; sl@0: static GMainLoop *main_loop; sl@0: sl@0: #ifdef SYMBIAN sl@0: #define BUFSIZE 1000 sl@0: #else sl@0: #define BUFSIZE 5000 /* Larger than the circular buffer in giowin32.c on purpose.*/ sl@0: #endif sl@0: sl@0: static int nkiddies; sl@0: sl@0: static struct { sl@0: int fd; sl@0: int seq; sl@0: } *seqtab; sl@0: sl@0: sl@0: sl@0: static GIOError sl@0: read_all (int fd, sl@0: GIOChannel *channel, sl@0: char *buffer, sl@0: guint nbytes, sl@0: guint *bytes_read) sl@0: { sl@0: guint left = nbytes; sl@0: gsize nb; sl@0: GIOError error = G_IO_ERROR_NONE; sl@0: char *bufp = buffer; sl@0: sl@0: /* g_io_channel_read() doesn't necessarily return all the sl@0: * data we want at once. sl@0: */ sl@0: *bytes_read = 0; sl@0: while (left) sl@0: { sl@0: error = g_io_channel_read (channel, bufp, left, &nb); sl@0: sl@0: if (error != G_IO_ERROR_NONE) sl@0: { sl@0: g_print ("gio-test: ...from %d: G_IO_ERROR_%s\n", fd, sl@0: (error == G_IO_ERROR_AGAIN ? "AGAIN" : sl@0: (error == G_IO_ERROR_INVAL ? "INVAL" : sl@0: (error == G_IO_ERROR_UNKNOWN ? "UNKNOWN" : "???")))); sl@0: if (error == G_IO_ERROR_AGAIN) sl@0: continue; sl@0: break; sl@0: } sl@0: if (nb == 0) sl@0: return error; sl@0: left -= nb; sl@0: bufp += nb; sl@0: *bytes_read += nb; sl@0: } sl@0: return error; sl@0: } sl@0: sl@0: static void sl@0: shutdown_source (gpointer data) sl@0: { sl@0: if (g_source_remove (*(guint *) data)) sl@0: { sl@0: nrunning--; sl@0: if (nrunning == 0) sl@0: g_main_loop_quit (main_loop); sl@0: } sl@0: } sl@0: sl@0: static gboolean sl@0: recv_message (GIOChannel *channel, sl@0: GIOCondition cond, sl@0: gpointer data) sl@0: { sl@0: gint fd = g_io_channel_unix_get_fd (channel); sl@0: gboolean retval = TRUE; sl@0: sl@0: #ifdef VERBOSE sl@0: g_print ("gio-test: ...from %d:%s%s%s%s\n", fd, sl@0: (cond & G_IO_ERR) ? " ERR" : "", sl@0: (cond & G_IO_HUP) ? " HUP" : "", sl@0: (cond & G_IO_IN) ? " IN" : "", sl@0: (cond & G_IO_PRI) ? " PRI" : ""); sl@0: #endif sl@0: sl@0: if ((cond & (G_IO_ERR | G_IO_HUP))) sl@0: { sl@0: shutdown_source (data); sl@0: retval = FALSE; sl@0: } sl@0: sl@0: if (cond & G_IO_IN) sl@0: { sl@0: char buf[BUFSIZE]; sl@0: guint nbytes; sl@0: guint nb; sl@0: int i, j, seq; sl@0: GIOError error; sl@0: sl@0: error = read_all (fd, channel, (gchar *) &seq, sizeof (seq), &nb); sl@0: if (error == G_IO_ERROR_NONE) sl@0: { sl@0: if (nb == 0) sl@0: { sl@0: #ifdef VERBOSE sl@0: g_print ("gio-test: ...from %d: EOF\n", fd); sl@0: #endif sl@0: shutdown_source (data); sl@0: return FALSE; sl@0: } sl@0: sl@0: g_assert (nb == sizeof (nbytes)); sl@0: sl@0: for (i = 0; i < nkiddies; i++) sl@0: if (seqtab[i].fd == fd) sl@0: { sl@0: if (seq != seqtab[i].seq) sl@0: { sl@0: g_print ("gio-test: ...from %d: invalid sequence number %d, expected %d\n", sl@0: fd, seq, seqtab[i].seq); sl@0: g_assert_not_reached (); sl@0: sl@0: g_assert(FALSE && "gio-test failed"); sl@0: } sl@0: seqtab[i].seq++; sl@0: break; sl@0: } sl@0: sl@0: sl@0: error = read_all (fd, channel, (gchar *) &nbytes, sizeof (nbytes), &nb); sl@0: } sl@0: sl@0: if (error != G_IO_ERROR_NONE) sl@0: return FALSE; sl@0: sl@0: if (nb == 0) sl@0: { sl@0: #ifdef VERBOSE sl@0: g_print ("gio-test: ...from %d: EOF\n", fd); sl@0: #endif sl@0: shutdown_source (data); sl@0: return FALSE; sl@0: } sl@0: sl@0: g_assert (nb == sizeof (nbytes)); sl@0: sl@0: if (nbytes >= BUFSIZE) sl@0: { sl@0: g_print ("gio-test: ...from %d: nbytes = %d (%#x)!\n", fd, nbytes, nbytes); sl@0: g_assert_not_reached (); sl@0: g_assert(FALSE && "gio-test failed"); sl@0: } sl@0: g_assert (nbytes >= 0 && nbytes < BUFSIZE); sl@0: #ifdef VERBOSE sl@0: g_print ("gio-test: ...from %d: %d bytes\n", fd, nbytes); sl@0: #endif sl@0: if (nbytes > 0) sl@0: { sl@0: error = read_all (fd, channel, buf, nbytes, &nb); sl@0: if(child_terminated) sl@0: shutdown_source (data); sl@0: sl@0: sl@0: if (error != G_IO_ERROR_NONE) sl@0: return FALSE; sl@0: sl@0: if (nb == 0) sl@0: { sl@0: #ifdef VERBOSE sl@0: g_print ("gio-test: ...from %d: EOF\n", fd); sl@0: #endif sl@0: shutdown_source (data); sl@0: return FALSE; sl@0: } sl@0: sl@0: for (j = 0; j < nbytes; j++) sl@0: if (buf[j] != ' ' + ((nbytes + j) % 95)) sl@0: { sl@0: g_print ("gio-test: ...from %d: buf[%d] == '%c', should be '%c'\n", sl@0: fd, j, buf[j], 'a' + ((nbytes + j) % 32)); sl@0: g_assert_not_reached (); sl@0: g_assert(FALSE && "gio-test failed"); sl@0: } sl@0: #ifdef VERBOSE sl@0: g_print ("gio-test: ...from %d: OK\n", fd); sl@0: #endif sl@0: } sl@0: } sl@0: return retval; sl@0: } sl@0: sl@0: #ifdef G_OS_WIN32 sl@0: sl@0: static gboolean sl@0: recv_windows_message (GIOChannel *channel, sl@0: GIOCondition cond, sl@0: gpointer data) sl@0: { sl@0: GIOError error; sl@0: MSG msg; sl@0: guint nb; sl@0: sl@0: while (1) sl@0: { sl@0: error = g_io_channel_read (channel, &msg, sizeof (MSG), &nb); sl@0: sl@0: if (error != G_IO_ERROR_NONE) sl@0: { sl@0: g_print ("gio-test: ...reading Windows message: G_IO_ERROR_%s\n", sl@0: (error == G_IO_ERROR_AGAIN ? "AGAIN" : sl@0: (error == G_IO_ERROR_INVAL ? "INVAL" : sl@0: (error == G_IO_ERROR_UNKNOWN ? "UNKNOWN" : "???")))); sl@0: if (error == G_IO_ERROR_AGAIN) sl@0: continue; sl@0: } sl@0: break; sl@0: } sl@0: sl@0: g_print ("gio-test: ...Windows message for %#x: %d,%d,%d\n", sl@0: msg.hwnd, msg.message, msg.wParam, msg.lParam); sl@0: sl@0: return TRUE; sl@0: } sl@0: sl@0: LRESULT CALLBACK sl@0: window_procedure (HWND hwnd, sl@0: UINT message, sl@0: WPARAM wparam, sl@0: LPARAM lparam) sl@0: { sl@0: g_print ("gio-test: window_procedure for %#x: %d,%d,%d\n", sl@0: hwnd, message, wparam, lparam); sl@0: return DefWindowProc (hwnd, message, wparam, lparam); sl@0: } sl@0: sl@0: #endif sl@0: sl@0: int sl@0: main (int argc, sl@0: char **argv) sl@0: { sl@0: sl@0: #ifdef SYMBIAN sl@0: /*GLIB_INIT();*/ sl@0: pthread_t thread_child; sl@0: int rc,t; sl@0: 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); sl@0: g_set_print_handler(mrtPrintHandler); sl@0: #endif /*SYMBIAN*/ sl@0: sl@0: sl@0: if (argc < 3) sl@0: { sl@0: /* Parent */ sl@0: sl@0: GIOChannel *my_read_channel; sl@0: gchar *cmdline; sl@0: guint *id; sl@0: int i; sl@0: #ifdef G_OS_WIN32 sl@0: GTimeVal start, end; sl@0: GPollFD pollfd; sl@0: int pollresult; sl@0: ATOM klass; sl@0: static WNDCLASS wcl; sl@0: HWND hwnd; sl@0: GIOChannel *windows_messages_channel; sl@0: #endif sl@0: sl@0: nkiddies = (argc == 1 ? 1 : atoi(argv[1])); sl@0: seqtab = g_malloc (nkiddies * 2 * sizeof (int)); sl@0: sl@0: #ifdef G_OS_WIN32 sl@0: wcl.style = 0; sl@0: wcl.lpfnWndProc = window_procedure; sl@0: wcl.cbClsExtra = 0; sl@0: wcl.cbWndExtra = 0; sl@0: wcl.hInstance = GetModuleHandle (NULL); sl@0: wcl.hIcon = NULL; sl@0: wcl.hCursor = NULL; sl@0: wcl.hbrBackground = NULL; sl@0: wcl.lpszMenuName = NULL; sl@0: wcl.lpszClassName = "gio-test"; sl@0: sl@0: klass = RegisterClass (&wcl); sl@0: sl@0: if (!klass) sl@0: { sl@0: g_print ("gio-test: RegisterClass failed\n"); sl@0: exit (1); sl@0: } sl@0: sl@0: hwnd = CreateWindow (MAKEINTATOM(klass), "gio-test", 0, 0, 0, 10, 10, sl@0: NULL, NULL, wcl.hInstance, NULL); sl@0: if (!hwnd) sl@0: { sl@0: g_print ("gio-test: CreateWindow failed\n"); sl@0: exit (1); sl@0: } sl@0: sl@0: windows_messages_channel = g_io_channel_win32_new_messages ((guint)hwnd); sl@0: g_io_add_watch (windows_messages_channel, G_IO_IN, recv_windows_message, 0); sl@0: #endif sl@0: sl@0: for (i = 0; i < nkiddies; i++) sl@0: { sl@0: int pipe_to_sub[2], pipe_from_sub[2]; sl@0: sl@0: if (pipe (pipe_to_sub) == -1 || sl@0: pipe (pipe_from_sub) == -1) sl@0: perror ("pipe"), exit (1); sl@0: sl@0: seqtab[i].fd = pipe_from_sub[0]; sl@0: seqtab[i].seq = 0; sl@0: sl@0: my_read_channel = g_io_channel_unix_new (pipe_from_sub[0]); sl@0: sl@0: id = g_new (guint, 1); sl@0: *id = sl@0: g_io_add_watch (my_read_channel, sl@0: G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, sl@0: recv_message, sl@0: id); sl@0: sl@0: nrunning++; sl@0: sl@0: #ifdef G_OS_WIN32 sl@0: cmdline = g_strdup_g_print ("%d:%d:%d", sl@0: pipe_to_sub[0], sl@0: pipe_from_sub[1], sl@0: hwnd); sl@0: _spawnl (_P_NOWAIT, argv[0], argv[0], "--child", cmdline, NULL); sl@0: #else sl@0: cmdline = g_strdup_printf ("%s --child %d:%d &", argv[0], sl@0: pipe_to_sub[0], pipe_from_sub[1]); sl@0: sl@0: sl@0: #ifndef SYMBIAN sl@0: system (cmdline); sl@0: #else sl@0: from_descriptor = pipe_to_sub[0]; sl@0: to_descriptor = pipe_from_sub[1]; sl@0: rc = pthread_create(&thread_child,NULL,child_function,NULL); sl@0: sl@0: sl@0: if(rc) sl@0: { sl@0: g_print("Failed to create thread.\n"); sl@0: exit(1); sl@0: } sl@0: #endif /*SYMBIAN*/ sl@0: sl@0: #endif sl@0: sl@0: #ifndef SYMBIAN sl@0: close (pipe_to_sub[0]); sl@0: close (pipe_from_sub [1]); sl@0: #endif sl@0: sl@0: #ifdef G_OS_WIN32 sl@0: g_get_current_time (&start); sl@0: g_io_channel_win32_make_pollfd (my_read_channel, G_IO_IN, &pollfd); sl@0: pollresult = g_io_channel_win32_poll (&pollfd, 1, 100); sl@0: g_get_current_time (&end); sl@0: if (end.tv_usec < start.tv_usec) sl@0: end.tv_sec--, end.tv_usec += 1000000; sl@0: g_print ("gio-test: had to wait %ld.%03ld s, result:%d\n", sl@0: end.tv_sec - start.tv_sec, sl@0: (end.tv_usec - start.tv_usec) / 1000, sl@0: pollresult); sl@0: #endif sl@0: } sl@0: sl@0: main_loop = g_main_loop_new (NULL, FALSE); sl@0: g_main_loop_run (main_loop); sl@0: sl@0: } sl@0: else if (argc == 3) sl@0: { sl@0: /* Child */ sl@0: sl@0: int readfd, writefd; sl@0: #ifdef G_OS_WIN32 sl@0: HWND hwnd; sl@0: #endif sl@0: int i, j; sl@0: char buf[BUFSIZE]; sl@0: int buflen; sl@0: GTimeVal tv; sl@0: int n; sl@0: sl@0: g_get_current_time (&tv); sl@0: sl@0: sscanf (argv[2], "%d:%d%n", &readfd, &writefd, &n); sl@0: sl@0: #ifdef G_OS_WIN32 sl@0: sscanf (argv[2] + n, ":%d", &hwnd); sl@0: #endif sl@0: sl@0: srand (tv.tv_sec ^ (tv.tv_usec / 1000) ^ readfd ^ (writefd << 4)); sl@0: sl@0: for (i = 0; i < 20 + rand() % 20; i++) sl@0: { sl@0: g_usleep (100 + (rand() % 10) * 5000); sl@0: buflen = rand() % BUFSIZE; sl@0: for (j = 0; j < buflen; j++) sl@0: buf[j] = ' ' + ((buflen + j) % 95); sl@0: #ifdef VERBOSE sl@0: g_print ("gio-test: child writing %d+%d bytes to %d\n", sl@0: (int)(sizeof(i) + sizeof(buflen)), buflen, writefd); sl@0: #endif sl@0: write (writefd, &i, sizeof (i)); sl@0: write (writefd, &buflen, sizeof (buflen)); sl@0: write (writefd, buf, buflen); sl@0: sl@0: #ifdef G_OS_WIN32 sl@0: if (rand() % 100 < 5) sl@0: { sl@0: int msg = WM_USER + (rand() % 100); sl@0: WPARAM wparam = rand (); sl@0: LPARAM lparam = rand (); sl@0: g_print ("gio-test: child posting message %d,%d,%d to %#x\n", sl@0: msg, wparam, lparam, hwnd); sl@0: PostMessage (hwnd, msg, wparam, lparam); sl@0: } sl@0: #endif sl@0: } sl@0: #ifdef VERBOSE sl@0: g_print ("gio-test: child exiting, closing %d\n", writefd); sl@0: #endif sl@0: close (writefd); sl@0: } sl@0: else sl@0: g_print ("Huh?\n"); sl@0: sl@0: sl@0: #ifdef SYMBIAN sl@0: close(from_descriptor); sl@0: close(to_descriptor); sl@0: #endif sl@0: sl@0: #ifdef VERBOSE sl@0: printf("Completed tests\n"); sl@0: #endif sl@0: sl@0: #if SYMBIAN sl@0: testResultXml("gio-test"); sl@0: #endif /* EMULATOR */ sl@0: sl@0: return 0; sl@0: } sl@0: sl@0: #ifdef SYMBIAN sl@0: void *child_function(void* t) sl@0: { sl@0: int readfd, writefd; sl@0: sl@0: int i, j; sl@0: char buf[BUFSIZE]; sl@0: int buflen; sl@0: GTimeVal tv; sl@0: int n; sl@0: sl@0: g_get_current_time (&tv); sl@0: sl@0: sl@0: readfd=from_descriptor; sl@0: writefd=to_descriptor; sl@0: sl@0: srand (tv.tv_sec ^ (tv.tv_usec / 1000) ^ readfd ^ (writefd << 4)); sl@0: sl@0: for (i = 0; i < 5; i++) sl@0: { sl@0: if(i==4) sl@0: child_terminated = TRUE; sl@0: g_usleep (100 + (rand() % 10) * 5000); sl@0: buflen = rand() % BUFSIZE; sl@0: for (j = 0; j < buflen; j++) sl@0: buf[j] = ' ' + ((buflen + j) % 95); sl@0: #ifdef VERBOSE sl@0: g_print ("gio-test: child writing %d+%d bytes to %d\n", sl@0: (int)(sizeof(i) + sizeof(buflen)), buflen, writefd); sl@0: #endif sl@0: write (writefd, &i, sizeof (i)); sl@0: write (writefd, &buflen, sizeof (buflen)); sl@0: write (writefd, buf, buflen); sl@0: } sl@0: #ifdef VERBOSE sl@0: g_print ("gio-test: child exiting, closing %d\n", writefd); sl@0: #endif sl@0: close (writefd); sl@0: sl@0: } sl@0: #endif