msvcp120: Add _Concurrent_queue_base_v4 multi-threaded tests.

Signed-off-by: Piotr Caban <piotr@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Piotr Caban 2018-01-23 17:04:24 +01:00 committed by Alexandre Julliard
parent 33ba5e296b
commit 2149f472ea
1 changed files with 198 additions and 13 deletions

View File

@ -24,37 +24,63 @@
#include "wine/test.h"
#include "winbase.h"
DWORD expect_idx;
#define DEFINE_EXPECT(func) \
static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
BOOL expect_ ## func, called_ ## func
struct expect_struct {
DEFINE_EXPECT(queue_char__Allocate_page);
DEFINE_EXPECT(queue_char__Deallocate_page);
DEFINE_EXPECT(queue_char__Move_item);
DEFINE_EXPECT(queue_char__Copy_item);
DEFINE_EXPECT(queue_char__Assign_and_destroy_item);
};
#define SET_EXPECT(func) \
do { \
expect_ ## func = TRUE; \
errno = 0xdeadbeef; \
struct expect_struct *p = TlsGetValue(expect_idx); \
ok(p != NULL, "expect_struct not initialized\n"); \
p->expect_ ## func = TRUE; \
}while(0)
#define CHECK_EXPECT2(func) \
do { \
ok(expect_ ##func, "unexpected call " #func "\n"); \
called_ ## func = TRUE; \
struct expect_struct *p = TlsGetValue(expect_idx); \
ok(p != NULL, "expect_struct not initialized\n"); \
ok(p->expect_ ##func, "unexpected call " #func "\n"); \
p->called_ ## func = TRUE; \
}while(0)
#define CHECK_EXPECT(func) \
do { \
struct expect_struct *p = TlsGetValue(expect_idx); \
ok(p != NULL, "expect_struct not initialized\n"); \
CHECK_EXPECT2(func); \
expect_ ## func = FALSE; \
p->expect_ ## func = FALSE; \
}while(0)
#define CHECK_CALLED(func) \
do { \
ok(called_ ## func, "expected " #func "\n"); \
expect_ ## func = called_ ## func = FALSE; \
struct expect_struct *p = TlsGetValue(expect_idx); \
ok(p != NULL, "expect_struct not initialized\n"); \
ok(p->called_ ## func, "expected " #func "\n"); \
p->expect_ ## func = p->called_ ## func = FALSE; \
}while(0)
DEFINE_EXPECT(queue_char__Allocate_page);
DEFINE_EXPECT(queue_char__Deallocate_page);
DEFINE_EXPECT(queue_char__Copy_item);
DEFINE_EXPECT(queue_char__Assign_and_destroy_item);
static void alloc_expect_struct(void)
{
struct expect_struct *p = malloc(sizeof(*p));
memset(p, 0, sizeof(*p));
ok(TlsSetValue(expect_idx, p), "TlsSetValue failed\n");
}
static void free_expect_struct(void)
{
struct expect_struct *p = TlsGetValue(expect_idx);
ok(TlsSetValue(expect_idx, NULL), "TlsSetValue failed\n");
free(p);
}
#undef __thiscall
#ifdef __i386__
@ -330,6 +356,7 @@ static void (__thiscall *p_queue_base_v4_dtor)(queue_base_v4*);
static MSVCP_bool (__thiscall *p_queue_base_v4__Internal_empty)(queue_base_v4*);
static size_t (__thiscall *p_queue_base_v4__Internal_size)(queue_base_v4*);
static void (__thiscall *p_queue_base_v4__Internal_push)(queue_base_v4*, const void*);
static void (__thiscall *p_queue_base_v4__Internal_move_push)(queue_base_v4*, void*);
static MSVCP_bool (__thiscall *p_queue_base_v4__Internal_pop_if_present)(queue_base_v4*, void*);
static void (__thiscall *p_queue_base_v4__Internal_finish_clear)(queue_base_v4*);
@ -460,6 +487,8 @@ static BOOL init(void)
"?_Internal_size@_Concurrent_queue_base_v4@details@Concurrency@@IEBA_KXZ");
SET(p_queue_base_v4__Internal_push,
"?_Internal_push@_Concurrent_queue_base_v4@details@Concurrency@@IEAAXPEBX@Z");
SET(p_queue_base_v4__Internal_move_push,
"?_Internal_move_push@_Concurrent_queue_base_v4@details@Concurrency@@IEAAXPEAX@Z");
SET(p_queue_base_v4__Internal_pop_if_present,
"?_Internal_pop_if_present@_Concurrent_queue_base_v4@details@Concurrency@@IEAA_NPEAX@Z");
SET(p_queue_base_v4__Internal_finish_clear,
@ -561,6 +590,8 @@ static BOOL init(void)
"?_Internal_size@_Concurrent_queue_base_v4@details@Concurrency@@IBEIXZ");
SET(p_queue_base_v4__Internal_push,
"?_Internal_push@_Concurrent_queue_base_v4@details@Concurrency@@IAEXPBX@Z");
SET(p_queue_base_v4__Internal_move_push,
"?_Internal_move_push@_Concurrent_queue_base_v4@details@Concurrency@@IAEXPAX@Z");
SET(p_queue_base_v4__Internal_pop_if_present,
"?_Internal_pop_if_present@_Concurrent_queue_base_v4@details@Concurrency@@IAE_NPAX@Z");
SET(p_queue_base_v4__Internal_finish_clear,
@ -590,6 +621,8 @@ static BOOL init(void)
"?_Internal_size@_Concurrent_queue_base_v4@details@Concurrency@@IBAIXZ");
SET(p_queue_base_v4__Internal_push,
"?_Internal_push@_Concurrent_queue_base_v4@details@Concurrency@@IAAXPBX@Z");
SET(p_queue_base_v4__Internal_move_push,
"?_Internal_move_push@_Concurrent_queue_base_v4@details@Concurrency@@IAAXPAX@Z");
SET(p_queue_base_v4__Internal_pop_if_present,
"?_Internal_pop_if_present@_Concurrent_queue_base_v4@details@Concurrency@@IAA_NPAX@Z");
SET(p_queue_base_v4__Internal_finish_clear,
@ -2245,13 +2278,21 @@ static void test_vector_base_v4__Segment_index_of(void)
}
}
static HANDLE block_start, block_end;
static BOOL block;
static void __thiscall queue_char__Move_item(
#ifndef __i386__
queue_base_v4 *this,
#endif
_Page *dst, size_t idx, void *src)
{
ok(0, "unexpected call\n");
CHECK_EXPECT(queue_char__Move_item);
if(block) {
block = FALSE;
SetEvent(block_start);
WaitForSingleObject(block_end, INFINITE);
}
memcpy(dst->data + idx, src, sizeof(char));
}
@ -2262,6 +2303,11 @@ static void __thiscall queue_char__Copy_item(
_Page *dst, size_t idx, const void *src)
{
CHECK_EXPECT(queue_char__Copy_item);
if(block) {
block = FALSE;
SetEvent(block_start);
WaitForSingleObject(block_end, INFINITE);
}
memcpy(dst->data + idx, src, sizeof(char));
}
@ -2272,6 +2318,11 @@ static void __thiscall queue_char__Assign_and_destroy_item(
void *dst, _Page *src, size_t idx)
{
CHECK_EXPECT(queue_char__Assign_and_destroy_item);
if(block) {
block = FALSE;
SetEvent(block_start);
WaitForSingleObject(block_end, INFINITE);
}
memcpy(dst, src->data + idx, sizeof(char));
}
@ -2305,14 +2356,59 @@ static const void* queue_char_vtbl[] =
queue_char__Deallocate_page
};
static DWORD WINAPI queue_move_push_thread(void *arg)
{
queue_base_v4 *queue = arg;
char c = 'm';
alloc_expect_struct();
SET_EXPECT(queue_char__Allocate_page); /* ignore page allocations */
SET_EXPECT(queue_char__Move_item);
call_func2(p_queue_base_v4__Internal_move_push, queue, &c);
CHECK_CALLED(queue_char__Move_item);
free_expect_struct();
return 0;
}
static DWORD WINAPI queue_push_thread(void *arg)
{
queue_base_v4 *queue = arg;
char c = 'c';
alloc_expect_struct();
SET_EXPECT(queue_char__Copy_item);
call_func2(p_queue_base_v4__Internal_push, queue, &c);
CHECK_CALLED(queue_char__Copy_item);
free_expect_struct();
return 0;
}
static DWORD WINAPI queue_pop_thread(void*arg)
{
queue_base_v4 *queue = arg;
char c;
alloc_expect_struct();
SET_EXPECT(queue_char__Assign_and_destroy_item);
call_func2(p_queue_base_v4__Internal_pop_if_present, queue, &c);
CHECK_CALLED(queue_char__Assign_and_destroy_item);
free_expect_struct();
return 0;
}
static void test_queue_base_v4(void)
{
queue_base_v4 queue;
HANDLE thread[2];
MSVCP_bool b;
size_t size;
DWORD ret;
int i;
char c;
block_start = CreateEventW(NULL, FALSE, FALSE, NULL);
block_end = CreateEventW(NULL, FALSE, FALSE, NULL);
call_func2(p_queue_base_v4_ctor, &queue, 0);
ok(queue.data != NULL, "queue.data = NULL\n");
ok(queue.alloc_count == 32, "queue.alloc_count = %ld\n", (long)queue.alloc_count);
@ -2406,11 +2502,98 @@ static void test_queue_base_v4(void)
CHECK_CALLED(queue_char__Deallocate_page);
call_func1(p_queue_base_v4_dtor, &queue);
/* test parallel push */
call_func2(p_queue_base_v4_ctor, &queue, 1);
queue.vtable = (void*)&queue_char_vtbl;
block = TRUE;
thread[0] = CreateThread(NULL, 0, queue_move_push_thread, &queue, 0, NULL);
WaitForSingleObject(block_start, INFINITE);
c = 'a';
for(i=0; i<7; i++) {
SET_EXPECT(queue_char__Allocate_page);
SET_EXPECT(queue_char__Copy_item);
call_func2(p_queue_base_v4__Internal_push, &queue, &c);
CHECK_CALLED(queue_char__Allocate_page);
CHECK_CALLED(queue_char__Copy_item);
}
thread[1] = CreateThread(NULL, 0, queue_push_thread, &queue, 0, NULL);
ret = WaitForSingleObject(thread[1], 100);
ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %x\n", ret);
SetEvent(block_end);
WaitForSingleObject(thread[0], INFINITE);
WaitForSingleObject(thread[1], INFINITE);
CloseHandle(thread[0]);
CloseHandle(thread[1]);
/* test parallel pop */
block = TRUE;
thread[0] = CreateThread(NULL, 0, queue_pop_thread, &queue, 0, NULL);
WaitForSingleObject(block_start, INFINITE);
for(i=0; i<7; i++) {
SET_EXPECT(queue_char__Assign_and_destroy_item);
b = (DWORD_PTR)call_func2(p_queue_base_v4__Internal_pop_if_present, &queue, &c);
CHECK_CALLED(queue_char__Assign_and_destroy_item);
ok(b, "pop returned false\n");
ok(c == 'a', "got '%c', expected 'a'\n", c);
}
thread[1] = CreateThread(NULL, 0, queue_pop_thread, &queue, 0, NULL);
ret = WaitForSingleObject(thread[1], 100);
ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %x\n", ret);
SetEvent(block_end);
WaitForSingleObject(thread[0], INFINITE);
WaitForSingleObject(thread[1], INFINITE);
CloseHandle(thread[0]);
CloseHandle(thread[1]);
/* test parallel push/pop */
for(i=0; i<8; i++) {
SET_EXPECT(queue_char__Copy_item);
call_func2(p_queue_base_v4__Internal_push, &queue, &c);
CHECK_CALLED(queue_char__Copy_item);
}
block = TRUE;
thread[0] = CreateThread(NULL, 0, queue_push_thread, &queue, 0, NULL);
WaitForSingleObject(block_start, INFINITE);
SET_EXPECT(queue_char__Assign_and_destroy_item);
call_func2(p_queue_base_v4__Internal_pop_if_present, &queue, &c);
CHECK_CALLED(queue_char__Assign_and_destroy_item);
SetEvent(block_end);
WaitForSingleObject(thread[0], INFINITE);
CloseHandle(thread[0]);
for(i=0; i<8; i++) {
SET_EXPECT(queue_char__Assign_and_destroy_item);
call_func2(p_queue_base_v4__Internal_pop_if_present, &queue, &c);
CHECK_CALLED(queue_char__Assign_and_destroy_item);
}
SET_EXPECT(queue_char__Deallocate_page);
call_func1(p_queue_base_v4__Internal_finish_clear, &queue);
CHECK_CALLED(queue_char__Deallocate_page);
call_func1(p_queue_base_v4_dtor, &queue);
CloseHandle(block_start);
CloseHandle(block_end);
}
START_TEST(msvcp120)
{
if(!init()) return;
expect_idx = TlsAlloc();
ok(expect_idx != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n");
alloc_expect_struct();
test__Xtime_diff_to_millis2();
test_xtime_get();
test__Getcvt();
@ -2446,5 +2629,7 @@ START_TEST(msvcp120)
test_vbtable_size_exports();
free_expect_struct();
TlsFree(expect_idx);
FreeLibrary(msvcp);
}