Skip to content

Commit fae9aa5

Browse files
committed
Add tests for MSVC multi-threading
... and fix some MSVC related (and other) things. Signed-off-by: Steffen Jaeckel <[email protected]>
1 parent 98655a8 commit fae9aa5

File tree

7 files changed

+101
-19
lines changed

7 files changed

+101
-19
lines changed

appveyor.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,17 @@ build_script:
1818
if "Visual Studio 2017"=="%APPVEYOR_BUILD_WORKER_IMAGE%" call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
1919
if "Visual Studio 2015"=="%APPVEYOR_BUILD_WORKER_IMAGE%" call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64
2020
if "Visual Studio 2015"=="%APPVEYOR_BUILD_WORKER_IMAGE%" call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64
21+
nmake -f makefile.msvc test.exe CFLAGS="/Ox /Oi /DMP_SMALL_STACK_SIZE"
22+
copy /Y test.exe test_small_stack.exe
23+
nmake -f makefile.msvc clean-obj
24+
nmake -f makefile.msvc test.exe CFLAGS="/Ox /Oi /DMP_SMALL_STACK_SIZE /DLTM_TEST_MULTITHREAD"
25+
copy /Y test.exe test_small_stack_multithreaded.exe
26+
nmake -f makefile.msvc clean-obj
2127
nmake -f makefile.msvc test.exe
2228
nmake -f makefile.msvc clean-obj
23-
nmake -f makefile.msvc test_dll.exe CFLAGS="/Ox /MD /DLTM_TEST_DYNAMIC"
29+
nmake -f makefile.msvc test_dll.exe CFLAGS="/Ox /Oi /MD /DLTM_TEST_DYNAMIC"
2430
test_script:
31+
- cmd: test_small_stack.exe
32+
- cmd: test_small_stack_multithreaded.exe
2533
- cmd: test.exe
2634
- cmd: test_dll.exe

demo/test.c

Lines changed: 75 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2455,14 +2455,40 @@ static int test_mp_pack_unpack(void)
24552455
#define ONLY_PUBLIC_API_C
24562456
#endif
24572457

2458-
#if !defined(LTM_TEST_MULTITHREAD) || !defined(MP_SMALL_STACK_SIZE)
2458+
#if !defined(LTM_TEST_MULTITHREAD)
24592459
#define SINGLE_THREADED_C
2460-
typedef unsigned long int pthread_t;
2461-
extern int pthread_create(pthread_t *, const void *, void *(*)(void *), void *);
2462-
extern int pthread_join(pthread_t, void **);
2460+
typedef uintptr_t thread_id_t;
24632461
#else
24642462
#define MULTI_THREADED_C
2463+
#if !defined(_WIN32)
2464+
#define MULTI_THREADED_PTHREAD_C
24652465
#include <pthread.h>
2466+
typedef pthread_t thread_id_t;
2467+
#else
2468+
#define MULTI_THREADED_MSVC_C
2469+
2470+
#ifndef _WIN32_WINNT
2471+
#define _WIN32_WINNT 0x0501
2472+
#endif
2473+
#ifndef WINVER
2474+
#define WINVER 0x0501
2475+
#endif
2476+
2477+
#define WIN32_LEAN_AND_MEAN
2478+
#include <windows.h>
2479+
typedef HANDLE thread_id_t;
2480+
#endif
2481+
#endif
2482+
2483+
#if !defined(MULTI_THREADED_PTHREAD_C)
2484+
extern int pthread_create(thread_id_t *, const void *, void *(*)(void *), void *);
2485+
extern int pthread_join(thread_id_t, void **);
2486+
#endif
2487+
2488+
#if !defined(MULTI_THREADED_MSVC_C)
2489+
extern thread_id_t CreateThread(void *, size_t, unsigned long (*)(void *), void *, unsigned long, void *);
2490+
extern unsigned long WaitForSingleObject(thread_id_t hHandle, unsigned long dwMilliseconds);
2491+
#define INFINITE ((unsigned long)-1)
24662492
#endif
24672493

