/* * 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) { fd_set readfds; fd_set writefds; unsigned int i; int any, max_fd, n, count; struct timeval timeout = { 1, 0 }; /* Use a 1s timeout. */ void *dbg_help = NULL; FD_ZERO(&readfds); FD_ZERO(&writefds); max_fd = 0; if(nonblock) timeout.tv_sec = 0; DEBUG_BEGIN(dbg_help, 3, "gpgme:select on [ "); any = 0; for(i = 0; i < nfds; i++) { if(fds[i].fd == -1) continue; if(fds[i].frozen) DEBUG_ADD1(dbg_help, "f%d ", fds[i].fd); else if(fds[i].for_read) { assert(!FD_ISSET(fds[i].fd, &readfds)); FD_SET(fds[i].fd, &readfds); if(fds[i].fd > max_fd) max_fd = fds[i].fd; DEBUG_ADD1(dbg_help, "r%d ", fds[i].fd); any = 1; } else if(fds[i].for_write) { assert(!FD_ISSET(fds[i].fd, &writefds)); FD_SET(fds[i].fd, &writefds); if(fds[i].fd > max_fd) max_fd = fds[i].fd; DEBUG_ADD1(dbg_help, "w%d ", fds[i].fd); any = 1; } fds[i].signaled = 0; } DEBUG_END(dbg_help, "]"); if(!any) return 0; do { count = _gpgme_ath_select(max_fd + 1, &readfds, &writefds, NULL, &timeout); } while(count < 0 && errno == EINTR); if(count < 0) { int saved_errno = errno; DEBUG1("_gpgme_io_select failed: %s\n", strerror(errno)); errno = saved_errno; return -1; /* error */ } DEBUG_BEGIN(dbg_help, 3, "select OK [ "); if(DEBUG_ENABLED(dbg_help)) { for(i = 0; i <= max_fd; i++) { if(FD_ISSET(i, &readfds)) DEBUG_ADD1(dbg_help, "r%d ", i); if(FD_ISSET(i, &writefds)) DEBUG_ADD1(dbg_help, "w%d ", i); } DEBUG_END(dbg_help, "]"); } /* n is used to optimize it a little bit. */ for(n = count, i = 0; i < nfds && n; i++) { if(fds[i].fd == -1) ; else if(fds[i].for_read) { if(FD_ISSET(fds[i].fd, &readfds)) { fds[i].signaled = 1; n--; } } else if(fds[i].for_write) { if(FD_ISSET(fds[i].fd, &writefds)) { fds[i].signaled = 1; n--; } } } return count; }
/* * 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 ) { HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS]; int waitidx[MAXIMUM_WAIT_OBJECTS]; int code, nwait; int i, any; int count; void *dbg_help; restart: DEBUG_BEGIN (dbg_help, 3, "select on [ "); any = 0; nwait = 0; count = 0; for ( i=0; i < nfds; i++ ) { if ( fds[i].fd == -1 ) continue; fds[i].signaled = 0; if ( fds[i].for_read || fds[i].for_write ) { if ( fds[i].frozen ) { DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd ); } else if ( fds[i].for_read ) { struct reader_context_s *c = find_reader (fds[i].fd,1); if (!c) { DEBUG1 ("oops: no reader thread for fd %d", fds[i].fd); } else { if ( nwait >= DIM (waitbuf) ) { DEBUG_END (dbg_help, "oops ]"); DEBUG0 ("Too many objects for WFMO!" ); return -1; } waitidx[nwait] = i; waitbuf[nwait++] = c->have_data_ev; } DEBUG_ADD1 (dbg_help, "r%d ", fds[i].fd ); any = 1; } else if ( fds[i].for_write ) { struct writer_context_s *c = find_writer (fds[i].fd,1); if (!c) { DEBUG1 ("oops: no writer thread for fd %d", fds[i].fd); } else { if ( nwait >= DIM (waitbuf) ) { DEBUG_END (dbg_help, "oops ]"); DEBUG0 ("Too many objects for WFMO!" ); return -1; } waitidx[nwait] = i; waitbuf[nwait++] = c->is_empty; } DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd ); any = 1; } } } DEBUG_END (dbg_help, "]"); if (!any) return 0; code = WaitForMultipleObjects ( nwait, waitbuf, 0, nonblock ? 0 : 1000); if ( code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait ) { /* This WFMO is a really silly function: It does return either * the index of the signaled object or if 2 objects have been * signalled at the same time, the index of the object with the * lowest object is returned - so and how do we find out * how many objects have been signaled???. * The only solution I can imagine is to test each object starting * with the returned index individually - how dull. */ any = 0; for (i=code - WAIT_OBJECT_0; i < nwait; i++ ) { if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0) { assert (waitidx[i] >=0 && waitidx[i] < nfds); fds[waitidx[i]].signaled = 1; any = 1; count++; } } if (!any) { DEBUG0 ("Oops: No signaled objects found after WFMO"); count = -1; } } else if ( code == WAIT_TIMEOUT ) { DEBUG0 ("WFMO timed out\n" ); } else if (code == WAIT_FAILED ) { int le = (int)GetLastError (); if ( le == ERROR_INVALID_HANDLE ) { int k, j = handle_to_fd (waitbuf[i]); DEBUG1 ("WFMO invalid handle %d removed\n", j); for (k=0 ; k < nfds; k++ ) { if ( fds[k].fd == j ) { fds[k].for_read = fds[k].for_write = 0; goto restart; } } DEBUG0 (" oops, or not???\n"); } DEBUG1 ("WFMO failed: %d\n", le ); count = -1; } else { DEBUG1 ("WFMO returned %d\n", code ); count = -1; } if ( count ) { DEBUG_BEGIN (dbg_help, 3, " signaled [ "); for ( i=0; i < nfds; i++ ) { if ( fds[i].fd == -1 ) continue; if ( (fds[i].for_read || fds[i].for_write) && fds[i].signaled ) { DEBUG_ADD2 (dbg_help, "%c%d ", fds[i].for_read? 'r':'w',fds[i].fd ); } } DEBUG_END (dbg_help, "]"); } return count; }