• futex_wait


    SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
            struct timespec __user *, utime, u32 __user *, uaddr2,
            u32, val3)
    {
        struct timespec ts;
        ktime_t t, *tp = NULL;
        u32 val2 = 0;
        int cmd = op & FUTEX_CMD_MASK;

        if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
                  cmd == FUTEX_WAIT_BITSET ||
                  cmd == FUTEX_WAIT_REQUEUE_PI)) {
            if (unlikely(should_fail_futex(!(op & FUTEX_PRIVATE_FLAG))))
                return -EFAULT;
            if (copy_from_user(&ts, utime, sizeof(ts)) != 0)
                return -EFAULT;
            if (!timespec_valid(&ts))
                return -EINVAL;

            t = timespec_to_ktime(ts);
            if (cmd == FUTEX_WAIT)
                t = ktime_add_safe(ktime_get(), t);
            tp = &t;
        }
        /*
         * requeue parameter in 'utime' if cmd == FUTEX_*_REQUEUE_*.
         * number of waiters to wake in 'utime' if cmd == FUTEX_WAKE_OP.
         */
        if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE ||
            cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)
            val2 = (u32) (unsigned long) utime;

        return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
    }

    long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
            u32 __user *uaddr2, u32 val2, u32 val3)
    {
        int cmd = op & FUTEX_CMD_MASK;
        unsigned int flags = 0;

        if (!(op & FUTEX_PRIVATE_FLAG))
            flags |= FLAGS_SHARED;

        if (op & FUTEX_CLOCK_REALTIME) {
            flags |= FLAGS_CLOCKRT;
            if (cmd != FUTEX_WAIT && cmd != FUTEX_WAIT_BITSET && \
                cmd != FUTEX_WAIT_REQUEUE_PI)
                return -ENOSYS;
        }

        switch (cmd) {
        case FUTEX_LOCK_PI:
        case FUTEX_UNLOCK_PI:
        case FUTEX_TRYLOCK_PI:
        case FUTEX_WAIT_REQUEUE_PI:
        case FUTEX_CMP_REQUEUE_PI:
            if (!futex_cmpxchg_enabled)
                return -ENOSYS;
        }

        switch (cmd) {
        case FUTEX_WAIT:
            val3 = FUTEX_BITSET_MATCH_ANY;
            /* fall through */
        case FUTEX_WAIT_BITSET:
            return futex_wait(uaddr, flags, val, timeout, val3);
        case FUTEX_WAKE:
            val3 = FUTEX_BITSET_MATCH_ANY;
            /* fall through */
        case FUTEX_WAKE_BITSET:
            return futex_wake(uaddr, flags, val, val3);
        case FUTEX_REQUEUE:
            return futex_requeue(uaddr, flags, uaddr2, val, val2, NULL, 0);
        case FUTEX_CMP_REQUEUE:
            return futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 0);
        case FUTEX_WAKE_OP:
            return futex_wake_op(uaddr, flags, uaddr2, val, val2, val3);
        case FUTEX_LOCK_PI:
            return futex_lock_pi(uaddr, flags, timeout, 0);
        case FUTEX_UNLOCK_PI:
            return futex_unlock_pi(uaddr, flags);
        case FUTEX_TRYLOCK_PI:
            return futex_lock_pi(uaddr, flags, NULL, 1);
        case FUTEX_WAIT_REQUEUE_PI:
            val3 = FUTEX_BITSET_MATCH_ANY;
            return futex_wait_requeue_pi(uaddr, flags, val, timeout, val3,
                             uaddr2);
        case FUTEX_CMP_REQUEUE_PI:
            return futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 1);
        }
        return -ENOSYS;
    }

    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))
            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))
            goto retry;

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

        restart = ¤t->restart_block;
        restart->fn = futex_wait_restart;
        restart->futex.uaddr = uaddr;
        restart->futex.val = val;
        restart->futex.time = *abs_time;
        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;
    }

    /*
     * Wake up waiters matching bitset queued on this futex (uaddr).
     */
    static int
    futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
    {
        struct futex_hash_bucket *hb;
        struct futex_q *this, *next;
        union futex_key key = FUTEX_KEY_INIT;
        int ret;
        DEFINE_WAKE_Q(wake_q);

        if (!bitset)
            return -EINVAL;

        ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_READ);
        if (unlikely(ret != 0))
            goto out;

        hb = hash_futex(&key);

        /* Make sure we really have tasks to wakeup */
        if (!hb_waiters_pending(hb))
            goto out_put_key;

        spin_lock(&hb->lock);

        plist_for_each_entry_safe(this, next, &hb->chain, list) {
            if (match_futex (&this->key, &key)) {
                if (this->pi_state || this->rt_waiter) {
                    ret = -EINVAL;
                    break;
                }

                /* Check if one of the bits is set in both bitsets */
                if (!(this->bitset & bitset))
                    continue;

                mark_wake_futex(&wake_q, this);
                if (++ret >= nr_wake)
                    break;
            }
        }

        spin_unlock(&hb->lock);
        wake_up_q(&wake_q);
    out_put_key:
        put_futex_key(&key);
    out:
        return ret;
    }

  • 相关阅读:
    win32-注册表-项名长度-值得最大长度-注意事项
    USB xHCI控制器使用总结
    python基于django的高校奖学金管理系统
    基于Echarts实现可视化数据大屏科技业务数据统计
    百度笔试题面试题总结1
    Haproxy-1.5.19版本的基础运用
    使用IDEA创建SpringCloud项目
    关于 Angular 里 module 和 Component 包含粒度的一个讨论
    Java-多态
    Spring核心接口InitializingBean
  • 原文地址:https://blog.csdn.net/wmzjzwlzs/article/details/128105799