24682494
struct test_fn {
@@ -2471,12 +2497,12 @@ struct test_fn {
24712497
};
24722498

24732499
struct thread_info {
2474-
pthread_t thread_id;
2500+
thread_id_t thread_id;
24752501
const struct test_fn *t;
24762502
int ret;
24772503
};
24782504

2479-
static void *run(void *arg)
2505+
static void *run_pthread(void *arg)
24802506
{
24812507
struct thread_info *tinfo = arg;
24822508

@@ -2485,6 +2511,38 @@ static void *run(void *arg)
24852511
return arg;
24862512
}
24872513

2514+
static unsigned long run_msvc(void *arg)
2515+
{
2516+
struct thread_info *tinfo = arg;
2517+
2518+
tinfo->ret = tinfo->t->fn();
2519+
2520+
return 0;
2521+
}
2522+
2523+
static int thread_start(struct thread_info *info)
2524+
{
2525+
if (MP_HAS(MULTI_THREADED_PTHREAD))
2526+
return pthread_create(&info->thread_id, NULL, run_pthread, info);
2527+
if (MP_HAS(MULTI_THREADED_MSVC)) {
2528+
info->thread_id = CreateThread(NULL, 0, run_msvc, info, 0, NULL);
2529+
return info->thread_id == (thread_id_t)NULL ? -1 : 0;
2530+
}
2531+
return -1;
2532+
}
2533+
2534+
static int thread_join(struct thread_info *info, struct thread_info **res)
2535+
{
2536+
if (MP_HAS(MULTI_THREADED_PTHREAD))
2537+
return pthread_join(info->thread_id, (void **)res);
2538+
if (MP_HAS(MULTI_THREADED_MSVC)) {
2539+
WaitForSingleObject(info->thread_id, INFINITE);
2540+
*res = info;
2541+
return 0;
2542+
}
2543+
return -1;
2544+
}
2545+
24882546
static int unit_tests(int argc, char **argv)
24892547
{
24902548
static const struct test_fn test[] = {
@@ -2551,26 +2609,32 @@ static int unit_tests(int argc, char **argv)
25512609
};
25522610
struct thread_info test_threads[sizeof(test)/sizeof(test[0])], *res;
25532611
unsigned long i, ok, fail, nop;
2612+
size_t n_threads = MP_HAS(MULTI_THREADED) ? sizeof(test) / sizeof(test[0]) : 1;
25542613
uint64_t t;
2555-
int j = -1;
2614+
int j;
25562615
ok = fail = nop = 0;
25572616

25582617
t = (uint64_t)time(NULL);
25592618
printf("SEED: 0x%" PRIx64 "\n\n", t);
25602619
s_mp_rand_jenkins_init(t);
25612620
mp_rand_source(s_mp_rand_jenkins);
25622621

2622+
if (MP_HAS(MP_SMALL_STACK_SIZE)) {
2623+
printf("Small-stack enabled with %zu warray buffers\n\n", n_threads);
2624+
DO(mp_warray_init(n_threads, 1));
2625+
}
2626+
25632627
if (MP_HAS(MULTI_THREADED)) {
25642628
printf("Multi-threading enabled\n\n");
2565-
DO(mp_warray_init(sizeof(test) / sizeof(test[0]), 1));
2566-
/* we ignore the fact that jenkings is not thread safe */
2629+
/* we ignore the fact that jenkins is not thread safe */
25672630
for (i = 0; i < (sizeof(test) / sizeof(test[0])); ++i) {
25682631
test_threads[i].t = &test[i];
2569-
EXPECT(pthread_create(&test_threads[i].thread_id, NULL, run, &test_threads[i]) == 0);
2632+
EXPECT(thread_start(&test_threads[i]) == 0);
25702633
}
25712634
}
25722635

25732636
for (i = 0; i < (sizeof(test) / sizeof(test[0])); ++i) {
2637+
j = -1;
25742638
if (MP_HAS(SINGLE_THREADED)) {
25752639
if (argc > 1) {
25762640
for (j = 1; j < argc; ++j) {
@@ -2584,7 +2648,7 @@ static int unit_tests(int argc, char **argv)
25842648
if (test[i].fn)
25852649
j = test[i].fn();
25862650
} else if (MP_HAS(MULTI_THREADED)) {
2587-
EXPECT(pthread_join(test_threads[i].thread_id, (void **)&res) == 0);
2651+
EXPECT(thread_join(&test_threads[i], &res) == 0);
25882652
j = res->ret;
25892653
}
25902654
printf("TEST %s\n", test[i].name);

makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,10 @@ c89:
172172
-e 's/UINT32_MAX/0xFFFFFFFFu/g' \
173173
-e 's/UINT64_MAX/(mp_u64)-1/g' \
174174
-e 's/INT32_MAX/0x7FFFFFFF/g' \
175-
-e 's/INT32_MIN/(-2147483647-1)/g' \
175+
-e 's/INT32_MIN/(-2147483647-1)/g' \
176176
-e 's/INT64_MAX/(mp_i64)(((mp_u64)1<<63)-1)/g' \
177177
-e 's/INT64_MIN/(mp_i64)((mp_u64)1<<63)/g' \
178+
-e 's/uintptr_t/mp_uintptr/g' \
178179
-e 's/SIZE_MAX/((size_t)-1)/g' \
179180
-e 's/\(PRI[ioux]64\)/MP_\1/g' \
180181
-e 's/uint\([0-9][0-9]*\)_t/mp_u\1/g' \
@@ -195,10 +196,11 @@ c99:
195196
-e 's/false_/MP_NO_/g' \
196197
-e 's/0xFFFFFFFFu/UINT32_MAX/g' \
197198
-e 's/(mp_u64)-1/UINT64_MAX/g' \
198-
-e 's/(-2147483647-1)/INT32_MIN/g' \
199+
-e 's/(-2147483647-1)/INT32_MIN/g' \
199200
-e 's/0x7FFFFFFF/INT32_MAX/g' \
200201
-e 's/(mp_i64)((mp_u64)1<<63)/INT64_MIN/g' \
201202
-e 's/(mp_i64)(((mp_u64)1<<63)-1)/INT64_MAX/g' \
203+
-e 's/mp_uintptr/uintptr_t/g' \
202204
-e 's/((size_t)-1)/SIZE_MAX/g' \
203205
-e 's/MP_\(PRI[ioux]64\)/\1/g' \
204206
-e 's/mp_u\([0-9][0-9]*\)/uint\1_t/g' \

makefile.msvc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
#The following can be overridden from command line e.g. make -f makefile.msvc CC=gcc ARFLAGS=rcs
1313
PREFIX = c:\devel
14-
CFLAGS = /Ox
14+
CFLAGS = /Ox /Oi
1515
LDFLAGS =
1616

1717
#Compilation flags

s_mp_cmpexch_n.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ static bool s_cmpexch_n_gcc(void **ptr, void **expected, void *desired)
2626

2727
static bool s_cmpexch_n_msvc(void **ptr, void **expected, void *desired)
2828
{
29-
InterlockedCompareExchangePointer(ptr, desired, *(expected));
30-
return *ptr == desired;
29+
return InterlockedCompareExchangePointer(ptr, desired, *(expected));
3130
}
3231
#endif
3332

s_mp_warray_get.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@ void *s_mp_warray_get(void)
1111
if (mp_warray_init(1, false) != MP_OKAY)
1212
return NULL;
1313
}
14-
for (n = 0; n < s_mp_warray.allocated; ++n) {
15-
if (s_mp_warray.l_free[n].warray == NULL)
14+
for (n = 0; n < s_mp_warray.allocated;) {
15+
if (s_mp_warray.l_free[n].warray == NULL) {
16+
n++;
1617
continue;
18+
}
1719
ret = s_mp_warray.l_free[n].warray;
1820
if (s_mp_cmpexch_n(&s_mp_warray.l_free[n].warray, &ret, NULL)) {
1921
s_mp_warray.l_used[n].warray = ret;
2022
goto LBL_OUT;
2123
}
24+
/* restart from the beginning if we missed a potential slot */
25+
n = 0;
2226
}
2327
ret = NULL;
2428
if (s_mp_warray.allocated + 1 > s_mp_warray.usable)

tommath_c89.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ typedef __UINT8_TYPE__ mp_u8;
2626
typedef __UINT16_TYPE__ mp_u16;
2727
typedef __UINT32_TYPE__ mp_u32;
2828
typedef __UINT64_TYPE__ mp_u64;
29+
# if __WORDSIZE == 64
30+
typedef __UINT64_TYPE__ mp_uintptr;
31+
# else
32+
typedef __UINT32_TYPE__ mp_uintptr;
33+
# endif
2934

3035
/* inttypes.h replacement, printf format specifier */
3136
# if __WORDSIZE == 64

0 commit comments

Comments
 (0)