atom: redesign API

This commit is contained in:
anna 2022-10-10 09:30:53 +02:00
parent f293c6661e
commit 3e35afcfa9
Signed by: fef
GPG key ID: EC22E476DC2D3D84
8 changed files with 225 additions and 98 deletions

View file

@ -19,8 +19,7 @@ configure_file(
target_sources(ardix_arch PRIVATE
arch_init.c
atom_get_put.S
atom.c
atom.S
atomic.c
do_switch.S
entry.c

114
arch/at91sam3x8e/atom.S Normal file
View file

@ -0,0 +1,114 @@
/* See the end of this file for copyright, license, and warranty information. */
.include "asm.S"
.text
/* int _atom_add(volatile int *atom, int val) */
func_begin _atom_add
push {r4}
1: ldrex r2, [r0] /* int old = __ldrex(atom) */
add r3, r2, r1 /* int new = old + val */
strex r4, r3, [r0] /* int err = __strex(atom, new) */
teq r4, #0 /* if (err) */
bne 1b /* goto 1 */
dmb /* data memory barrier */
mov r0, r2 /* return old */
pop {r4}
bx lr
func_end _atom_add
/* these are the same as _atom_add except for the instruction
* in the LDREX/STREX pair, so i'm not gonna annotate them */
func_begin _atom_sub
push {r4}
1: ldrex r2, [r0]
sub r3, r2, r1
strex r4, r3, [r0]
teq r4, #0
bne 1b
dmb
mov r0, r2
pop {r4}
bx lr
func_end _atom_sub
func_begin _atom_and
push {r4}
1: ldrex r2, [r0]
and r3, r2, r1
strex r4, r3, [r0]
teq r4, #0
bne 1b
dmb
mov r0, r2
pop {r4}
bx lr
func_end _atom_and
func_begin _atom_or
push {r4}
1: ldrex r2, [r0]
orr r3, r2, r1
strex r4, r3, [r0]
teq r4, #0
bne 1b
dmb
mov r0, r2
pop {r4}
bx lr
func_end _atom_or
func_begin _atom_xor
push {r4}
1: ldrex r2, [r0]
eor r3, r2, r1
strex r4, r3, [r0]
teq r4, #0
bne 1b
dmb
mov r0, r2
pop {r4}
bx lr
func_end _atom_xor
/* int _atom_xchg(volatile int *atom, int val) */
func_begin _atom_xchg
ldrex r2, [r0] /* int old = __ldrex(atom) */
strex r3, r1, [r0] /* int err = __strex(atom, val) */
teq r3, #0 /* if (err) */
bne _atom_xchg /* goto _atom_xchg */
dmb /* data memory barrier */
mov r0, r2 /* return old */
bx lr
func_end _atom_xchg
/* int _atom_cmpxchg(volatile int *atom, int cmp, int val) */
func_begin _atom_cmpxchg
push {r4}
1: mov r4, #0 /* int err = 0 */
ldrex r3, [r0] /* int old = __ldrex(atom) */
teq r3, r1 /* if (old == cmp) */
it eq
strexeq r4, r1, [r0] /* err = __strex(atom, val) */
teq r4, #0 /* if (err) */
bne 1b /* goto 1b */
dmb /* data memory barrier */
mov r0, r3 /* return old */
pop {r4}
bx lr
func_end _atom_cmpxchg
/*
* This file is part of Ardix.
* Copyright (c) 2021 Felix Kopp <owo@fef.moe>.
*
* Ardix is non-violent software: you may only use, redistribute,
* and/or modify it under the terms of the CNPLv6+ as found in
* the LICENSE file in the source code root directory or at
* <https://git.pixie.town/thufie/CNPL>.
*
* Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
* permitted by applicable law. See the CNPLv6+ for details.
*/

View file

@ -1,27 +0,0 @@
/* See the end of this file for copyright, license, and warranty information. */
#include <ardix/atom.h>
#include <stddef.h>
void atom_init(atom_t *atom)
{
atom->count = 0;
}
int atom_count(atom_t *atom)
{
return atom->count;
}
/*
* This file is part of Ardix.
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
*
* Ardix is non-violent software: you may only use, redistribute,
* and/or modify it under the terms of the CNPLv6+ as found in
* the LICENSE file in the source code root directory or at
* <https://git.pixie.town/thufie/CNPL>.
*
* Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
* permitted by applicable law. See the CNPLv6+ for details.
*/

View file

@ -1,46 +0,0 @@
/* See the end of this file for copyright, license, and warranty information. */
.include "asm.S"
.text
/* int _atom_get(int *count); */
func_begin _atom_get
ldrex r1, [r0] /* int tmp = atom->count */
add r2, r1, #1 /* int newval = tmp + 1 */
strex r3, r2, [r0] /* atom->count = newval */
teq r3, #0 /* store successful? */
bne _atom_get /* -> goto _atom_get to try again if not */
dmb /* data memory barrier */
mov r0, r2 /* return newval */
bx lr
func_end _atom_get
/* int _atom_put(int *count); */
func_begin _atom_put
ldrex r1, [r0] /* int tmp = atom->count */
sub r2, r1, #1 /* int newval = tmp - 1 */
strex r3, r2, [r0] /* atom->count = newval */
teq r3, #0 /* store successful? */
bne _atom_put /* -> goto _atom_put to try again if not */
dmb /* data memory barrier */
mov r0, r2 /* return newval */
bx lr
func_end _atom_put
/*
* This file is part of Ardix.
* Copyright (c) 2021 Felix Kopp <owo@fef.moe>.
*
* Ardix is non-violent software: you may only use, redistribute,
* and/or modify it under the terms of the CNPLv6+ as found in
* the LICENSE file in the source code root directory or at
* <https://git.pixie.town/thufie/CNPL>.
*
* Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
* permitted by applicable law. See the CNPLv6+ for details.
*/

View file

@ -3,7 +3,7 @@
#include <ardix/atomic.h>
#include <ardix/atom.h>
static ATOM(atomic_context);
static ATOM(atomic_context, 0);
void atomic_enter(void)
{
@ -17,7 +17,7 @@ void atomic_leave(void)
int is_atomic(void)
{
return atom_count(&atomic_context);
return atom_read(&atomic_context);
}
/*

View file

@ -5,28 +5,119 @@
#include <ardix/types.h>
#include <toolchain.h>
#define ATOM(name) atom_t name = { .count = 0, }
#define ATOM_DEFINE(val) { ._val = val, }
#define ATOM(name, val) atom_t name = ATOM_DEFINE(val)
void atom_init(atom_t *atom);
extern int _atom_get(int *count);
extern int _atom_put(int *count);
__always_inline int atom_get(atom_t *atom)
static __always_inline void atom_init(atom_t *atom, int val)
{
return _atom_get(&atom->count);
atom->_val = val;
}
__always_inline int atom_put(atom_t *atom)
static __always_inline int atom_read(atom_t *atom)
{
return _atom_put(&atom->count);
return atom->_val;
}
int atom_count(atom_t *atom);
/*
* These are implemented in arch/<arch>/atom.S
*/
extern int _atom_add(volatile int *atom, int val);
extern int _atom_sub(volatile int *atom, int val);
extern int _atom_and(volatile int *atom, int val);
extern int _atom_or(volatile int *atom, int val);
extern int _atom_xor(volatile int *atom, int val);
extern int _atom_xchg(volatile int *atom, int val);
extern int _atom_cmpxchg(volatile int *atom, int cmp, int val);
/**
* @brief Atomically add `val` to `atom`.
* @return The old value of `atom`, before the addition
*/
static __always_inline int atom_add(atom_t *atom, int val)
{
return _atom_add(&atom->_val, val);
}
/**
* @brief Atomically subtract `val` from `atom`.
* @return The old value of `atom` before the subtraction
*/
static __always_inline int atom_sub(atom_t *atom, int val)
{
return _atom_sub(&atom->_val, val);
}
/**
* @brief Atomically do a bitwise AND of `val` and `atom`.
* @return The old value of `atom`, before the AND
*/
static __always_inline int atom_and(atom_t *atom, int val)
{
return _atom_and(&atom->_val, val);
}
/**
* @brief Atomically do a bitwise OR of `val` and `atom`.
* @return The old value of `atom`, before the OR
*/
static __always_inline int atom_or(atom_t *atom, int val)
{
return _atom_or(&atom->_val, val);
}
/**
* @brief Atomically do a bitwise XOR of `val` and `atom`.
* @return The old value of `atom`, before the XOR
*/
static __always_inline int atom_xor(atom_t *atom, int val)
{
return _atom_xor(&atom->_val, val);
}
/**
* @brief Atomically increment `atom` by 1.
* @return The old value of `atom`, before the increment
*/
static __always_inline int atom_get(atom_t *atom)
{
return _atom_add(&atom->_val, 1);
}
/**
* @brief Atomically decrement `atom` by 1.
* @return The old value of `atom`, before the decrement
*/
static __always_inline int atom_put(atom_t *atom)
{
return _atom_sub(&atom->_val, 1);
}
/**
* @brief Atomically exchange the value of `atom` with `val`.
* @return The old value of `atom`
*/
static __always_inline int atom_xchg(atom_t *atom, int val)
{
return _atom_xchg(&atom->_val, val);
}
/**
* @brief Atomically compare the value of `atom` with `cmp` and,
* if found to be equal, exchange it with `val`.
* @param atom atom to perform the operation on
* @param cmp value to compare the atom with
* @param val new value to be written to atom if it is equal to `cmp`
* @return The old value of `atom`
*/
static __always_inline int atom_cmpxchg(atom_t *atom, int cmp, int val)
{
return _atom_cmpxchg(&atom->_val, cmp, val);
}
/*
* This file is part of Ardix.
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
* Copyright (c) 2020, 2021, 2022 Felix Kopp <owo@fef.moe>.
*
* Ardix is non-violent software: you may only use, redistribute,
* and/or modify it under the terms of the CNPLv6+ as found in

View file

@ -16,9 +16,9 @@
/** Process identifier. */
typedef _PID_TYPE_ pid_t;
/** Simple atomic reference counter */
/** Simple atomic integer */
typedef struct {
int count;
volatile int _val;
} atom_t;
#include <arch/hardware.h>

View file

@ -1,9 +1,7 @@
/* See the end of this file for copyright, license, and warranty information. */
#include <ardix/atom.h>
#include <ardix/malloc.h>
#include <ardix/kent.h>
#include <ardix/list.h>
#include <errno.h>
#include <stddef.h>
@ -19,8 +17,7 @@ int kent_root_init(void)
kent_root->parent = NULL;
kent_root->destroy = NULL;
atom_init(&kent_root->refcount);
kent_get(kent_root);
atom_init(&kent_root->refcount, 1);
return 0;
}
@ -31,8 +28,7 @@ int kent_init(struct kent *kent)
return -EFAULT;
kent_get(kent->parent);
atom_init(&kent->refcount);
kent_get(kent);
atom_init(&kent->refcount, 1);
return 0;
}
@ -46,7 +42,7 @@ void kent_put(struct kent *kent)
{
struct kent *parent = kent->parent;
if (atom_put(&kent->refcount) == 0) {
if (atom_put(&kent->refcount) == 1) {
kent->destroy(kent);
if (parent != NULL)