linux/lib/atomic64_test.c
<<
>>
Prefs
   1/*
   2 * Testsuite for atomic64_t functions
   3 *
   4 * Copyright © 2010  Luca Barbieri
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 */
  11
  12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  13
  14#include <linux/init.h>
  15#include <linux/bug.h>
  16#include <linux/kernel.h>
  17#include <linux/atomic.h>
  18
  19#ifdef CONFIG_X86
  20#include <asm/cpufeature.h>     /* for boot_cpu_has below */
  21#endif
  22
  23#define TEST(bit, op, c_op, val)                                \
  24do {                                                            \
  25        atomic##bit##_set(&v, v0);                              \
  26        r = v0;                                                 \
  27        atomic##bit##_##op(val, &v);                            \
  28        r c_op val;                                             \
  29        WARN(atomic##bit##_read(&v) != r, "%Lx != %Lx\n",       \
  30                (unsigned long long)atomic##bit##_read(&v),     \
  31                (unsigned long long)r);                         \
  32} while (0)
  33
  34/*
  35 * Test for a atomic operation family,
  36 * @test should be a macro accepting parameters (bit, op, ...)
  37 */
  38
  39#define FAMILY_TEST(test, bit, op, args...)     \
  40do {                                            \
  41        test(bit, op, ##args);          \
  42        test(bit, op##_acquire, ##args);        \
  43        test(bit, op##_release, ##args);        \
  44        test(bit, op##_relaxed, ##args);        \
  45} while (0)
  46
  47#define TEST_RETURN(bit, op, c_op, val)                         \
  48do {                                                            \
  49        atomic##bit##_set(&v, v0);                              \
  50        r = v0;                                                 \
  51        r c_op val;                                             \
  52        BUG_ON(atomic##bit##_##op(val, &v) != r);               \
  53        BUG_ON(atomic##bit##_read(&v) != r);                    \
  54} while (0)
  55
  56#define TEST_FETCH(bit, op, c_op, val)                          \
  57do {                                                            \
  58        atomic##bit##_set(&v, v0);                              \
  59        r = v0;                                                 \
  60        r c_op val;                                             \
  61        BUG_ON(atomic##bit##_##op(val, &v) != v0);              \
  62        BUG_ON(atomic##bit##_read(&v) != r);                    \
  63} while (0)
  64
  65#define RETURN_FAMILY_TEST(bit, op, c_op, val)                  \
  66do {                                                            \
  67        FAMILY_TEST(TEST_RETURN, bit, op, c_op, val);           \
  68} while (0)
  69
  70#define FETCH_FAMILY_TEST(bit, op, c_op, val)                   \
  71do {                                                            \
  72        FAMILY_TEST(TEST_FETCH, bit, op, c_op, val);            \
  73} while (0)
  74
  75#define TEST_ARGS(bit, op, init, ret, expect, args...)          \
  76do {                                                            \
  77        atomic##bit##_set(&v, init);                            \
  78        BUG_ON(atomic##bit##_##op(&v, ##args) != ret);          \
  79        BUG_ON(atomic##bit##_read(&v) != expect);               \
  80} while (0)
  81
  82#define XCHG_FAMILY_TEST(bit, init, new)                                \
  83do {                                                                    \
  84        FAMILY_TEST(TEST_ARGS, bit, xchg, init, init, new, new);        \
  85} while (0)
  86
  87#define CMPXCHG_FAMILY_TEST(bit, init, new, wrong)                      \
  88do {                                                                    \
  89        FAMILY_TEST(TEST_ARGS, bit, cmpxchg,                            \
  90                        init, init, new, init, new);                    \
  91        FAMILY_TEST(TEST_ARGS, bit, cmpxchg,                            \
  92                        init, init, init, wrong, new);                  \
  93} while (0)
  94
  95#define INC_RETURN_FAMILY_TEST(bit, i)                  \
  96do {                                                    \
  97        FAMILY_TEST(TEST_ARGS, bit, inc_return,         \
  98                        i, (i) + one, (i) + one);       \
  99} while (0)
 100
 101#define DEC_RETURN_FAMILY_TEST(bit, i)                  \
 102do {                                                    \
 103        FAMILY_TEST(TEST_ARGS, bit, dec_return,         \
 104                        i, (i) - one, (i) - one);       \
 105} while (0)
 106
 107static __init void test_atomic(void)
 108{
 109        int v0 = 0xaaa31337;
 110        int v1 = 0xdeadbeef;
 111        int onestwos = 0x11112222;
 112        int one = 1;
 113
 114        atomic_t v;
 115        int r;
 116
 117        TEST(, add, +=, onestwos);
 118        TEST(, add, +=, -one);
 119        TEST(, sub, -=, onestwos);
 120        TEST(, sub, -=, -one);
 121        TEST(, or, |=, v1);
 122        TEST(, and, &=, v1);
 123        TEST(, xor, ^=, v1);
 124        TEST(, andnot, &= ~, v1);
 125
 126        RETURN_FAMILY_TEST(, add_return, +=, onestwos);
 127        RETURN_FAMILY_TEST(, add_return, +=, -one);
 128        RETURN_FAMILY_TEST(, sub_return, -=, onestwos);
 129        RETURN_FAMILY_TEST(, sub_return, -=, -one);
 130
 131        FETCH_FAMILY_TEST(, fetch_add, +=, onestwos);
 132        FETCH_FAMILY_TEST(, fetch_add, +=, -one);
 133        FETCH_FAMILY_TEST(, fetch_sub, -=, onestwos);
 134        FETCH_FAMILY_TEST(, fetch_sub, -=, -one);
 135
 136        FETCH_FAMILY_TEST(, fetch_or,  |=, v1);
 137        FETCH_FAMILY_TEST(, fetch_and, &=, v1);
 138        FETCH_FAMILY_TEST(, fetch_andnot, &= ~, v1);
 139        FETCH_FAMILY_TEST(, fetch_xor, ^=, v1);
 140
 141        INC_RETURN_FAMILY_TEST(, v0);
 142        DEC_RETURN_FAMILY_TEST(, v0);
 143
 144        XCHG_FAMILY_TEST(, v0, v1);
 145        CMPXCHG_FAMILY_TEST(, v0, v1, onestwos);
 146
 147}
 148
 149#define INIT(c) do { atomic64_set(&v, c); r = c; } while (0)
 150static __init void test_atomic64(void)
 151{
 152        long long v0 = 0xaaa31337c001d00dLL;
 153        long long v1 = 0xdeadbeefdeafcafeLL;
 154        long long v2 = 0xfaceabadf00df001LL;
 155        long long onestwos = 0x1111111122222222LL;
 156        long long one = 1LL;
 157
 158        atomic64_t v = ATOMIC64_INIT(v0);
 159        long long r = v0;
 160        BUG_ON(v.counter != r);
 161
 162        atomic64_set(&v, v1);
 163        r = v1;
 164        BUG_ON(v.counter != r);
 165        BUG_ON(atomic64_read(&v) != r);
 166
 167        TEST(64, add, +=, onestwos);
 168        TEST(64, add, +=, -one);
 169        TEST(64, sub, -=, onestwos);
 170        TEST(64, sub, -=, -one);
 171        TEST(64, or, |=, v1);
 172        TEST(64, and, &=, v1);
 173        TEST(64, xor, ^=, v1);
 174        TEST(64, andnot, &= ~, v1);
 175
 176        RETURN_FAMILY_TEST(64, add_return, +=, onestwos);
 177        RETURN_FAMILY_TEST(64, add_return, +=, -one);
 178        RETURN_FAMILY_TEST(64, sub_return, -=, onestwos);
 179        RETURN_FAMILY_TEST(64, sub_return, -=, -one);
 180
 181        FETCH_FAMILY_TEST(64, fetch_add, +=, onestwos);
 182        FETCH_FAMILY_TEST(64, fetch_add, +=, -one);
 183        FETCH_FAMILY_TEST(64, fetch_sub, -=, onestwos);
 184        FETCH_FAMILY_TEST(64, fetch_sub, -=, -one);
 185
 186        FETCH_FAMILY_TEST(64, fetch_or,  |=, v1);
 187        FETCH_FAMILY_TEST(64, fetch_and, &=, v1);
 188        FETCH_FAMILY_TEST(64, fetch_andnot, &= ~, v1);
 189        FETCH_FAMILY_TEST(64, fetch_xor, ^=, v1);
 190
 191        INIT(v0);
 192        atomic64_inc(&v);
 193        r += one;
 194        BUG_ON(v.counter != r);
 195
 196        INIT(v0);
 197        atomic64_dec(&v);
 198        r -= one;
 199        BUG_ON(v.counter != r);
 200
 201        INC_RETURN_FAMILY_TEST(64, v0);
 202        DEC_RETURN_FAMILY_TEST(64, v0);
 203
 204        XCHG_FAMILY_TEST(64, v0, v1);
 205        CMPXCHG_FAMILY_TEST(64, v0, v1, v2);
 206
 207        INIT(v0);
 208        BUG_ON(atomic64_add_unless(&v, one, v0));
 209        BUG_ON(v.counter != r);
 210
 211        INIT(v0);
 212        BUG_ON(!atomic64_add_unless(&v, one, v1));
 213        r += one;
 214        BUG_ON(v.counter != r);
 215
 216        INIT(onestwos);
 217        BUG_ON(atomic64_dec_if_positive(&v) != (onestwos - 1));
 218        r -= one;
 219        BUG_ON(v.counter != r);
 220
 221        INIT(0);
 222        BUG_ON(atomic64_dec_if_positive(&v) != -one);
 223        BUG_ON(v.counter != r);
 224
 225        INIT(-one);
 226        BUG_ON(atomic64_dec_if_positive(&v) != (-one - one));
 227        BUG_ON(v.counter != r);
 228
 229        INIT(onestwos);
 230        BUG_ON(!atomic64_inc_not_zero(&v));
 231        r += one;
 232        BUG_ON(v.counter != r);
 233
 234        INIT(0);
 235        BUG_ON(atomic64_inc_not_zero(&v));
 236        BUG_ON(v.counter != r);
 237
 238        INIT(-one);
 239        BUG_ON(!atomic64_inc_not_zero(&v));
 240        r += one;
 241        BUG_ON(v.counter != r);
 242}
 243
 244static __init int test_atomics(void)
 245{
 246        test_atomic();
 247        test_atomic64();
 248
 249#ifdef CONFIG_X86
 250        pr_info("passed for %s platform %s CX8 and %s SSE\n",
 251#ifdef CONFIG_X86_64
 252                "x86-64",
 253#elif defined(CONFIG_X86_CMPXCHG64)
 254                "i586+",
 255#else
 256                "i386+",
 257#endif
 258               boot_cpu_has(X86_FEATURE_CX8) ? "with" : "without",
 259               boot_cpu_has(X86_FEATURE_XMM) ? "with" : "without");
 260#else
 261        pr_info("passed\n");
 262#endif
 263
 264        return 0;
 265}
 266
 267core_initcall(test_atomics);
 268