[runtime] Move unit tests to separate directory.
authorMark Probst <mark.probst@gmail.com>
Thu, 6 Mar 2014 03:34:36 +0000 (19:34 -0800)
committerMark Probst <mark.probst@gmail.com>
Mon, 10 Mar 2014 22:59:07 +0000 (15:59 -0700)
configure.in
mono/Makefile.am
mono/metadata/Makefile.am.in
mono/metadata/test-gc-memfuncs.c [deleted file]
mono/metadata/test-mono-linked-list-set.c [deleted file]
mono/metadata/test-sgen-qsort.c [deleted file]
mono/unit-tests/Makefile.am [new file with mode: 0644]
mono/unit-tests/test-gc-memfuncs.c [new file with mode: 0644]
mono/unit-tests/test-mono-linked-list-set.c [new file with mode: 0644]
mono/unit-tests/test-sgen-qsort.c [new file with mode: 0644]

index f6fb3b31fbad1448495e42545ff24e04b77a7b49..630cd7e2ce90ce1968790e0014c9b468af11583d 100644 (file)
@@ -3530,6 +3530,7 @@ mono/tests/cas/inheritance/Makefile
 mono/tests/cas/linkdemand/Makefile
 mono/tests/cas/threads/Makefile
 mono/tests/gc-descriptors/Makefile
+mono/unit-tests/Makefile
 mono/benchmark/Makefile
 mono/monograph/Makefile
 mono/io-layer/Makefile
index d74089a9c17441209c9a97188283a6596eb81dbb..495f16922edfe722c816e02232eea5a225f35191 100644 (file)
@@ -26,7 +26,7 @@ monotouch-do-clean:
          (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$target); \
     done;
 else
-SUBDIRS = arch utils io-layer cil metadata $(interpreter_dir) mini dis monograph tests benchmark profiler
+SUBDIRS = arch utils io-layer cil metadata $(interpreter_dir) mini dis monograph tests unit-tests benchmark profiler
 endif
 endif
-DIST_SUBDIRS = arch utils io-layer cil metadata interpreter mini dis monograph tests benchmark profiler
+DIST_SUBDIRS = arch utils io-layer cil metadata interpreter mini dis monograph tests unit-tests benchmark profiler
index 70f9028c43bcb8a8b07bbf14bb6421ab274f55a2..da301bfd33818045767c5f65ef6960c82e94e56d 100644 (file)
@@ -333,40 +333,3 @@ else
 Makefile.am: Makefile.am.in
        cp $< $@
 endif
