Sample spinlock test case with the option to implement the spinlock by means of GCC atomic instructions or unsafe memory operations. Additionally, printf is wrapped around a spinlock to avoid concurrent access to the serial device.
Suggested-by: Jani Kokkonen <[email protected]> Suggested-by: Claudio Fontana <[email protected]> Signed-off-by: Alexander Spyridakis <[email protected]> --- tests/atomic-test/Makefile | 3 +++ tests/atomic-test/helpers.c | 21 +++++++++++++++++++++ tests/atomic-test/helpers.h | 12 ++++++++++++ tests/atomic-test/main.c | 35 ++++++++++++++++++++++++++++++++++- tests/atomic-test/printf.c | 5 +++++ 5 files changed, 75 insertions(+), 1 deletion(-) diff --git a/tests/atomic-test/Makefile b/tests/atomic-test/Makefile index 094e01a..d1e992d 100644 --- a/tests/atomic-test/Makefile +++ b/tests/atomic-test/Makefile @@ -12,6 +12,9 @@ LD_SCRIPT = link.ld.S LIBS = $(shell $(CC) $(CCFLAGS) -print-libgcc-file-name) CPPFLAGS += -gdwarf-2 -fno-stack-protector -nostdinc -fno-builtin +# Set to ATOMIC to implement spinlock test with real atomic instructions +TEST = ATOMIC + # # Target specific variables # diff --git a/tests/atomic-test/helpers.c b/tests/atomic-test/helpers.c index 8ac8c2c..fd2d4cf 100644 --- a/tests/atomic-test/helpers.c +++ b/tests/atomic-test/helpers.c @@ -82,3 +82,24 @@ void power_off(void) /* Shut down system */ psci_call(PSCI_SYSTEM_OFF, 0, 0, 0); } + +void atomic_lock(int *lock_var) +{ + while (__sync_lock_test_and_set(lock_var, 1)); +} + +void atomic_unlock(int *lock_var) +{ + __sync_lock_release(lock_var); +} + +void non_atomic_lock(int *lock_var) +{ + while (*lock_var != 0); + *lock_var = 1; +} + +void non_atomic_unlock(int *lock_var) +{ + *lock_var = 0; +} diff --git a/tests/atomic-test/helpers.h b/tests/atomic-test/helpers.h index 66d440e..93036be 100644 --- a/tests/atomic-test/helpers.h +++ b/tests/atomic-test/helpers.h @@ -29,6 +29,18 @@ #define PSCI_CPU_OFF 0x84000002 #define PSCI_SYSTEM_OFF 0x84000008 +#ifdef ATOMIC +#define LOCK atomic_lock +#define UNLOCK atomic_unlock +#else +#define LOCK non_atomic_lock +#define UNLOCK non_atomic_unlock +#endif + +int global_lock; +int global_a; +int global_b; + int get_cpuid(void); void power_secondary(void); void power_off(); diff --git a/tests/atomic-test/main.c b/tests/atomic-test/main.c index 72eaf59..3143f7c 100644 --- a/tests/atomic-test/main.c +++ b/tests/atomic-test/main.c @@ -15,9 +15,42 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "helpers.h" + +#define LOOP_SIZE 1000000 + +void test_spinlock() +{ + int i, errors = 0; + int cpu = get_cpuid(); + + for (i = 0; i < LOOP_SIZE; i++) { + LOCK(&global_lock); + + if (global_a == (cpu + 1) % 2) { + global_a = 1; + global_b = 0; + } else { + global_a = 0; + global_b = 1; + } + + if (global_a == global_b) { + errors++; + } + UNLOCK(&global_lock); + } + + printf("CPU%d: Done - Errors: %d\n", cpu, errors); +} + void main(void) { - printf("CPU %d on\n", get_cpuid()); + if (!get_cpuid()) { + printf("Starting test\n"); + } + + test_spinlock(); power_off(); } diff --git a/tests/atomic-test/printf.c b/tests/atomic-test/printf.c index 7c40d37..78a9e54 100644 --- a/tests/atomic-test/printf.c +++ b/tests/atomic-test/printf.c @@ -17,6 +17,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "helpers.h" + #define UARTDR UART_PHYS #define UARTFR 0x18 #define UARTFR_TXFF (1 << 5) @@ -28,6 +30,7 @@ typedef __builtin_va_list va_list; int *uart_phys = (int *)(UART_PHYS); int *uart_busy = (int *)(UART_PHYS + UARTFR); +int printf_lock; static void putc(char c) { @@ -72,6 +75,7 @@ void printf(const char *fmt, ...) int alt_form; unsigned long long val; + atomic_lock(&printf_lock); va_start(ap, fmt); for (; *fmt; fmt++) { @@ -149,4 +153,5 @@ void printf(const char *fmt, ...) } va_end(ap); + atomic_unlock(&printf_lock); } -- 2.1.4
