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:
parent
33ba5e296b
commit
2149f472ea
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue