Linux wait返回及timer(4)

static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val,
              ktime_t *abs_time, u32 bitset)
{
    struct hrtimer_sleeper timeout, *to = NULL;
    struct restart_block *restart;
    struct futex_hash_bucket *hb;
    struct futex_q q = futex_q_init;
    int ret;

if (!bitset)
        return -EINVAL;
    q.bitset = bitset;

if (abs_time) {
        to = &timeout;

hrtimer_init_on_stack(&to->timer, (flags & FLAGS_CLOCKRT) ?
                      CLOCK_REALTIME : CLOCK_MONOTONIC,
                      HRTIMER_MODE_ABS);
        hrtimer_init_sleeper(to, current);
        hrtimer_set_expires_range_ns(&to->timer, *abs_time,
                        current->timer_slack_ns);
    }


retry:
    /*
    * Prepare to wait on uaddr. On success, holds hb lock and increments
    * q.key refs.
    */

ret = futex_wait_setup(uaddr, val, flags, &q, &hb);
    if (ret)
        goto out;

/* queue_me and wait for wakeup, timeout, or a signal. */
    futex_wait_queue_me(hb, &q, to);

/* 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;  // 不是等待的信号唤醒,futex_q was still queued,unqueue_me返回1,流程不走这
    }
    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)) {
        goto retry;        // 是该线程定时器唤醒,不走这
    }

ret = -ERESTARTSYS;
    if (!abs_time) {
        goto out;        // 最后流程到这里,则ret = -ERESTARTSYS
    }

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;            // 返回值为-ERESTARTSYS(-512)
}

从上面代码可以看出,futex_wait的返回值并不为0,但到了应用层得到的返回值就变成0了,分析后发现是c库的代码不严谨导致的,如下面代码:

bionic\libc\bionic\ Pthread_cond.cpp

__LIBC_HIDDEN__
int __pthread_cond_timedwait_relative(pthread_cond_t* cond, pthread_mutex_t* mutex, const timespec* reltime) {
  int old_value = cond->value;

pthread_mutex_unlock(mutex);
  int status = __futex_wait_ex(&cond->value, COND_IS_SHARED(cond->value), old_value, reltime);
  pthread_mutex_lock(mutex);

if (status == -ETIMEDOUT) {
    return ETIMEDOUT;        // 只有超时返回时,才返回非0值,其它情况都是返回0
  }

return 0;
}

这样就导致了上层无法识别出除了超时之外的其它情况返回。

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

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