Skip to content

Commit

Permalink
Add tests for MSVC multi-threading
Browse files Browse the repository at this point in the history
... and fix some MSVC related (and other) things.

Signed-off-by: Steffen Jaeckel <[email protected]>
  • Loading branch information
sjaeckel committed Mar 26, 2024
1 parent 8442b30 commit 2723f09
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 17 deletions.
10 changes: 9 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,17 @@ build_script:
if "Visual Studio 2017"=="%APPVEYOR_BUILD_WORKER_IMAGE%" call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
if "Visual Studio 2015"=="%APPVEYOR_BUILD_WORKER_IMAGE%" call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64
if "Visual Studio 2015"=="%APPVEYOR_BUILD_WORKER_IMAGE%" call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64
nmake -f makefile.msvc test.exe CFLAGS="/Ox /Oi /DMP_SMALL_STACK_SIZE"
copy /Y test.exe test_small_stack.exe
nmake -f makefile.msvc clean-obj
nmake -f makefile.msvc test.exe CFLAGS="/Ox /Oi /DMP_SMALL_STACK_SIZE /DLTM_TEST_MULTITHREAD"
copy /Y test.exe test_small_stack_multithreaded.exe
nmake -f makefile.msvc clean-obj
nmake -f makefile.msvc test.exe
nmake -f makefile.msvc clean-obj
nmake -f makefile.msvc test_dll.exe CFLAGS="/Ox /MD /DLTM_TEST_DYNAMIC"
nmake -f makefile.msvc test_dll.exe CFLAGS="/Ox /Oi /MD /DLTM_TEST_DYNAMIC"
test_script:
- cmd: test_small_stack.exe
- cmd: test_small_stack_multithreaded.exe
- cmd: test.exe
- cmd: test_dll.exe
86 changes: 75 additions & 11 deletions demo/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -2455,14 +2455,40 @@ static int test_mp_pack_unpack(void)
#define ONLY_PUBLIC_API_C
#endif

#if !defined(LTM_TEST_MULTITHREAD) || !defined(MP_SMALL_STACK_SIZE)
#if !defined(LTM_TEST_MULTITHREAD)
#define SINGLE_THREADED_C
typedef unsigned long int pthread_t;
extern int pthread_create(pthread_t *, const void *, void *(*)(void *), void *);
extern int pthread_join(pthread_t, void **);
typedef uintptr_t thread_id_t;
#else
#define MULTI_THREADED_C
#if !defined(_WIN32)
#define MULTI_THREADED_PTHREAD_C
#include <pthread.h>
typedef pthread_t thread_id_t;
#else
#define MULTI_THREADED_MSVC_C

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#ifndef WINVER
#define WINVER 0x0501
#endif

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
typedef HANDLE thread_id_t;
#endif
#endif

#if !defined(MULTI_THREADED_PTHREAD_C)
extern int pthread_create(thread_id_t *, const void *, void *(*)(void *), void *);
extern int pthread_join(thread_id_t, void **);
#endif

#if !defined(MULTI_THREADED_MSVC_C)
extern thread_id_t CreateThread(void *, size_t, unsigned long (*)(void *), void *, unsigned long, void *);
extern unsigned long WaitForSingleObject(thread_id_t hHandle, unsigned long dwMilliseconds);
#define INFINITE ((unsigned long)-1)
#endif

