* Copyright 2013 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ithamar R. Adema, ithamar@upgrade-android.com
*/
#include <KernelExport.h>
#include <kernel.h>
#include <user_atomic.h>
#include <util/AutoLock.h>
#ifdef ATOMIC64_FUNCS_ARE_SYSCALLS
* NOTE: Unlike their 32-bit counterparts, these functions can use
* spinlocks safely currently, as no atomic 64-bit operations are
* done in the spinlock code. If this ever changes, this code will
* have to change.
*
* This code is here for ARMv6, which cannot do proper 64-bit atomic
* operations. Anything newer is capable, and does therefore not
* depend on this code.
*/
static spinlock atomic_lock = B_SPINLOCK_INITIALIZER;
void
atomic_set64(int64 *value, int64 newValue)
{
SpinLocker locker(&atomic_lock);
*value = newValue;
}
int64
atomic_get_and_set64(int64 *value, int64 newValue)
{
SpinLocker locker(&atomic_lock);
int64 oldValue = *value;
*value = newValue;
return oldValue;
}
int64
atomic_test_and_set64(int64 *value, int64 newValue, int64 testAgainst)
{
SpinLocker locker(&atomic_lock);
int64 oldValue = *value;
if (oldValue == testAgainst)
*value = newValue;
return oldValue;
}
int64
atomic_add64(int64 *value, int64 addValue)
{
SpinLocker locker(&atomic_lock);
int64 oldValue = *value;
*value += addValue;
return oldValue;
}
int64
atomic_and64(int64 *value, int64 andValue)
{
SpinLocker locker(&atomic_lock);
int64 oldValue = *value;
*value &= andValue;
return oldValue;
}
int64
atomic_or64(int64 *value, int64 orValue)
{
SpinLocker locker(&atomic_lock);
int64 oldValue = *value;
*value |= orValue;
return oldValue;
}
int64
atomic_get64(int64 *value)
{
SpinLocker locker(&atomic_lock);
return *value;
}
int64
_user_atomic_get_and_set64(int64 *value, int64 newValue)
{
if (IS_USER_ADDRESS(value)
&& lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
int64 oldValue = atomic_get_and_set64(value, newValue);
unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
return oldValue;
}
access_violation:
return -1;
}
void
_user_atomic_set64(int64 *value, int64 newValue)
{
if (IS_USER_ADDRESS(value)
&& lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
atomic_set64(value, newValue);
unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
return;
}
access_violation:
return;
}
int64
_user_atomic_test_and_set64(int64 *value, int64 newValue, int64 testAgainst)
{
if (IS_USER_ADDRESS(value)
&& lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
int64 oldValue = atomic_test_and_set64(value, newValue, testAgainst);
unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
return oldValue;
}
access_violation:
return -1;
}
int64
_user_atomic_add64(int64 *value, int64 addValue)
{
if (IS_USER_ADDRESS(value)
&& lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
int64 oldValue = atomic_add64(value, addValue);
unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
return oldValue;
}
access_violation:
return -1;
}
int64
_user_atomic_and64(int64 *value, int64 andValue)
{
if (IS_USER_ADDRESS(value)
&& lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
int64 oldValue = atomic_and64(value, andValue);
unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
return oldValue;
}
access_violation:
return -1;
}
int64
_user_atomic_or64(int64 *value, int64 orValue)
{
if (IS_USER_ADDRESS(value)
&& lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
int64 oldValue = atomic_or64(value, orValue);
unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
return oldValue;
}
access_violation:
return -1;
}
int64
_user_atomic_get64(int64 *value)
{
if (IS_USER_ADDRESS(value)
&& lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
int64 oldValue = atomic_get64(value);
unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
return oldValue;
}
access_violation:
return -1;
}
#endif