/** * Add an event source for a GIOChannel. * * @param channel The GIOChannel. * @param events Events to poll on. * @param timeout Max time to wait before the callback is called, ignored if 0. * @param cb Callback function to add. Must not be NULL. * @param cb_data Data for the callback function. Can be NULL. * * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or * SR_ERR_MALLOC upon memory allocation errors. */ SR_API int sr_session_source_add_channel(GIOChannel *channel, int events, int timeout, sr_receive_data_callback_t cb, void *cb_data) { GPollFD p; #ifdef _WIN32 g_io_channel_win32_make_pollfd(channel, events, &p); #else p.fd = g_io_channel_unix_get_fd(channel); p.events = events; #endif return _sr_session_source_add(&p, timeout, cb, cb_data, (gintptr)channel); }
/** * Add an event source for a GIOChannel. * * @param session The session to use. Must not be NULL. * @param channel The GIOChannel. * @param events Events to poll on. * @param timeout Max time in ms to wait before the callback is called, * or -1 to wait indefinitely. * @param cb Callback function to add. Must not be NULL. * @param cb_data Data for the callback function. Can be NULL. * * @retval SR_OK Success. * @retval SR_ERR_ARG Invalid argument. * * @since 0.3.0 * @private */ SR_PRIV int sr_session_source_add_channel(struct sr_session *session, GIOChannel *channel, int events, int timeout, sr_receive_data_callback cb, void *cb_data) { GPollFD pollfd; if (!channel) { sr_err("%s: channel was NULL", __func__); return SR_ERR_ARG; } /* We should be using g_io_create_watch(), but can't without * changing the driver API, as the callback signature is different. */ #ifdef G_OS_WIN32 g_io_channel_win32_make_pollfd(channel, events, &pollfd); #else pollfd.fd = g_io_channel_unix_get_fd(channel); pollfd.events = events; #endif return sr_session_fd_source_add(session, channel, pollfd.fd, pollfd.events, timeout, cb, cb_data); }
/* Select on the list of fds. Returns: -1 = error, 0 = timeout or nothing to select, > 0 = number of signaled fds. */ int _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) { int npollfds; GPollFD *pollfds; int *pollfds_map; int i; int j; int any; int n; int count; /* Use a 1s timeout. */ int timeout = 1000; void *dbg_help = NULL; TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds, "nfds=%u, nonblock=%u", nfds, nonblock); if (nonblock) timeout = 0; pollfds = calloc (nfds, sizeof *pollfds); if (!pollfds) return -1; pollfds_map = calloc (nfds, sizeof *pollfds_map); if (!pollfds_map) { free (pollfds); return -1; } npollfds = 0; TRACE_SEQ (dbg_help, "select on [ "); any = 0; for (i = 0; i < nfds; i++) { GIOChannel *chan = NULL; if (fds[i].fd == -1) continue; if ((fds[i].for_read || fds[i].for_write) && !(chan = find_channel (fds[i].fd))) { TRACE_ADD1 (dbg_help, "[BAD0x%x ", fds[i].fd); TRACE_END (dbg_help, "]"); assert (!"see log file"); } else if (fds[i].for_read ) { assert(chan); g_io_channel_win32_make_pollfd (chan, G_IO_IN, pollfds + npollfds); pollfds_map[npollfds] = i; TRACE_ADD2 (dbg_help, "r0x%x<%d> ", fds[i].fd, pollfds[npollfds].fd); npollfds++; any = 1; } else if (fds[i].for_write) { assert(chan); g_io_channel_win32_make_pollfd (chan, G_IO_OUT, pollfds + npollfds); pollfds_map[npollfds] = i; TRACE_ADD2 (dbg_help, "w0x%x<%d> ", fds[i].fd, pollfds[npollfds].fd); npollfds++; any = 1; } fds[i].signaled = 0; } TRACE_END (dbg_help, "]"); if (!any) { count = 0; goto leave; } count = g_io_channel_win32_poll (pollfds, npollfds, timeout); if (count < 0) { int saved_errno = errno; errno = saved_errno; goto leave; } TRACE_SEQ (dbg_help, "select OK [ "); if (TRACE_ENABLED (dbg_help)) { for (i = 0; i < npollfds; i++) { if ((pollfds[i].revents & G_IO_IN)) TRACE_ADD1 (dbg_help, "r0x%x ", fds[pollfds_map[i]].fd); if ((pollfds[i].revents & G_IO_OUT)) TRACE_ADD1 (dbg_help, "w0x%x ", fds[pollfds_map[i]].fd); } TRACE_END (dbg_help, "]"); } /* COUNT is used to stop the lop as soon as possible. */ for (n = count, i = 0; i < npollfds && n; i++) { j = pollfds_map[i]; assert (j >= 0 && j < nfds); if (fds[j].fd == -1) ; else if (fds[j].for_read) { if ((pollfds[i].revents & G_IO_IN)) { fds[j].signaled = 1; n--; } } else if (fds[j].for_write) { if ((pollfds[i].revents & G_IO_OUT)) { fds[j].signaled = 1; n--; } } } leave: free (pollfds); free (pollfds_map); return TRACE_SYSRES (count); }
int main (int argc, char **argv) { if (argc < 3) { /* Parent */ GIOChannel *my_read_channel; gchar *cmdline; guint *id; int i; #ifdef G_OS_WIN32 GTimeVal start, end; GPollFD pollfd; int pollresult; ATOM klass; static WNDCLASS wcl; HWND hwnd; GIOChannel *windows_messages_channel; #endif nkiddies = (argc == 1 ? 1 : atoi(argv[1])); seqtab = g_malloc (nkiddies * 2 * sizeof (int)); #ifdef G_OS_WIN32 wcl.style = 0; wcl.lpfnWndProc = window_procedure; wcl.cbClsExtra = 0; wcl.cbWndExtra = 0; wcl.hInstance = GetModuleHandle (NULL); wcl.hIcon = NULL; wcl.hCursor = NULL; wcl.hbrBackground = NULL; wcl.lpszMenuName = NULL; wcl.lpszClassName = "gio-test"; klass = RegisterClass (&wcl); if (!klass) { g_print ("gio-test: RegisterClass failed\n"); exit (1); } hwnd = CreateWindow (MAKEINTATOM(klass), "gio-test", 0, 0, 0, 10, 10, NULL, NULL, wcl.hInstance, NULL); if (!hwnd) { g_print ("gio-test: CreateWindow failed\n"); exit (1); } windows_messages_channel = g_io_channel_win32_new_messages ((guint)hwnd); g_io_add_watch (windows_messages_channel, G_IO_IN, recv_windows_message, 0); #endif for (i = 0; i < nkiddies; i++) { int pipe_to_sub[2], pipe_from_sub[2]; if (pipe (pipe_to_sub) == -1 || pipe (pipe_from_sub) == -1) perror ("pipe"), exit (1); seqtab[i].fd = pipe_from_sub[0]; seqtab[i].seq = 0; my_read_channel = g_io_channel_unix_new (pipe_from_sub[0]); id = g_new (guint, 1); *id = g_io_add_watch (my_read_channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, recv_message, id); nrunning++; #ifdef G_OS_WIN32 cmdline = g_strdup_printf ("%d:%d:%d", pipe_to_sub[0], pipe_from_sub[1], hwnd); _spawnl (_P_NOWAIT, argv[0], argv[0], "--child", cmdline, NULL); #else cmdline = g_strdup_printf ("%s --child %d:%d &", argv[0], pipe_to_sub[0], pipe_from_sub[1]); system (cmdline); #endif close (pipe_to_sub[0]); close (pipe_from_sub [1]); #ifdef G_OS_WIN32 g_get_current_time (&start); g_io_channel_win32_make_pollfd (my_read_channel, G_IO_IN, &pollfd); pollresult = g_io_channel_win32_poll (&pollfd, 1, 100); g_get_current_time (&end); if (end.tv_usec < start.tv_usec) end.tv_sec--, end.tv_usec += 1000000; g_print ("gio-test: had to wait %ld.%03ld s, result:%d\n", end.tv_sec - start.tv_sec, (end.tv_usec - start.tv_usec) / 1000, pollresult); #endif } main_loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (main_loop); } else if (argc == 3) { /* Child */ int readfd, writefd; #ifdef G_OS_WIN32 HWND hwnd; #endif int i, j; char buf[BUFSIZE]; int buflen; GTimeVal tv; int n; g_get_current_time (&tv); sscanf (argv[2], "%d:%d%n", &readfd, &writefd, &n); #ifdef G_OS_WIN32 sscanf (argv[2] + n, ":%d", &hwnd); #endif srand (tv.tv_sec ^ (tv.tv_usec / 1000) ^ readfd ^ (writefd << 4)); for (i = 0; i < 20 + rand() % 20; i++) { g_usleep (100 + (rand() % 10) * 5000); buflen = rand() % BUFSIZE; for (j = 0; j < buflen; j++) buf[j] = ' ' + ((buflen + j) % 95); #ifdef VERBOSE g_print ("gio-test: child writing %d+%d bytes to %d\n", (int)(sizeof(i) + sizeof(buflen)), buflen, writefd); #endif write (writefd, &i, sizeof (i)); write (writefd, &buflen, sizeof (buflen)); write (writefd, buf, buflen); #ifdef G_OS_WIN32 if (rand() % 100 < 5) { int msg = WM_USER + (rand() % 100); WPARAM wparam = rand (); LPARAM lparam = rand (); g_print ("gio-test: child posting message %d,%d,%d to %#x\n", msg, wparam, lparam, hwnd); PostMessage (hwnd, msg, wparam, lparam); } #endif } #ifdef VERBOSE g_print ("gio-test: child exiting, closing %d\n", writefd); #endif close (writefd); } else g_print ("Huh?\n"); return 0; }