xref: /haiku/src/system/kernel/arch/arm/arch_atomic32.cpp (revision 4e3137c085bae361922078f123dceb92da700640)
1 /*
2  * Copyright 2013 Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ithamar R. Adema, ithamar@upgrade-android.com
7  */
8 
9 #include <KernelExport.h>
10 
11 #include <kernel.h>
12 #include <user_atomic.h>
13 
14 #include <util/AutoLock.h>
15 
16 #ifdef ATOMIC_FUNCS_ARE_SYSCALLS
17 
18 /*
19  * NOTE: These functions are _intentionally_ not using spinlocks, unlike
20  * the 64 bit versions. The reason for this is that they are used by the
21  * spinlock code itself, and therefore would deadlock.
22  *
23  * Since these are only really needed for ARMv5, which is not SMP anyway,
24  * this is an acceptable compromise.
25  */
26 
27 void
28 atomic_set(int32 *value, int32 newValue)
29 {
30 	InterruptsLocker locker;
31 	*value = newValue;
32 }
33 
34 int32
35 atomic_get_and_set(int32 *value, int32 newValue)
36 {
37 	InterruptsLocker locker;
38 	int32 oldValue = *value;
39 	atomic_set(value, newValue);
40 	return oldValue;
41 }
42 
43 int32
44 atomic_test_and_set(int32 *value, int32 newValue, int32 testAgainst)
45 {
46 	InterruptsLocker locker;
47 
48 	int32 oldValue = *value;
49 	if (oldValue == testAgainst)
50 		*value = newValue;
51 	return oldValue;
52 }
53 
54 int32
55 atomic_add(int32 *value, int32 addValue)
56 {
57 	InterruptsLocker locker;
58 
59 	int32 oldValue = *value;
60 	*value += addValue;
61 	return oldValue;
62 }
63 
64 int32
65 atomic_and(int32 *value, int32 andValue)
66 {
67 	InterruptsLocker locker;
68 
69 	int32 oldValue = *value;
70 	*value &= andValue;
71 	return oldValue;
72 }
73 
74 int32
75 atomic_or(int32 *value, int32 orValue)
76 {
77 	InterruptsLocker locker;
78 
79 	int32 oldValue = *value;
80 	*value |= orValue;
81 	return oldValue;
82 }
83 
84 int32
85 atomic_get(int32 *value)
86 {
87 	InterruptsLocker locker;
88 
89 	int32 oldValue = *value;
90 	return oldValue;
91 }
92 
93 void
94 _user_atomic_set(int32 *value, int32 newValue)
95 {
96 	if (IS_USER_ADDRESS(value)
97 		&& lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) {
98 		atomic_set(value, newValue);
99 		unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
100 		return;
101 	}
102 
103 access_violation:
104 	// XXX kill application
105 	return;
106 }
107 
108 int32
109 _user_atomic_get_and_set(int32 *value, int32 newValue)
110 {
111 	if (IS_USER_ADDRESS(value)
112 		&& lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) {
113 		int32 oldValue = atomic_get_and_set(value, newValue);
114 		unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
115 		return oldValue;
116 	}
117 
118 access_violation:
119 	// XXX kill application
120 	return -1;
121 }
122 
123 int32
124 _user_atomic_test_and_set(int32 *value, int32 newValue, int32 testAgainst)
125 {
126 	if (IS_USER_ADDRESS(value)
127 		&& lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) {
128 		int32 oldValue = atomic_test_and_set((int32*)value, newValue, testAgainst);
129 		unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
130 		return oldValue;
131 	}
132 
133 access_violation:
134 	// XXX kill application
135 	return -1;
136 }
137 
138 int32
139 _user_atomic_add(int32 *value, int32 addValue)
140 {
141 	if (IS_USER_ADDRESS(value)
142 		&& lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) {
143 		int32 oldValue = atomic_add(value, addValue);
144 		unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
145 		return oldValue;
146 	}
147 
148 access_violation:
149 	// XXX kill application
150 	return -1;
151 }
152 
153 int32
154 _user_atomic_and(int32 *value, int32 andValue)
155 {
156 	if (IS_USER_ADDRESS(value)
157 		&& lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) {
158 		int32 oldValue = atomic_and(value, andValue);
159 		unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
160 		return oldValue;
161 	}
162 
163 access_violation:
164 	// XXX kill application
165 	return -1;
166 }
167 
168 int32
169 _user_atomic_or(int32 *value, int32 orValue)
170 {
171 	if (IS_USER_ADDRESS(value)
172 		&& lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) {
173 		int32 oldValue = atomic_or(value, orValue);
174 		unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
175 		return oldValue;
176 	}
177 
178 access_violation:
179 	// XXX kill application
180 	return -1;
181 }
182 
183 int32
184 _user_atomic_get(int32 *value)
185 {
186 	if (IS_USER_ADDRESS(value)
187 		&& lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) {
188 		int32 oldValue = atomic_get(value);
189 		unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
190 		return oldValue;
191 	}
192 
193 access_violation:
194 	// XXX kill application
195 	return -1;
196 }
197 
198 #endif /* ATOMIC_FUNCS_ARE_SYSCALLS */
199