-
-if !CROSS_COMPILING
-if !HOST_WIN32
-if SUPPORT_BOEHM
-
-test_sgen_qsort_SOURCES = test-sgen-qsort.c
-test_sgen_qsort_CFLAGS = $(SGEN_DEFINES)
-test_sgen_qsort_LDADD = libmonoruntimesgen.la ../io-layer/libwapi.la ../utils/libmonoutils.la \
-       $(LIBGC_LIBS) $(GLIB_LIBS) -lm $(LIBICONV)
-if PLATFORM_DARWIN
-test_sgen_qsort_LDFLAGS=-framework CoreFoundation -framework Foundation
-endif
-
-test_gc_memfuncs_SOURCES = test-gc-memfuncs.c
-test_gc_memfuncs_CFLAGS = $(SGEN_DEFINES)
-test_gc_memfuncs_LDADD = libmonoruntimesgen.la ../io-layer/libwapi.la ../utils/libmonoutils.la \
-       $(LIBGC_LIBS) $(GLIB_LIBS) -lm $(LIBICONV)
-if PLATFORM_DARWIN
-test_gc_memfuncs_LDFLAGS=-framework CoreFoundation -framework Foundation
-endif
-
-test_mono_linked_list_set_SOURCES = test-mono-linked-list-set.c
-test_mono_linked_list_set_CFLAGS = $(AM_CFLAGS)
-test_mono_linked_list_set_LDADD = libmonoruntime.la ../io-layer/libwapi.la ../utils/libmonoutils.la \
-       $(LIBGC_LIBS) $(GLIB_LIBS) -lm $(LIBICONV) $(PEDUMP_DTRACE_OBJECT)
-
-if PLATFORM_DARWIN
-test_mono_linked_list_set_LDFLAGS=-framework CoreFoundation -framework Foundation
-endif
-
-noinst_PROGRAMS = test-sgen-qsort test-gc-memfuncs test-mono-linked-list-set
-
-TESTS = test-sgen-qsort test-gc-memfuncs test-mono-linked-list-set
-
-endif SUPPORT_BOEHM
-endif !HOST_WIN32
-endif !CROSS_COMPILING
diff --git a/mono/metadata/test-gc-memfuncs.c b/mono/metadata/test-gc-memfuncs.c
deleted file mode 100644 (file)
index a8ccf88..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * test-sgen-qsort.c: Unit test for our own bzero/memmove.
- *
- * Copyright (C) 2013 Xamarin Inc
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "config.h"
-
-#include "metadata/gc-internal.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <assert.h>
-
-#define POOL_SIZE      2048
-#define START_OFFSET   128
-
-#define BZERO_OFFSETS  64
-#define BZERO_SIZES    256
-
-#define MEMMOVE_SRC_OFFSETS            32
-#define MEMMOVE_DEST_OFFSETS           32
-#define MEMMOVE_SIZES                  256
-#define MEMMOVE_NONOVERLAP_START       1024
-
-int
-main (void)
-{
-       unsigned char *random_mem = malloc (POOL_SIZE);
-       unsigned char *reference = malloc (POOL_SIZE);
-       unsigned char *playground = malloc (POOL_SIZE);
-       long *long_random_mem;
-       int i, offset, size, src_offset, dest_offset;
-
-       srandom (time (NULL));
-
-       /* init random memory */
-       long_random_mem = (long*)random_mem;
-       for (i = 0; i < POOL_SIZE / sizeof (long); ++i)
-               long_random_mem [i] = random ();
-
-       /* test bzero */
-       for (offset = 0; offset <= BZERO_OFFSETS; ++offset) {
-               for (size = 0; size <= BZERO_SIZES; ++size) {
-                       memcpy (reference, random_mem, POOL_SIZE);
-                       memcpy (playground, random_mem, POOL_SIZE);
-
-                       bzero (reference + START_OFFSET + offset, size);
-                       mono_gc_bzero_atomic (playground + START_OFFSET + offset, size);
-
-                       assert (!memcmp (reference, playground, POOL_SIZE));
-               }
-       }
-
-       /* test memmove */
-       for (src_offset = -MEMMOVE_SRC_OFFSETS; src_offset <= MEMMOVE_SRC_OFFSETS; ++src_offset) {
-               for (dest_offset = -MEMMOVE_DEST_OFFSETS; dest_offset <= MEMMOVE_DEST_OFFSETS; ++dest_offset) {
-                       for (size = 0; size <= MEMMOVE_SIZES; ++size) {
-                               /* overlapping */
-                               memcpy (reference, random_mem, POOL_SIZE);
-                               memcpy (playground, random_mem, POOL_SIZE);
-
-                               memmove (reference + START_OFFSET + dest_offset, reference + START_OFFSET + src_offset, size);
-                               mono_gc_memmove_atomic (playground + START_OFFSET + dest_offset, playground + START_OFFSET + src_offset, size);
-
-                               assert (!memcmp (reference, playground, POOL_SIZE));
-
-                               /* non-overlapping with dest < src */
-                               memcpy (reference, random_mem, POOL_SIZE);
-                               memcpy (playground, random_mem, POOL_SIZE);
-
-                               memmove (reference + START_OFFSET + dest_offset, reference + MEMMOVE_NONOVERLAP_START + src_offset, size);
-                               mono_gc_memmove_atomic (playground + START_OFFSET + dest_offset, playground + MEMMOVE_NONOVERLAP_START + src_offset, size);
-
-                               assert (!memcmp (reference, playground, POOL_SIZE));
-
-                               /* non-overlapping with dest > src */
-                               memcpy (reference, random_mem, POOL_SIZE);
-                               memcpy (playground, random_mem, POOL_SIZE);
-
-                               memmove (reference + MEMMOVE_NONOVERLAP_START + dest_offset, reference + START_OFFSET + src_offset, size);
-                               mono_gc_memmove_atomic (playground + MEMMOVE_NONOVERLAP_START + dest_offset, playground + START_OFFSET + src_offset, size);
-
-                               assert (!memcmp (reference, playground, POOL_SIZE));
-                       }
-               }
-       }
-
-       return 0;
-}
diff --git a/mono/metadata/test-mono-linked-list-set.c b/mono/metadata/test-mono-linked-list-set.c
deleted file mode 100644 (file)
index 299a66c..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-#include <assert.h>
-#include <pthread.h>
-
-#include <config.h>
-#include <mono/metadata/metadata.h>
-#include <mono/utils/mono-threads.h>
-#include <mono/utils/hazard-pointer.h>
-#include <mono/utils/mono-linked-list-set.h>
-#include <mono/utils/atomic.h>
-
-static MonoLinkedListSet lls;
-
-enum {
-       STATE_OUT,
-       STATE_BUSY,
-       STATE_IN
-};
-
-#define N 23
-#define NUM_ITERS 1000000
-#define NUM_THREADS 8
-
-typedef struct {
-       MonoLinkedListSetNode node;
-       int state;
-} node_t;
-
-typedef struct {
-       int skip;
-       int num_adds;
-       int num_removes;
-       pthread_t thread;
-} thread_data_t;
-
-static node_t nodes [N];
-
-static inline void
-mono_hazard_pointer_clear_all (MonoThreadHazardPointers *hp, int retain)
-{
-       if (retain != 0)
-               mono_hazard_pointer_clear (hp, 0);
-       if (retain != 1)
-               mono_hazard_pointer_clear (hp, 1);
-       if (retain != 2)
-               mono_hazard_pointer_clear (hp, 2);
-}
-
-static void
-free_node (void *n)
-{
-       node_t *node = n;
-       assert (node->state == STATE_BUSY);
-       node->state = STATE_OUT;
-}
-
-static void*
-worker (void *arg)
-{
-       thread_data_t *thread_data = arg;
-       MonoThreadHazardPointers *hp;
-       int skip = thread_data->skip;
-       int i, j;
-       gboolean result;
-
-       mono_thread_info_register_small_id ();
-
-       hp = mono_hazard_pointer_get ();
-
-       i = 0;
-       for (j = 0; j < NUM_ITERS; ++j) {
-               switch (nodes [i].state) {
-               case STATE_BUSY:
-                       mono_thread_hazardous_try_free_some ();
-                       break;
-               case STATE_OUT:
-                       if (InterlockedCompareExchange (&nodes [i].state, STATE_BUSY, STATE_OUT) == STATE_OUT) {
-                               result = mono_lls_find (&lls, hp, i);
-                               assert (!result);
-                               mono_hazard_pointer_clear_all (hp, -1);
-
-                               result = mono_lls_insert (&lls, hp, &nodes [i].node);
-                               mono_hazard_pointer_clear_all (hp, -1);
-
-                               assert (nodes [i].state == STATE_BUSY);
-                               nodes [i].state = STATE_IN;
-
-                               ++thread_data->num_adds;
-                       }
-                       break;
-               case STATE_IN:
-                       if (InterlockedCompareExchange (&nodes [i].state, STATE_BUSY, STATE_IN) == STATE_IN) {
-                               result = mono_lls_find (&lls, hp, i);
-                               assert (result);
-                               assert (mono_hazard_pointer_get_val (hp, 1) == &nodes [i].node);
-                               mono_hazard_pointer_clear_all (hp, -1);
-
-                               result = mono_lls_remove (&lls, hp, &nodes [i].node);
-                               mono_hazard_pointer_clear_all (hp, -1);
-
-                               ++thread_data->num_removes;
-                       }
-                       break;
-               default:
-                       assert (FALSE);
-               }
-
-               i += skip;
-               if (i >= N)
-                       i -= N;
-       }
-
-       return NULL;
-}
-
-int
-main (int argc, char *argv [])
-{
-       int primes [] = { 1, 2, 3, 5, 7, 11, 13, 17 };
-       MonoThreadInfoCallbacks thread_callbacks;
-       thread_data_t thread_data [NUM_THREADS];
-       int i;
-
-       memset (&thread_callbacks, 0, sizeof (thread_callbacks));
-
-       mono_metadata_init ();
-
-       mono_threads_init (&thread_callbacks, 0);
-
-       mono_thread_smr_init ();
-       mono_lls_init (&lls, free_node);
-
-       for (i = 0; i < N; ++i) {
-               nodes [i].node.key = i;
-               nodes [i].state = STATE_OUT;
-       }
-
-       for (i = 0; i < NUM_THREADS; ++i) {
-               int result;
-
-               thread_data [i].num_adds = thread_data [i].num_removes = 0;
-               thread_data [i].skip = primes [i];
-               result = pthread_create (&thread_data [i].thread, NULL, worker, &thread_data [i]);
-               assert (!result);
-       }
-
-       for (i = 0; i < NUM_THREADS; ++i) {
-               int result = pthread_join (thread_data [i].thread, NULL);
-               assert (!result);
-               printf ("thread %d  adds %d  removes %d\n", i, thread_data [i].num_adds, thread_data [i].num_removes);
-       }
-
-       return 0;
-}
diff --git a/mono/metadata/test-sgen-qsort.c b/mono/metadata/test-sgen-qsort.c
deleted file mode 100644 (file)
index 3c98fe9..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * test-sgen-qsort.c: Unit test for quicksort.
- *
- * Copyright (C) 2013 Xamarin Inc
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "config.h"
-
-#include "metadata/sgen-gc.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <assert.h>
-
-static int
-compare_ints (const void *pa, const void *pb)
-{
-       int a = *(const int*)pa;
-       int b = *(const int*)pb;
-       if (a < b)
-               return -1;
-       if (a == b)
-               return 0;
-       return 1;
-}
-
-typedef struct {
-       int key;
-       int val;
-} teststruct_t;
-
-static int
-compare_teststructs (const void *pa, const void *pb)
-{
-       int a = ((const teststruct_t*)pa)->key;
-       int b = ((const teststruct_t*)pb)->key;
-       if (a < b)
-               return -1;
-       if (a == b)
-               return 0;
-       return 1;
-}
-
-static void
-compare_sorts (void *base, size_t nel, size_t width, int (*compar) (const void*, const void*))
-{
-       size_t len = nel * width;
-       void *b1 = malloc (len);
-       void *b2 = malloc (len);
-
-       memcpy (b1, base, len);
-       memcpy (b2, base, len);
-
-       qsort (b1, nel, width, compar);
-       sgen_qsort (b2, nel, width, compar);
-
-       assert (!memcmp (b1, b2, len));
-
-       free (b1);
-       free (b2);
-}
-
-int
-main (void)
-{
-       int i;
-       for (i = 1; i < 4000; ++i) {
-               int a [i];
-               int j;
-
-               for (j = 0; j < i; ++j)
-                       a [j] = i - j - 1;
-               compare_sorts (a, i, sizeof (int), compare_ints);
-       }
-
-       srandom (time (NULL));
-       for (i = 0; i < 2000; ++i) {
-               teststruct_t a [200];
-               int j;
-               for (j = 0; j < 200; ++j) {
-                       a [j].key = random ();
-                       a [j].val = random ();
-               }
-
-               compare_sorts (a, 200, sizeof (teststruct_t), compare_teststructs);
-       }
-
-       return 0;
-}
diff --git a/mono/unit-tests/Makefile.am b/mono/unit-tests/Makefile.am
new file mode 100644 (file)
index 0000000..d2be67a
--- /dev/null
@@ -0,0 +1,38 @@
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/mono $(LIBGC_CPPFLAGS) $(GLIB_CFLAGS) -DMONO_BINDIR=\"$(bindir)/\" -DMONO_ASSEMBLIES=\"$(assembliesdir)\" -DMONO_CFG_DIR=\"$(confdir)\"
+
+if !CROSS_COMPILING
+if !HOST_WIN32
+if SUPPORT_BOEHM
+
+test_sgen_qsort_SOURCES = test-sgen-qsort.c
+test_sgen_qsort_CFLAGS = $(SGEN_DEFINES)
+test_sgen_qsort_LDADD = ../metadata/libmonoruntimesgen.la ../io-layer/libwapi.la ../utils/libmonoutils.la \
+       $(LIBGC_LIBS) $(GLIB_LIBS) -lm $(LIBICONV)
+if PLATFORM_DARWIN
+test_sgen_qsort_LDFLAGS=-framework CoreFoundation -framework Foundation
+endif
+
+test_gc_memfuncs_SOURCES = test-gc-memfuncs.c
+test_gc_memfuncs_CFLAGS = $(SGEN_DEFINES)
+test_gc_memfuncs_LDADD = ../metadata/libmonoruntimesgen.la ../io-layer/libwapi.la ../utils/libmonoutils.la \
+       $(LIBGC_LIBS) $(GLIB_LIBS) -lm $(LIBICONV)
+if PLATFORM_DARWIN
+test_gc_memfuncs_LDFLAGS=-framework CoreFoundation -framework Foundation
+endif
+
+test_mono_linked_list_set_SOURCES = test-mono-linked-list-set.c
+test_mono_linked_list_set_CFLAGS = $(AM_CFLAGS)
+test_mono_linked_list_set_LDADD = ../metadata/libmonoruntime.la ../io-layer/libwapi.la ../utils/libmonoutils.la \
+       $(LIBGC_LIBS) $(GLIB_LIBS) -lm $(LIBICONV) $(PEDUMP_DTRACE_OBJECT)
+
+if PLATFORM_DARWIN
+test_mono_linked_list_set_LDFLAGS=-framework CoreFoundation -framework Foundation
+endif
+
+noinst_PROGRAMS = test-sgen-qsort test-gc-memfuncs test-mono-linked-list-set
+
+TESTS = test-sgen-qsort test-gc-memfuncs test-mono-linked-list-set
+
+endif SUPPORT_BOEHM
+endif !HOST_WIN32
+endif !CROSS_COMPILING
diff --git a/mono/unit-tests/test-gc-memfuncs.c b/mono/unit-tests/test-gc-memfuncs.c
new file mode 100644 (file)
index 0000000..a8ccf88
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * test-sgen-qsort.c: Unit test for our own bzero/memmove.
+ *
+ * Copyright (C) 2013 Xamarin Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License 2.0 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License 2.0 along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+
+#include "metadata/gc-internal.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+
+#define POOL_SIZE      2048
+#define START_OFFSET   128
+
+#define BZERO_OFFSETS  64
+#define BZERO_SIZES    256
+
+#define MEMMOVE_SRC_OFFSETS            32
+#define MEMMOVE_DEST_OFFSETS           32
+#define MEMMOVE_SIZES                  256
+#define MEMMOVE_NONOVERLAP_START       1024
+
+int
+main (void)
+{
+       unsigned char *random_mem = malloc (POOL_SIZE);
+       unsigned char *reference = malloc (POOL_SIZE);
+       unsigned char *playground = malloc (POOL_SIZE);
+       long *long_random_mem;
+       int i, offset, size, src_offset, dest_offset;
+
+       srandom (time (NULL));
+
+       /* init random memory */
+       long_random_mem = (long*)random_mem;
+       for (i = 0; i < POOL_SIZE / sizeof (long); ++i)
+               long_random_mem [i] = random ();
+
+       /* test bzero */
+       for (offset = 0; offset <= BZERO_OFFSETS; ++offset) {
+               for (size = 0; size <= BZERO_SIZES; ++size) {
+                       memcpy (reference, random_mem, POOL_SIZE);
+                       memcpy (playground, random_mem, POOL_SIZE);
+
+                       bzero (reference + START_OFFSET + offset, size);
+                       mono_gc_bzero_atomic (playground + START_OFFSET + offset, size);
+
+                       assert (!memcmp (reference, playground, POOL_SIZE));
+               }
+       }
+
+       /* test memmove */
+       for (src_offset = -MEMMOVE_SRC_OFFSETS; src_offset <= MEMMOVE_SRC_OFFSETS; ++src_offset) {
+               for (dest_offset = -MEMMOVE_DEST_OFFSETS; dest_offset <= MEMMOVE_DEST_OFFSETS; ++dest_offset) {
+                       for (size = 0; size <= MEMMOVE_SIZES; ++size) {
+                               /* overlapping */
+                               memcpy (reference, random_mem, POOL_SIZE);
+                               memcpy (playground, random_mem, POOL_SIZE);
+
+                               memmove (reference + START_OFFSET + dest_offset, reference + START_OFFSET + src_offset, size);
+                               mono_gc_memmove_atomic (playground + START_OFFSET + dest_offset, playground + START_OFFSET + src_offset, size);
+
+                               assert (!memcmp (reference, playground, POOL_SIZE));
+
+                               /* non-overlapping with dest < src */
+                               memcpy (reference, random_mem, POOL_SIZE);
+                               memcpy (playground, random_mem, POOL_SIZE);
+
+                               memmove (reference + START_OFFSET + dest_offset, reference + MEMMOVE_NONOVERLAP_START + src_offset, size);
+                               mono_gc_memmove_atomic (playground + START_OFFSET + dest_offset, playground + MEMMOVE_NONOVERLAP_START + src_offset, size);
+
+                               assert (!memcmp (reference, playground, POOL_SIZE));
+
+                               /* non-overlapping with dest > src */
+                               memcpy (reference, random_mem, POOL_SIZE);
+                               memcpy (playground, random_mem, POOL_SIZE);
+
+                               memmove (reference + MEMMOVE_NONOVERLAP_START + dest_offset, reference + START_OFFSET + src_offset, size);
+                               mono_gc_memmove_atomic (playground + MEMMOVE_NONOVERLAP_START + dest_offset, playground + START_OFFSET + src_offset, size);
+
+                               assert (!memcmp (reference, playground, POOL_SIZE));
+                       }
+               }
+       }
+
+       return 0;
+}
diff --git a/mono/unit-tests/test-mono-linked-list-set.c b/mono/unit-tests/test-mono-linked-list-set.c
new file mode 100644 (file)
index 0000000..299a66c
--- /dev/null
@@ -0,0 +1,153 @@
+#include <assert.h>
+#include <pthread.h>
+
+#include <config.h>
+#include <mono/metadata/metadata.h>
+#include <mono/utils/mono-threads.h>
+#include <mono/utils/hazard-pointer.h>
+#include <mono/utils/mono-linked-list-set.h>
+#include <mono/utils/atomic.h>
+
+static MonoLinkedListSet lls;
+
+enum {
+       STATE_OUT,
+       STATE_BUSY,
+       STATE_IN
+};
+
+#define N 23
+#define NUM_ITERS 1000000
+#define NUM_THREADS 8
+
+typedef struct {
+       MonoLinkedListSetNode node;
+       int state;
+} node_t;
+
+typedef struct {
+       int skip;
+       int num_adds;
+       int num_removes;
+       pthread_t thread;
+} thread_data_t;
+
+static node_t nodes [N];
+
+static inline void
+mono_hazard_pointer_clear_all (MonoThreadHazardPointers *hp, int retain)
+{
+       if (retain != 0)
+               mono_hazard_pointer_clear (hp, 0);
+       if (retain != 1)
+               mono_hazard_pointer_clear (hp, 1);
+       if (retain != 2)
+               mono_hazard_pointer_clear (hp, 2);
+}
+
+static void
+free_node (void *n)
+{
+       node_t *node = n;
+       assert (node->state == STATE_BUSY);
+       node->state = STATE_OUT;
+}
+
+static void*
+worker (void *arg)
+{
+       thread_data_t *thread_data = arg;
+       MonoThreadHazardPointers *hp;
+       int skip = thread_data->skip;
+       int i, j;
+       gboolean result;
+
+       mono_thread_info_register_small_id ();
+
+       hp = mono_hazard_pointer_get ();
+
+       i = 0;
+       for (j = 0; j < NUM_ITERS; ++j) {
+               switch (nodes [i].state) {
+               case STATE_BUSY:
+                       mono_thread_hazardous_try_free_some ();
+                       break;
+               case STATE_OUT:
+                       if (InterlockedCompareExchange (&nodes [i].state, STATE_BUSY, STATE_OUT) == STATE_OUT) {
+                               result = mono_lls_find (&lls, hp, i);
+                               assert (!result);
+                               mono_hazard_pointer_clear_all (hp, -1);
+
+                               result = mono_lls_insert (&lls, hp, &nodes [i].node);
+                               mono_hazard_pointer_clear_all (hp, -1);
+
+                               assert (nodes [i].state == STATE_BUSY);
+                               nodes [i].state = STATE_IN;
+
+                               ++thread_data->num_adds;
+                       }
+                       break;
+               case STATE_IN:
+                       if (InterlockedCompareExchange (&nodes [i].state, STATE_BUSY, STATE_IN) == STATE_IN) {
+                               result = mono_lls_find (&lls, hp, i);
+                               assert (result);
+                               assert (mono_hazard_pointer_get_val (hp, 1) == &nodes [i].node);
+                               mono_hazard_pointer_clear_all (hp, -1);
+
+                               result = mono_lls_remove (&lls, hp, &nodes [i].node);
+                               mono_hazard_pointer_clear_all (hp, -1);
+
+                               ++thread_data->num_removes;
+                       }
+                       break;
+               default:
+                       assert (FALSE);
+               }
+
+               i += skip;
+               if (i >= N)
+                       i -= N;
+       }
+
+       return NULL;
+}
+
+int
+main (int argc, char *argv [])
+{
+       int primes [] = { 1, 2, 3, 5, 7, 11, 13, 17 };
+       MonoThreadInfoCallbacks thread_callbacks;
+       thread_data_t thread_data [NUM_THREADS];
+       int i;
+
+       memset (&thread_callbacks, 0, sizeof (thread_callbacks));
+
+       mono_metadata_init ();
+
+       mono_threads_init (&thread_callbacks, 0);
+
+       mono_thread_smr_init ();
+       mono_lls_init (&lls, free_node);
+
+       for (i = 0; i < N; ++i) {
+               nodes [i].node.key = i;
+               nodes [i].state = STATE_OUT;
+       }
+
+       for (i = 0; i < NUM_THREADS; ++i) {
+               int result;
+
+               thread_data [i].num_adds = thread_data [i].num_removes = 0;
+               thread_data [i].skip = primes [i];
+               result = pthread_create (&thread_data [i].thread, NULL, worker, &thread_data [i]);
+               assert (!result);
+       }
+
+       for (i = 0; i < NUM_THREADS; ++i) {
+               int result = pthread_join (thread_data [i].thread, NULL);
+               assert (!result);
+               printf ("thread %d  adds %d  removes %d\n", i, thread_data [i].num_adds, thread_data [i].num_removes);
+       }
+
+       return 0;
+}
diff --git a/mono/unit-tests/test-sgen-qsort.c b/mono/unit-tests/test-sgen-qsort.c
new file mode 100644 (file)
index 0000000..3fe33bb
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * test-sgen-qsort.c: Unit test for quicksort.
+ *
+ * Copyright (C) 2013 Xamarin Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License 2.0 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License 2.0 along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+
+#include <metadata/sgen-gc.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+
+static int
+compare_ints (const void *pa, const void *pb)
+{
+       int a = *(const int*)pa;
+       int b = *(const int*)pb;
+       if (a < b)
+               return -1;
+       if (a == b)
+               return 0;
+       return 1;
+}
+
+typedef struct {
+       int key;
+       int val;
+} teststruct_t;
+
+static int
+compare_teststructs (const void *pa, const void *pb)
+{
+       int a = ((const teststruct_t*)pa)->key;
+       int b = ((const teststruct_t*)pb)->key;
+       if (a < b)
+               return -1;
+       if (a == b)
+               return 0;
+       return 1;
+}
+
+static void
+compare_sorts (void *base, size_t nel, size_t width, int (*compar) (const void*, const void*))
+{
+       size_t len = nel * width;
+       void *b1 = malloc (len);
+       void *b2 = malloc (len);
+
+       memcpy (b1, base, len);
+       memcpy (b2, base, len);
+
+       qsort (b1, nel, width, compar);
+       sgen_qsort (b2, nel, width, compar);
+
+       assert (!memcmp (b1, b2, len));
+
+       free (b1);
+       free (b2);
+}
+
+int
+main (void)
+{
+       int i;
+       for (i = 1; i < 4000; ++i) {
+               int a [i];
+               int j;
+
+               for (j = 0; j < i; ++j)
+                       a [j] = i - j - 1;
+               compare_sorts (a, i, sizeof (int), compare_ints);
+       }
+
+       srandom (time (NULL));
+       for (i = 0; i < 2000; ++i) {
+               teststruct_t a [200];
+               int j;
+               for (j = 0; j < 200; ++j) {
+                       a [j].key = random ();
+                       a [j].val = random ();
+               }
+
+               compare_sorts (a, 200, sizeof (teststruct_t), compare_teststructs);
+       }
+
+       return 0;
+}