mutex: use uint8_t instead of int for lock value

This commit is contained in:
anna 2021-08-01 16:48:19 +02:00
parent d20da423ec
commit f54a4a0fa9
Signed by: fef
GPG key ID: EC22E476DC2D3D84
2 changed files with 108 additions and 19 deletions
arch/at91sam3x8e
include/ardix

View file

@ -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

View file

@ -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>.