Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

47
external/bdwgc/tests/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,47 @@
#
# Copyright (c) 1994 by Xerox Corporation. All rights reserved.
# Copyright (c) 1996 by Silicon Graphics. All rights reserved.
# Copyright (c) 1998 by Fergus Henderson. All rights reserved.
# Copyright (c) 2000-2010 by Hewlett-Packard Company. All rights reserved.
##
# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
##
# Permission is hereby granted to use or copy this program
# for any purpose, provided the above notices are retained on all copies.
# Permission to modify the code and to distribute modified code is granted,
# provided the above notices are retained, and a notice that the code was
# modified is included with the above copyright notice.
##
ADD_DEFINITIONS(-DGC_NOT_DLL)
# Compile some tests as C++ to test extern "C" in header files.
SET_SOURCE_FILES_PROPERTIES(
leak_test.c
test.c
PROPERTIES LANGUAGE CXX)
ADD_EXECUTABLE(gctest WIN32 test.c)
TARGET_LINK_LIBRARIES(gctest gc-lib)
ADD_TEST(NAME gctest COMMAND gctest)
ADD_EXECUTABLE(hugetest huge_test.c)
TARGET_LINK_LIBRARIES(hugetest gc-lib)
ADD_TEST(NAME hugetest COMMAND hugetest)
ADD_EXECUTABLE(leaktest leak_test.c)
TARGET_LINK_LIBRARIES(leaktest gc-lib)
ADD_TEST(NAME leaktest COMMAND leaktest)
ADD_EXECUTABLE(middletest middle.c)
TARGET_LINK_LIBRARIES(middletest gc-lib)
ADD_TEST(NAME middletest COMMAND middletest)
ADD_EXECUTABLE(realloc_test realloc_test.c)
TARGET_LINK_LIBRARIES(realloc_test gc-lib)
ADD_TEST(NAME realloc_test COMMAND realloc_test)
ADD_EXECUTABLE(smashtest smash_test.c)
TARGET_LINK_LIBRARIES(smashtest gc-lib)
ADD_TEST(NAME smashtest COMMAND smashtest)

158
external/bdwgc/tests/disclaim_bench.c vendored Normal file
View File

