/* * Copyright 2013 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Ithamar R. Adema, ithamar@upgrade-android.com */ #include #include #include #include #ifdef ATOMIC_FUNCS_ARE_SYSCALLS /* * NOTE: These functions are _intentionally_ not using spinlocks, unlike * the 64 bit versions. The reason for this is that they are used by the * spinlock code itself, and therefore would deadlock. * * Since these are only really needed for ARMv5, which is not SMP anyway, * this is an acceptable compromise. */ void atomic_set(int32 *value, int32 newValue) { InterruptsLocker locker; *value = newValue; } int32 atomic_get_and_set(int32 *value, int32 newValue) { InterruptsLocker locker; int32 oldValue = *value; atomic_set(value, newValue); return oldValue; } int32 atomic_test_and_set(int32 *value, int32 newValue, int32 testAgainst) { InterruptsLocker locker; int32 oldValue = *value; if (oldValue == testAgainst) *value = newValue; return oldValue; } int32 atomic_add(int32 *value, int32 addValue) { InterruptsLocker locker; int32 oldValue = *value; *value += addValue; return oldValue; } int32 atomic_and(int32 *value, int32 andValue) { InterruptsLocker locker; int32 oldValue = *value; *value &= andValue; return oldValue; } int32 atomic_or(int32 *value, int32 orValue) { InterruptsLocker locker; int32 oldValue = *value; *value |= orValue; return oldValue; } int32 atomic_get(int32 *value) { InterruptsLocker locker; int32 oldValue = *value; return oldValue; } void _user_atomic_set(int32 *value, int32 newValue) { if (IS_USER_ADDRESS(value) && lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) { atomic_set(value, newValue); unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE); return; } access_violation: // XXX kill application return; } int32 _user_atomic_get_and_set(int32 *value, int32 newValue) { if (IS_USER_ADDRESS(value) && lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) { int32 oldValue = atomic_get_and_set(value, newValue); unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE); return oldValue; } access_violation: // XXX kill application return -1; } int32 _user_atomic_test_and_set(int32 *value, int32 newValue, int32 testAgainst) { if (IS_USER_ADDRESS(value) && lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) { int32 oldValue = atomic_test_and_set((int32*)value, newValue, testAgainst); unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE); return oldValue; } access_violation: // XXX kill application return -1; } int32 _user_atomic_add(int32 *value, int32 addValue) { if (IS_USER_ADDRESS(value) && lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) { int32 oldValue = atomic_add(value, addValue); unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE); return oldValue; } access_violation: // XXX kill application return -1; } int32 _user_atomic_and(int32 *value, int32 andValue) { if (IS_USER_ADDRESS(value) && lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) { int32 oldValue = atomic_and(value, andValue); unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE); return oldValue; } access_violation: // XXX kill application return -1; } int32 _user_atomic_or(int32 *value, int32 orValue) { if (IS_USER_ADDRESS(value) && lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) { int32 oldValue = atomic_or(value, orValue); unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE); return oldValue; } access_violation: // XXX kill application return -1; } int32 _user_atomic_get(int32 *value) { if (IS_USER_ADDRESS(value) && lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) { int32 oldValue = atomic_get(value); unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE); return oldValue; } access_violation: // XXX kill application return -1; } #endif /* ATOMIC_FUNCS_ARE_SYSCALLS */