Atomics

Atomics test source.

/******************************************************************************
* Copyright (c) Intel Corporation - All rights reserved.                      *
* This file is part of the LIBXS library.                                     *
*                                                                             *
* For information on the license, see the LICENSE file.                       *
* Further information: https://github.com/hfp/libxs/                          *
* SPDX-License-Identifier: BSD-3-Clause                                       *
******************************************************************************/
#include <libxs_source.h>

#if !defined(ATOMIC_KIND)
# define ATOMIC_KIND LIBXS_ATOMIC_LOCKORDER
#endif

#if !defined(PRINT) && (defined(_DEBUG) || 0)
# define PRINT
#endif
#if defined(PRINT)
# define FPRINTF(STREAM, ...) do { fprintf(STREAM, __VA_ARGS__); } while(0)
#else
# define FPRINTF(STREAM, ...) do {} while(0)
#endif


int main(void)
{
  LIBXS_ALIGNED(LIBXS_ATOMIC_LOCKTYPE lock = 0/*unlocked*/, LIBXS_ALIGNMENT);
  int result = EXIT_SUCCESS;
  int mh = 1051981, hp, tmp;

  LIBXS_NONATOMIC_STORE(&hp, 25071975, ATOMIC_KIND);
  tmp = LIBXS_NONATOMIC_LOAD(&hp, ATOMIC_KIND);
  if (tmp != LIBXS_ATOMIC_LOAD(&hp, ATOMIC_KIND)) {
    result = EXIT_FAILURE;
  }
  if (mh != LIBXS_NONATOMIC_SUB_FETCH(&hp, 24019994, ATOMIC_KIND)) {
    result = EXIT_FAILURE;
  }
  if (mh != LIBXS_ATOMIC_FETCH_ADD(&hp, 24019994, ATOMIC_KIND)) {
    result = EXIT_FAILURE;
  }
  LIBXS_ATOMIC_STORE(&tmp, mh, ATOMIC_KIND);
  if (25071975 != LIBXS_NONATOMIC_FETCH_OR(&hp, tmp, ATOMIC_KIND)) {
    result = EXIT_FAILURE;
  }
  if ((25071975 | mh) != hp) {
    result = EXIT_FAILURE;
  }
  /* check if non-atomic and atomic are compatible */
  if (LIBXS_NONATOMIC_TRYLOCK(&lock, ATOMIC_KIND)) {
    if (LIBXS_ATOMIC_TRYLOCK(&lock, ATOMIC_KIND)) {
      result = EXIT_FAILURE;
    }
    LIBXS_NONATOMIC_RELEASE(&lock, ATOMIC_KIND);
    if (0 != lock) result = EXIT_FAILURE;
  }
  else {
    result = EXIT_FAILURE;
  }

  LIBXS_ATOMIC_ACQUIRE(&lock, LIBXS_SYNC_NPAUSE, ATOMIC_KIND);
  if (0 == lock) result = EXIT_FAILURE;
  if (LIBXS_ATOMIC_TRYLOCK(&lock, ATOMIC_KIND)) {
    result = EXIT_FAILURE;
  }
  if (LIBXS_ATOMIC_TRYLOCK(&lock, ATOMIC_KIND)) {
    result = EXIT_FAILURE;
  }
  if (0 == lock) result = EXIT_FAILURE;
  LIBXS_ATOMIC_RELEASE(&lock, ATOMIC_KIND);
  if (0 != lock) result = EXIT_FAILURE;

  /* check LIBXS_ATOMIC_ADD_FETCH */
  if (EXIT_SUCCESS == result) {
    int val = 10;
    int r = LIBXS_ATOMIC_ADD_FETCH(&val, 5, ATOMIC_KIND);
    if (15 != r || 15 != val) {
      FPRINTF(stderr, "ERROR line #%i: ATOMIC_ADD_FETCH r=%i val=%i\n", __LINE__, r, val);
      result = EXIT_FAILURE;
    }
  }

  /* check LIBXS_ATOMIC_SUB_FETCH */
  if (EXIT_SUCCESS == result) {
    int val = 20;
    int r = LIBXS_ATOMIC_SUB_FETCH(&val, 7, ATOMIC_KIND);
    if (13 != r || 13 != val) {
      FPRINTF(stderr, "ERROR line #%i: ATOMIC_SUB_FETCH r=%i val=%i\n", __LINE__, r, val);
      result = EXIT_FAILURE;
    }
  }

  /* check LIBXS_ATOMIC_FETCH_SUB (returns old value) */
  if (EXIT_SUCCESS == result) {
    int val = 100;
    int old = LIBXS_ATOMIC_FETCH_SUB(&val, 30, ATOMIC_KIND);
    if (100 != old || 70 != val) {
      FPRINTF(stderr, "ERROR line #%i: ATOMIC_FETCH_SUB old=%i val=%i\n", __LINE__, old, val);
      result = EXIT_FAILURE;
    }
  }

  /* check LIBXS_ATOMIC_CMPSWP - successful swap */
  if (EXIT_SUCCESS == result) {
    int val = 42;
    if (!LIBXS_ATOMIC_CMPSWP(&val, 42, 99, ATOMIC_KIND)) {
      FPRINTF(stderr, "ERROR line #%i: CMPSWP should succeed\n", __LINE__);
      result = EXIT_FAILURE;
    }
    if (EXIT_SUCCESS == result && 99 != val) {
      FPRINTF(stderr, "ERROR line #%i: CMPSWP val=%i expected 99\n", __LINE__, val);
      result = EXIT_FAILURE;
    }
  }

  /* check LIBXS_ATOMIC_CMPSWP - failed swap (value mismatch) */
  if (EXIT_SUCCESS == result) {
    int val = 10;
    if (LIBXS_ATOMIC_CMPSWP(&val, 20, 30, ATOMIC_KIND)) {
      FPRINTF(stderr, "ERROR line #%i: CMPSWP should fail\n", __LINE__);
      result = EXIT_FAILURE;
    }
    if (EXIT_SUCCESS == result && 10 != val) {
      FPRINTF(stderr, "ERROR line #%i: CMPSWP should not modify val=%i\n", __LINE__, val);
      result = EXIT_FAILURE;
    }
  }

  /* CMPSWP regression: must fail even when OLDVAL == NEWVAL and *dst != OLDVAL */
  if (EXIT_SUCCESS == result) {
    int val = 5;
    if (LIBXS_ATOMIC_CMPSWP(&val, 7, 7, ATOMIC_KIND)) {
      FPRINTF(stderr, "ERROR line #%i: CMPSWP(5,7,7) should fail\n", __LINE__);
      result = EXIT_FAILURE;
    }
    if (EXIT_SUCCESS == result && 5 != val) {
      FPRINTF(stderr, "ERROR line #%i: CMPSWP should not modify val=%i\n", __LINE__, val);
      result = EXIT_FAILURE;
    }
  }

  /* check LIBXS_ATOMIC_STORE_ZERO */
  if (EXIT_SUCCESS == result) {
    int val = 12345;
    LIBXS_ATOMIC_STORE_ZERO(&val, ATOMIC_KIND);
    if (0 != val) {
      FPRINTF(stderr, "ERROR line #%i: STORE_ZERO val=%i\n", __LINE__, val);
      result = EXIT_FAILURE;
    }
  }

  /* check LIBXS_ATOMIC_SYNC (just verify it compiles and doesn't crash) */
  LIBXS_ATOMIC_SYNC(ATOMIC_KIND);

  return result;
}