kernel/user_mutex: Create utility functions for the user_atomics.

In the future, these should be moved to another file (and fault handlers
used), but at least this de-clutters the code a bit for now.
This commit is contained in:
Augustin Cavalier
2023-06-05 20:53:55 -04:00
parent 17d9a20c62
commit cf1b26a933
+60 -41
View File
@@ -63,6 +63,52 @@ static UserMutexTable sUserMutexTable;
static mutex sUserMutexTableLock = MUTEX_INITIALIZER("user mutex table"); static mutex sUserMutexTableLock = MUTEX_INITIALIZER("user mutex table");
// #pragma mark - user atomics
static int32
user_atomic_or(int32* value, int32 orValue)
{
set_ac();
int32 result = atomic_or(value, orValue);
clear_ac();
return result;
}
static int32
user_atomic_and(int32* value, int32 orValue)
{
set_ac();
int32 result = atomic_and(value, orValue);
clear_ac();
return result;
}
static int32
user_atomic_get(int32* value)
{
set_ac();
int32 result = atomic_get(value);
clear_ac();
return result;
}
static int32
user_atomic_test_and_set(int32* value, int32 newValue, int32 testAgainst)
{
set_ac();
int32 result = atomic_test_and_set(value, newValue, testAgainst);
clear_ac();
return result;
}
// #pragma mark - user mutex entries
static void static void
add_user_mutex_entry(UserMutexEntry* entry) add_user_mutex_entry(UserMutexEntry* entry)
{ {
@@ -135,17 +181,13 @@ user_mutex_lock_locked(int32* mutex, addr_t physicalAddress,
const char* name, uint32 flags, bigtime_t timeout, MutexLocker& locker) const char* name, uint32 flags, bigtime_t timeout, MutexLocker& locker)
{ {
// mark the mutex locked + waiting // mark the mutex locked + waiting
set_ac(); int32 oldValue = user_atomic_or(mutex,
int32 oldValue = atomic_or(mutex,
B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING); B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING);
clear_ac();
if ((oldValue & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) == 0 if ((oldValue & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) == 0
|| (oldValue & B_USER_MUTEX_DISABLED) != 0) { || (oldValue & B_USER_MUTEX_DISABLED) != 0) {
// clear the waiting flag and be done // clear the waiting flag and be done
set_ac(); user_atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING);
atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING);
clear_ac();
return B_OK; return B_OK;
} }
@@ -154,9 +196,7 @@ user_mutex_lock_locked(int32* mutex, addr_t physicalAddress,
flags, timeout, locker, lastWaiter); flags, timeout, locker, lastWaiter);
if (lastWaiter) { if (lastWaiter) {
set_ac(); user_atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING);
atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING);
clear_ac();
} }
return error; return error;
@@ -169,18 +209,14 @@ user_mutex_unlock_locked(int32* mutex, addr_t physicalAddress, uint32 flags)
UserMutexEntry* entry = sUserMutexTable.Lookup(physicalAddress); UserMutexEntry* entry = sUserMutexTable.Lookup(physicalAddress);
if (entry == NULL) { if (entry == NULL) {
// no one is waiting -- clear locked flag // no one is waiting -- clear locked flag
set_ac(); user_atomic_and(mutex, ~(int32)B_USER_MUTEX_LOCKED);
atomic_and(mutex, ~(int32)B_USER_MUTEX_LOCKED);
clear_ac();
return; return;
} }
// Someone is waiting -- set the locked flag. It might still be set, // Someone is waiting -- set the locked flag. It might still be set,
// but when using userland atomic operations, the caller will usually // but when using userland atomic operations, the caller will usually
// have cleared it already. // have cleared it already.
set_ac(); int32 oldValue = user_atomic_or(mutex, B_USER_MUTEX_LOCKED);
int32 oldValue = atomic_or(mutex, B_USER_MUTEX_LOCKED);
clear_ac();
// unblock the first thread // unblock the first thread
entry->locked = true; entry->locked = true;
@@ -196,15 +232,11 @@ user_mutex_unlock_locked(int32* mutex, addr_t physicalAddress, uint32 flags)
// dequeue the first thread and mark the mutex uncontended // dequeue the first thread and mark the mutex uncontended
sUserMutexTable.Remove(entry); sUserMutexTable.Remove(entry);
set_ac(); user_atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING);
atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING);
clear_ac();
} else { } else {
bool otherWaiters = remove_user_mutex_entry(entry); bool otherWaiters = remove_user_mutex_entry(entry);
if (!otherWaiters) { if (!otherWaiters) {
set_ac(); user_atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING);
atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING);
clear_ac();
} }
} }
} }
@@ -216,13 +248,9 @@ user_mutex_sem_acquire_locked(int32* sem, addr_t physicalAddress,
{ {
// The semaphore may have been released in the meantime, and we also // The semaphore may have been released in the meantime, and we also
// need to mark it as contended if it isn't already. // need to mark it as contended if it isn't already.
set_ac(); int32 oldValue = user_atomic_get(sem);
int32 oldValue = atomic_get(sem);
clear_ac();
while (oldValue > -1) { while (oldValue > -1) {
set_ac(); int32 value = user_atomic_test_and_set(sem, oldValue - 1, oldValue);
int32 value = atomic_test_and_set(sem, oldValue - 1, oldValue);
clear_ac();
if (value == oldValue && value > 0) if (value == oldValue && value > 0)
return B_OK; return B_OK;
oldValue = value; oldValue = value;
@@ -232,11 +260,8 @@ user_mutex_sem_acquire_locked(int32* sem, addr_t physicalAddress,
status_t error = user_mutex_wait_locked(sem, physicalAddress, name, flags, status_t error = user_mutex_wait_locked(sem, physicalAddress, name, flags,
timeout, locker, lastWaiter); timeout, locker, lastWaiter);
if (lastWaiter) { if (lastWaiter)
set_ac(); user_atomic_test_and_set(sem, 0, -1);
atomic_test_and_set(sem, 0, -1);
clear_ac();
}
return error; return error;
} }
@@ -248,14 +273,10 @@ user_mutex_sem_release_locked(int32* sem, addr_t physicalAddress)
UserMutexEntry* entry = sUserMutexTable.Lookup(physicalAddress); UserMutexEntry* entry = sUserMutexTable.Lookup(physicalAddress);
if (!entry) { if (!entry) {
// no waiters - mark as uncontended and release // no waiters - mark as uncontended and release
set_ac(); int32 oldValue = user_atomic_get(sem);
int32 oldValue = atomic_get(sem);
clear_ac();
while (true) { while (true) {
int32 inc = oldValue < 0 ? 2 : 1; int32 inc = oldValue < 0 ? 2 : 1;
set_ac(); int32 value = user_atomic_test_and_set(sem, oldValue + inc, oldValue);
int32 value = atomic_test_and_set(sem, oldValue + inc, oldValue);
clear_ac();
if (value == oldValue) if (value == oldValue)
return; return;
oldValue = value; oldValue = value;
@@ -269,9 +290,7 @@ user_mutex_sem_release_locked(int32* sem, addr_t physicalAddress)
if (!otherWaiters) { if (!otherWaiters) {
// mark the semaphore uncontended // mark the semaphore uncontended
set_ac(); user_atomic_test_and_set(sem, 0, -1);
atomic_test_and_set(sem, 0, -1);
clear_ac();
} }
} }