struct test_fn {
Expand All @@ -2471,12 +2497,12 @@ struct test_fn {
};

struct thread_info {
pthread_t thread_id;
thread_id_t thread_id;
const struct test_fn *t;
int ret;
};

static void *run(void *arg)
static void *run_pthread(void *arg)
{
struct thread_info *tinfo = arg;

Expand All @@ -2485,6 +2511,38 @@ static void *run(void *arg)
return arg;
}

static unsigned long run_msvc(void *arg)
{
struct thread_info *tinfo = arg;

tinfo->ret = tinfo->t->fn();

return 0;
}

static int thread_start(struct thread_info *info)
{
if (MP_HAS(MULTI_THREADED_PTHREAD))
return pthread_create(&info->thread_id, NULL, run_pthread, info);
if (MP_HAS(MULTI_THREADED_MSVC)) {
info->thread_id = CreateThread(NULL, 0, run_msvc, info, 0, NULL);
return info->thread_id == (thread_id_t)NULL ? -1 : 0;
}
return -1;
}

static int thread_join(struct thread_info *info, struct thread_info **res)
{
if (MP_HAS(MULTI_THREADED_PTHREAD))
return pthread_join(info->thread_id, (void **)res);
if (MP_HAS(MULTI_THREADED_MSVC)) {
WaitForSingleObject(info->thread_id, INFINITE);
*res = info;
return 0;
}
return -1;
}

static int unit_tests(int argc, char **argv)
{
static const struct test_fn test[] = {
Expand Down Expand Up @@ -2551,26 +2609,32 @@ static int unit_tests(int argc, char **argv)
};
struct thread_info test_threads[sizeof(test)/sizeof(test[0])], *res;
unsigned long i, ok, fail, nop;
size_t n_threads = MP_HAS(MULTI_THREADED) ? sizeof(test) / sizeof(test[0]) : 1;
uint64_t t;
int j = -1;
int j;
ok = fail = nop = 0;

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

if (MP_HAS(MP_SMALL_STACK_SIZE)) {
printf("Small-stack enabled with %zu warray buffers\n\n", n_threads);
DO(mp_warray_init(n_threads, 1));
}

if (MP_HAS(MULTI_THREADED)) {
printf("Multi-threading enabled\n\n");
DO(mp_warray_init(sizeof(test) / sizeof(test[0]), 1));
/* we ignore the fact that jenkings is not thread safe */
/* we ignore the fact that jenkins is not thread safe */
for (i = 0; i < (sizeof(test) / sizeof(test[0])); ++i) {
test_threads[i].t = &test[i];
EXPECT(pthread_create(&test_threads[i].thread_id, NULL, run, &test_threads[i]) == 0);
EXPECT(thread_start(&test_threads[i]) == 0);
}
}

for (i = 0; i < (sizeof(test) / sizeof(test[0])); ++i) {
j = -1;
if (MP_HAS(SINGLE_THREADED)) {
if (argc > 1) {
for (j = 1; j < argc; ++j) {
Expand All @@ -2584,7 +2648,7 @@ static int unit_tests(int argc, char **argv)
if (test[i].fn)
j = test[i].fn();
} else if (MP_HAS(MULTI_THREADED)) {
EXPECT(pthread_join(test_threads[i].thread_id, (void **)&res) == 0);
EXPECT(thread_join(&test_threads[i], &res) == 0);
j = res->ret;
}
printf("TEST %s\n", test[i].name);
Expand Down
2 changes: 1 addition & 1 deletion makefile.msvc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

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

#Compilation flags
Expand Down
3 changes: 1 addition & 2 deletions s_mp_cmpexch_n.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ static bool s_cmpexch_n_gcc(void **ptr, void **expected, void *desired)

static bool s_cmpexch_n_msvc(void **ptr, void **expected, void *desired)
{
InterlockedCompareExchangePointer(ptr, desired, *(expected));
return *ptr == desired;
return InterlockedCompareExchangePointer(ptr, desired, *(expected));
}
#endif

Expand Down
8 changes: 6 additions & 2 deletions s_mp_warray_get.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ void *s_mp_warray_get(void)
if (mp_warray_init(1, false) != MP_OKAY)
return NULL;
}
for (n = 0; n < s_mp_warray.allocated; ++n) {
if (s_mp_warray.l_free[n].warray == NULL)
for (n = 0; n < s_mp_warray.allocated;) {
if (s_mp_warray.l_free[n].warray == NULL) {
n++;
continue;
}
ret = s_mp_warray.l_free[n].warray;
if (s_mp_cmpexch_n(&s_mp_warray.l_free[n].warray, &ret, NULL)) {
s_mp_warray.l_used[n].warray = ret;
goto LBL_OUT;
}
/* restart from the beginning if we missed a potential slot */
n = 0;
}
ret = NULL;
if (s_mp_warray.allocated + 1 > s_mp_warray.usable)
Expand Down

0 comments on commit 2723f09

Please sign in to comment.