Beispiel #1
0
/*
 * 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;
}
Beispiel #2
0
/*
 * 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;
}