linux/include/asm-generic/futex.h
<<
>>
Prefs
   1#ifndef _ASM_GENERIC_FUTEX_H
   2#define _ASM_GENERIC_FUTEX_H
   3
   4#include <linux/futex.h>
   5#include <linux/uaccess.h>
   6#include <asm/errno.h>
   7
   8#ifndef CONFIG_SMP
   9/*
  10 * The following implementation only for uniprocessor machines.
  11 * It relies on preempt_disable() ensuring mutual exclusion.
  12 *
  13 */
  14
  15/**
  16 * futex_atomic_op_inuser() - Atomic arithmetic operation with constant
  17 *                        argument and comparison of the previous
  18 *                        futex value with another constant.
  19 *
  20 * @encoded_op: encoded operation to execute
  21 * @uaddr:      pointer to user space address
  22 *
  23 * Return:
  24 * 0 - On success
  25 * <0 - On error
  26 */
  27static inline int
  28futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
  29{
  30        int op = (encoded_op >> 28) & 7;
  31        int cmp = (encoded_op >> 24) & 15;
  32        int oparg = (encoded_op << 8) >> 20;
  33        int cmparg = (encoded_op << 20) >> 20;
  34        int oldval, ret;
  35        u32 tmp;
  36
  37        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
  38                oparg = 1 << oparg;
  39
  40        preempt_disable();
  41        pagefault_disable();
  42
  43        ret = -EFAULT;
  44        if (unlikely(get_user(oldval, uaddr) != 0))
  45                goto out_pagefault_enable;
  46
  47        ret = 0;
  48        tmp = oldval;
  49
  50        switch (op) {
  51        case FUTEX_OP_SET:
  52                tmp = oparg;
  53                break;
  54        case FUTEX_OP_ADD:
  55                tmp += oparg;
  56                break;
  57        case FUTEX_OP_OR:
  58                tmp |= oparg;
  59                break;
  60        case FUTEX_OP_ANDN:
  61                tmp &= ~oparg;
  62                break;
  63        case FUTEX_OP_XOR:
  64                tmp ^= oparg;
  65                break;
  66        default:
  67                ret = -ENOSYS;
  68        }
  69
  70        if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0))
  71                ret = -EFAULT;
  72
  73out_pagefault_enable:
  74        pagefault_enable();
  75        preempt_enable();
  76
  77        if (ret == 0) {
  78                switch (cmp) {
  79                case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
  80                case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
  81                case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
  82                case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
  83                case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
  84                case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
  85                default: ret = -ENOSYS;
  86                }
  87        }
  88        return ret;
  89}
  90
  91/**
  92 * futex_atomic_cmpxchg_inatomic() - Compare and exchange the content of the
  93 *                              uaddr with newval if the current value is
  94 *                              oldval.
  95 * @uval:       pointer to store content of @uaddr
  96 * @uaddr:      pointer to user space address
  97 * @oldval:     old value
  98 * @newval:     new value to store to @uaddr
  99 *
 100 * Return:
 101 * 0 - On success
 102 * <0 - On error
 103 */
 104static inline int
 105futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
 106                              u32 oldval, u32 newval)
 107{
 108        u32 val;
 109
 110        preempt_disable();
 111        if (unlikely(get_user(val, uaddr) != 0)) {
 112                preempt_enable();
 113                return -EFAULT;
 114        }
 115
 116        if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
 117                preempt_enable();
 118                return -EFAULT;
 119        }
 120
 121        *uval = val;
 122        preempt_enable();
 123
 124        return 0;
 125}
 126
 127#else
 128static inline int
 129futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
 130{
 131        int op = (encoded_op >> 28) & 7;
 132        int cmp = (encoded_op >> 24) & 15;
 133        int oparg = (encoded_op << 8) >> 20;
 134        int cmparg = (encoded_op << 20) >> 20;
 135        int oldval = 0, ret;
 136        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
 137                oparg = 1 << oparg;
 138
 139        if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
 140                return -EFAULT;
 141
 142        pagefault_disable();
 143
 144        switch (op) {
 145        case FUTEX_OP_SET:
 146        case FUTEX_OP_ADD:
 147        case FUTEX_OP_OR:
 148        case FUTEX_OP_ANDN:
 149        case FUTEX_OP_XOR:
 150        default:
 151                ret = -ENOSYS;
 152        }
 153
 154        pagefault_enable();
 155
 156        if (!ret) {
 157                switch (cmp) {
 158                case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
 159                case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
 160                case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
 161                case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
 162                case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
 163                case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
 164                default: ret = -ENOSYS;
 165                }
 166        }
 167        return ret;
 168}
 169
 170static inline int
 171futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
 172                              u32 oldval, u32 newval)
 173{
 174        return -ENOSYS;
 175}
 176
 177#endif /* CONFIG_SMP */
 178#endif
 179