def __run_blast_select_loop(input_file, popens, fields):
    '''
    Run the select(2) loop to handle blast I/O to the given set of Popen
    objects.

    Yields records back that have been read from blast processes.
    '''

    def make_nonblocking(f):
        fl = fcntl.fcntl(f.fileno(), fcntl.F_GETFL)
        fl |= os.O_NONBLOCK
        fcntl.fcntl(f.fileno(), fcntl.F_SETFL, fl)

    rfds = set()
    wfds = set()
    fd_map = {}

    for p in popens:
        make_nonblocking(p.stdout)
        rfds.add(p.stdout.fileno())
        fd_map[p.stdout.fileno()] = {
            'popen': p,
            'query_buffer': '',
            'result_buffer': ''}

        make_nonblocking(p.stdin)
        wfds.add(p.stdin.fileno())
        fd_map[p.stdin.fileno()] = fd_map[p.stdout.fileno()]

    while len(rfds) + len(wfds) > 0:
        # XXX: Should we be tracking excepted file descriptors as well?
        rl, wl, _ = select.select(rfds, wfds, [])

        # For each of our readable blast processes, read response
        # records and emit them
        for fd in rl:
            rs = fd_map[fd]['result_buffer']
            rbuf = os.read(fd, select.PIPE_BUF)

            # The blast process has finished emitting records. Stop
            # attempting to read from or write to it. If we have
            # excess data in our result_buffer, c'est la vie.
            if rbuf == '':
                p = fd_map[fd]['popen']

                rfds.remove(p.stdout.fileno())
                p.stdout.close()

                if not p.stdin.closed:
                    wfds.remove(p.stdin.fileno())
                    p.stdin.close()
                
                continue

            rs += rbuf
            while True:
                rec, rs = __read_single_query_result(rs, fields)
                if rec is None:
                    break
                yield rec

            fd_map[fd]['result_buffer'] = rs

        # For each of our writable blast processes, grab a new query
        # sequence and send it off to them.
        for fd in wl:
            qs = fd_map[fd]['query_buffer']
            if not qs:
                ql = __read_single_fasta_query_lines(input_file)

                # No more input records available. Close the pipe to
                # signal this to the blast process.
                if ql is None:
                    p = fd_map[fd]['popen']

                    wfds.remove(p.stdin.fileno())
                    p.stdin.close()

                    continue

                qs = ''.join(ql)

            # XXX: For some reason, despite select(2) indicating that
            #      this file descriptor is writable, writes can fail
            #      with EWOULDBLOCK. Handle this gracefully.
            try:
                written = os.write(fd, qs)
                qs = qs[written:]
            except OSError, e:
                assert e.errno == errno.EWOULDBLOCK

            fd_map[fd]['query_buffer'] = qs