Add mq (message queue) to test infrastructure.
Add mtx (mutex) to test infrastructure, in order to avoid bootstrapping complications that would result from directly using malloc_mutex. Rename test infrastructure's thread abstraction from je_thread to thd. Fix some header ordering issues.
This commit is contained in:
parent
19609724f9
commit
0f4f1efd94
@ -103,10 +103,12 @@ DOCS_XML := $(objroot)doc/jemalloc$(install_suffix).xml
|
|||||||
DOCS_HTML := $(DOCS_XML:$(objroot)%.xml=$(srcroot)%.html)
|
DOCS_HTML := $(DOCS_XML:$(objroot)%.xml=$(srcroot)%.html)
|
||||||
DOCS_MAN3 := $(DOCS_XML:$(objroot)%.xml=$(srcroot)%.3)
|
DOCS_MAN3 := $(DOCS_XML:$(objroot)%.xml=$(srcroot)%.3)
|
||||||
DOCS := $(DOCS_HTML) $(DOCS_MAN3)
|
DOCS := $(DOCS_HTML) $(DOCS_MAN3)
|
||||||
C_TESTLIB_SRCS := $(srcroot)test/src/math.c $(srcroot)test/src/SFMT.c \
|
C_TESTLIB_SRCS := $(srcroot)test/src/math.c $(srcroot)test/src/mtx.c \
|
||||||
$(srcroot)test/src/test.c $(srcroot)test/src/thread.c
|
$(srcroot)test/src/SFMT.c $(srcroot)test/src/test.c \
|
||||||
|
$(srcroot)test/src/thd.c
|
||||||
C_UTIL_INTEGRATION_SRCS := $(srcroot)src/util.c
|
C_UTIL_INTEGRATION_SRCS := $(srcroot)src/util.c
|
||||||
TESTS_UNIT := $(srcroot)test/unit/bitmap.c $(srcroot)test/unit/math.c \
|
TESTS_UNIT := $(srcroot)test/unit/bitmap.c $(srcroot)test/unit/math.c \
|
||||||
|
$(srcroot)test/unit/mq.c $(srcroot)test/unit/mtx.c \
|
||||||
$(srcroot)test/unit/SFMT.c $(srcroot)test/unit/tsd.c
|
$(srcroot)test/unit/SFMT.c $(srcroot)test/unit/tsd.c
|
||||||
TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \
|
TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \
|
||||||
$(srcroot)test/integration/allocated.c \
|
$(srcroot)test/integration/allocated.c \
|
||||||
|
@ -43,14 +43,14 @@ JEMALLOC_INLINE uint32_t
|
|||||||
hash_get_block_32(const uint32_t *p, int i)
|
hash_get_block_32(const uint32_t *p, int i)
|
||||||
{
|
{
|
||||||
|
|
||||||
return p[i];
|
return (p[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_INLINE uint64_t
|
JEMALLOC_INLINE uint64_t
|
||||||
hash_get_block_64(const uint64_t *p, int i)
|
hash_get_block_64(const uint64_t *p, int i)
|
||||||
{
|
{
|
||||||
|
|
||||||
return p[i];
|
return (p[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_INLINE uint32_t
|
JEMALLOC_INLINE uint32_t
|
||||||
@ -63,7 +63,7 @@ hash_fmix_32(uint32_t h)
|
|||||||
h *= 0xc2b2ae35;
|
h *= 0xc2b2ae35;
|
||||||
h ^= h >> 16;
|
h ^= h >> 16;
|
||||||
|
|
||||||
return h;
|
return (h);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_INLINE uint64_t
|
JEMALLOC_INLINE uint64_t
|
||||||
@ -76,7 +76,7 @@ hash_fmix_64(uint64_t k)
|
|||||||
k *= QU(0xc4ceb9fe1a85ec53LLU);
|
k *= QU(0xc4ceb9fe1a85ec53LLU);
|
||||||
k ^= k >> 33;
|
k ^= k >> 33;
|
||||||
|
|
||||||
return k;
|
return (k);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_INLINE uint32_t
|
JEMALLOC_INLINE uint32_t
|
||||||
@ -127,7 +127,7 @@ hash_x86_32(const void *key, int len, uint32_t seed)
|
|||||||
|
|
||||||
h1 = hash_fmix_32(h1);
|
h1 = hash_fmix_32(h1);
|
||||||
|
|
||||||
return h1;
|
return (h1);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNUSED JEMALLOC_INLINE void
|
UNUSED JEMALLOC_INLINE void
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#ifndef JEMALLOC_INTERNAL_DEFS_H_
|
||||||
|
#define JEMALLOC_INTERNAL_DEFS_H_
|
||||||
/*
|
/*
|
||||||
* If JEMALLOC_PREFIX is defined via --with-jemalloc-prefix, it will cause all
|
* If JEMALLOC_PREFIX is defined via --with-jemalloc-prefix, it will cause all
|
||||||
* public APIs to be prefixed. This makes it possible, with some care, to use
|
* public APIs to be prefixed. This makes it possible, with some care, to use
|
||||||
@ -193,3 +195,5 @@
|
|||||||
|
|
||||||
/* sizeof(intmax_t) == 2^LG_SIZEOF_INTMAX_T. */
|
/* sizeof(intmax_t) == 2^LG_SIZEOF_INTMAX_T. */
|
||||||
#undef LG_SIZEOF_INTMAX_T
|
#undef LG_SIZEOF_INTMAX_T
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_INTERNAL_DEFS_H_ */
|
||||||
|
@ -348,7 +348,7 @@ a_name##_tsd_get_wrapper(void) \
|
|||||||
wrapper = tsd_init_check_recursion( \
|
wrapper = tsd_init_check_recursion( \
|
||||||
&a_name##_tsd_init_head, &block); \
|
&a_name##_tsd_init_head, &block); \
|
||||||
if (wrapper) \
|
if (wrapper) \
|
||||||
return wrapper; \
|
return (wrapper); \
|
||||||
wrapper = (a_name##_tsd_wrapper_t *) \
|
wrapper = (a_name##_tsd_wrapper_t *) \
|
||||||
malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \
|
malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \
|
||||||
block.data = wrapper; \
|
block.data = wrapper; \
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <errno.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
@ -45,6 +47,10 @@
|
|||||||
|
|
||||||
#include "test/jemalloc_test_defs.h"
|
#include "test/jemalloc_test_defs.h"
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_OSSPIN
|
||||||
|
# include <libkern/OSAtomic.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_ALTIVEC) && !defined(__APPLE__)
|
#if defined(HAVE_ALTIVEC) && !defined(__APPLE__)
|
||||||
# include <altivec.h>
|
# include <altivec.h>
|
||||||
#endif
|
#endif
|
||||||
@ -75,13 +81,13 @@
|
|||||||
# define JEMALLOC_N(n) @private_namespace@##n
|
# define JEMALLOC_N(n) @private_namespace@##n
|
||||||
# include "jemalloc/internal/private_namespace.h"
|
# include "jemalloc/internal/private_namespace.h"
|
||||||
|
|
||||||
# include <stdarg.h>
|
|
||||||
# include <errno.h>
|
|
||||||
# define JEMALLOC_H_TYPES
|
# define JEMALLOC_H_TYPES
|
||||||
# define JEMALLOC_H_STRUCTS
|
# define JEMALLOC_H_STRUCTS
|
||||||
# define JEMALLOC_H_EXTERNS
|
# define JEMALLOC_H_EXTERNS
|
||||||
# define JEMALLOC_H_INLINES
|
# define JEMALLOC_H_INLINES
|
||||||
# include "jemalloc/internal/util.h"
|
# include "jemalloc/internal/util.h"
|
||||||
|
# include "jemalloc/internal/qr.h"
|
||||||
|
# include "jemalloc/internal/ql.h"
|
||||||
# undef JEMALLOC_H_TYPES
|
# undef JEMALLOC_H_TYPES
|
||||||
# undef JEMALLOC_H_STRUCTS
|
# undef JEMALLOC_H_STRUCTS
|
||||||
# undef JEMALLOC_H_EXTERNS
|
# undef JEMALLOC_H_EXTERNS
|
||||||
@ -124,7 +130,9 @@
|
|||||||
* Common test utilities.
|
* Common test utilities.
|
||||||
*/
|
*/
|
||||||
#include "test/math.h"
|
#include "test/math.h"
|
||||||
|
#include "test/mtx.h"
|
||||||
|
#include "test/mq.h"
|
||||||
#include "test/test.h"
|
#include "test/test.h"
|
||||||
#include "test/thread.h"
|
#include "test/thd.h"
|
||||||
#define MEXP 19937
|
#define MEXP 19937
|
||||||
#include "test/SFMT.h"
|
#include "test/SFMT.h"
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#include "jemalloc/internal/jemalloc_internal_defs.h"
|
||||||
|
|
||||||
/* For use by SFMT. */
|
/* For use by SFMT. */
|
||||||
#undef HAVE_SSE2
|
#undef HAVE_SSE2
|
||||||
#undef HAVE_ALTIVEC
|
#undef HAVE_ALTIVEC
|
||||||
|
110
test/include/test/mq.h
Normal file
110
test/include/test/mq.h
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Simple templated message queue implementation that relies on only mutexes for
|
||||||
|
* synchronization (which reduces portability issues). Given the following
|
||||||
|
* setup:
|
||||||
|
*
|
||||||
|
* typedef struct mq_msg_s mq_msg_t;
|
||||||
|
* struct mq_msg_s {
|
||||||
|
* mq_msg(mq_msg_t) link;
|
||||||
|
* [message data]
|
||||||
|
* };
|
||||||
|
* mq_gen(, mq_, mq_t, mq_msg_t, link)
|
||||||
|
*
|
||||||
|
* The API is as follows:
|
||||||
|
*
|
||||||
|
* bool mq_init(mq_t *mq);
|
||||||
|
* void mq_fini(mq_t *mq);
|
||||||
|
* unsigned mq_count(mq_t *mq);
|
||||||
|
* mq_msg_t *mq_tryget(mq_t *mq);
|
||||||
|
* mq_msg_t *mq_get(mq_t *mq);
|
||||||
|
* void mq_put(mq_t *mq, mq_msg_t *msg);
|
||||||
|
*
|
||||||
|
* The message queue linkage embedded in each message is to be treated as
|
||||||
|
* externally opaque (no need to initialize or clean up externally). mq_fini()
|
||||||
|
* does not perform any cleanup of messages, since it knows nothing of their
|
||||||
|
* payloads.
|
||||||
|
*/
|
||||||
|
#define mq_msg(a_mq_msg_type) ql_elm(a_mq_msg_type)
|
||||||
|
|
||||||
|
#define mq_gen(a_attr, a_prefix, a_mq_type, a_mq_msg_type, a_field) \
|
||||||
|
typedef struct { \
|
||||||
|
mtx_t lock; \
|
||||||
|
ql_head(a_mq_msg_type) msgs; \
|
||||||
|
unsigned count; \
|
||||||
|
} a_mq_type; \
|
||||||
|
a_attr bool \
|
||||||
|
a_prefix##init(a_mq_type *mq) { \
|
||||||
|
\
|
||||||
|
if (mtx_init(&mq->lock)) \
|
||||||
|
return (true); \
|
||||||
|
ql_new(&mq->msgs); \
|
||||||
|
mq->count = 0; \
|
||||||
|
return (false); \
|
||||||
|
} \
|
||||||
|
a_attr void \
|
||||||
|
a_prefix##fini(a_mq_type *mq) \
|
||||||
|
{ \
|
||||||
|
\
|
||||||
|
mtx_fini(&mq->lock); \
|
||||||
|
} \
|
||||||
|
a_attr unsigned \
|
||||||
|
a_prefix##count(a_mq_type *mq) \
|
||||||
|
{ \
|
||||||
|
unsigned count; \
|
||||||
|
\
|
||||||
|
mtx_lock(&mq->lock); \
|
||||||
|
count = mq->count; \
|
||||||
|
mtx_unlock(&mq->lock); \
|
||||||
|
return (count); \
|
||||||
|
} \
|
||||||
|
a_attr a_mq_msg_type * \
|
||||||
|
a_prefix##tryget(a_mq_type *mq) \
|
||||||
|
{ \
|
||||||
|
a_mq_msg_type *msg; \
|
||||||
|
\
|
||||||
|
mtx_lock(&mq->lock); \
|
||||||
|
msg = ql_first(&mq->msgs); \
|
||||||
|
if (msg != NULL) { \
|
||||||
|
ql_head_remove(&mq->msgs, a_mq_msg_type, a_field); \
|
||||||
|
mq->count--; \
|
||||||
|
} \
|
||||||
|
mtx_unlock(&mq->lock); \
|
||||||
|
return (msg); \
|
||||||
|
} \
|
||||||
|
a_attr a_mq_msg_type * \
|
||||||
|
a_prefix##get(a_mq_type *mq) \
|
||||||
|
{ \
|
||||||
|
a_mq_msg_type *msg; \
|
||||||
|
struct timespec timeout; \
|
||||||
|
\
|
||||||
|
msg = a_prefix##tryget(mq); \
|
||||||
|
if (msg != NULL) \
|
||||||
|
return (msg); \
|
||||||
|
\
|
||||||
|
timeout.tv_sec = 0; \
|
||||||
|
timeout.tv_nsec = 1; \
|
||||||
|
while (true) { \
|
||||||
|
nanosleep(&timeout, NULL); \
|
||||||
|
msg = a_prefix##tryget(mq); \
|
||||||
|
if (msg != NULL) \
|
||||||
|
return (msg); \
|
||||||
|
if (timeout.tv_sec == 0) { \
|
||||||
|
/* Double sleep time, up to max 1 second. */ \
|
||||||
|
timeout.tv_nsec <<= 1; \
|
||||||
|
if (timeout.tv_nsec >= 1000*1000*1000) { \
|
||||||
|
timeout.tv_sec = 1; \
|
||||||
|
timeout.tv_nsec = 0; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
a_attr void \
|
||||||
|
a_prefix##put(a_mq_type *mq, a_mq_msg_type *msg) \
|
||||||
|
{ \
|
||||||
|
\
|
||||||
|
mtx_lock(&mq->lock); \
|
||||||
|
ql_elm_new(msg, a_field); \
|
||||||
|
ql_tail_insert(&mq->msgs, msg, a_field); \
|
||||||
|
mq->count++; \
|
||||||
|
mtx_unlock(&mq->lock); \
|
||||||
|
}
|
21
test/include/test/mtx.h
Normal file
21
test/include/test/mtx.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* mtx is a slightly simplified version of malloc_mutex. This code duplication
|
||||||
|
* is unfortunate, but there are allocator bootstrapping considerations that
|
||||||
|
* would leak into the test infrastructure if malloc_mutex were used directly
|
||||||
|
* in tests.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
#ifdef _WIN32
|
||||||
|
CRITICAL_SECTION lock;
|
||||||
|
#elif (defined(JEMALLOC_OSSPIN))
|
||||||
|
OSSpinLock lock;
|
||||||
|
#else
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
#endif
|
||||||
|
} mtx_t;
|
||||||
|
|
||||||
|
bool mtx_init(mtx_t *mtx);
|
||||||
|
void mtx_fini(mtx_t *mtx);
|
||||||
|
void mtx_lock(mtx_t *mtx);
|
||||||
|
void mtx_unlock(mtx_t *mtx);
|
9
test/include/test/thd.h
Normal file
9
test/include/test/thd.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/* Abstraction layer for threading in tests */
|
||||||
|
#ifdef _WIN32
|
||||||
|
typedef HANDLE thd_t;
|
||||||
|
#else
|
||||||
|
typedef pthread_t thd_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void thd_create(thd_t *thd, void *(*proc)(void *), void *arg);
|
||||||
|
void thd_join(thd_t thd, void **ret);
|
@ -1,9 +0,0 @@
|
|||||||
/* Abstraction layer for threading in tests */
|
|
||||||
#ifdef _WIN32
|
|
||||||
typedef HANDLE je_thread_t;
|
|
||||||
#else
|
|
||||||
typedef pthread_t je_thread_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void je_thread_create(je_thread_t *thread, void *(*proc)(void *), void *arg);
|
|
||||||
void je_thread_join(je_thread_t thread, void **ret);
|
|
@ -3,7 +3,7 @@
|
|||||||
#define NTHREADS 10
|
#define NTHREADS 10
|
||||||
|
|
||||||
void *
|
void *
|
||||||
je_thread_start(void *arg)
|
thd_start(void *arg)
|
||||||
{
|
{
|
||||||
unsigned thread_ind = (unsigned)(uintptr_t)arg;
|
unsigned thread_ind = (unsigned)(uintptr_t)arg;
|
||||||
unsigned arena_ind;
|
unsigned arena_ind;
|
||||||
@ -36,16 +36,16 @@ je_thread_start(void *arg)
|
|||||||
|
|
||||||
TEST_BEGIN(test_ALLOCM_ARENA)
|
TEST_BEGIN(test_ALLOCM_ARENA)
|
||||||
{
|
{
|
||||||
je_thread_t threads[NTHREADS];
|
thd_t thds[NTHREADS];
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
for (i = 0; i < NTHREADS; i++) {
|
for (i = 0; i < NTHREADS; i++) {
|
||||||
je_thread_create(&threads[i], je_thread_start,
|
thd_create(&thds[i], thd_start,
|
||||||
(void *)(uintptr_t)i);
|
(void *)(uintptr_t)i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < NTHREADS; i++)
|
for (i = 0; i < NTHREADS; i++)
|
||||||
je_thread_join(threads[i], NULL);
|
thd_join(thds[i], NULL);
|
||||||
}
|
}
|
||||||
TEST_END
|
TEST_END
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ static const bool config_stats =
|
|||||||
;
|
;
|
||||||
|
|
||||||
void *
|
void *
|
||||||
je_thread_start(void *arg)
|
thd_start(void *arg)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
void *p;
|
void *p;
|
||||||
@ -98,16 +98,16 @@ label_ENOENT:
|
|||||||
TEST_BEGIN(test_main_thread)
|
TEST_BEGIN(test_main_thread)
|
||||||
{
|
{
|
||||||
|
|
||||||
je_thread_start(NULL);
|
thd_start(NULL);
|
||||||
}
|
}
|
||||||
TEST_END
|
TEST_END
|
||||||
|
|
||||||
TEST_BEGIN(test_subthread)
|
TEST_BEGIN(test_subthread)
|
||||||
{
|
{
|
||||||
je_thread_t thread;
|
thd_t thd;
|
||||||
|
|
||||||
je_thread_create(&thread, je_thread_start, NULL);
|
thd_create(&thd, thd_start, NULL);
|
||||||
je_thread_join(thread, NULL);
|
thd_join(thd, NULL);
|
||||||
}
|
}
|
||||||
TEST_END
|
TEST_END
|
||||||
|
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* This header should be included by tests, rather than directly including
|
|
||||||
* jemalloc/jemalloc.h, because --with-install-suffix may cause the header to
|
|
||||||
* have a different name.
|
|
||||||
*/
|
|
||||||
#include "jemalloc/jemalloc@install_suffix@.h"
|
|
||||||
#include "jemalloc/internal/jemalloc_internal.h"
|
|
||||||
|
|
||||||
/* Abstraction layer for threading in tests. */
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
typedef HANDLE je_thread_t;
|
|
||||||
|
|
||||||
void
|
|
||||||
je_thread_create(je_thread_t *thread, void *(*proc)(void *), void *arg)
|
|
||||||
{
|
|
||||||
LPTHREAD_START_ROUTINE routine = (LPTHREAD_START_ROUTINE)proc;
|
|
||||||
*thread = CreateThread(NULL, 0, routine, arg, 0, NULL);
|
|
||||||
if (*thread == NULL)
|
|
||||||
test_fail("Error in CreateThread()\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
je_thread_join(je_thread_t thread, void **ret)
|
|
||||||
{
|
|
||||||
|
|
||||||
WaitForSingleObject(thread, INFINITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
typedef pthread_t je_thread_t;
|
|
||||||
|
|
||||||
void
|
|
||||||
je_thread_create(je_thread_t *thread, void *(*proc)(void *), void *arg)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (pthread_create(thread, NULL, proc, arg) != 0)
|
|
||||||
test_fail("Error in pthread_create()\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
je_thread_join(je_thread_t thread, void **ret)
|
|
||||||
{
|
|
||||||
|
|
||||||
pthread_join(thread, ret);
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -3,7 +3,7 @@
|
|||||||
#define NTHREADS 10
|
#define NTHREADS 10
|
||||||
|
|
||||||
void *
|
void *
|
||||||
je_thread_start(void *arg)
|
thd_start(void *arg)
|
||||||
{
|
{
|
||||||
unsigned main_arena_ind = *(unsigned *)arg;
|
unsigned main_arena_ind = *(unsigned *)arg;
|
||||||
void *p;
|
void *p;
|
||||||
@ -43,7 +43,7 @@ TEST_BEGIN(test_thread_arena)
|
|||||||
unsigned arena_ind;
|
unsigned arena_ind;
|
||||||
size_t size;
|
size_t size;
|
||||||
int err;
|
int err;
|
||||||
je_thread_t threads[NTHREADS];
|
thd_t thds[NTHREADS];
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
p = malloc(1);
|
p = malloc(1);
|
||||||
@ -58,13 +58,13 @@ TEST_BEGIN(test_thread_arena)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < NTHREADS; i++) {
|
for (i = 0; i < NTHREADS; i++) {
|
||||||
je_thread_create(&threads[i], je_thread_start,
|
thd_create(&thds[i], thd_start,
|
||||||
(void *)&arena_ind);
|
(void *)&arena_ind);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < NTHREADS; i++) {
|
for (i = 0; i < NTHREADS; i++) {
|
||||||
intptr_t join_ret;
|
intptr_t join_ret;
|
||||||
je_thread_join(threads[i], (void *)&join_ret);
|
thd_join(thds[i], (void *)&join_ret);
|
||||||
assert_zd_eq(join_ret, 0, "Unexpected thread join error");
|
assert_zd_eq(join_ret, 0, "Unexpected thread join error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ static const bool config_tcache =
|
|||||||
;
|
;
|
||||||
|
|
||||||
void *
|
void *
|
||||||
je_thread_start(void *arg)
|
thd_start(void *arg)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
size_t sz;
|
size_t sz;
|
||||||
@ -86,16 +86,16 @@ label_ENOENT:
|
|||||||
TEST_BEGIN(test_main_thread)
|
TEST_BEGIN(test_main_thread)
|
||||||
{
|
{
|
||||||
|
|
||||||
je_thread_start(NULL);
|
thd_start(NULL);
|
||||||
}
|
}
|
||||||
TEST_END
|
TEST_END
|
||||||
|
|
||||||
TEST_BEGIN(test_subthread)
|
TEST_BEGIN(test_subthread)
|
||||||
{
|
{
|
||||||
je_thread_t thread;
|
thd_t thd;
|
||||||
|
|
||||||
je_thread_create(&thread, je_thread_start, NULL);
|
thd_create(&thd, thd_start, NULL);
|
||||||
je_thread_join(thread, NULL);
|
thd_join(thd, NULL);
|
||||||
}
|
}
|
||||||
TEST_END
|
TEST_END
|
||||||
|
|
||||||
|
62
test/src/mtx.c
Normal file
62
test/src/mtx.c
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#include "test/jemalloc_test.h"
|
||||||
|
|
||||||
|
bool
|
||||||
|
mtx_init(mtx_t *mtx)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (!InitializeCriticalSectionAndSpinCount(&mtx->lock, _CRT_SPINCOUNT))
|
||||||
|
return (true);
|
||||||
|
#elif (defined(JEMALLOC_OSSPIN))
|
||||||
|
mtx->lock = 0;
|
||||||
|
#else
|
||||||
|
pthread_mutexattr_t attr;
|
||||||
|
|
||||||
|
if (pthread_mutexattr_init(&attr) != 0)
|
||||||
|
return (true);
|
||||||
|
pthread_mutexattr_settype(&attr, MALLOC_MUTEX_TYPE);
|
||||||
|
if (pthread_mutex_init(&mtx->lock, &attr) != 0) {
|
||||||
|
pthread_mutexattr_destroy(&attr);
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
pthread_mutexattr_destroy(&attr);
|
||||||
|
#endif
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mtx_fini(mtx_t *mtx)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#elif (defined(JEMALLOC_OSSPIN))
|
||||||
|
#else
|
||||||
|
pthread_mutex_destroy(&mtx->lock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mtx_lock(mtx_t *mtx)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
EnterCriticalSection(&mtx->lock);
|
||||||
|
#elif (defined(JEMALLOC_OSSPIN))
|
||||||
|
OSSpinLockLock(&mtx->lock);
|
||||||
|
#else
|
||||||
|
pthread_mutex_lock(&mtx->lock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mtx_unlock(mtx_t *mtx)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
LeaveCriticalSection(&mtx->lock);
|
||||||
|
#elif (defined(JEMALLOC_OSSPIN))
|
||||||
|
OSSpinLockUnlock(&mtx->lock);
|
||||||
|
#else
|
||||||
|
pthread_mutex_unlock(&mtx->lock);
|
||||||
|
#endif
|
||||||
|
}
|
35
test/src/thd.c
Normal file
35
test/src/thd.c
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include "test/jemalloc_test.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
void
|
||||||
|
thd_create(thd_t *thd, void *(*proc)(void *), void *arg)
|
||||||
|
{
|
||||||
|
LPTHREAD_START_ROUTINE routine = (LPTHREAD_START_ROUTINE)proc;
|
||||||
|
*thd = CreateThread(NULL, 0, routine, arg, 0, NULL);
|
||||||
|
if (*thd == NULL)
|
||||||
|
test_fail("Error in CreateThread()\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
thd_join(thd_t thd, void **ret)
|
||||||
|
{
|
||||||
|
|
||||||
|
WaitForSingleObject(thd, INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
void
|
||||||
|
thd_create(thd_t *thd, void *(*proc)(void *), void *arg)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (pthread_create(thd, NULL, proc, arg) != 0)
|
||||||
|
test_fail("Error in pthread_create()\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
thd_join(thd_t thd, void **ret)
|
||||||
|
{
|
||||||
|
|
||||||
|
pthread_join(thd, ret);
|
||||||
|
}
|
||||||
|
#endif
|
@ -1,35 +0,0 @@
|
|||||||
#include "test/jemalloc_test.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
void
|
|
||||||
je_thread_create(je_thread_t *thread, void *(*proc)(void *), void *arg)
|
|
||||||
{
|
|
||||||
LPTHREAD_START_ROUTINE routine = (LPTHREAD_START_ROUTINE)proc;
|
|
||||||
*thread = CreateThread(NULL, 0, routine, arg, 0, NULL);
|
|
||||||
if (*thread == NULL)
|
|
||||||
test_fail("Error in CreateThread()\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
je_thread_join(je_thread_t thread, void **ret)
|
|
||||||
{
|
|
||||||
|
|
||||||
WaitForSingleObject(thread, INFINITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
void
|
|
||||||
je_thread_create(je_thread_t *thread, void *(*proc)(void *), void *arg)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (pthread_create(thread, NULL, proc, arg) != 0)
|
|
||||||
test_fail("Error in pthread_create()\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
je_thread_join(je_thread_t thread, void **ret)
|
|
||||||
{
|
|
||||||
|
|
||||||
pthread_join(thread, ret);
|
|
||||||
}
|
|
||||||
#endif
|
|
91
test/unit/mq.c
Normal file
91
test/unit/mq.c
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#include "test/jemalloc_test.h"
|
||||||
|
|
||||||
|
#define NSENDERS 3
|
||||||
|
#define NMSGS 100000
|
||||||
|
|
||||||
|
typedef struct mq_msg_s mq_msg_t;
|
||||||
|
struct mq_msg_s {
|
||||||
|
mq_msg(mq_msg_t) link;
|
||||||
|
};
|
||||||
|
mq_gen(static, mq_, mq_t, mq_msg_t, link)
|
||||||
|
|
||||||
|
TEST_BEGIN(test_mq_basic)
|
||||||
|
{
|
||||||
|
mq_t mq;
|
||||||
|
mq_msg_t msg;
|
||||||
|
|
||||||
|
assert_false(mq_init(&mq), "Unexpected mq_init() failure");
|
||||||
|
assert_u_eq(mq_count(&mq), 0, "mq should be empty");
|
||||||
|
assert_ptr_null(mq_tryget(&mq),
|
||||||
|
"mq_tryget() should fail when the queue is empty");
|
||||||
|
|
||||||
|
mq_put(&mq, &msg);
|
||||||
|
assert_u_eq(mq_count(&mq), 1, "mq should contain one message");
|
||||||
|
assert_ptr_eq(mq_tryget(&mq), &msg, "mq_tryget() should return msg");
|
||||||
|
|
||||||
|
mq_put(&mq, &msg);
|
||||||
|
assert_ptr_eq(mq_get(&mq), &msg, "mq_get() should return msg");
|
||||||
|
|
||||||
|
mq_fini(&mq);
|
||||||
|
}
|
||||||
|
TEST_END
|
||||||
|
|
||||||
|
static void *
|
||||||
|
thd_receiver_start(void *arg)
|
||||||
|
{
|
||||||
|
mq_t *mq = (mq_t *)arg;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (i = 0; i < (NSENDERS * NMSGS); i++) {
|
||||||
|
mq_msg_t *msg = mq_get(mq);
|
||||||
|
assert_ptr_not_null(msg, "mq_get() should never return NULL");
|
||||||
|
assert_d_eq(jet_dallocm(msg, 0), ALLOCM_SUCCESS,
|
||||||
|
"Unexpected dallocm() failure");
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
thd_sender_start(void *arg)
|
||||||
|
{
|
||||||
|
mq_t *mq = (mq_t *)arg;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (i = 0; i < NMSGS; i++) {
|
||||||
|
mq_msg_t *msg;
|
||||||
|
assert_d_eq(jet_allocm((void **)&msg, NULL, sizeof(mq_msg_t),
|
||||||
|
0), ALLOCM_SUCCESS, "Unexpected allocm() failure");
|
||||||
|
mq_put(mq, msg);
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_BEGIN(test_mq_threaded)
|
||||||
|
{
|
||||||
|
mq_t mq;
|
||||||
|
thd_t receiver;
|
||||||
|
thd_t senders[NSENDERS];
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
assert_false(mq_init(&mq), "Unexpected mq_init() failure");
|
||||||
|
|
||||||
|
thd_create(&receiver, thd_receiver_start, (void *)&mq);
|
||||||
|
for (i = 0; i < NSENDERS; i++)
|
||||||
|
thd_create(&senders[i], thd_sender_start, (void *)&mq);
|
||||||
|
|
||||||
|
thd_join(receiver, NULL);
|
||||||
|
for (i = 0; i < NSENDERS; i++)
|
||||||
|
thd_join(senders[i], NULL);
|
||||||
|
|
||||||
|
mq_fini(&mq);
|
||||||
|
}
|
||||||
|
TEST_END
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
return (test(
|
||||||
|
test_mq_basic,
|
||||||
|
test_mq_threaded));
|
||||||
|
}
|
||||||
|
|
60
test/unit/mtx.c
Normal file
60
test/unit/mtx.c
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#include "test/jemalloc_test.h"
|
||||||
|
|
||||||
|
#define NTHREADS 2
|
||||||
|
#define NINCRS 2000000
|
||||||
|
|
||||||
|
TEST_BEGIN(test_mtx_basic)
|
||||||
|
{
|
||||||
|
mtx_t mtx;
|
||||||
|
|
||||||
|
assert_false(mtx_init(&mtx), "Unexpected mtx_init() failure");
|
||||||
|
mtx_lock(&mtx);
|
||||||
|
mtx_unlock(&mtx);
|
||||||
|
mtx_fini(&mtx);
|
||||||
|
}
|
||||||
|
TEST_END
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
mtx_t mtx;
|
||||||
|
unsigned x;
|
||||||
|
} thd_start_arg_t;
|
||||||
|
|
||||||
|
static void *
|
||||||
|
thd_start(void *varg)
|
||||||
|
{
|
||||||
|
thd_start_arg_t *arg = (thd_start_arg_t *)varg;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (i = 0; i < NINCRS; i++) {
|
||||||
|
mtx_lock(&arg->mtx);
|
||||||
|
arg->x++;
|
||||||
|
mtx_unlock(&arg->mtx);
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_BEGIN(test_mtx_race)
|
||||||
|
{
|
||||||
|
thd_start_arg_t arg;
|
||||||
|
thd_t thds[NTHREADS];
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
assert_false(mtx_init(&arg.mtx), "Unexpected mtx_init() failure");
|
||||||
|
arg.x = 0;
|
||||||
|
for (i = 0; i < NTHREADS; i++)
|
||||||
|
thd_create(&thds[i], thd_start, (void *)&arg);
|
||||||
|
for (i = 0; i < NTHREADS; i++)
|
||||||
|
thd_join(thds[i], NULL);
|
||||||
|
assert_u_eq(arg.x, NTHREADS * NINCRS,
|
||||||
|
"Race-related counter corruption");
|
||||||
|
}
|
||||||
|
TEST_END
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (test(
|
||||||
|
test_mtx_basic,
|
||||||
|
test_mtx_race));
|
||||||
|
}
|
@ -22,8 +22,8 @@ malloc_tsd_externs(data, data_t)
|
|||||||
malloc_tsd_data(, data, data_t, DATA_INIT)
|
malloc_tsd_data(, data, data_t, DATA_INIT)
|
||||||
malloc_tsd_funcs(, data, data_t, DATA_INIT, data_cleanup)
|
malloc_tsd_funcs(, data, data_t, DATA_INIT, data_cleanup)
|
||||||
|
|
||||||
void *
|
static void *
|
||||||
je_thread_start(void *arg)
|
thd_start(void *arg)
|
||||||
{
|
{
|
||||||
data_t d = (data_t)(uintptr_t)arg;
|
data_t d = (data_t)(uintptr_t)arg;
|
||||||
assert_x_eq(*data_tsd_get(), DATA_INIT,
|
assert_x_eq(*data_tsd_get(), DATA_INIT,
|
||||||
@ -37,23 +37,23 @@ je_thread_start(void *arg)
|
|||||||
assert_x_eq(*data_tsd_get(), (data_t)(uintptr_t)arg,
|
assert_x_eq(*data_tsd_get(), (data_t)(uintptr_t)arg,
|
||||||
"Resetting local data should have no effect on tsd");
|
"Resetting local data should have no effect on tsd");
|
||||||
|
|
||||||
return NULL;
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_BEGIN(test_tsd_main_thread)
|
TEST_BEGIN(test_tsd_main_thread)
|
||||||
{
|
{
|
||||||
|
|
||||||
je_thread_start((void *) 0xa5f3e329);
|
thd_start((void *) 0xa5f3e329);
|
||||||
}
|
}
|
||||||
TEST_END
|
TEST_END
|
||||||
|
|
||||||
TEST_BEGIN(test_tsd_sub_thread)
|
TEST_BEGIN(test_tsd_sub_thread)
|
||||||
{
|
{
|
||||||
je_thread_t thread;
|
thd_t thd;
|
||||||
|
|
||||||
data_cleanup_executed = false;
|
data_cleanup_executed = false;
|
||||||
je_thread_create(&thread, je_thread_start, (void *) THREAD_DATA);
|
thd_create(&thd, thd_start, (void *)THREAD_DATA);
|
||||||
je_thread_join(thread, NULL);
|
thd_join(thd, NULL);
|
||||||
assert_true(data_cleanup_executed,
|
assert_true(data_cleanup_executed,
|
||||||
"Cleanup function should have executed");
|
"Cleanup function should have executed");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user