'Returns a list of (host, task) tuples, where the task may
be a noop task to keep the iterator in lock step across
all hosts.'

def _get_next_task_lockstep(self, hosts, iterator):

    noop_task = Task()
    noop_task.action = 'meta'
    noop_task.args['_raw_params'] = 'noop'
    noop_task.set_loader(iterator._play._loader)
    host_tasks = {}
    display.debug('building    list    of    next    tasks    for    hosts')
    for host in hosts:
        host_tasks[host.name] = iterator.get_next_task_for_host(host, peek=True)
    display.debug('done    building    task    lists')
    num_setups = 0
    num_tasks = 0
    num_rescue = 0
    num_always = 0
    display.debug('counting    tasks    in    each    state    of    execution')
    host_tasks_to_run = [(host, state_task) for (host, state_task) in iteritems(host_tasks) if (state_task and state_task[1])]
    if host_tasks_to_run:
        try:
            lowest_cur_block = min((s.cur_block for (h, (s, t)) in host_tasks_to_run if (s.run_state != PlayIterator.ITERATING_COMPLETE)))
        except ValueError:
            lowest_cur_block = None
    else:
        lowest_cur_block = None
    for (k, v) in host_tasks_to_run:
        (s, t) = v
        if (s.cur_block > lowest_cur_block):
            continue
        if (s.run_state == PlayIterator.ITERATING_SETUP):
            num_setups += 1
        elif (s.run_state == PlayIterator.ITERATING_TASKS):
            num_tasks += 1
        elif (s.run_state == PlayIterator.ITERATING_RESCUE):
            num_rescue += 1
        elif (s.run_state == PlayIterator.ITERATING_ALWAYS):
            num_always += 1
    display.debug(('done    counting    tasks    in    each    state    of    execution:\n DCTB num_setups:    %s\n DCTB num_tasks:    %s\n DCTB num_rescue:    %s\n DCTB num_always:    %s' % (num_setups, num_tasks, num_rescue, num_always)))
    def _advance_selected_hosts(hosts, cur_block, cur_state):
        '\n                                                This    helper    returns    the    task    for    all    hosts    in    the    requested\n                                                state,    otherwise    they    get    a    noop    dummy    task.    This    also    advances\n                                                the    state    of    the    host,    since    the    given    states    are    determined\n                                                while    using    peek=True.\n                                                '
        rvals = []
        display.debug('starting    to    advance    hosts')
        for host in hosts:
            host_state_task = host_tasks.get(host.name)
            if (host_state_task is None):
                continue
            (s, t) = host_state_task
            if (t is None):
                continue
            if ((s.run_state == cur_state) and (s.cur_block == cur_block)):
                new_t = iterator.get_next_task_for_host(host)
                rvals.append((host, t))
            else:
                rvals.append((host, noop_task))
        display.debug('done    advancing    hosts    to    next    task')
        return rvals
    if num_setups:
        display.debug('advancing    hosts    in    ITERATING_SETUP')
        return _advance_selected_hosts(hosts, lowest_cur_block, PlayIterator.ITERATING_SETUP)
    if num_tasks:
        display.debug('advancing    hosts    in    ITERATING_TASKS')
        return _advance_selected_hosts(hosts, lowest_cur_block, PlayIterator.ITERATING_TASKS)
    if num_rescue:
        display.debug('advancing    hosts    in    ITERATING_RESCUE')
        return _advance_selected_hosts(hosts, lowest_cur_block, PlayIterator.ITERATING_RESCUE)
    if num_always:
        display.debug('advancing    hosts    in    ITERATING_ALWAYS')
        return _advance_selected_hosts(hosts, lowest_cur_block, PlayIterator.ITERATING_ALWAYS)
    display.debug("all    hosts    are    done,    so    returning    None's    for    all    hosts")
    return [(host, None) for host in hosts]
