Linux wait返回及timer(3)

/* If we were woken (and unqueued), we succeeded, whatever. */
    ret = 0;
    /* unqueue_me() drops q.key ref */
    if (!unqueue_me(&q)) {                 
        /* unqueue_me返回值情况 */
        /* 1 - if the futex_q was still queued (and we removed unqueued it); */
        /* 0 - if the futex_q was already removed by the waking thread(发送信号唤醒的情况) */ 

goto out;                        // 正常等到信号后返回走这里
    }
    ret = -ETIMEDOUT;
    if (to && !to->task) {
        goto out;
    }

/*
    * We expect signal_pending(current), but we might be the
    * victim of a spurious wakeup as well.
    */
    if (!signal_pending(current)) {
        trace_printk("retry\n");
        goto retry;
    }

ret = -ERESTARTSYS;
    if (!abs_time) {
        goto out;
    }

restart = &current_thread_info()->restart_block;
    restart->fn = futex_wait_restart;
    restart->futex.uaddr = uaddr;
    restart->futex.val = val;
    restart->futex.time = abs_time->tv64;
    restart->futex.bitset = bitset;
    restart->futex.flags = flags | FLAGS_HAS_TIMEOUT;

ret = -ERESTART_RESTARTBLOCK;

out:
    if (to) {
        hrtimer_cancel(&to->timer);
        destroy_hrtimer_on_stack(&to->timer);
    }

return ret;            // 正常返回值为0
}

kernel\kernel\ Futex.c

static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
                struct hrtimer_sleeper *timeout)
{
    /*
    * The task state is guaranteed to be set before another task can
    * wake it. set_current_state() is implemented using set_mb() and
    * queue_me() calls spin_unlock() upon completion, both serializing
    * access to the hash list and forcing another memory barrier.
    */
    set_current_state(TASK_INTERRUPTIBLE);
    queue_me(q, hb);

/* Arm the timer */
    if (timeout) {
        hrtimer_start_expires(&timeout->timer, HRTIMER_MODE_ABS);
        if (!hrtimer_active(&timeout->timer))
            timeout->task = NULL;
    }

/*
    * If we have been removed from the hash list, then another task
    * has tried to wake us, and we can skip the call to schedule().
    */
    if (likely(!plist_node_empty(&q->list))) {
        /*
        * If the timer has already expired, current will already be
        * flagged for rescheduling. Only call schedule if there
        * is no timeout, or if it has yet to expire.
        */
        if (!timeout || timeout->task) {
            freezable_schedule();       
        }
    }
    __set_current_state(TASK_RUNNING);
}

如果该等待线程使用timer_create创建了定时器,并且创建的定时器超时是给当前线程发送信号(timer_create的创建在第4节分析),当定时器超时后,就会把当前线程设置为可运行的状态,等待系统调度运行。若这时该线程刚好调用了wait在等待信号,由于该线程已经被设置为可运行状态,当调度到该线程运行时,futex_wait_queue_me函数的freezable_schedule()就会返回,这时futex_wait返回流程与返回值都与正常接收到信号时返回的不一样,如下面代码标示:
kernel\kernel\ Futex.c

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/baa9f29ea8eb34fc042dbed89dcbdd91.html