@@ -0,0 +1,158 @@
/*
* Copyright (c) 2011 by Hewlett-Packard Company. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
*
* Permission is hereby granted to use or copy this program
* for any purpose, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gc_disclaim.h"
/* Include gc_priv.h is done after including GC public headers, so */
/* that GC_BUILD has no effect on the public prototypes. */
#include "private/gc_priv.h" /* for CLOCK_TYPE, COVERT_DATAFLOW, GC_random */
#ifdef LINT2
# undef rand
# define rand() (int)GC_random()
#endif
#define my_assert(e) \
if (!(e)) { \
fprintf(stderr, "Assertion failure, line %d: " #e "\n", __LINE__); \
exit(-1); \
}
static int free_count = 0;
struct testobj_s {
struct testobj_s *keep_link;
int i;
};
typedef struct testobj_s *testobj_t;
void GC_CALLBACK testobj_finalize(void *obj, void *carg)
{
++*(int *)carg;
my_assert(((testobj_t)obj)->i == 109);
((testobj_t)obj)->i = 110;
}
static const struct GC_finalizer_closure fclos = {
testobj_finalize,
&free_count
};
testobj_t testobj_new(int model)
{
testobj_t obj;
switch (model) {
case 0:
obj = GC_NEW(struct testobj_s);
if (obj != NULL)
GC_REGISTER_FINALIZER_NO_ORDER(obj, testobj_finalize,
&free_count, NULL, NULL);
break;
case 1:
obj = (testobj_t)GC_finalized_malloc(sizeof(struct testobj_s),
&fclos);
break;
case 2:
obj = GC_NEW(struct testobj_s);
break;
default:
exit(-1);
}
if (obj == NULL) {
fprintf(stderr, "Out of memory!\n");
exit(3);
}
my_assert(obj->i == 0 && obj->keep_link == NULL);
obj->i = 109;
return obj;
}
#define ALLOC_CNT (4*1024*1024)
#define KEEP_CNT (32*1024)
static char const *model_str[3] = {
"regular finalization",
"finalize on reclaim",
"no finalization"
};
int main(int argc, char **argv)
{
int i;
int model, model_min, model_max;
testobj_t *keep_arr;
GC_INIT();
GC_init_finalized_malloc();
if (argc == 2 && strcmp(argv[1], "--help") == 0) {
fprintf(stderr,
"Usage: %s [FINALIZATION_MODEL]\n"
"\t0 -- original finalization\n"
"\t1 -- finalization on reclaim\n"
"\t2 -- no finalization\n", argv[0]);
return 1;
}
if (argc == 2) {
model_min = model_max = (int)COVERT_DATAFLOW(atoi(argv[1]));
if (model_min < 0 || model_max > 2)
exit(2);
}
else {
model_min = 0;
model_max = 2;
}
keep_arr = (testobj_t *)GC_MALLOC(sizeof(void *) * KEEP_CNT);
if (NULL == keep_arr) {
fprintf(stderr, "Out of memory!\n");
exit(3);
}
printf("\t\t\tfin. ratio time/s time/fin.\n");
for (model = model_min; model <= model_max; ++model) {
double t = 0.0;
# ifndef NO_CLOCK
CLOCK_TYPE tI, tF;
GET_TIME(tI);
# endif
free_count = 0;
for (i = 0; i < ALLOC_CNT; ++i) {
int k = rand() % KEEP_CNT;
keep_arr[k] = testobj_new(model);
}
GC_gcollect();
# ifndef NO_CLOCK
GET_TIME(tF);
t = MS_TIME_DIFF(tF, tI)*1e-3;
# endif
if (model < 2 && free_count > 0)
printf("%20s: %12.4f %12g %12g\n", model_str[model],
free_count/(double)ALLOC_CNT, t, t/free_count);
else
printf("%20s: %12.4f %12g %12s\n",
model_str[model], 0.0, t, "N/A");
}
return 0;
}

258
external/bdwgc/tests/disclaim_test.c vendored Normal file
View File

@@ -0,0 +1,258 @@
/*
* Copyright (c) 2011 by Hewlett-Packard Company. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
*
* Permission is hereby granted to use or copy this program
* for any purpose, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*
*/
/* Test that objects reachable from an object allocated with */
/* GC_malloc_with_finalizer is not reclaimable before the finalizer */
/* is called. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_CONFIG_H
/* For GC_[P]THREADS */
# include "config.h"
#endif
#undef GC_NO_THREAD_REDIRECTS
#include "gc_disclaim.h"
#ifdef LINT2
/* Avoid include gc_priv.h. */
# ifndef GC_API_PRIV
# define GC_API_PRIV GC_API
# endif
# ifdef __cplusplus
extern "C" {
# endif
GC_API_PRIV long GC_random(void);
# ifdef __cplusplus
} /* extern "C" */
# endif
# undef rand
# define rand() (int)GC_random()
#endif /* LINT2 */
#define my_assert(e) \
if (!(e)) { \
fflush(stdout); \
fprintf(stderr, "Assertion failure, line %d: " #e "\n", __LINE__); \
exit(-1); \
}
int memeq(void *s, int c, size_t len)
{
while (len--) {
if (*(char *)s != c)
return 0;
s = (char *)s + 1;
}
return 1;
}
void GC_CALLBACK misc_sizes_dct(void *obj, void *cd)
{
unsigned log_size = *(unsigned char *)obj;
size_t size;
my_assert(log_size < sizeof(size_t) * 8);
my_assert(cd == NULL);
size = (size_t)1 << log_size;
my_assert(memeq((char *)obj + 1, 0x56, size - 1));
}
void test_misc_sizes(void)
{
static const struct GC_finalizer_closure fc = { misc_sizes_dct, NULL };
int i;
for (i = 1; i <= 20; ++i) { /* Up to 1 MiB. */
void *p = GC_finalized_malloc((size_t)1 << i, &fc);
if (p == NULL) {
fprintf(stderr, "Out of memory!\n");
exit(3);
}
my_assert(memeq(p, 0, (size_t)1 << i));
memset(p, 0x56, (size_t)1 << i);
*(unsigned char *)p = i;
}
}
typedef struct pair_s *pair_t;
struct pair_s {
char magic[16];
int checksum;
pair_t car;
pair_t cdr;
};
static const char * const pair_magic = "PAIR_MAGIC_BYTES";
int is_pair(pair_t p)
{
return memcmp(p->magic, pair_magic, sizeof(p->magic)) == 0;
}
void GC_CALLBACK pair_dct(void *obj, void *cd)
{
pair_t p = (pair_t)obj;
int checksum;
/* Check that obj and its car and cdr are not trashed. */
# ifdef DEBUG_DISCLAIM_DESTRUCT
printf("Destruct %p = (%p, %p)\n",
(void *)p, (void *)p->car, (void *)p->cdr);
# endif
my_assert(GC_base(obj));
my_assert(is_pair(p));
my_assert(!p->car || is_pair(p->car));
my_assert(!p->cdr || is_pair(p->cdr));
checksum = 782;
if (p->car) checksum += p->car->checksum;
if (p->cdr) checksum += p->cdr->checksum;
my_assert(p->checksum == checksum);
/* Invalidate it. */
memset(p->magic, '*', sizeof(p->magic));
p->checksum = 0;
p->car = (pair_t)cd;
p->cdr = NULL;
GC_end_stubborn_change(p);
}
pair_t
pair_new(pair_t car, pair_t cdr)
{
pair_t p;
static const struct GC_finalizer_closure fc = { pair_dct, NULL };
p = (pair_t)GC_finalized_malloc(sizeof(struct pair_s), &fc);
if (p == NULL) {
fprintf(stderr, "Out of memory!\n");
exit(3);
}
my_assert(!is_pair(p));
my_assert(memeq(p, 0, sizeof(struct pair_s)));
memcpy(p->magic, pair_magic, sizeof(p->magic));
p->checksum = 782 + (car? car->checksum : 0) + (cdr? cdr->checksum : 0);
p->car = car;
p->cdr = cdr;
GC_end_stubborn_change(p);
# ifdef DEBUG_DISCLAIM_DESTRUCT
printf("Construct %p = (%p, %p)\n",
(void *)p, (void *)p->car, (void *)p->cdr);
# endif
return p;
}
void
pair_check_rec(pair_t p)
{
while (p) {
int checksum = 782;
if (p->car) checksum += p->car->checksum;
if (p->cdr) checksum += p->cdr->checksum;
my_assert(p->checksum == checksum);
if (rand() % 2)
p = p->car;
else
p = p->cdr;
}
}
#ifdef GC_PTHREADS
# ifndef NTHREADS
# define NTHREADS 6
# endif
# include <pthread.h>
#else
# undef NTHREADS
# define NTHREADS 1
#endif
#define POP_SIZE 1000
#if NTHREADS > 1
# define MUTATE_CNT (2000000/NTHREADS)
#else
# define MUTATE_CNT 10000000
#endif
#define GROW_LIMIT (MUTATE_CNT/10)
void *test(void *data)
{
int i;
pair_t pop[POP_SIZE];
memset(pop, 0, sizeof(pop));
for (i = 0; i < MUTATE_CNT; ++i) {
int t = rand() % POP_SIZE;
switch (rand() % (i > GROW_LIMIT? 5 : 3)) {
case 0: case 3:
if (pop[t])
pop[t] = pop[t]->car;
break;
case 1: case 4:
if (pop[t])
pop[t] = pop[t]->cdr;
break;
case 2:
pop[t] = pair_new(pop[rand() % POP_SIZE],
pop[rand() % POP_SIZE]);
break;
}
if (rand() % 8 == 1)
pair_check_rec(pop[rand() % POP_SIZE]);
}
return data;
}
int main(void)
{
# if NTHREADS > 1
pthread_t th[NTHREADS];
int i;
# endif
GC_set_all_interior_pointers(0); /* for a stricter test */
GC_INIT();
GC_init_finalized_malloc();
# ifndef NO_INCREMENTAL
GC_enable_incremental();
# endif
test_misc_sizes();
# if NTHREADS > 1
printf("Threaded disclaim test.\n");
for (i = 0; i < NTHREADS; ++i) {
int err = pthread_create(&th[i], NULL, test, NULL);
if (err) {
fprintf(stderr, "Failed to create thread # %d: %s\n", i,
strerror(err));
exit(1);
}
}
for (i = 0; i < NTHREADS; ++i) {
int err = pthread_join(th[i], NULL);
if (err) {
fprintf(stderr, "Failed to join thread # %d: %s\n", i,
strerror(err));
exit(69);
}
}
# else
printf("Unthreaded disclaim test.\n");
test(NULL);
# endif
return 0;
}

64
external/bdwgc/tests/huge_test.c vendored Normal file
View File

@@ -0,0 +1,64 @@
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#ifndef GC_IGNORE_WARN
/* Ignore misleading "Out of Memory!" warning (which is printed on */
/* every GC_MALLOC call below) by defining this macro before "gc.h" */
/* inclusion. */
# define GC_IGNORE_WARN
#endif
#ifndef GC_MAXIMUM_HEAP_SIZE
# define GC_MAXIMUM_HEAP_SIZE 100 * 1024 * 1024
# define GC_INITIAL_HEAP_SIZE GC_MAXIMUM_HEAP_SIZE / 20
/* Otherwise heap expansion aborts when deallocating large block. */
/* That's OK. We test this corner case mostly to make sure that */
/* it fails predictably. */
#endif
#ifndef GC_ATTR_ALLOC_SIZE
/* Omit alloc_size attribute to avoid compiler warnings about */
/* exceeding maximum object size when values close to GC_SWORD_MAX */
/* are passed to GC_MALLOC. */
# define GC_ATTR_ALLOC_SIZE(argnum) /* empty */
#endif
#include "gc.h"
/*
* Check that very large allocation requests fail. "Success" would usually
* indicate that the size was somehow converted to a negative
* number. Clients shouldn't do this, but we should fail in the
* expected manner.
*/
#define CHECK_ALLOC_FAILED(r, sz_str) \
do { \
if (NULL != (r)) { \
fprintf(stderr, \
"Size " sz_str " allocation unexpectedly succeeded\n"); \
exit(1); \
} \
} while (0)
#define GC_WORD_MAX ((GC_word)-1)
#define GC_SWORD_MAX ((GC_signed_word)(GC_WORD_MAX >> 1))
int main(void)
{
GC_INIT();
CHECK_ALLOC_FAILED(GC_MALLOC(GC_SWORD_MAX - 1024), "SWORD_MAX-1024");
CHECK_ALLOC_FAILED(GC_MALLOC(GC_SWORD_MAX), "SWORD_MAX");
CHECK_ALLOC_FAILED(GC_MALLOC((GC_word)GC_SWORD_MAX + 1), "SWORD_MAX+1");
CHECK_ALLOC_FAILED(GC_MALLOC((GC_word)GC_SWORD_MAX + 1024),
"SWORD_MAX+1024");
CHECK_ALLOC_FAILED(GC_MALLOC(GC_WORD_MAX - 1024), "WORD_MAX-1024");
CHECK_ALLOC_FAILED(GC_MALLOC(GC_WORD_MAX - 16), "WORD_MAX-16");
CHECK_ALLOC_FAILED(GC_MALLOC(GC_WORD_MAX - 8), "WORD_MAX-8");
CHECK_ALLOC_FAILED(GC_MALLOC(GC_WORD_MAX - 4), "WORD_MAX-4");
CHECK_ALLOC_FAILED(GC_MALLOC(GC_WORD_MAX), "WORD_MAX");
return 0;
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2011 Ludovic Courtes
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
*
* Permission is hereby granted to use or copy this program
* for any purpose, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
/* Make sure 'GC_INIT' can be called from threads other than the initial
* thread.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifndef GC_THREADS
# define GC_THREADS
#endif
#define GC_NO_THREAD_REDIRECTS 1
/* Do not redirect thread creation and join calls. */
#include "gc.h"
#ifdef GC_PTHREADS
# include <pthread.h>
#else
# include <windows.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#ifdef GC_PTHREADS
static void *thread(void *arg)
#else
static DWORD WINAPI thread(LPVOID arg)
#endif
{
GC_INIT();
(void)GC_MALLOC(123);
(void)GC_MALLOC(12345);
# ifdef GC_PTHREADS
return arg;
# else
return (DWORD)(GC_word)arg;
# endif
}
#include "private/gcconfig.h"
int main(void)
{
# ifdef GC_PTHREADS
int code;
pthread_t t;
# ifdef LINT2
t = pthread_self(); /* explicitly initialize to some value */
# endif
# else
HANDLE t;
DWORD thread_id;
# endif
# if !(defined(BEOS) || defined(MSWIN32) || defined(MSWINCE) \
|| defined(CYGWIN32) || defined(GC_OPENBSD_UTHREADS) \
|| (defined(DARWIN) && !defined(NO_PTHREAD_GET_STACKADDR_NP)) \
|| ((defined(FREEBSD) || defined(LINUX) || defined(NETBSD) \
|| defined(HOST_ANDROID)) && !defined(NO_PTHREAD_GETATTR_NP) \
&& !defined(NO_PTHREAD_ATTR_GET_NP)) \
|| (defined(GC_SOLARIS_THREADS) && !defined(_STRICT_STDC)) \
|| (!defined(STACKBOTTOM) && (defined(HEURISTIC1) \
|| (!defined(LINUX_STACKBOTTOM) && !defined(FREEBSD_STACKBOTTOM)))))
/* GC_INIT() must be called from main thread only. */
GC_INIT();
# endif
(void)GC_get_parallel(); /* linking fails if no threads support */
# ifdef GC_PTHREADS
if ((code = pthread_create (&t, NULL, thread, NULL)) != 0) {
fprintf(stderr, "Thread creation failed %d\n", code);
return 1;
}
if ((code = pthread_join (t, NULL)) != 0) {
fprintf(stderr, "Thread join failed %d\n", code);
return 1;
}
# else
t = CreateThread(NULL, 0, thread, 0, 0, &thread_id);
if (t == NULL) {
fprintf(stderr, "Thread creation failed %d\n", (int)GetLastError());
return 1;
}
if (WaitForSingleObject(t, INFINITE) != WAIT_OBJECT_0) {
fprintf(stderr, "Thread join failed %d\n", (int)GetLastError());
CloseHandle(t);
return 1;
}
CloseHandle(t);
# endif
return 0;
}

25
external/bdwgc/tests/leak_test.c vendored Normal file
View File

@@ -0,0 +1,25 @@
#include "leak_detector.h"
int main(void) {
int *p[10];
int i;
GC_set_find_leak(1); /* for new collect versions not compiled */
/* with -DFIND_LEAK. */
GC_INIT(); /* Needed if thread-local allocation is enabled. */
/* FIXME: This is not ideal. */
for (i = 0; i < 10; ++i) {
p[i] = (int*)malloc(sizeof(int)+i);
}
CHECK_LEAKS();
for (i = 1; i < 10; ++i) {
free(p[i]);
}
for (i = 0; i < 9; ++i) {
p[i] = (int*)malloc(sizeof(int)+i);
}
CHECK_LEAKS();
CHECK_LEAKS();
CHECK_LEAKS();
return 0;
}

25
external/bdwgc/tests/middle.c vendored Normal file
View File

@@ -0,0 +1,25 @@
/*
* Test at the boundary between small and large objects.
* Inspired by a test case from Zoltan Varga.
*/
#include "gc.h"
#include <stdio.h>
int main (void)
{
int i;
GC_set_all_interior_pointers(0);
GC_INIT();
for (i = 0; i < 20000; ++i) {
(void)GC_malloc_atomic(4096);
(void)GC_malloc(4096);
}
for (i = 0; i < 20000; ++i) {
(void)GC_malloc_atomic(2048);
(void)GC_malloc(2048);
}
printf("Final heap size is %lu\n", (unsigned long)GC_get_heap_size());
return 0;
}

34
external/bdwgc/tests/realloc_test.c vendored Normal file
View File

@@ -0,0 +1,34 @@
#include <stdio.h>
#include <stdlib.h>
#include "gc.h"
#define COUNT 10000000
int main(void) {
int i;
unsigned long last_heap_size = 0;
GC_INIT();
for (i = 0; i < COUNT; i++) {
int **p = GC_NEW(int *);
int *q = (int*)GC_MALLOC_ATOMIC(sizeof(int));
if (p == 0 || *p != 0) {
fprintf(stderr, "GC_malloc returned garbage (or NULL)\n");
exit(1);
}
*p = (int*)GC_REALLOC(q, 2 * sizeof(int));
if (i % 10 == 0) {
unsigned long heap_size = (unsigned long)GC_get_heap_size();
if (heap_size != last_heap_size) {
printf("Heap size: %lu\n", heap_size);
last_heap_size = heap_size;
}
}
}
return 0;
}

28
external/bdwgc/tests/smash_test.c vendored Normal file
View File

@@ -0,0 +1,28 @@
/*
* Test that overwrite error detection works reasonably.
*/
#define GC_DEBUG
#include "gc.h"
#include <stdio.h>
#define COUNT 7000
#define SIZE 40
char * A[COUNT];
int main(void)
{
int i;
char *p;
GC_INIT();
for (i = 0; i < COUNT; ++i) {
A[i] = p = (char*)GC_MALLOC(SIZE);
if (i%3000 == 0) GC_gcollect();
if (i%5678 == 0 && p != 0) p[SIZE + i/2000] = 42;
}
return 0;
}

59
external/bdwgc/tests/staticrootslib.c vendored Normal file
View File

@@ -0,0 +1,59 @@
/* This test file is intended to be compiled into a DLL. */
#ifndef GC_DEBUG
# define GC_DEBUG
#endif
#include "gc.h"
#ifndef GC_TEST_EXPORT_API
# if defined(GC_VISIBILITY_HIDDEN_SET) \
&& !defined(__CEGCC__) && !defined(__CYGWIN__) && !defined(__MINGW32__)
# define GC_TEST_EXPORT_API \
extern __attribute__((__visibility__("default")))
# else
# define GC_TEST_EXPORT_API extern
# endif
#endif
struct treenode {
struct treenode *x;
struct treenode *y;
};
static struct treenode *root[10] = { 0 };
static struct treenode *root_nz[10] = { (struct treenode *)(GC_word)2 };
#ifdef STATICROOTSLIB2
# define libsrl_getpelem libsrl_getpelem2
#else
GC_TEST_EXPORT_API struct treenode * libsrl_mktree(int i)
{
struct treenode * r = GC_NEW(struct treenode);
if (0 == i)
return 0;
if (1 == i)
r = (struct treenode *)GC_MALLOC_ATOMIC(sizeof(struct treenode));
if (r) {
r -> x = libsrl_mktree(i-1);
r -> y = libsrl_mktree(i-1);
}
return r;
}
GC_TEST_EXPORT_API void * libsrl_init(void)
{
# ifndef STATICROOTSLIB_INIT_IN_MAIN
GC_INIT();
# endif
return GC_MALLOC(sizeof(struct treenode));
}
#endif /* !STATICROOTSLIB2 */
GC_TEST_EXPORT_API struct treenode ** libsrl_getpelem(int i, int j)
{
return &((j & 1) != 0 ? root_nz : root)[i];
}

75
external/bdwgc/tests/staticrootstest.c vendored Normal file
View File

@@ -0,0 +1,75 @@
#include <stdio.h>
#include <string.h>
#ifndef GC_DEBUG
# define GC_DEBUG
#endif
#include "gc.h"
#include "gc_backptr.h"
#ifndef GC_TEST_IMPORT_API
# define GC_TEST_IMPORT_API extern
#endif
/* Should match that in staticrootslib.c. */
struct treenode {
struct treenode *x;
struct treenode *y;
};
struct treenode *root[10] = { NULL };
/* Same as "root" variable but initialized to some non-zero value (to */
/* be placed to .data section instead of .bss). */
struct treenode *root_nz[10] = { (struct treenode *)(GC_word)1 };
static char *staticroot; /* intentionally static */
GC_TEST_IMPORT_API struct treenode * libsrl_mktree(int i);
GC_TEST_IMPORT_API void * libsrl_init(void);
GC_TEST_IMPORT_API struct treenode ** libsrl_getpelem(int i, int j);
GC_TEST_IMPORT_API struct treenode ** libsrl_getpelem2(int i, int j);
void init_staticroot(void)
{
/* Intentionally put staticroot initialization in a function other */
/* than main to prevent CSA warning that staticroot variable can be */
/* changed to be a local one). */
staticroot = (char *)libsrl_init();
}
int main(void)
{
int i, j;
# ifdef STATICROOTSLIB_INIT_IN_MAIN
GC_INIT();
# endif
init_staticroot();
if (NULL == staticroot) {
fprintf(stderr, "GC_malloc returned NULL\n");
return 2;
}
memset(staticroot, 0x42, sizeof(struct treenode));
GC_gcollect();
for (j = 0; j < 4; j++) {
for (i = 0; i < (int)(sizeof(root) / sizeof(root[0])); ++i) {
# ifdef STATICROOTSLIB2
*libsrl_getpelem2(i, j) = libsrl_mktree(12);
# endif
*libsrl_getpelem(i, j) = libsrl_mktree(12);
((j & 1) != 0 ? root_nz : root)[i] = libsrl_mktree(12);
GC_gcollect();
}
for (i = 0; i < (int)sizeof(struct treenode); ++i) {
if (staticroot[i] != 0x42) {
fprintf(stderr, "Memory check failed\n");
return -1;
}
}
}
return 0;
}

168
external/bdwgc/tests/subthread_create.c vendored Normal file
View File

@@ -0,0 +1,168 @@
#ifdef HAVE_CONFIG_H
/* For PARALLEL_MARK */
# include "config.h"
#endif
#ifndef GC_THREADS
# define GC_THREADS
#endif
#include "gc.h"
#ifdef PARALLEL_MARK
# define AO_REQUIRE_CAS
#endif
#include "private/gc_atomic_ops.h"
#include <stdio.h>
#ifdef AO_HAVE_fetch_and_add1
#ifdef GC_PTHREADS
# include <pthread.h>
#else
# include <windows.h>
#endif
#if defined(__HAIKU__)
# include <errno.h>
#endif
#include <stdlib.h>
#include <string.h>
#ifndef NTHREADS
# define NTHREADS 31 /* number of initial threads */
#endif
#ifndef MAX_SUBTHREAD_DEPTH
# define MAX_ALIVE_THREAD_COUNT 55
# define MAX_SUBTHREAD_DEPTH 7
# define MAX_SUBTHREAD_COUNT 200
#endif
#ifndef DECAY_NUMER
# define DECAY_NUMER 15
# define DECAY_DENOM 16
#endif
volatile AO_t thread_created_cnt = 0;
volatile AO_t thread_ended_cnt = 0;
#ifdef GC_PTHREADS
void *entry(void *arg)
#else
DWORD WINAPI entry(LPVOID arg)
#endif
{
int thread_num = AO_fetch_and_add1(&thread_created_cnt);
GC_word my_depth = (GC_word)arg + 1;
if (my_depth <= MAX_SUBTHREAD_DEPTH
&& thread_num < MAX_SUBTHREAD_COUNT
&& (thread_num % DECAY_DENOM) < DECAY_NUMER
&& thread_num - (int)AO_load(&thread_ended_cnt)
<= MAX_ALIVE_THREAD_COUNT) {
# ifdef GC_PTHREADS
int err;
pthread_t th;
err = pthread_create(&th, NULL, entry, (void *)my_depth);
if (err != 0) {
fprintf(stderr, "Thread #%d creation failed: %s\n", thread_num,
strerror(err));
exit(2);
}
err = pthread_detach(th);
if (err != 0) {
fprintf(stderr, "Thread #%d detach failed: %s\n", thread_num,
strerror(err));
exit(2);
}
# else
HANDLE th;
DWORD thread_id;
th = CreateThread(NULL, 0, entry, (LPVOID)my_depth, 0, &thread_id);
if (th == NULL) {
fprintf(stderr, "Thread #%d creation failed: %d\n", thread_num,
(int)GetLastError());
exit(2);
}
CloseHandle(th);
# endif
}
(void)AO_fetch_and_add1(&thread_ended_cnt);
return 0;
}
int main(void)
{
#if NTHREADS > 0
int i;
# ifdef GC_PTHREADS
int err;
pthread_t th[NTHREADS];
# else
HANDLE th[NTHREADS];
# endif
GC_INIT();
for (i = 0; i < NTHREADS; ++i) {
# ifdef GC_PTHREADS
err = pthread_create(&th[i], NULL, entry, 0);
if (err) {
fprintf(stderr, "Thread creation failed: %s\n", strerror(err));
exit(1);
}
# else
DWORD thread_id;
th[i] = CreateThread(NULL, 0, entry, 0, 0, &thread_id);
if (th[i] == NULL) {
fprintf(stderr, "Thread creation failed: %d\n",
(int)GetLastError());
exit(1);
}
# endif
}
for (i = 0; i < NTHREADS; ++i) {
# ifdef GC_PTHREADS
void *res;
err = pthread_join(th[i], &res);
if (err) {
fprintf(stderr, "Failed to join thread: %s\n", strerror(err));
# if defined(__HAIKU__)
/* The error is just ignored (and the test is ended) to */
/* workaround some bug in Haiku pthread_join. */
/* TODO: The thread is not deleted from GC_threads. */
if (ESRCH == err) break;
# endif
exit(1);
}
# else
if (WaitForSingleObject(th[i], INFINITE) != WAIT_OBJECT_0) {
fprintf(stderr, "Failed to join thread: %d\n",
(int)GetLastError());
CloseHandle(th[i]);
exit(1);
}
CloseHandle(th[i]);
# endif
}
#endif
printf("subthread_create: created %d threads (%d ended)\n",
(int)AO_load(&thread_created_cnt), (int)AO_load(&thread_ended_cnt));
return 0;
}
#else
int main(void)
{
printf("subthread_create test skipped\n");
return 0;
}
#endif /* !AO_HAVE_fetch_and_add1 */

2345
external/bdwgc/tests/test.c vendored Normal file

File diff suppressed because it is too large Load Diff

98
external/bdwgc/tests/test_atomic_ops.c vendored Normal file
View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2017 Ivan Maidanski
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
*
* Permission is hereby granted to use or copy this program
* for any purpose, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
/* Minimal testing of atomic operations used by the BDWGC. Primary use */
/* is to determine whether compiler atomic intrinsics can be relied on. */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#if defined(GC_BUILTIN_ATOMIC) || defined(GC_THREADS)
# include <stdlib.h>
# ifdef PARALLEL_MARK
# define AO_REQUIRE_CAS
# endif
# include "private/gc_atomic_ops.h"
# define TA_assert(e) \
if (!(e)) { \
fprintf(stderr, "Assertion failure, line %d: " #e "\n", __LINE__); \
exit(-1); \
}
int main(void) {
AO_t x = 13;
# if defined(AO_HAVE_char_load) || defined(AO_HAVE_char_store)
unsigned char c = 117;
# endif
# ifdef AO_HAVE_test_and_set_acquire
AO_TS_t z = AO_TS_INITIALIZER;
TA_assert(AO_test_and_set_acquire(&z) == AO_TS_CLEAR);
TA_assert(AO_test_and_set_acquire(&z) == AO_TS_SET);
AO_CLEAR(&z);
# endif
AO_compiler_barrier();
# ifdef AO_HAVE_nop_full
AO_nop_full();
# endif
# ifdef AO_HAVE_char_load
TA_assert(AO_char_load(&c) == 117);
# endif
# ifdef AO_HAVE_char_store
AO_char_store(&c, 119);
TA_assert(c == 119);
# endif
# ifdef AO_HAVE_load_acquire
TA_assert(AO_load_acquire(&x) == 13);
# endif
# if defined(AO_HAVE_fetch_and_add) && defined(AO_HAVE_fetch_and_add1)
TA_assert(AO_fetch_and_add(&x, 42) == 13);
TA_assert(AO_fetch_and_add(&x, (AO_t)(-43)) == 55);
TA_assert(AO_fetch_and_add1(&x) == 12);
# endif
# ifdef AO_HAVE_compare_and_swap_release
TA_assert(!AO_compare_and_swap(&x, 14, 42));
TA_assert(x == 13);
TA_assert(AO_compare_and_swap_release(&x, 13, 42));
TA_assert(x == 42);
# else
if (*(volatile AO_t *)&x == 13)
*(volatile AO_t *)&x = 42;
# endif
# ifdef AO_HAVE_or
AO_or(&x, 66);
TA_assert(x == 106);
# endif
# ifdef AO_HAVE_store_release
AO_store_release(&x, 113);
TA_assert(x == 113);
# endif
return 0;
}
#else
int main(void)
{
printf("test_atomic_ops skipped\n");
return 0;
}
#endif

395
external/bdwgc/tests/test_cpp.cc vendored Normal file
View File

@@ -0,0 +1,395 @@
/****************************************************************************
Copyright (c) 1994 by Xerox Corporation. All rights reserved.
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
Permission is hereby granted to use or copy this program for any
purpose, provided the above notices are retained on all copies.
Permission to modify the code and to distribute modified code is
granted, provided the above notices are retained, and a notice that
the code was modified is included with the above copyright notice.
****************************************************************************
usage: test_cpp number-of-iterations
This program tries to test the specific C++ functionality provided by
gc_c++.h that isn't tested by the more general test routines of the
collector.
A recommended value for number-of-iterations is 10, which will take a
few minutes to complete.
***************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#undef GC_BUILD
#include "gc_cpp.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef DONT_USE_STD_ALLOCATOR
# include "gc_allocator.h"
#else
/* Note: This works only for ancient STL versions. */
# include "new_gc_alloc.h"
#endif
# include "private/gcconfig.h"
# ifndef GC_API_PRIV
# define GC_API_PRIV GC_API
# endif
extern "C" {
GC_API_PRIV void GC_printf(const char * format, ...);
/* Use GC private output to reach the same log file. */
/* Don't include gc_priv.h, since that may include Windows system */
/* header files that don't take kindly to this context. */
}
#ifdef MSWIN32
# include <windows.h>
#endif
#ifdef GC_NAME_CONFLICT
# define USE_GC GC_NS_QUALIFY(UseGC)
struct foo * GC;
#else
# define USE_GC GC_NS_QUALIFY(GC)
#endif
#define my_assert( e ) \
if (! (e)) { \
GC_printf( "Assertion failure in " __FILE__ ", line %d: " #e "\n", \
__LINE__ ); \
exit( 1 ); }
#ifndef GC_ATTR_EXPLICIT
# if (__cplusplus >= 201103L) || defined(CPPCHECK)
# define GC_ATTR_EXPLICIT explicit
# else
# define GC_ATTR_EXPLICIT /* empty */
# endif
#endif
class A {public:
/* An uncollectible class. */
GC_ATTR_EXPLICIT A( int iArg ): i( iArg ) {}
void Test( int iArg ) {
my_assert( i == iArg );}
int i;};
class B: public GC_NS_QUALIFY(gc), public A { public:
/* A collectible class. */
GC_ATTR_EXPLICIT B( int j ): A( j ) {}
virtual ~B() {
my_assert( deleting );}
static void Deleting( int on ) {
deleting = on;}
static int deleting;};
int B::deleting = 0;
class C: public GC_NS_QUALIFY(gc_cleanup), public A { public:
/* A collectible class with cleanup and virtual multiple inheritance. */
// The class uses dynamic memory/resource allocation, so provide both
// a copy constructor and an assignment operator to workaround a cppcheck
// warning.
C(const C& c) : A(c.i), level(c.level) {
left = c.left ? new C(*c.left) : 0;
right = c.right ? new C(*c.right) : 0;
}
C& operator=(const C& c) {
if (this != &c) {
delete left;
delete right;
i = c.i;
level = c.level;
left = c.left ? new C(*c.left) : 0;
right = c.right ? new C(*c.right) : 0;
}
return *this;
}
GC_ATTR_EXPLICIT C( int levelArg ): A( levelArg ), level( levelArg ) {
nAllocated++;
if (level > 0) {
left = new C( level - 1 );
right = new C( level - 1 );}
else {
left = right = 0;}}
~C() {
this->A::Test( level );
nFreed++;
my_assert( level == 0 ?
left == 0 && right == 0 :
level == left->level + 1 && level == right->level + 1 );
left = right = 0;
level = -123456;}
static void Test() {
my_assert( nFreed <= nAllocated && nFreed >= .8 * nAllocated );}
static int nFreed;
static int nAllocated;
int level;
C* left;
C* right;};
int C::nFreed = 0;
int C::nAllocated = 0;
class D: public GC_NS_QUALIFY(gc) { public:
/* A collectible class with a static member function to be used as
an explicit clean-up function supplied to ::new. */
GC_ATTR_EXPLICIT D( int iArg ): i( iArg ) {
nAllocated++;}
static void CleanUp( void* obj, void* data ) {
D* self = static_cast<D*>(obj);
nFreed++;
my_assert( (GC_word)self->i == (GC_word)data );}
static void Test() {
my_assert( nFreed >= .8 * nAllocated );}
int i;
static int nFreed;
static int nAllocated;};
int D::nFreed = 0;
int D::nAllocated = 0;
class E: public GC_NS_QUALIFY(gc_cleanup) { public:
/* A collectible class with clean-up for use by F. */
E() {
nAllocated++;}
~E() {
nFreed++;}
static int nFreed;
static int nAllocated;};
int E::nFreed = 0;
int E::nAllocated = 0;
class F: public E {public:
/* A collectible class with clean-up, a base with clean-up, and a
member with clean-up. */
F() {
nAllocatedF++;
}
~F() {
nFreedF++;
}
static void Test() {
my_assert(nFreedF >= .8 * nAllocatedF);
my_assert(2 * nFreedF == nFreed);
}
E e;
static int nFreedF;
static int nAllocatedF;
};
int F::nFreedF = 0;
int F::nAllocatedF = 0;
GC_word Disguise( void* p ) {
return ~ (GC_word) p;}
void* Undisguise( GC_word i ) {
return (void*) ~ i;}
#define GC_CHECKED_DELETE(p) \
do { \
size_t freed_before = GC_get_expl_freed_bytes_since_gc(); \
delete p; /* the operator should invoke GC_FREE() */ \
size_t freed_after = GC_get_expl_freed_bytes_since_gc(); \
my_assert(freed_before != freed_after); \
} while (0)
#if ((defined(MSWIN32) && !defined(__MINGW32__)) || defined(MSWINCE)) \
&& !defined(NO_WINMAIN_ENTRY)
int APIENTRY WinMain( HINSTANCE /* instance */, HINSTANCE /* prev */,
LPSTR cmd, int /* cmdShow */)
{
int argc = 0;
char* argv[ 3 ];
# if defined(CPPCHECK)
GC_noop1((GC_word)&WinMain);
# endif
if (cmd != 0)
for (argc = 1; argc < (int)(sizeof(argv) / sizeof(argv[0])); argc++) {
// Parse the command-line string. Non-reentrant strtok() is not used
// to avoid complains of static analysis tools. (And, strtok_r() is
// not available on some platforms.) The code is equivalent to:
// if (!(argv[argc] = strtok(argc == 1 ? cmd : 0, " \t"))) break;
if (NULL == cmd) {
argv[argc] = NULL;
break;
}
argv[argc] = cmd;
for (; *cmd != '\0'; cmd++) {
if (*cmd != ' ' && *cmd != '\t')
break;
}
if ('\0' == *cmd) {
argv[argc] = NULL;
break;
}
argv[argc] = cmd;
while (*(++cmd) != '\0') {
if (*cmd == ' ' || *cmd == '\t')
break;
}
if (*cmd != '\0') {
*(cmd++) = '\0';
} else {
cmd = NULL;
}
}
#elif defined(MACOS)
int main() {
char* argv_[] = {"test_cpp", "10"}; // MacOS doesn't have a command line
argv = argv_;
argc = sizeof(argv_)/sizeof(argv_[0]);
#else
int main( int argc, char* argv[] ) {
#endif
GC_set_all_interior_pointers(1);
/* needed due to C++ multiple inheritance used */
GC_INIT();
int i, iters, n;
# ifndef DONT_USE_STD_ALLOCATOR
int *x = gc_allocator<int>().allocate(1);
int *xio;
xio = gc_allocator_ignore_off_page<int>().allocate(1);
(void)xio;
int **xptr = traceable_allocator<int *>().allocate(1);
# else
int *x = (int *)gc_alloc::allocate(sizeof(int));
# endif
*x = 29;
# ifndef DONT_USE_STD_ALLOCATOR
if (!xptr) {
fprintf(stderr, "Out of memory!\n");
exit(3);
}
*xptr = x;
x = 0;
# endif
if (argc != 2
|| (n = (int)COVERT_DATAFLOW(atoi(argv[1]))) <= 0) {
GC_printf("usage: test_cpp number-of-iterations\n"
"Assuming 10 iters\n");
n = 10;
}
for (iters = 1; iters <= n; iters++) {
GC_printf( "Starting iteration %d\n", iters );
/* Allocate some uncollectible As and disguise their pointers.
Later we'll check to see if the objects are still there. We're
checking to make sure these objects really are uncollectible. */
GC_word as[ 1000 ];
GC_word bs[ 1000 ];
for (i = 0; i < 1000; i++) {
as[ i ] = Disguise( new (GC_NS_QUALIFY(NoGC)) A(i) );
bs[ i ] = Disguise( new (GC_NS_QUALIFY(NoGC)) B(i) ); }
/* Allocate a fair number of finalizable Cs, Ds, and Fs.
Later we'll check to make sure they've gone away. */
for (i = 0; i < 1000; i++) {
C* c = new C( 2 );
C c1( 2 ); /* stack allocation should work too */
D* d;
F* f;
d = ::new (USE_GC, D::CleanUp, (void*)(GC_word)i) D( i );
(void)d;
f = new F;
F** fa = new F*[1];
fa[0] = f;
(void)fa;
delete[] fa;
if (0 == i % 10)
GC_CHECKED_DELETE(c);
}
/* Allocate a very large number of collectible As and Bs and
drop the references to them immediately, forcing many
collections. */
for (i = 0; i < 1000000; i++) {
A* a;
a = new (USE_GC) A( i );
(void)a;
B* b;
b = new B( i );
(void)b;
b = new (USE_GC) B( i );
if (0 == i % 10) {
B::Deleting( 1 );
GC_CHECKED_DELETE(b);
B::Deleting( 0 );}
# ifdef FINALIZE_ON_DEMAND
GC_invoke_finalizers();
# endif
}
/* Make sure the uncollectible As and Bs are still there. */
for (i = 0; i < 1000; i++) {
A* a = static_cast<A*>(Undisguise(as[i]));
B* b = static_cast<B*>(Undisguise(bs[i]));
a->Test( i );
# if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER)
// Workaround for ASan/MSan: the linker uses operator delete
// implementation from libclang_rt instead of gc_cpp (thus
// causing incompatible alloc/free).
GC_FREE(a);
# else
GC_CHECKED_DELETE(a);
# endif
b->Test( i );
B::Deleting( 1 );
GC_CHECKED_DELETE(b);
B::Deleting( 0 );
# ifdef FINALIZE_ON_DEMAND
GC_invoke_finalizers();
# endif
}
/* Make sure most of the finalizable Cs, Ds, and Fs have
gone away. */
C::Test();
D::Test();
F::Test();}
# ifndef DONT_USE_STD_ALLOCATOR
x = *xptr;
# endif
my_assert (29 == x[0]);
GC_printf( "The test appears to have succeeded.\n" );
return( 0 );
}

149
external/bdwgc/tests/tests.am vendored Normal file
View File

@@ -0,0 +1,149 @@
#
# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
#
# Permission is hereby granted to use or copy this program
# for any purpose, provided the above notices are retained on all copies.
# Permission to modify the code and to distribute modified code is granted,
# provided the above notices are retained, and a notice that the code was
# modified is included with the above copyright notice.
# Common libs to _LDADD for all tests.
test_ldadd = $(top_builddir)/libgc.la $(EXTRA_TEST_LIBS)
TESTS += gctest$(EXEEXT)
check_PROGRAMS += gctest
gctest_SOURCES = tests/test.c
gctest_LDADD = $(test_ldadd)
if THREADS
gctest_LDADD += $(THREADDLLIBS)
endif
gctest_DEPENDENCIES = $(top_builddir)/libgc.la
TESTS += leaktest$(EXEEXT)
check_PROGRAMS += leaktest
leaktest_SOURCES = tests/leak_test.c
leaktest_LDADD = $(test_ldadd)
TESTS += middletest$(EXEEXT)
check_PROGRAMS += middletest
middletest_SOURCES = tests/middle.c
middletest_LDADD = $(test_ldadd)
TESTS += smashtest$(EXEEXT)
check_PROGRAMS += smashtest
smashtest_SOURCES = tests/smash_test.c
smashtest_LDADD = $(test_ldadd)
TESTS += hugetest$(EXEEXT)
check_PROGRAMS += hugetest
hugetest_SOURCES = tests/huge_test.c
hugetest_LDADD = $(test_ldadd)
TESTS += realloc_test$(EXEEXT)
check_PROGRAMS += realloc_test
realloc_test_SOURCES = tests/realloc_test.c
realloc_test_LDADD = $(test_ldadd)
TESTS += staticrootstest$(EXEEXT)
check_PROGRAMS += staticrootstest
staticrootstest_SOURCES = tests/staticrootstest.c
staticrootstest_CFLAGS = -DSTATICROOTSLIB2
staticrootstest_LDADD = $(test_ldadd) libstaticrootslib_test.la \
libstaticrootslib2_test.la
check_LTLIBRARIES += libstaticrootslib_test.la libstaticrootslib2_test.la
libstaticrootslib_test_la_SOURCES = tests/staticrootslib.c
libstaticrootslib_test_la_LIBADD = $(test_ldadd)
libstaticrootslib_test_la_LDFLAGS = -no-undefined -rpath /nowhere
libstaticrootslib_test_la_DEPENDENCIES = $(top_builddir)/libgc.la
libstaticrootslib2_test_la_SOURCES = tests/staticrootslib.c
libstaticrootslib2_test_la_LIBADD = $(test_ldadd)
libstaticrootslib2_test_la_CFLAGS = -DSTATICROOTSLIB2
libstaticrootslib2_test_la_LDFLAGS = -no-undefined -rpath /nowhere
if KEEP_BACK_PTRS
TESTS += tracetest$(EXEEXT)
check_PROGRAMS += tracetest
tracetest_SOURCES = tests/trace_test.c
tracetest_LDADD = $(test_ldadd)
endif
if THREADS
TESTS += test_atomic_ops$(EXEEXT)
check_PROGRAMS += test_atomic_ops
test_atomic_ops_SOURCES = tests/test_atomic_ops.c
# Really should need only $(ATOMIC_OPS_LIBS)
test_atomic_ops_LDADD = $(test_ldadd) $(THREADDLLIBS)
TESTS += threadleaktest$(EXEEXT)
check_PROGRAMS += threadleaktest
threadleaktest_SOURCES = tests/thread_leak_test.c
threadleaktest_LDADD = $(test_ldadd) $(THREADDLLIBS)
TESTS += threadkey_test$(EXEEXT)
check_PROGRAMS += threadkey_test
threadkey_test_SOURCES = tests/threadkey_test.c
threadkey_test_LDADD = $(test_ldadd) $(THREADDLLIBS)
TESTS += subthreadcreate_test$(EXEEXT)
check_PROGRAMS += subthreadcreate_test
subthreadcreate_test_SOURCES = tests/subthread_create.c
subthreadcreate_test_LDADD = $(test_ldadd) $(THREADDLLIBS)
TESTS += initsecondarythread_test$(EXEEXT)
check_PROGRAMS += initsecondarythread_test
initsecondarythread_test_SOURCES = tests/initsecondarythread.c
initsecondarythread_test_LDADD = $(test_ldadd) $(THREADDLLIBS)
endif
if CPLUSPLUS
TESTS += test_cpp$(EXEEXT)
check_PROGRAMS += test_cpp
test_cpp_SOURCES = tests/test_cpp.cc
if AVOID_CPP_LIB
test_cpp_LDADD = gc_cpp.o $(test_ldadd) $(CXXLIBS)
else
test_cpp_LDADD = libgccpp.la $(test_ldadd) $(CXXLIBS)
endif
endif
if ENABLE_DISCLAIM
TESTS += disclaim_test$(EXEEXT)
check_PROGRAMS += disclaim_test
disclaim_test_SOURCES = tests/disclaim_test.c
disclaim_test_LDADD = $(test_ldadd)
if THREADS
disclaim_test_LDADD += $(THREADDLLIBS)
endif
TESTS += disclaim_bench$(EXEEXT)
check_PROGRAMS += disclaim_bench
disclaim_bench_SOURCES = tests/disclaim_bench.c
disclaim_bench_LDADD = $(test_ldadd)
endif
# Run the tests directly (without test-driver):
.PHONY: check-without-test-driver
check-without-test-driver: $(TESTS)
./gctest$(EXEEXT)
./hugetest$(EXEEXT)
./leaktest$(EXEEXT)
./middletest$(EXEEXT)
./realloc_test$(EXEEXT)
./smashtest$(EXEEXT)
./staticrootstest$(EXEEXT)
test ! -f disclaim_bench$(EXEEXT) || ./disclaim_bench$(EXEEXT)
test ! -f disclaim_test$(EXEEXT) || ./disclaim_test$(EXEEXT)
test ! -f initsecondarythread_test$(EXEEXT) \
|| ./initsecondarythread_test$(EXEEXT)
test ! -f test_atomic_ops$(EXEEXT) || ./test_atomic_ops$(EXEEXT)
test ! -f threadkey_test$(EXEEXT) || ./threadkey_test$(EXEEXT)
test ! -f threadleaktest$(EXEEXT) || ./threadleaktest$(EXEEXT)
test ! -f subthreadcreate_test$(EXEEXT) || ./subthreadcreate_test$(EXEEXT)
test ! -f test_cpp$(EXEEXT) || ./test_cpp$(EXEEXT)
test ! -f tracetest$(EXEEXT) || ./tracetest$(EXEEXT)
./cordtest$(EXEEXT)

95
external/bdwgc/tests/thread_leak_test.c vendored Normal file
View File

@@ -0,0 +1,95 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifndef GC_THREADS
# define GC_THREADS
#endif
#undef GC_NO_THREAD_REDIRECTS
#include "leak_detector.h"
#ifdef GC_PTHREADS
# include <pthread.h>
#else
# include <windows.h>
#endif
#include <stdio.h>
#ifdef GC_PTHREADS
void * test(void * arg)
#else
DWORD WINAPI test(LPVOID arg)
#endif
{
int *p[10];
int i;
for (i = 0; i < 10; ++i) {
p[i] = (int *)malloc(sizeof(int) + i);
}
CHECK_LEAKS();
for (i = 1; i < 10; ++i) {
free(p[i]);
}
# ifdef GC_PTHREADS
return arg;
# else
return (DWORD)(GC_word)arg;
# endif
}
#ifndef NTHREADS
# define NTHREADS 5
#endif
int main(void) {
# if NTHREADS > 0
int i;
# ifdef GC_PTHREADS
pthread_t t[NTHREADS];
# else
HANDLE t[NTHREADS];
DWORD thread_id;
# endif
int code;
# endif
GC_set_find_leak(1); /* for new collect versions not compiled */
/* with -DFIND_LEAK. */
GC_INIT();
# if NTHREADS > 0
for (i = 0; i < NTHREADS; ++i) {
# ifdef GC_PTHREADS
code = pthread_create(t + i, 0, test, 0);
# else
t[i] = CreateThread(NULL, 0, test, 0, 0, &thread_id);
code = t[i] != NULL ? 0 : (int)GetLastError();
# endif
if (code != 0) {
fprintf(stderr, "Thread creation failed %d\n", code);
exit(2);
}
}
for (i = 0; i < NTHREADS; ++i) {
# ifdef GC_PTHREADS
code = pthread_join(t[i], 0);
# else
code = WaitForSingleObject(t[i], INFINITE) == WAIT_OBJECT_0 ? 0 :
(int)GetLastError();
# endif
if (code != 0) {
fprintf(stderr, "Thread join failed %d\n", code);
exit(2);
}
}
# endif
CHECK_LEAKS();
CHECK_LEAKS();
CHECK_LEAKS();
return 0;
}

115
external/bdwgc/tests/threadkey_test.c vendored Normal file
View File

@@ -0,0 +1,115 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifndef GC_THREADS
# define GC_THREADS
#endif
#define GC_NO_THREAD_REDIRECTS 1
#include "gc.h"
#include <stdio.h>
#include <stdlib.h>
#if (!defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS) \
|| defined(__native_client__)) && !defined(SKIP_THREADKEY_TEST)
/* FIXME: Skip this test on Solaris for now. The test may fail on */
/* other targets as well. Currently, tested only on Linux, Cygwin */
/* and Darwin. */
# define SKIP_THREADKEY_TEST
#endif
#ifdef SKIP_THREADKEY_TEST
int main (void)
{
printf("threadkey_test skipped\n");
return 0;
}
#else
#include <pthread.h>
pthread_key_t key;
#ifdef GC_SOLARIS_THREADS
/* pthread_once_t key_once = { PTHREAD_ONCE_INIT }; */
#else
pthread_once_t key_once = PTHREAD_ONCE_INIT;
#endif
void * entry (void *arg)
{
pthread_setspecific(key,
(void *)GC_HIDE_POINTER(GC_STRDUP("hello, world")));
return arg;
}
void * GC_CALLBACK on_thread_exit_inner (struct GC_stack_base * sb, void * arg)
{
int res = GC_register_my_thread (sb);
pthread_t t;
int creation_res; /* Used to suppress a warning about */
/* unchecked pthread_create() result. */
pthread_attr_t attr;
if (pthread_attr_init(&attr) != 0
|| pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) {
fprintf(stderr, "Thread attribute init or setdetachstate failed\n");
exit(2);
}
creation_res = GC_pthread_create(&t, &attr, entry, NULL);
(void)pthread_attr_destroy(&attr);
if (res == GC_SUCCESS)
GC_unregister_my_thread ();
return arg ? (void*)(GC_word)creation_res : 0;
}
void on_thread_exit (void *v)
{
GC_call_with_stack_base (on_thread_exit_inner, v);
}
void make_key (void)
{
pthread_key_create (&key, on_thread_exit);
}
#ifndef NTHREADS
# define NTHREADS 30 /* number of initial threads */
#endif
int main (void)
{
int i;
GC_INIT ();
# ifdef GC_SOLARIS_THREADS
pthread_key_create (&key, on_thread_exit);
# else
pthread_once (&key_once, make_key);
# endif
for (i = 0; i < NTHREADS; i++) {
pthread_t t;
if (GC_pthread_create(&t, NULL, entry, NULL) == 0) {
void *res;
int code = (i & 1) != 0 ? GC_pthread_join(t, &res)
: GC_pthread_detach(t);
if (code != 0) {
fprintf(stderr, "Thread %s failed %d\n",
(i & 1) != 0 ? "join" : "detach", code);
exit(2);
}
}
}
return 0;
}
#endif /* !SKIP_THREADKEY_TEST */

43
external/bdwgc/tests/trace_test.c vendored Normal file
View File

@@ -0,0 +1,43 @@
#include <stdio.h>
#include <stdlib.h>
#ifndef GC_DEBUG
# define GC_DEBUG
#endif
#include "gc.h"
#include "gc_backptr.h"
struct treenode {
struct treenode *x;
struct treenode *y;
} * root[10];
struct treenode * mktree(int i) {
struct treenode * r = GC_NEW(struct treenode);
if (0 == i)
return 0;
if (1 == i)
r = (struct treenode *)GC_MALLOC_ATOMIC(sizeof(struct treenode));
if (r == NULL) {
fprintf(stderr, "Out of memory\n");
exit(1);
}
r -> x = mktree(i-1);
r -> y = mktree(i-1);
return r;
}
int main(void)
{
int i;
GC_INIT();
for (i = 0; i < 10; ++i) {
root[i] = mktree(12);
}
GC_generate_random_backtrace();
GC_generate_random_backtrace();
GC_generate_random_backtrace();
GC_generate_random_backtrace();
return 0;
}