diff --git a/arch/at91sam3x8e/CMakeLists.txt b/arch/at91sam3x8e/CMakeLists.txt index d42afb5..02f88ec 100644 --- a/arch/at91sam3x8e/CMakeLists.txt +++ b/arch/at91sam3x8e/CMakeLists.txt @@ -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 diff --git a/arch/at91sam3x8e/atom.S b/arch/at91sam3x8e/atom.S new file mode 100644 index 0000000..47726dd --- /dev/null +++ b/arch/at91sam3x8e/atom.S @@ -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 . + * + * 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 + * . + * + * Ardix comes with ABSOLUTELY NO WARRANTY, to the extent + * permitted by applicable law. See the CNPLv6+ for details. + */ diff --git a/arch/at91sam3x8e/atom.c b/arch/at91sam3x8e/atom.c deleted file mode 100644 index 19217cb..0000000 --- a/arch/at91sam3x8e/atom.c +++ /dev/null @@ -1,27 +0,0 @@ -/* See the end of this file for copyright, license, and warranty information. */ - -#include -#include - -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 . - * - * 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 - * . - * - * Ardix comes with ABSOLUTELY NO WARRANTY, to the extent - * permitted by applicable law. See the CNPLv6+ for details. - */ diff --git a/arch/at91sam3x8e/atom_get_put.S b/arch/at91sam3x8e/atom_get_put.S deleted file mode 100644 index 1e833fd..0000000 --- a/arch/at91sam3x8e/atom_get_put.S +++ /dev/null @@ -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 . - * - * 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 - * . - * - * Ardix comes with ABSOLUTELY NO WARRANTY, to the extent - * permitted by applicable law. See the CNPLv6+ for details. - */ diff --git a/arch/at91sam3x8e/atomic.c b/arch/at91sam3x8e/atomic.c index f80da00..76f61d9 100644 --- a/arch/at91sam3x8e/atomic.c +++ b/arch/at91sam3x8e/atomic.c @@ -3,7 +3,7 @@ #include #include -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); } /* diff --git a/include/ardix/atom.h b/include/ardix/atom.h index a8d6d3f..4ba0fcb 100644 --- a/include/ardix/atom.h +++ b/include/ardix/atom.h @@ -5,28 +5,119 @@ #include #include -#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//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 . + * Copyright (c) 2020, 2021, 2022 Felix Kopp . * * Ardix is non-violent software: you may only use, redistribute, * and/or modify it under the terms of the CNPLv6+ as found in diff --git a/include/ardix/types.h b/include/ardix/types.h index afee697..51e536b 100644 --- a/include/ardix/types.h +++ b/include/ardix/types.h @@ -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 diff --git a/kernel/kent.c b/kernel/kent.c index 5c29823..3c83a11 100644 --- a/kernel/kent.c +++ b/kernel/kent.c @@ -1,9 +1,7 @@ /* See the end of this file for copyright, license, and warranty information. */ #include -#include #include -#include #include #include @@ -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)