Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/include/asm-generic/futex.h
26282 views
1
/* SPDX-License-Identifier: GPL-2.0 */
2
#ifndef _ASM_GENERIC_FUTEX_H
3
#define _ASM_GENERIC_FUTEX_H
4
5
#include <linux/futex.h>
6
#include <linux/uaccess.h>
7
#include <asm/errno.h>
8
9
#ifndef futex_atomic_cmpxchg_inatomic
10
#ifndef CONFIG_SMP
11
/*
12
* The following implementation only for uniprocessor machines.
13
* It relies on preempt_disable() ensuring mutual exclusion.
14
*
15
*/
16
#define futex_atomic_cmpxchg_inatomic(uval, uaddr, oldval, newval) \
17
futex_atomic_cmpxchg_inatomic_local(uval, uaddr, oldval, newval)
18
#define arch_futex_atomic_op_inuser(op, oparg, oval, uaddr) \
19
futex_atomic_op_inuser_local(op, oparg, oval, uaddr)
20
#endif /* CONFIG_SMP */
21
#endif
22
23
/**
24
* futex_atomic_op_inuser_local() - Atomic arithmetic operation with constant
25
* argument and comparison of the previous
26
* futex value with another constant.
27
*
28
* @encoded_op: encoded operation to execute
29
* @uaddr: pointer to user space address
30
*
31
* Return:
32
* 0 - On success
33
* -EFAULT - User access resulted in a page fault
34
* -EAGAIN - Atomic operation was unable to complete due to contention
35
* -ENOSYS - Operation not supported
36
*/
37
static inline int
38
futex_atomic_op_inuser_local(int op, u32 oparg, int *oval, u32 __user *uaddr)
39
{
40
int oldval, ret;
41
u32 tmp;
42
43
preempt_disable();
44
45
ret = -EFAULT;
46
if (unlikely(get_user(oldval, uaddr) != 0))
47
goto out_pagefault_enable;
48
49
ret = 0;
50
tmp = oldval;
51
52
switch (op) {
53
case FUTEX_OP_SET:
54
tmp = oparg;
55
break;
56
case FUTEX_OP_ADD:
57
tmp += oparg;
58
break;
59
case FUTEX_OP_OR:
60
tmp |= oparg;
61
break;
62
case FUTEX_OP_ANDN:
63
tmp &= ~oparg;
64
break;
65
case FUTEX_OP_XOR:
66
tmp ^= oparg;
67
break;
68
default:
69
ret = -ENOSYS;
70
}
71
72
if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0))
73
ret = -EFAULT;
74
75
out_pagefault_enable:
76
preempt_enable();
77
78
if (ret == 0)
79
*oval = oldval;
80
81
return ret;
82
}
83
84
/**
85
* futex_atomic_cmpxchg_inatomic_local() - Compare and exchange the content of the
86
* uaddr with newval if the current value is
87
* oldval.
88
* @uval: pointer to store content of @uaddr
89
* @uaddr: pointer to user space address
90
* @oldval: old value
91
* @newval: new value to store to @uaddr
92
*
93
* Return:
94
* 0 - On success
95
* -EFAULT - User access resulted in a page fault
96
* -EAGAIN - Atomic operation was unable to complete due to contention
97
*/
98
static inline int
99
futex_atomic_cmpxchg_inatomic_local(u32 *uval, u32 __user *uaddr,
100
u32 oldval, u32 newval)
101
{
102
u32 val;
103
104
preempt_disable();
105
if (unlikely(get_user(val, uaddr) != 0)) {
106
preempt_enable();
107
return -EFAULT;
108
}
109
110
if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
111
preempt_enable();
112
return -EFAULT;
113
}
114
115
*uval = val;
116
preempt_enable();
117
118
return 0;
119
}
120
121
#endif
122
123