atom: redesign API
This commit is contained in:
parent
f293c6661e
commit
3e35afcfa9
8 changed files with 225 additions and 98 deletions
|
@ -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
114
arch/at91sam3x8e/atom.S
Normal 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.
|
||||
*/
|
|
@ -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.
|
||||
*/
|
|
@ -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.
|
||||
*/
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue