Logo Search packages:      
Sourcecode: libatomic-ops version File versions

test_atomic.c

/*
 * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
 *
 * This file is covered by the GNU general public license, version 2.
 * see doc/COPYING for details.
 */

#if defined(_MSC_VER) || \
    defined(_WIN32) && !defined(__CYGWIN32__) && !defined(__CYGWIN__) || \
    defined(_WIN32_WINCE)
#  define USE_WINTHREADS
#else
#  define USE_PTHREADS
#endif

#include <stdlib.h>
#include <stdio.h>

#ifdef USE_PTHREADS
# include <pthread.h>
#endif

#ifdef USE_WINTHREADS
# include <windows.h>
#endif

#include "atomic_ops.h"

#include "test_atomic_include.h"

typedef void * (* thr_func)(void *);

typedef int (* test_func)(void);    /* Returns != 0 on success */

#ifdef USE_PTHREADS
void * run_parallel(int nthreads, thr_func f1, test_func t, char *name)
{
  pthread_attr_t attr;
  pthread_t thr[100];
  int i;
  int code;

  fprintf(stderr, "Testing %s\n", name);
  if (nthreads > 100) 
    {
      fprintf(stderr, "run_parallel: requested too many threads\n");
      abort();
    }

  pthread_attr_init(&attr);

  for (i = 0; i < nthreads; ++i)
    {
      if ((code = pthread_create(thr + i, &attr, f1, (void *)(long)i)) != 0)
      {
        perror("Thread creation failed");
        fprintf(stderr, "Pthread_create returned %d, thread %d\n", code, i);
        abort();
        }
    }
  for (i = 0; i < nthreads; ++i)
    {
      if ((code = pthread_join(thr[i], NULL)) != 0)
      {
        perror("Thread join failed");
        fprintf(stderr, "Pthread_join returned %d, thread %d\n", code, i);
        abort();
        }
    }
  if (t())
    {
      fprintf(stderr, "Succeeded\n");
    }
  else
    {
      fprintf(stderr, "Failed\n");
      abort();
    }
  return 0;
}
#endif /* USE_PTHREADS */

#ifdef USE_WINTHREADS

struct tramp_args {
  thr_func fn;
  long arg;
};

DWORD WINAPI tramp(LPVOID param)
{
  struct tramp_args *args = (struct tramp_args *)param;

  return (DWORD)(args -> fn)((LPVOID)(args -> arg));
}

void * run_parallel(int nthreads, thr_func f1, test_func t, char *name)
{
  HANDLE thr[100];
  struct tramp_args args[100];
  int i;
  DWORD code;

  fprintf(stderr, "Testing %s\n", name);
  if (nthreads > 100) 
    {
      fprintf(stderr, "run_parallel: requested too many threads\n");
      abort();
    }

  for (i = 0; i < nthreads; ++i)
    {
      args[i].fn = f1;
      args[i].arg = i;
      if ((thr[i] = CreateThread(NULL, 0, tramp, (LPVOID)(args+i), 0, NULL))
        == NULL)
      {
        perror("Thread creation failed");
        fprintf(stderr, "CreateThread failed with %d, thread %d\n",
                    GetLastError(), i);
        abort();
        }
    }
  for (i = 0; i < nthreads; ++i)
    {
      if ((code = WaitForSingleObject(thr[i], INFINITE)) != WAIT_OBJECT_0)
      {
        perror("Thread join failed");
        fprintf(stderr, "WaitForSingleObject returned %d, thread %d\n",
                    code, i);
        abort();
        }
    }
  if (t())
    {
      fprintf(stderr, "Succeeded\n");
    }
  else
    {
      fprintf(stderr, "Failed\n");
      abort();
    }
  return 0;
}
#endif /* USE_WINTHREADS */

#ifdef AO_USE_PTHREAD_DEFS
# define NITERS 100000
#else
# define NITERS 1000000
#endif

#if defined(AO_HAVE_fetch_and_add1) && defined(AO_HAVE_fetch_and_sub1)

AO_T counter = 0;

void * add1sub1_thr(void * id)
{
  int me = (int)(long)id;

  int i;

  for (i = 0; i < NITERS; ++i)
    if (me & 1)
      AO_fetch_and_sub1(&counter);
    else
      AO_fetch_and_add1(&counter);

  return 0;
}

int add1sub1_test(void)
{
  return counter == 0;
}

#endif /* defined(AO_HAVE_fetch_and_add1) && defined(AO_HAVE_fetch_and_sub1) */

#if defined(AO_HAVE_store_release_write) && defined(AO_HAVE_load_acquire_read)

/* Invariant: counter1 >= counter2 */
AO_T counter1 = 0;
AO_T counter2 = 0;

void * acqrel_thr(void *id)
{
  int me = (int)(long)id;

  int i;

  for (i = 0; i < NITERS; ++i)
    if (me & 1)
      {
        AO_T my_counter1;
      if (me != 1)
        fprintf(stderr, "acqrel test: too many threads\n");
      my_counter1 = AO_load(&counter1);
      AO_store(&counter1, my_counter1 + 1);
      AO_store_release_write(&counter2, my_counter1 + 1);
      }
    else
      {
      AO_T my_counter2;
      AO_T my_counter1;
      my_counter2 = AO_load_acquire_read(&counter2);
      my_counter1 = AO_load(&counter1);
      if (my_counter1 < my_counter2)
        {
          fprintf(stderr, "Saw release store out of order: %lu < %lu\n",
                (unsigned long)my_counter1, (unsigned long)my_counter2);
          abort();
        }
      }

  return 0;
}

int acqrel_test(void)
{
  return counter1 == NITERS && counter2 == NITERS;
}

#endif /* AO_HAVE_store_release_write && AO_HAVE_load_acquire_read */

#if defined(AO_HAVE_test_and_set_acquire)

AO_TS_T lock = AO_TS_INITIALIZER;

unsigned long locked_counter;
volatile unsigned long junk = 13;

void * test_and_set_thr(void * id)
{
  unsigned long i;

  for (i = 0; i < NITERS/10; ++i)
    {
      while (AO_test_and_set_acquire(&lock) != AO_TS_CLEAR);
      ++locked_counter;
      if (locked_counter != 1)
        {
          fprintf(stderr, "Test and set failure 1, counter = %ld\n",
                  locked_counter);
          abort();
        }
      locked_counter *= 2;
      locked_counter -= 1;
      locked_counter *= 5;
      locked_counter -= 4;
      if (locked_counter != 1)
        {
          fprintf(stderr, "Test and set failure 2, counter = %ld\n",
                  locked_counter);
          abort();
        }
      --locked_counter;
      AO_CLEAR(&lock);
      /* Spend a bit of time outside the lock. */
        junk *= 17;
        junk *= 17;
    }
  return 0;
}

int test_and_set_test(void)
{
  return locked_counter == 0;
}

#endif /* defined(AO_HAVE_test_and_set_acquire) */

int main()
{
  test_atomic();
  test_atomic_acquire();
  test_atomic_release();
  test_atomic_read();
  test_atomic_write();
  test_atomic_full();
  test_atomic_release_write();
  test_atomic_acquire_read();
# if defined(AO_HAVE_fetch_and_add1) && defined(AO_HAVE_fetch_and_sub1)
    run_parallel(4, add1sub1_thr, add1sub1_test, "add1/sub1");
# endif
# if defined(AO_HAVE_store_release_write) && defined(AO_HAVE_load_acquire_read)
    run_parallel(3, acqrel_thr, acqrel_test,
             "store_release_write/load_acquire_read");
# endif
# if defined(AO_HAVE_test_and_set_acquire)
    run_parallel(5, test_and_set_thr, test_and_set_test,
             "test_and_set");
# endif
  return 0;
}

Generated by  Doxygen 1.6.0   Back to index