mutex: use uint8_t instead of int for lock value
This commit is contained in:
parent
d20da423ec
commit
f54a4a0fa9
2 changed files with 108 additions and 19 deletions
|
@ -2,32 +2,51 @@
|
|||
|
||||
.include "asm.S"
|
||||
|
||||
.text
|
||||
.section .text.shared
|
||||
|
||||
/* int _mutex_lock(int *lock); */
|
||||
/* void _mutex_lock(uint8_t *lock); */
|
||||
func_begin _mutex_lock
|
||||
|
||||
mov r1, #1
|
||||
mov r1, #1 /* uint8_t newval = 1; */
|
||||
|
||||
1: ldrex r2, [r0]
|
||||
cmp r2, #0
|
||||
itt eq
|
||||
strexeq r2, r1, [r0]
|
||||
cmpeq r2, #0
|
||||
1: ldrexb r2, [r0] /* uint8_t tmp = __ldrexb(lock); */
|
||||
|
||||
bne 1b
|
||||
cmp r2, #0
|
||||
itt eq
|
||||
strexbeq r2, r1, [r0] /* tmp = __strexb(newval, lock); */
|
||||
cmpeq r2, #0
|
||||
|
||||
bne 1b
|
||||
|
||||
dmb
|
||||
eor r0, r0
|
||||
bx lr
|
||||
bx lr
|
||||
|
||||
func_end _mutex_lock
|
||||
|
||||
/* int _mutex_unlock(int *lock); */
|
||||
/* int _mutex_trylock(uint8_t *lock); */
|
||||
func_begin _mutex_trylock
|
||||
|
||||
mov r1, #1 /* uint8_t newval = 1; */
|
||||
/* move lock to r2 to make room in r0 for the return value */
|
||||
mov r2, r0
|
||||
|
||||
ldrexb r0, [r2] /* uint8_t tmp = __ldrexb(lock); */
|
||||
|
||||
cmp r0, #0
|
||||
ittt eq
|
||||
strexbeq r0, r1, [r2] /* tmp = __strexb(newval, lock); */
|
||||
cmpeq r0, #0
|
||||
dmbeq /* if (tmp == 0) __dmb(); */
|
||||
|
||||
bx lr /* return tmp; */
|
||||
|
||||
func_end _mutex_trylock
|
||||
|
||||
/* void _mutex_unlock(uint8_t *lock); */
|
||||
func_begin _mutex_unlock
|
||||
|
||||
mov r1, #0
|
||||
str r1, [r0]
|
||||
strb r1, [r0]
|
||||
dmb
|
||||
bx lr
|
||||
|
||||
|
|
|
@ -2,38 +2,108 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <ardix/types.h>
|
||||
|
||||
#include <toolchain.h>
|
||||
|
||||
/**
|
||||
* @defgroup mutex Synchronization Primitives
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief A simple mutex.
|
||||
*
|
||||
* Mutexes can be locked using the `mutex_lock()` and `mutex_unlock()` methods
|
||||
* respectively. The former will block until the lock is acquired and thus
|
||||
* should never be used from interrupt context. Use `mutex_trylock()` if you
|
||||
* don't want blocking.
|
||||
*/
|
||||
struct mutex {
|
||||
int lock;
|
||||
uint8_t lock; /**< Current lock value, don't read directly */
|
||||
};
|
||||
|
||||
extern int _mutex_lock(int *lock);
|
||||
extern int _mutex_trylock(int *lock);
|
||||
extern void _mutex_unlock(int *lock);
|
||||
/**
|
||||
* @brief Internal assembly routine for `mutex_lock()`.
|
||||
* @private
|
||||
*/
|
||||
extern void _mutex_lock(uint8_t *lock);
|
||||
/**
|
||||
* @brief Internal assembly routine for `mutex_trylock()`.
|
||||
* @private
|
||||
*/
|
||||
extern int _mutex_trylock(uint8_t *lock);
|
||||
/**
|
||||
* @brief Internal assembly routine for `mutex_unlock()`.
|
||||
* @private
|
||||
*/
|
||||
extern void _mutex_unlock(uint8_t *lock);
|
||||
|
||||
/**
|
||||
* @brief Initialize a mutex and set it to unlocked.
|
||||
*
|
||||
* @param mutex Mutex to initialize
|
||||
*/
|
||||
__always_inline void mutex_init(struct mutex *mutex)
|
||||
{
|
||||
mutex->lock = 0;
|
||||
}
|
||||
|
||||
__always_inline int mutex_lock(struct mutex *mutex)
|
||||
/**
|
||||
* @brief Acquire an exclusive lock on a mutex.
|
||||
* This call will block until the lock was acquired and therefore cannot fail.
|
||||
*
|
||||
* @param mutex Mutex to lock
|
||||
*/
|
||||
__always_inline void mutex_lock(struct mutex *mutex)
|
||||
{
|
||||
return _mutex_lock(&mutex->lock);
|
||||
_mutex_lock(&mutex->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Release an exclusive lock on a mutex.
|
||||
*
|
||||
* @param mutex Mutex to unlock
|
||||
*/
|
||||
__always_inline void mutex_unlock(struct mutex *mutex)
|
||||
{
|
||||
_mutex_unlock(&mutex->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Attempt to acquire an exclusive lock on a mutex.
|
||||
* The return value is zero if the claim succeeds, and nonzero otherwise.
|
||||
*
|
||||
* @param mutex Mutex to attempt to lock
|
||||
* @returns 0 if the lock was acquired, a nonzero value otherwise
|
||||
*/
|
||||
__always_inline int mutex_trylock(struct mutex *mutex)
|
||||
{
|
||||
return _mutex_trylock(&mutex->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determine whether a mutex is locked.
|
||||
*
|
||||
* @param mutex Mutex to get the lock value of
|
||||
* @returns Nonzero if the mutex is locked, zero otherwise
|
||||
*/
|
||||
__always_inline int mutex_is_locked(struct mutex *mutex)
|
||||
{
|
||||
return mutex->lock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Statically declare and define a mutex (file scope only).
|
||||
* The mutex does not need to be initialized using `mutex_init()`.
|
||||
*
|
||||
* @param name Name of the `struct mutex` that will be defined
|
||||
*/
|
||||
#define MUTEX(name) struct mutex name = { .lock = 0 }
|
||||
|
||||
/** @} */
|
||||
|
||||
/*
|
||||
* This file is part of Ardix.
|
||||
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
|
||||
|
|
Loading…
Reference in a new issue