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 = ¤t_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;
}
这样就导致了上层无法识别出除了超时之外的其它情况返回。