/* * Copyright 2014 Yifu Wang for ESRI * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include "wine/test.h" #include "winbase.h" DWORD expect_idx; static int vector_alloc_count; static int vector_elem_count; #define DEFINE_EXPECT(func) \ 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_EXPECT(concurrent_vector_int_alloc); DEFINE_EXPECT(concurrent_vector_int_destroy); DEFINE_EXPECT(concurrent_vector_int_copy); }; #define SET_EXPECT(func) \ do { \ 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 { \ 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); \ p->expect_ ## func = FALSE; \ }while(0) #define CHECK_CALLED(func) \ do { \ 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) 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__ #define __thiscall __stdcall #else #define __thiscall __cdecl #endif /* Emulate a __thiscall */ #ifdef __i386__ #include "pshpack1.h" struct thiscall_thunk { BYTE pop_eax; /* popl %eax (ret addr) */ BYTE pop_edx; /* popl %edx (func) */ BYTE pop_ecx; /* popl %ecx (this) */ BYTE push_eax; /* pushl %eax */ WORD jmp_edx; /* jmp *%edx */ }; #include "poppack.h" static void * (WINAPI *call_thiscall_func1)( void *func, void *this ); static void * (WINAPI *call_thiscall_func2)( void *func, void *this, const void *a ); static void * (WINAPI *call_thiscall_func3)( void *func, void *this, const void *a, const void *b ); static void * (WINAPI *call_thiscall_func4)( void *func, void *this, const void *a, const void *b, const void *c ); static void init_thiscall_thunk(void) { struct thiscall_thunk *thunk = VirtualAlloc( NULL, sizeof(*thunk), MEM_COMMIT, PAGE_EXECUTE_READWRITE ); thunk->pop_eax = 0x58; /* popl %eax */ thunk->pop_edx = 0x5a; /* popl %edx */ thunk->pop_ecx = 0x59; /* popl %ecx */ thunk->push_eax = 0x50; /* pushl %eax */ thunk->jmp_edx = 0xe2ff; /* jmp *%edx */ call_thiscall_func1 = (void *)thunk; call_thiscall_func2 = (void *)thunk; call_thiscall_func3 = (void *)thunk; call_thiscall_func4 = (void *)thunk; } #define call_func1(func,_this) call_thiscall_func1(func,_this) #define call_func2(func,_this,a) call_thiscall_func2(func,_this,(const void*)(a)) #define call_func3(func,_this,a,b) call_thiscall_func3(func,_this,(const void*)(a),\ (const void*)(b)) #define call_func4(func,_this,a,b,c) call_thiscall_func4(func,_this,(const void*)(a),\ (const void*)(b),(const void*)(c)) #else #define init_thiscall_thunk() #define call_func1(func,_this) func(_this) #define call_func2(func,_this,a) func(_this,a) #define call_func3(func,_this,a,b) func(_this,a,b) #define call_func4(func,_this,a,b,c) func(_this,a,b,c) #endif /* __i386__ */ static inline float __port_infinity(void) { static const unsigned __inf_bytes = 0x7f800000; return *(const float *)&__inf_bytes; } #define INFINITY __port_infinity() static inline float __port_nan(void) { static const unsigned __nan_bytes = 0x7fc00000; return *(const float *)&__nan_bytes; } #define NAN __port_nan() typedef int MSVCRT_long; typedef unsigned char MSVCP_bool; /* xtime */ typedef struct { __time64_t sec; MSVCRT_long nsec; } xtime; typedef struct { unsigned page; int mb_max; int unk; BYTE isleadbyte[32]; } _Cvtvec; struct space_info { ULONGLONG capacity; ULONGLONG free; ULONGLONG available; }; enum file_type { status_unknown, file_not_found, regular_file, directory_file, symlink_file, block_file, character_file, fifo_file, socket_file, type_unknown }; static BOOL compare_float(float f, float g, unsigned int ulps) { int x = *(int *)&f; int y = *(int *)&g; if (x < 0) x = INT_MIN - x; if (y < 0) y = INT_MIN - y; if (abs(x - y) > ulps) return FALSE; return TRUE; } static char* (__cdecl *p_setlocale)(int, const char*); static int (__cdecl *p__setmbcp)(int); static int (__cdecl *p__ismbblead)(unsigned int); static MSVCRT_long (__cdecl *p__Xtime_diff_to_millis2)(const xtime*, const xtime*); static int (__cdecl *p_xtime_get)(xtime*, int); static _Cvtvec* (__cdecl *p__Getcvt)(_Cvtvec*); static void (CDECL *p__Call_once)(int *once, void (CDECL *func)(void)); static void (CDECL *p__Call_onceEx)(int *once, void (CDECL *func)(void*), void *argv); static void (CDECL *p__Do_call)(void *this); static short (__cdecl *p__Dtest)(double *d); static short (__cdecl *p__Dscale)(double *d, int exp); static short (__cdecl *p__FExp)(float *x, float y, int exp); /* filesystem */ static ULONGLONG(__cdecl *p_tr2_sys__File_size)(char const*); static ULONGLONG(__cdecl *p_tr2_sys__File_size_wchar)(WCHAR const*); static int (__cdecl *p_tr2_sys__Equivalent)(char const*, char const*); static int (__cdecl *p_tr2_sys__Equivalent_wchar)(WCHAR const*, WCHAR const*); static char* (__cdecl *p_tr2_sys__Current_get)(char *); static WCHAR* (__cdecl *p_tr2_sys__Current_get_wchar)(WCHAR *); static MSVCP_bool (__cdecl *p_tr2_sys__Current_set)(char const*); static MSVCP_bool (__cdecl *p_tr2_sys__Current_set_wchar)(WCHAR const*); static int (__cdecl *p_tr2_sys__Make_dir)(char const*); static int (__cdecl *p_tr2_sys__Make_dir_wchar)(WCHAR const*); static MSVCP_bool (__cdecl *p_tr2_sys__Remove_dir)(char const*); static MSVCP_bool (__cdecl *p_tr2_sys__Remove_dir_wchar)(WCHAR const*); static int (__cdecl *p_tr2_sys__Copy_file)(char const*, char const*, MSVCP_bool); static int (__cdecl *p_tr2_sys__Copy_file_wchar)(WCHAR const*, WCHAR const*, MSVCP_bool); static int (__cdecl *p_tr2_sys__Rename)(char const*, char const*); static int (__cdecl *p_tr2_sys__Rename_wchar)(WCHAR const*, WCHAR const*); static struct space_info* (__cdecl *p_tr2_sys__Statvfs)(struct space_info*, char const*); static struct space_info* (__cdecl *p_tr2_sys__Statvfs_wchar)(struct space_info*, WCHAR const*); static enum file_type (__cdecl *p_tr2_sys__Stat)(char const*, int *); static enum file_type (__cdecl *p_tr2_sys__Stat_wchar)(WCHAR const*, int *); static enum file_type (__cdecl *p_tr2_sys__Lstat)(char const*, int *); static enum file_type (__cdecl *p_tr2_sys__Lstat_wchar)(WCHAR const*, int *); static __int64 (__cdecl *p_tr2_sys__Last_write_time)(char const*); static void (__cdecl *p_tr2_sys__Last_write_time_set)(char const*, __int64); static void* (__cdecl *p_tr2_sys__Open_dir)(char*, char const*, int *, enum file_type*); static char* (__cdecl *p_tr2_sys__Read_dir)(char*, void*, enum file_type*); static void (__cdecl *p_tr2_sys__Close_dir)(void*); static int (__cdecl *p_tr2_sys__Link)(char const*, char const*); static int (__cdecl *p_tr2_sys__Symlink)(char const*, char const*); static int (__cdecl *p_tr2_sys__Unlink)(char const*); /* thrd */ typedef struct { HANDLE hnd; DWORD id; } _Thrd_t; #define TIMEDELTA 250 /* 250 ms uncertainty allowed */ typedef int (__cdecl *_Thrd_start_t)(void*); static int (__cdecl *p__Thrd_equal)(_Thrd_t, _Thrd_t); static int (__cdecl *p__Thrd_lt)(_Thrd_t, _Thrd_t); static void (__cdecl *p__Thrd_sleep)(const xtime*); static _Thrd_t (__cdecl *p__Thrd_current)(void); static int (__cdecl *p__Thrd_create)(_Thrd_t*, _Thrd_start_t, void*); static int (__cdecl *p__Thrd_join)(_Thrd_t, int*); static int (__cdecl *p__Thrd_detach)(_Thrd_t); #ifdef __i386__ static ULONGLONG (__cdecl *p_i386_Thrd_current)(void); static _Thrd_t __cdecl i386_Thrd_current(void) { union { _Thrd_t thr; ULONGLONG ull; } r; r.ull = p_i386_Thrd_current(); return r.thr; } #endif /* mtx */ typedef struct cs_queue { struct cs_queue *next; BOOL free; int unknown; } cs_queue; typedef struct { ULONG_PTR unk_thread_id; cs_queue unk_active; void *unknown[2]; cs_queue *head; void *tail; } critical_section; typedef struct { DWORD flags; critical_section cs; DWORD thread_id; DWORD count; } *_Mtx_t; static int (__cdecl *p__Mtx_init)(_Mtx_t*, int); static void (__cdecl *p__Mtx_destroy)(_Mtx_t*); static int (__cdecl *p__Mtx_lock)(_Mtx_t*); static int (__cdecl *p__Mtx_unlock)(_Mtx_t*); /* cnd */ typedef void *_Cnd_t; static int (__cdecl *p__Cnd_init)(_Cnd_t*); static void (__cdecl *p__Cnd_destroy)(_Cnd_t*); static int (__cdecl *p__Cnd_wait)(_Cnd_t*, _Mtx_t*); static int (__cdecl *p__Cnd_timedwait)(_Cnd_t*, _Mtx_t*, const xtime*); static int (__cdecl *p__Cnd_broadcast)(_Cnd_t*); static int (__cdecl *p__Cnd_signal)(_Cnd_t*); static void (__cdecl *p__Cnd_register_at_thread_exit)(_Cnd_t*, _Mtx_t*, int*); static void (__cdecl *p__Cnd_unregister_at_thread_exit)(_Mtx_t*); static void (__cdecl *p__Cnd_do_broadcast_at_thread_exit)(void); /* _Pad */ typedef void (*vtable_ptr)(void); typedef struct { const vtable_ptr *vtable; _Cnd_t cnd; _Mtx_t mtx; MSVCP_bool launched; } _Pad; static _Pad* (__thiscall *p__Pad_ctor)(_Pad*); static _Pad* (__thiscall *p__Pad_copy_ctor)(_Pad*, const _Pad*); static void (__thiscall *p__Pad_dtor)(_Pad*); static _Pad* (__thiscall *p__Pad_op_assign)(_Pad*, const _Pad*); static void (__thiscall *p__Pad__Launch)(_Pad*, _Thrd_t*); static void (__thiscall *p__Pad__Release)(_Pad*); static void (__cdecl *p_threads__Mtx_new)(void **mtx); static void (__cdecl *p_threads__Mtx_delete)(void *mtx); static void (__cdecl *p_threads__Mtx_lock)(void *mtx); static void (__cdecl *p_threads__Mtx_unlock)(void *mtx); static BOOLEAN (WINAPI *pCreateSymbolicLinkA)(LPCSTR,LPCSTR,DWORD); static size_t (__cdecl *p_vector_base_v4__Segment_index_of)(size_t); typedef struct { const vtable_ptr *vtable; void *data; size_t alloc_count; size_t item_size; } queue_base_v4; typedef struct { struct _Page *_Next; size_t _Mask; char data[1]; } _Page; static queue_base_v4* (__thiscall *p_queue_base_v4_ctor)(queue_base_v4*, size_t); 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*); typedef struct vector_base_v4 { void* (__cdecl *allocator)(struct vector_base_v4*, size_t); void *storage[3]; size_t first_block; size_t early_size; void **segment; } vector_base_v4; static void (__thiscall *p_vector_base_v4_dtor)(vector_base_v4*); static size_t (__thiscall *p_vector_base_v4__Internal_capacity)(vector_base_v4*); static void* (__thiscall *p_vector_base_v4__Internal_push_back)( vector_base_v4*, size_t, size_t*); static size_t (__thiscall *p_vector_base_v4__Internal_clear)( vector_base_v4*, void (__cdecl*)(void*, size_t)); static void (__thiscall *p_vector_base_v4__Internal_copy)( vector_base_v4*, vector_base_v4*, size_t, void (__cdecl*)(void*, const void*, size_t)); static HMODULE msvcp; #define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcp,y) #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0) static BOOL init(void) { HANDLE hdll; msvcp = LoadLibraryA("msvcp120.dll"); if(!msvcp) { win_skip("msvcp120.dll not installed\n"); return FALSE; } SET(p__Xtime_diff_to_millis2, "_Xtime_diff_to_millis2"); SET(p_xtime_get, "xtime_get"); SET(p__Getcvt, "_Getcvt"); SET(p__Call_once, "_Call_once"); SET(p__Call_onceEx, "_Call_onceEx"); SET(p__Do_call, "_Do_call"); SET(p__Dtest, "_Dtest"); SET(p__Dscale, "_Dscale"); SET(p__FExp, "_FExp"); if(sizeof(void*) == 8) { /* 64-bit initialization */ SET(p_tr2_sys__File_size, "?_File_size@sys@tr2@std@@YA_KPEBD@Z"); SET(p_tr2_sys__File_size_wchar, "?_File_size@sys@tr2@std@@YA_KPEB_W@Z"); SET(p_tr2_sys__Equivalent, "?_Equivalent@sys@tr2@std@@YAHPEBD0@Z"); SET(p_tr2_sys__Equivalent_wchar, "?_Equivalent@sys@tr2@std@@YAHPEB_W0@Z"); SET(p_tr2_sys__Current_get, "?_Current_get@sys@tr2@std@@YAPEADAEAY0BAE@D@Z"); SET(p_tr2_sys__Current_get_wchar, "?_Current_get@sys@tr2@std@@YAPEA_WAEAY0BAE@_W@Z"); SET(p_tr2_sys__Current_set, "?_Current_set@sys@tr2@std@@YA_NPEBD@Z"); SET(p_tr2_sys__Current_set_wchar, "?_Current_set@sys@tr2@std@@YA_NPEB_W@Z"); SET(p_tr2_sys__Make_dir, "?_Make_dir@sys@tr2@std@@YAHPEBD@Z"); SET(p_tr2_sys__Make_dir_wchar, "?_Make_dir@sys@tr2@std@@YAHPEB_W@Z"); SET(p_tr2_sys__Remove_dir, "?_Remove_dir@sys@tr2@std@@YA_NPEBD@Z"); SET(p_tr2_sys__Remove_dir_wchar, "?_Remove_dir@sys@tr2@std@@YA_NPEB_W@Z"); SET(p_tr2_sys__Copy_file, "?_Copy_file@sys@tr2@std@@YAHPEBD0_N@Z"); SET(p_tr2_sys__Copy_file_wchar, "?_Copy_file@sys@tr2@std@@YAHPEB_W0_N@Z"); SET(p_tr2_sys__Rename, "?_Rename@sys@tr2@std@@YAHPEBD0@Z"); SET(p_tr2_sys__Rename_wchar, "?_Rename@sys@tr2@std@@YAHPEB_W0@Z"); SET(p_tr2_sys__Statvfs, "?_Statvfs@sys@tr2@std@@YA?AUspace_info@123@PEBD@Z"); SET(p_tr2_sys__Statvfs_wchar, "?_Statvfs@sys@tr2@std@@YA?AUspace_info@123@PEB_W@Z"); SET(p_tr2_sys__Stat, "?_Stat@sys@tr2@std@@YA?AW4file_type@123@PEBDAEAH@Z"); SET(p_tr2_sys__Stat_wchar, "?_Stat@sys@tr2@std@@YA?AW4file_type@123@PEB_WAEAH@Z"); SET(p_tr2_sys__Lstat, "?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PEBDAEAH@Z"); SET(p_tr2_sys__Lstat_wchar, "?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PEB_WAEAH@Z"); SET(p_tr2_sys__Last_write_time, "?_Last_write_time@sys@tr2@std@@YA_JPEBD@Z"); SET(p_tr2_sys__Last_write_time_set, "?_Last_write_time@sys@tr2@std@@YAXPEBD_J@Z"); SET(p_tr2_sys__Open_dir, "?_Open_dir@sys@tr2@std@@YAPEAXAEAY0BAE@DPEBDAEAHAEAW4file_type@123@@Z"); SET(p_tr2_sys__Read_dir, "?_Read_dir@sys@tr2@std@@YAPEADAEAY0BAE@DPEAXAEAW4file_type@123@@Z"); SET(p_tr2_sys__Close_dir, "?_Close_dir@sys@tr2@std@@YAXPEAX@Z"); SET(p_tr2_sys__Link, "?_Link@sys@tr2@std@@YAHPEBD0@Z"); SET(p_tr2_sys__Symlink, "?_Symlink@sys@tr2@std@@YAHPEBD0@Z"); SET(p_tr2_sys__Unlink, "?_Unlink@sys@tr2@std@@YAHPEBD@Z"); SET(p__Thrd_current, "_Thrd_current"); SET(p__Pad_ctor, "??0_Pad@std@@QEAA@XZ"); SET(p__Pad_copy_ctor, "??0_Pad@std@@QEAA@AEBV01@@Z"); SET(p__Pad_dtor, "??1_Pad@std@@QEAA@XZ"); SET(p__Pad_op_assign, "??4_Pad@std@@QEAAAEAV01@AEBV01@@Z"); SET(p__Pad__Launch, "?_Launch@_Pad@std@@QEAAXPEAU_Thrd_imp_t@@@Z"); SET(p__Pad__Release, "?_Release@_Pad@std@@QEAAXXZ"); SET(p_threads__Mtx_new, "?_Mtx_new@threads@stdext@@YAXAEAPEAX@Z"); SET(p_threads__Mtx_delete, "?_Mtx_delete@threads@stdext@@YAXPEAX@Z"); SET(p_threads__Mtx_lock, "?_Mtx_lock@threads@stdext@@YAXPEAX@Z"); SET(p_threads__Mtx_unlock, "?_Mtx_unlock@threads@stdext@@YAXPEAX@Z"); SET(p_vector_base_v4__Segment_index_of, "?_Segment_index_of@_Concurrent_vector_base_v4@details@Concurrency@@KA_K_K@Z"); SET(p_queue_base_v4_ctor, "??0_Concurrent_queue_base_v4@details@Concurrency@@IEAA@_K@Z"); SET(p_queue_base_v4_dtor, "??1_Concurrent_queue_base_v4@details@Concurrency@@MEAA@XZ"); SET(p_queue_base_v4__Internal_empty, "?_Internal_empty@_Concurrent_queue_base_v4@details@Concurrency@@IEBA_NXZ"); SET(p_queue_base_v4__Internal_size, "?_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, "?_Internal_finish_clear@_Concurrent_queue_base_v4@details@Concurrency@@IEAAXXZ"); SET(p_vector_base_v4_dtor, "??1_Concurrent_vector_base_v4@details@Concurrency@@IEAA@XZ"); SET(p_vector_base_v4__Internal_capacity, "?_Internal_capacity@_Concurrent_vector_base_v4@details@Concurrency@@IEBA_KXZ"); SET(p_vector_base_v4__Internal_push_back, "?_Internal_push_back@_Concurrent_vector_base_v4@details@Concurrency@@IEAAPEAX_KAEA_K@Z"); SET(p_vector_base_v4__Internal_clear, "?_Internal_clear@_Concurrent_vector_base_v4@details@Concurrency@@IEAA_KP6AXPEAX_K@Z@Z"); SET(p_vector_base_v4__Internal_copy, "?_Internal_copy@_Concurrent_vector_base_v4@details@Concurrency@@IEAAXAEBV123@_KP6AXPEAXPEBX1@Z@Z"); } else { SET(p_tr2_sys__File_size, "?_File_size@sys@tr2@std@@YA_KPBD@Z"); SET(p_tr2_sys__File_size_wchar, "?_File_size@sys@tr2@std@@YA_KPB_W@Z"); SET(p_tr2_sys__Equivalent, "?_Equivalent@sys@tr2@std@@YAHPBD0@Z"); SET(p_tr2_sys__Equivalent_wchar, "?_Equivalent@sys@tr2@std@@YAHPB_W0@Z"); SET(p_tr2_sys__Current_get, "?_Current_get@sys@tr2@std@@YAPADAAY0BAE@D@Z"); SET(p_tr2_sys__Current_get_wchar, "?_Current_get@sys@tr2@std@@YAPA_WAAY0BAE@_W@Z"); SET(p_tr2_sys__Current_set, "?_Current_set@sys@tr2@std@@YA_NPBD@Z"); SET(p_tr2_sys__Current_set_wchar, "?_Current_set@sys@tr2@std@@YA_NPB_W@Z"); SET(p_tr2_sys__Make_dir, "?_Make_dir@sys@tr2@std@@YAHPBD@Z"); SET(p_tr2_sys__Make_dir_wchar, "?_Make_dir@sys@tr2@std@@YAHPB_W@Z"); SET(p_tr2_sys__Remove_dir, "?_Remove_dir@sys@tr2@std@@YA_NPBD@Z"); SET(p_tr2_sys__Remove_dir_wchar, "?_Remove_dir@sys@tr2@std@@YA_NPB_W@Z"); SET(p_tr2_sys__Copy_file, "?_Copy_file@sys@tr2@std@@YAHPBD0_N@Z"); SET(p_tr2_sys__Copy_file_wchar, "?_Copy_file@sys@tr2@std@@YAHPB_W0_N@Z"); SET(p_tr2_sys__Rename, "?_Rename@sys@tr2@std@@YAHPBD0@Z"); SET(p_tr2_sys__Rename_wchar, "?_Rename@sys@tr2@std@@YAHPB_W0@Z"); SET(p_tr2_sys__Statvfs, "?_Statvfs@sys@tr2@std@@YA?AUspace_info@123@PBD@Z"); SET(p_tr2_sys__Statvfs_wchar, "?_Statvfs@sys@tr2@std@@YA?AUspace_info@123@PB_W@Z"); SET(p_tr2_sys__Stat, "?_Stat@sys@tr2@std@@YA?AW4file_type@123@PBDAAH@Z"); SET(p_tr2_sys__Stat_wchar, "?_Stat@sys@tr2@std@@YA?AW4file_type@123@PB_WAAH@Z"); SET(p_tr2_sys__Lstat, "?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PBDAAH@Z"); SET(p_tr2_sys__Lstat_wchar, "?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PB_WAAH@Z"); SET(p_tr2_sys__Last_write_time, "?_Last_write_time@sys@tr2@std@@YA_JPBD@Z"); SET(p_tr2_sys__Last_write_time_set, "?_Last_write_time@sys@tr2@std@@YAXPBD_J@Z"); SET(p_tr2_sys__Open_dir, "?_Open_dir@sys@tr2@std@@YAPAXAAY0BAE@DPBDAAHAAW4file_type@123@@Z"); SET(p_tr2_sys__Read_dir, "?_Read_dir@sys@tr2@std@@YAPADAAY0BAE@DPAXAAW4file_type@123@@Z"); SET(p_tr2_sys__Close_dir, "?_Close_dir@sys@tr2@std@@YAXPAX@Z"); SET(p_tr2_sys__Link, "?_Link@sys@tr2@std@@YAHPBD0@Z"); SET(p_tr2_sys__Symlink, "?_Symlink@sys@tr2@std@@YAHPBD0@Z"); SET(p_tr2_sys__Unlink, "?_Unlink@sys@tr2@std@@YAHPBD@Z"); SET(p_threads__Mtx_new, "?_Mtx_new@threads@stdext@@YAXAAPAX@Z"); SET(p_threads__Mtx_delete, "?_Mtx_delete@threads@stdext@@YAXPAX@Z"); SET(p_threads__Mtx_lock, "?_Mtx_lock@threads@stdext@@YAXPAX@Z"); SET(p_threads__Mtx_unlock, "?_Mtx_unlock@threads@stdext@@YAXPAX@Z"); SET(p_vector_base_v4__Segment_index_of, "?_Segment_index_of@_Concurrent_vector_base_v4@details@Concurrency@@KAII@Z"); #ifdef __i386__ SET(p_i386_Thrd_current, "_Thrd_current"); p__Thrd_current = i386_Thrd_current; SET(p__Pad_ctor, "??0_Pad@std@@QAE@XZ"); SET(p__Pad_copy_ctor, "??0_Pad@std@@QAE@ABV01@@Z"); SET(p__Pad_dtor, "??1_Pad@std@@QAE@XZ"); SET(p__Pad_op_assign, "??4_Pad@std@@QAEAAV01@ABV01@@Z"); SET(p__Pad__Launch, "?_Launch@_Pad@std@@QAEXPAU_Thrd_imp_t@@@Z"); SET(p__Pad__Release, "?_Release@_Pad@std@@QAEXXZ"); SET(p_queue_base_v4_ctor, "??0_Concurrent_queue_base_v4@details@Concurrency@@IAE@I@Z"); SET(p_queue_base_v4_dtor, "??1_Concurrent_queue_base_v4@details@Concurrency@@MAE@XZ"); SET(p_queue_base_v4__Internal_empty, "?_Internal_empty@_Concurrent_queue_base_v4@details@Concurrency@@IBE_NXZ"); SET(p_queue_base_v4__Internal_size, "?_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, "?_Internal_finish_clear@_Concurrent_queue_base_v4@details@Concurrency@@IAEXXZ"); SET(p_vector_base_v4_dtor, "??1_Concurrent_vector_base_v4@details@Concurrency@@IAE@XZ"); SET(p_vector_base_v4__Internal_capacity, "?_Internal_capacity@_Concurrent_vector_base_v4@details@Concurrency@@IBEIXZ"); SET(p_vector_base_v4__Internal_push_back, "?_Internal_push_back@_Concurrent_vector_base_v4@details@Concurrency@@IAEPAXIAAI@Z"); SET(p_vector_base_v4__Internal_clear, "?_Internal_clear@_Concurrent_vector_base_v4@details@Concurrency@@IAEIP6AXPAXI@Z@Z"); SET(p_vector_base_v4__Internal_copy, "?_Internal_copy@_Concurrent_vector_base_v4@details@Concurrency@@IAEXABV123@IP6AXPAXPBXI@Z@Z"); #else SET(p__Thrd_current, "_Thrd_current"); SET(p__Pad_ctor, "??0_Pad@std@@QAA@XZ"); SET(p__Pad_copy_ctor, "??0_Pad@std@@QAA@ABV01@@Z"); SET(p__Pad_dtor, "??1_Pad@std@@QAA@XZ"); SET(p__Pad_op_assign, "??4_Pad@std@@QAAAAV01@ABV01@@Z"); SET(p__Pad__Launch, "?_Launch@_Pad@std@@QAAXPAU_Thrd_imp_t@@@Z"); SET(p__Pad__Release, "?_Release@_Pad@std@@QAAXXZ"); SET(p_queue_base_v4_ctor, "??0_Concurrent_queue_base_v4@details@Concurrency@@IAA@I@Z"); SET(p_queue_base_v4_dtor, "??1_Concurrent_queue_base_v4@details@Concurrency@@MAA@XZ"); SET(p_queue_base_v4__Internal_empty, "?_Internal_empty@_Concurrent_queue_base_v4@details@Concurrency@@IBA_NXZ"); SET(p_queue_base_v4__Internal_size, "?_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, "?_Internal_finish_clear@_Concurrent_queue_base_v4@details@Concurrency@@IAAXXZ"); SET(p_vector_base_v4_dtor, "??1_Concurrent_vector_base_v4@details@Concurrency@@IAA@XZ"); SET(p_vector_base_v4__Internal_capacity, "?_Internal_capacity@_Concurrent_vector_base_v4@details@Concurrency@@IBAIXZ"); SET(p_vector_base_v4__Internal_push_back, "?_Internal_push_back@_Concurrent_vector_base_v4@details@Concurrency@@IAAPAXIAAI@Z"); SET(p_vector_base_v4__Internal_clear, "?_Internal_clear@_Concurrent_vector_base_v4@details@Concurrency@@IAAIP6AXPAXI@Z@Z"); SET(p_vector_base_v4__Internal_copy, "?_Internal_copy@_Concurrent_vector_base_v4@details@Concurrency@@IAAXABV123@IP6AXPAXPBXI@Z@Z"); #endif } SET(p__Thrd_equal, "_Thrd_equal"); SET(p__Thrd_lt, "_Thrd_lt"); SET(p__Thrd_sleep, "_Thrd_sleep"); SET(p__Thrd_create, "_Thrd_create"); SET(p__Thrd_join, "_Thrd_join"); SET(p__Thrd_detach, "_Thrd_detach"); SET(p__Mtx_init, "_Mtx_init"); SET(p__Mtx_destroy, "_Mtx_destroy"); SET(p__Mtx_lock, "_Mtx_lock"); SET(p__Mtx_unlock, "_Mtx_unlock"); SET(p__Cnd_init, "_Cnd_init"); SET(p__Cnd_destroy, "_Cnd_destroy"); SET(p__Cnd_wait, "_Cnd_wait"); SET(p__Cnd_timedwait, "_Cnd_timedwait"); SET(p__Cnd_broadcast, "_Cnd_broadcast"); SET(p__Cnd_signal, "_Cnd_signal"); SET(p__Cnd_register_at_thread_exit, "_Cnd_register_at_thread_exit"); SET(p__Cnd_unregister_at_thread_exit, "_Cnd_unregister_at_thread_exit"); SET(p__Cnd_do_broadcast_at_thread_exit, "_Cnd_do_broadcast_at_thread_exit"); hdll = GetModuleHandleA("msvcr120.dll"); p_setlocale = (void*)GetProcAddress(hdll, "setlocale"); p__setmbcp = (void*)GetProcAddress(hdll, "_setmbcp"); p__ismbblead = (void*)GetProcAddress(hdll, "_ismbblead"); hdll = GetModuleHandleA("kernel32.dll"); pCreateSymbolicLinkA = (void*)GetProcAddress(hdll, "CreateSymbolicLinkA"); init_thiscall_thunk(); return TRUE; } static void test__Xtime_diff_to_millis2(void) { struct { __time64_t sec_before; MSVCRT_long nsec_before; __time64_t sec_after; MSVCRT_long nsec_after; MSVCRT_long expect; } tests[] = { {1, 0, 2, 0, 1000}, {0, 1000000000, 0, 2000000000, 1000}, {1, 100000000, 2, 100000000, 1000}, {1, 100000000, 1, 200000000, 100}, {0, 0, 0, 1000000000, 1000}, {0, 0, 0, 1200000000, 1200}, {0, 0, 0, 1230000000, 1230}, {0, 0, 0, 1234000000, 1234}, {0, 0, 0, 1234100000, 1235}, {0, 0, 0, 1234900000, 1235}, {0, 0, 0, 1234010000, 1235}, {0, 0, 0, 1234090000, 1235}, {0, 0, 0, 1234000001, 1235}, {0, 0, 0, 1234000009, 1235}, {0, 0, -1, 0, 0}, {1, 0, 0, 0, 0}, {0, 1000000000, 0, 0, 0}, {0x7FFFFFFF / 1000, 0, 0, 0, 0}, {2147484, 0, 0, 0, 0}, /* ceil(0x80000000 / 1000) */ {2147485, 0, 0, 0, 0}, /* ceil(0x80000000 / 1000) + 1*/ {0, 0, 0x7FFFFFFF / 1000, 0, 2147483000}, {0, 0, 0x7FFFFFFF / 1000, 647000000, 0x7FFFFFFF}, /* max */ {0, 0, 0x7FFFFFFF / 1000, 647000001, -2147483648}, /* overflow. */ {0, 0, 2147484, 0, -2147483296}, /* ceil(0x80000000 / 1000), overflow*/ {0, 0, 0, -10000000, 0}, {0, 0, -1, -100000000, 0}, {-1, 0, 0, 0, 1000}, {0, -100000000, 0, 0, 100}, {-1, -100000000, 0, 0, 1100}, {0, 0, -1, 2000000000, 1000}, {0, 0, -2, 2000000000, 0}, {0, 0, -2, 2100000000, 100}, {0, 0, _I64_MAX / 1000, 0, -808}, /* Still fits in a signed 64 bit number */ {0, 0, _I64_MAX / 1000, 1000000000, 192}, /* Overflows a signed 64 bit number */ {0, 0, (((ULONGLONG)0x80000000 << 32) | 0x1000) / 1000, 1000000000, 4192}, /* 64 bit overflow */ {_I64_MAX - 2, 0, _I64_MAX, 0, 2000}, /* Not an overflow */ {_I64_MAX, 0, _I64_MAX - 2, 0, 0}, /* Not an overflow */ /* October 11th 2017, 12:34:59 UTC */ {1507725144, 983274000, 0, 0, 0}, {0, 0, 1507725144, 983274000, 191624088}, {1507725144, 983274000, 1507725145, 983274000, 1000}, {1507725145, 983274000, 1507725145, 983274000, 0}, }; int i; MSVCRT_long ret; xtime t1, t2; for(i = 0; i < ARRAY_SIZE(tests); ++ i) { t1.sec = tests[i].sec_before; t1.nsec = tests[i].nsec_before; t2.sec = tests[i].sec_after; t2.nsec = tests[i].nsec_after; ret = p__Xtime_diff_to_millis2(&t2, &t1); ok(ret == tests[i].expect, "_Xtime_diff_to_millis2(): test: %d expect: %d, got: %d\n", i, tests[i].expect, ret); } } static void test_xtime_get(void) { static const MSVCRT_long tests[] = {1, 50, 100, 200, 500}; MSVCRT_long diff; xtime before, after; int i; for(i = 0; i < ARRAY_SIZE(tests); i ++) { p_xtime_get(&before, 1); Sleep(tests[i]); p_xtime_get(&after, 1); diff = p__Xtime_diff_to_millis2(&after, &before); ok(diff >= tests[i], "xtime_get() not functioning correctly, test: %d, expect: %d, got: %d\n", i, tests[i], diff); } /* Test parameter and return value */ before.sec = 0xdeadbeef, before.nsec = 0xdeadbeef; i = p_xtime_get(&before, 0); ok(i == 0, "expect xtime_get() to return 0, got: %d\n", i); ok(before.sec == 0xdeadbeef && before.nsec == 0xdeadbeef, "xtime_get() shouldn't have modified the xtime struct with the given option\n"); before.sec = 0xdeadbeef, before.nsec = 0xdeadbeef; i = p_xtime_get(&before, 1); ok(i == 1, "expect xtime_get() to return 1, got: %d\n", i); ok(before.sec != 0xdeadbeef && before.nsec != 0xdeadbeef, "xtime_get() should have modified the xtime struct with the given option\n"); } static void test__Getcvt(void) { _Cvtvec cvtvec; int i; p__Getcvt(&cvtvec); ok(cvtvec.page == 0, "cvtvec.page = %d\n", cvtvec.page); ok(cvtvec.mb_max == 1, "cvtvec.mb_max = %d\n", cvtvec.mb_max); todo_wine ok(cvtvec.unk == 1, "cvtvec.unk = %d\n", cvtvec.unk); for(i=0; i<32; i++) ok(cvtvec.isleadbyte[i] == 0, "cvtvec.isleadbyte[%d] = %x\n", i, cvtvec.isleadbyte[i]); if(!p_setlocale(LC_ALL, ".936")) { win_skip("_Getcvt tests\n"); return; } p__Getcvt(&cvtvec); ok(cvtvec.page == 936, "cvtvec.page = %d\n", cvtvec.page); ok(cvtvec.mb_max == 2, "cvtvec.mb_max = %d\n", cvtvec.mb_max); ok(cvtvec.unk == 0, "cvtvec.unk = %d\n", cvtvec.unk); for(i=0; i<32; i++) { BYTE b = 0; int j; for(j=0; j<8; j++) b |= (p__ismbblead(i*8+j) ? 1 : 0) << j; ok(cvtvec.isleadbyte[i] ==b, "cvtvec.isleadbyte[%d] = %x (%x)\n", i, cvtvec.isleadbyte[i], b); } p__setmbcp(936); p__Getcvt(&cvtvec); ok(cvtvec.page == 936, "cvtvec.page = %d\n", cvtvec.page); ok(cvtvec.mb_max == 2, "cvtvec.mb_max = %d\n", cvtvec.mb_max); ok(cvtvec.unk == 0, "cvtvec.unk = %d\n", cvtvec.unk); for(i=0; i<32; i++) { BYTE b = 0; int j; for(j=0; j<8; j++) b |= (p__ismbblead(i*8+j) ? 1 : 0) << j; ok(cvtvec.isleadbyte[i] ==b, "cvtvec.isleadbyte[%d] = %x (%x)\n", i, cvtvec.isleadbyte[i], b); } } static int cnt; static int once; static void __cdecl call_once_func(void) { ok(!once, "once != 0\n"); cnt += 0x10000; } static void __cdecl call_once_ex_func(void *arg) { int *i = arg; ok(!once, "once != 0\n"); (*i)++; } static DWORD WINAPI call_once_thread(void *arg) { p__Call_once(&once, call_once_func); return 0; } static DWORD WINAPI call_once_ex_thread(void *arg) { p__Call_onceEx(&once, call_once_ex_func, &cnt); return 0; } static void test__Call_once(void) { HANDLE h[4]; int i; for(i=0; i<4; i++) h[i] = CreateThread(NULL, 0, call_once_thread, &once, 0, NULL); ok(WaitForMultipleObjects(4, h, TRUE, INFINITE) == WAIT_OBJECT_0, "error waiting for all threads to finish\n"); ok(cnt == 0x10000, "cnt = %x\n", cnt); ok(once == 1, "once = %x\n", once); once = cnt = 0; for(i=0; i<4; i++) h[i] = CreateThread(NULL, 0, call_once_ex_thread, &once, 0, NULL); ok(WaitForMultipleObjects(4, h, TRUE, INFINITE) == WAIT_OBJECT_0, "error waiting for all threads to finish\n"); ok(cnt == 1, "cnt = %x\n", cnt); ok(once == 1, "once = %x\n", once); } static void **vtbl_func0; #ifdef __i386__ /* TODO: this should be a __thiscall function */ static void __stdcall thiscall_func(void) { cnt = 1; } #else static void __cdecl thiscall_func(void *this) { ok(this == &vtbl_func0, "incorrect this value\n"); cnt = 1; } #endif static void test__Do_call(void) { void *pfunc = thiscall_func; cnt = 0; vtbl_func0 = &pfunc; p__Do_call(&vtbl_func0); ok(cnt == 1, "func was not called\n"); } static void test__Dtest(void) { double d; short ret; d = 0; ret = p__Dtest(&d); ok(ret == FP_ZERO, "_Dtest(0) returned %x\n", ret); d = 1; ret = p__Dtest(&d); ok(ret == FP_NORMAL, "_Dtest(1) returned %x\n", ret); d = -1; ret = p__Dtest(&d); ok(ret == FP_NORMAL, "_Dtest(-1) returned %x\n", ret); d = INFINITY; ret = p__Dtest(&d); ok(ret == FP_INFINITE, "_Dtest(INF) returned %x\n", ret); d = NAN; ret = p__Dtest(&d); ok(ret == FP_NAN, "_Dtest(NAN) returned %x\n", ret); } static void test__Dscale(void) { double d; short ret; d = 0; ret = p__Dscale(&d, 0); ok(d == 0, "d = %f\n", d); ok(ret == FP_ZERO, "ret = %x\n", ret); d = 0; ret = p__Dscale(&d, 1); ok(d == 0, "d = %f\n", d); ok(ret == FP_ZERO, "ret = %x\n", ret); d = 0; ret = p__Dscale(&d, -1); ok(d == 0, "d = %f\n", d); ok(ret == FP_ZERO, "ret = %x\n", ret); d = 1; ret = p__Dscale(&d, 0); ok(d == 1, "d = %f\n", d); ok(ret == FP_NORMAL, "ret = %x\n", ret); d = 1; ret = p__Dscale(&d, 1); ok(d == 2, "d = %f\n", d); ok(ret == FP_NORMAL, "ret = %x\n", ret); d = 1; ret = p__Dscale(&d, -1); ok(d == 0.5, "d = %f\n", d); ok(ret == FP_NORMAL, "ret = %x\n", ret); d = 1; ret = p__Dscale(&d, -99999); ok(d == 0, "d = %f\n", d); ok(ret == FP_ZERO, "ret = %x\n", ret); d = 1; ret = p__Dscale(&d, 999999); ok(d == INFINITY, "d = %f\n", d); ok(ret == FP_INFINITE, "ret = %x\n", ret); d = NAN; ret = p__Dscale(&d, 1); ok(ret == FP_NAN, "ret = %x\n", ret); } static void test__FExp(void) { float d; short ret; d = 0; ret = p__FExp(&d, 0, 0); ok(d == 0, "d = %f\n", d); ok(ret == FP_ZERO, "ret = %x\n", ret); d = 0; ret = p__FExp(&d, 1, 0); ok(d == 1.0, "d = %f\n", d); ok(ret == FP_NORMAL, "ret = %x\n", ret); d = 0; ret = p__FExp(&d, 1, 1); ok(d == 2.0, "d = %f\n", d); ok(ret == FP_NORMAL, "ret = %x\n", ret); d = 0; ret = p__FExp(&d, 1, 2); ok(d == 4.0, "d = %f\n", d); ok(ret == FP_NORMAL, "ret = %x\n", ret); d = 0; ret = p__FExp(&d, 10, 0); ok(d == 10.0, "d = %f\n", d); ok(ret == FP_NORMAL, "ret = %x\n", ret); d = 1; ret = p__FExp(&d, 0, 0); ok(d == 0, "d = %f\n", d); ok(ret == FP_ZERO, "ret = %x\n", ret); d = 1; ret = p__FExp(&d, 1, 0); ok(compare_float(d, 2.7182817, 4), "d = %f\n", d); ok(ret == FP_NORMAL, "ret = %x\n", ret); d = 9e20; ret = p__FExp(&d, 0, 0); ok(d == 0, "d = %f\n", d); ok(ret == FP_ZERO, "ret = %x\n", ret); d = 90; ret = p__FExp(&d, 1, 0); ok(ret == FP_INFINITE, "ret = %x\n", ret); d = 90; ret = p__FExp(&d, 1, -50); ok(compare_float(d, 1.0839359e+024, 4), "d = %g\n", d); ok(ret == FP_NORMAL, "ret = %x\n", ret); } static void test_tr2_sys__File_size(void) { ULONGLONG val; HANDLE file; LARGE_INTEGER file_size; WCHAR testW[] = {'t','r','2','_','t','e','s','t','_','d','i','r','/','f','1',0}; CreateDirectoryA("tr2_test_dir", NULL); file = CreateFileA("tr2_test_dir/f1", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n"); file_size.QuadPart = 7; ok(SetFilePointerEx(file, file_size, NULL, FILE_BEGIN), "SetFilePointerEx failed\n"); ok(SetEndOfFile(file), "SetEndOfFile failed\n"); CloseHandle(file); val = p_tr2_sys__File_size("tr2_test_dir/f1"); ok(val == 7, "file_size is %s\n", wine_dbgstr_longlong(val)); val = p_tr2_sys__File_size_wchar(testW); ok(val == 7, "file_size is %s\n", wine_dbgstr_longlong(val)); file = CreateFileA("tr2_test_dir/f2", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n"); CloseHandle(file); val = p_tr2_sys__File_size("tr2_test_dir/f2"); ok(val == 0, "file_size is %s\n", wine_dbgstr_longlong(val)); val = p_tr2_sys__File_size("tr2_test_dir"); ok(val == 0, "file_size is %s\n", wine_dbgstr_longlong(val)); errno = 0xdeadbeef; val = p_tr2_sys__File_size("tr2_test_dir/not_exists_file"); ok(val == 0, "file_size is %s\n", wine_dbgstr_longlong(val)); ok(errno == 0xdeadbeef, "errno = %d\n", errno); errno = 0xdeadbeef; val = p_tr2_sys__File_size(NULL); ok(val == 0, "file_size is %s\n", wine_dbgstr_longlong(val)); ok(errno == 0xdeadbeef, "errno = %d\n", errno); ok(DeleteFileA("tr2_test_dir/f1"), "expect tr2_test_dir/f1 to exist\n"); ok(DeleteFileA("tr2_test_dir/f2"), "expect tr2_test_dir/f2 to exist\n"); ok(p_tr2_sys__Remove_dir("tr2_test_dir"), "expect tr2_test_dir to exist\n"); } static void test_tr2_sys__Equivalent(void) { int val, i; HANDLE file; char temp_path[MAX_PATH], current_path[MAX_PATH]; WCHAR testW[] = {'t','r','2','_','t','e','s','t','_','d','i','r','/','f','1',0}; WCHAR testW2[] = {'t','r','2','_','t','e','s','t','_','d','i','r','/','f','2',0}; struct { char const *path1; char const *path2; int equivalent; } tests[] = { { NULL, NULL, -1 }, { NULL, "f1", -1 }, { "f1", NULL, -1 }, { "f1", "tr2_test_dir", -1 }, { "tr2_test_dir", "f1", -1 }, { "tr2_test_dir", "tr2_test_dir", -1 }, { "tr2_test_dir/./f1", "tr2_test_dir/f2", 0 }, { "tr2_test_dir/f1" , "tr2_test_dir/f1", 1 }, { "not_exists_file" , "tr2_test_dir/f1", 0 }, { "tr2_test_dir\\f1" , "tr2_test_dir/./f1", 1 }, { "not_exists_file" , "not_exists_file", -1 }, { "tr2_test_dir/f1" , "not_exists_file", 0 }, { "tr2_test_dir/../tr2_test_dir/f1", "tr2_test_dir/f1", 1 } }; memset(current_path, 0, MAX_PATH); GetCurrentDirectoryA(MAX_PATH, current_path); memset(temp_path, 0, MAX_PATH); GetTempPathA(MAX_PATH, temp_path); ok(SetCurrentDirectoryA(temp_path), "SetCurrentDirectoryA to temp_path failed\n"); CreateDirectoryA("tr2_test_dir", NULL); file = CreateFileA("tr2_test_dir/f1", 0, 0, NULL, CREATE_ALWAYS, 0, NULL); ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n"); CloseHandle(file); file = CreateFileA("tr2_test_dir/f2", 0, 0, NULL, CREATE_ALWAYS, 0, NULL); ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n"); CloseHandle(file); for(i=0; i>"), "p_tr2_sys__Current_set to ??invalid_name>> succeed\n"); ok(errno == 0xdeadbeef, "errno = %d\n", errno); ok(p_tr2_sys__Current_set(origin_path), "p_tr2_sys__Current_set to origin_path failed\n"); memset(current_path, 0, MAX_PATH); temp = p_tr2_sys__Current_get(current_path); ok(temp == current_path, "p_tr2_sys__Current_get returned different buffer\n"); ok(!strcmp(origin_path, current_path), "test_tr2_sys__Current_get(): expect: %s, got %s\n", origin_path, current_path); } static void test_tr2_sys__Make_dir(void) { int ret, i; WCHAR testW[] = {'w','d',0}; struct { char const *path; int val; } tests[] = { { "tr2_test_dir", 1 }, { "tr2_test_dir", 0 }, { NULL, -1 }, { "??invalid_name>>", -1 } }; for(i=0; i>", FALSE } }; ok(p_tr2_sys__Make_dir("tr2_test_dir"), "tr2_sys__Make_dir() failed\n"); for(i=0; i>", ERROR_INVALID_NAME }, { "tr2_test_dir\\not_exist_file", "tr2_test_dir\\not_exist_rename", ERROR_FILE_NOT_FOUND } }; memset(current_path, 0, MAX_PATH); GetCurrentDirectoryA(MAX_PATH, current_path); memset(temp_path, 0, MAX_PATH); GetTempPathA(MAX_PATH, temp_path); ok(SetCurrentDirectoryA(temp_path), "SetCurrentDirectoryA to temp_path failed\n"); ret = p_tr2_sys__Make_dir("tr2_test_dir"); ok(ret == 1, "test_tr2_sys__Make_dir(): expect 1 got %d\n", ret); file = CreateFileA("tr2_test_dir\\f1", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n"); CloseHandle(file); ret = p_tr2_sys__Rename("tr2_test_dir\\f1", "tr2_test_dir\\f1"); todo_wine ok(ERROR_SUCCESS == ret, "test_tr2_sys__Rename(): expect: ERROR_SUCCESS, got %d\n", ret); for(i=0; i= info.free, "test_tr2_sys__Statvfs(): info.capacity < info.free\n"); ok(info.free >= info.available, "test_tr2_sys__Statvfs(): info.free < info.available\n"); p_tr2_sys__Statvfs_wchar(&info, current_path_wchar); ok(info.capacity >= info.free, "tr2_sys__Statvfs_wchar(): info.capacity < info.free\n"); ok(info.free >= info.available, "tr2_sys__Statvfs_wchar(): info.free < info.available\n"); p_tr2_sys__Statvfs(&info, NULL); ok(info.available == 0, "test_tr2_sys__Statvfs(): info.available expect: %d, got %s\n", 0, wine_dbgstr_longlong(info.available)); ok(info.capacity == 0, "test_tr2_sys__Statvfs(): info.capacity expect: %d, got %s\n", 0, wine_dbgstr_longlong(info.capacity)); ok(info.free == 0, "test_tr2_sys__Statvfs(): info.free expect: %d, got %s\n", 0, wine_dbgstr_longlong(info.free)); p_tr2_sys__Statvfs(&info, "not_exist"); ok(info.available == 0, "test_tr2_sys__Statvfs(): info.available expect: %d, got %s\n", 0, wine_dbgstr_longlong(info.available)); ok(info.capacity == 0, "test_tr2_sys__Statvfs(): info.capacity expect: %d, got %s\n", 0, wine_dbgstr_longlong(info.capacity)); ok(info.free == 0, "test_tr2_sys__Statvfs(): info.free expect: %d, got %s\n", 0, wine_dbgstr_longlong(info.free)); } static void test_tr2_sys__Stat(void) { int i, err_code, ret; HANDLE file; enum file_type val; struct { char const *path; enum file_type ret; int err_code; int is_todo; } tests[] = { { NULL, status_unknown, ERROR_INVALID_PARAMETER, FALSE }, { "tr2_test_dir", directory_file, ERROR_SUCCESS, FALSE }, { "tr2_test_dir\\f1", regular_file, ERROR_SUCCESS, FALSE }, { "tr2_test_dir\\not_exist_file ", file_not_found, ERROR_SUCCESS, FALSE }, { "tr2_test_dir\\??invalid_name>>", file_not_found, ERROR_SUCCESS, FALSE }, { "tr2_test_dir\\f1_link" , regular_file, ERROR_SUCCESS, TRUE }, { "tr2_test_dir\\dir_link", directory_file, ERROR_SUCCESS, TRUE }, }; WCHAR testW[] = {'t','r','2','_','t','e','s','t','_','d','i','r',0}; WCHAR testW2[] = {'t','r','2','_','t','e','s','t','_','d','i','r','/','f','1',0}; CreateDirectoryA("tr2_test_dir", NULL); file = CreateFileA("tr2_test_dir/f1", 0, 0, NULL, CREATE_ALWAYS, 0, NULL); ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n"); ok(CloseHandle(file), "CloseHandle\n"); SetLastError(0xdeadbeef); ret = pCreateSymbolicLinkA ? pCreateSymbolicLinkA("tr2_test_dir/f1_link", "tr2_test_dir/f1", 0) : FALSE; if(!ret && (!pCreateSymbolicLinkA || GetLastError()==ERROR_PRIVILEGE_NOT_HELD||GetLastError()==ERROR_INVALID_FUNCTION)) { tests[5].ret = tests[6].ret = file_not_found; win_skip("Privilege not held or symbolic link not supported, skipping symbolic link tests.\n"); }else { ok(ret, "CreateSymbolicLinkA failed\n"); ok(pCreateSymbolicLinkA("tr2_test_dir/dir_link", "tr2_test_dir", 1), "CreateSymbolicLinkA failed\n"); } file = CreateNamedPipeA("\\\\.\\PiPe\\tests_pipe.c", PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT, 2, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); ok(file != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); err_code = 0xdeadbeef; val = p_tr2_sys__Stat("\\\\.\\PiPe\\tests_pipe.c", &err_code); todo_wine ok(regular_file == val, "tr2_sys__Stat(): expect: regular_file, got %d\n", val); todo_wine ok(ERROR_SUCCESS == err_code, "tr2_sys__Stat(): err_code expect: ERROR_SUCCESS, got %d\n", err_code); err_code = 0xdeadbeef; val = p_tr2_sys__Lstat("\\\\.\\PiPe\\tests_pipe.c", &err_code); ok(status_unknown == val, "tr2_sys__Lstat(): expect: status_unknown, got %d\n", val); todo_wine ok(ERROR_PIPE_BUSY == err_code, "tr2_sys__Lstat(): err_code expect: ERROR_PIPE_BUSY, got %d\n", err_code); ok(CloseHandle(file), "CloseHandle\n"); file = CreateNamedPipeA("\\\\.\\PiPe\\tests_pipe.c", PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT, 2, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); ok(file != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); err_code = 0xdeadbeef; val = p_tr2_sys__Lstat("\\\\.\\PiPe\\tests_pipe.c", &err_code); todo_wine ok(regular_file == val, "tr2_sys__Lstat(): expect: regular_file, got %d\n", val); todo_wine ok(ERROR_SUCCESS == err_code, "tr2_sys__Lstat(): err_code expect: ERROR_SUCCESS, got %d\n", err_code); ok(CloseHandle(file), "CloseHandle\n"); for(i=0; i 2000 - TIMEDELTA, "got %d\n", diff); /* test for current */ ta = p__Thrd_current(); tb = p__Thrd_current(); ok(ta.id == tb.id, "got a %d b %d\n", ta.id, tb.id); ok(ta.id == GetCurrentThreadId(), "expected %d, got %d\n", GetCurrentThreadId(), ta.id); /* these can be different if new threads are created at same time */ ok(ta.hnd == tb.hnd, "got a %p b %p\n", ta.hnd, tb.hnd); ok(!CloseHandle(ta.hnd), "handle %p not closed\n", ta.hnd); ok(!CloseHandle(tb.hnd), "handle %p not closed\n", tb.hnd); /* test for create/join */ if (0) /* crash on Windows */ { p__Thrd_create(NULL, thrd_thread, NULL); p__Thrd_create(&ta, NULL, NULL); } r = -1; ret = p__Thrd_create(&ta, thrd_thread, (void*)&tb); ok(!ret, "failed to create thread, got %d\n", ret); ret = p__Thrd_join(ta, &r); ok(!ret, "failed to join thread, got %d\n", ret); ok(ta.id == tb.id, "expected %d, got %d\n", ta.id, tb.id); ok(ta.hnd != tb.hnd, "same handles, got %p\n", ta.hnd); ok(r == 0x42, "expected 0x42, got %d\n", r); ret = p__Thrd_detach(ta); ok(ret == 4, "_Thrd_detach should have failed with error 4, got %d\n", ret); ret = p__Thrd_create(&ta, thrd_thread, NULL); ok(!ret, "failed to create thread, got %d\n", ret); ret = p__Thrd_detach(ta); ok(!ret, "_Thrd_detach failed, got %d\n", ret); } #define NUM_THREADS 10 struct cndmtx { HANDLE initialized; int started; int thread_no; _Cnd_t cnd; _Mtx_t mtx; BOOL timed_wait; }; static int __cdecl cnd_wait_thread(void *arg) { struct cndmtx *cm = arg; int r; p__Mtx_lock(&cm->mtx); if(InterlockedIncrement(&cm->started) == cm->thread_no) SetEvent(cm->initialized); if(cm->timed_wait) { xtime xt; p_xtime_get(&xt, 1); xt.sec += 2; r = p__Cnd_timedwait(&cm->cnd, &cm->mtx, &xt); ok(!r, "timed wait failed\n"); } else { r = p__Cnd_wait(&cm->cnd, &cm->mtx); ok(!r, "wait failed\n"); } p__Mtx_unlock(&cm->mtx); return 0; } static void test_cnd(void) { _Thrd_t threads[NUM_THREADS]; xtime xt, before, after; MSVCRT_long diff; struct cndmtx cm; _Cnd_t cnd; _Mtx_t mtx; int r, i; r = p__Cnd_init(&cnd); ok(!r, "failed to init cnd\n"); r = p__Mtx_init(&mtx, 0); ok(!r, "failed to init mtx\n"); if (0) /* crash on Windows */ { p__Cnd_init(NULL); p__Cnd_wait(NULL, &mtx); p__Cnd_wait(&cnd, NULL); p__Cnd_timedwait(NULL, &mtx, &xt); p__Cnd_timedwait(&cnd, &mtx, &xt); } p__Cnd_destroy(NULL); /* test _Cnd_signal/_Cnd_wait */ cm.initialized = CreateEventW(NULL, FALSE, FALSE, NULL); cm.started = 0; cm.thread_no = 1; cm.cnd = cnd; cm.mtx = mtx; cm.timed_wait = FALSE; p__Thrd_create(&threads[0], cnd_wait_thread, (void*)&cm); WaitForSingleObject(cm.initialized, INFINITE); p__Mtx_lock(&mtx); p__Mtx_unlock(&mtx); r = p__Cnd_signal(&cm.cnd); ok(!r, "failed to signal\n"); p__Thrd_join(threads[0], NULL); /* test _Cnd_timedwait time out */ p__Mtx_lock(&mtx); p_xtime_get(&before, 1); xt = before; xt.sec += 1; r = p__Cnd_timedwait(&cnd, &mtx, &xt); p_xtime_get(&after, 1); p__Mtx_unlock(&mtx); diff = p__Xtime_diff_to_millis2(&after, &before); ok(r == 2, "should have timed out\n"); ok(diff > 1000 - TIMEDELTA, "got %d\n", diff); /* test _Cnd_timedwait */ cm.started = 0; cm.timed_wait = TRUE; p__Thrd_create(&threads[0], cnd_wait_thread, (void*)&cm); WaitForSingleObject(cm.initialized, INFINITE); p__Mtx_lock(&mtx); p__Mtx_unlock(&mtx); r = p__Cnd_signal(&cm.cnd); ok(!r, "failed to signal\n"); p__Thrd_join(threads[0], NULL); /* test _Cnd_do_broadcast_at_thread_exit */ cm.started = 0; cm.timed_wait = FALSE; p__Thrd_create(&threads[0], cnd_wait_thread, (void*)&cm); WaitForSingleObject(cm.initialized, INFINITE); p__Mtx_lock(&mtx); r = 0xcafe; p__Cnd_unregister_at_thread_exit((_Mtx_t*)0xdeadbeef); p__Cnd_register_at_thread_exit(&cnd, &mtx, &r); ok(r == 0xcafe, "r = %x\n", r); p__Cnd_register_at_thread_exit(&cnd, &mtx, &r); p__Cnd_unregister_at_thread_exit(&mtx); p__Cnd_do_broadcast_at_thread_exit(); ok(mtx->count == 1, "mtx.count = %d\n", mtx->count); p__Cnd_register_at_thread_exit(&cnd, &mtx, &r); ok(r == 0xcafe, "r = %x\n", r); p__Cnd_do_broadcast_at_thread_exit(); ok(r == 1, "r = %x\n", r); p__Thrd_join(threads[0], NULL); /* crash if _Cnd_do_broadcast_at_thread_exit is called on exit */ p__Cnd_register_at_thread_exit((_Cnd_t*)0xdeadbeef, (_Mtx_t*)0xdeadbeef, (int*)0xdeadbeef); /* test _Cnd_broadcast */ cm.started = 0; cm.thread_no = NUM_THREADS; for(i = 0; i < cm.thread_no; i++) p__Thrd_create(&threads[i], cnd_wait_thread, (void*)&cm); WaitForSingleObject(cm.initialized, INFINITE); p__Mtx_lock(&mtx); p__Mtx_unlock(&mtx); r = p__Cnd_broadcast(&cnd); ok(!r, "failed to broadcast\n"); for(i = 0; i < cm.thread_no; i++) p__Thrd_join(threads[i], NULL); /* test broadcast with _Cnd_destroy */ cm.started = 0; for(i = 0; i < cm.thread_no; i++) p__Thrd_create(&threads[i], cnd_wait_thread, (void*)&cm); WaitForSingleObject(cm.initialized, INFINITE); p__Mtx_lock(&mtx); p__Mtx_unlock(&mtx); p__Cnd_destroy(&cnd); for(i = 0; i < cm.thread_no; i++) p__Thrd_join(threads[i], NULL); p__Mtx_destroy(&mtx); CloseHandle(cm.initialized); } static struct { int value[2]; const char* export_name; } vbtable_size_exports_list[] = { {{0x20, 0x20}, "??_8?$basic_iostream@DU?$char_traits@D@std@@@std@@7B?$basic_istream@DU?$char_traits@D@std@@@1@@"}, {{0x10, 0x10}, "??_8?$basic_iostream@DU?$char_traits@D@std@@@std@@7B?$basic_ostream@DU?$char_traits@D@std@@@1@@"}, {{0x20, 0x20}, "??_8?$basic_iostream@GU?$char_traits@G@std@@@std@@7B?$basic_istream@GU?$char_traits@G@std@@@1@@"}, {{0x10, 0x10}, "??_8?$basic_iostream@GU?$char_traits@G@std@@@std@@7B?$basic_ostream@GU?$char_traits@G@std@@@1@@"}, {{0x20, 0x20}, "??_8?$basic_iostream@_WU?$char_traits@_W@std@@@std@@7B?$basic_istream@_WU?$char_traits@_W@std@@@1@@"}, {{0x10, 0x10}, "??_8?$basic_iostream@_WU?$char_traits@_W@std@@@std@@7B?$basic_ostream@_WU?$char_traits@_W@std@@@1@@"}, {{0x18, 0x18}, "??_8?$basic_istream@DU?$char_traits@D@std@@@std@@7B@"}, {{0x18, 0x18}, "??_8?$basic_istream@GU?$char_traits@G@std@@@std@@7B@"}, {{0x18, 0x18}, "??_8?$basic_istream@_WU?$char_traits@_W@std@@@std@@7B@"}, {{ 0x8, 0x10}, "??_8?$basic_ostream@DU?$char_traits@D@std@@@std@@7B@"}, {{ 0x8, 0x10}, "??_8?$basic_ostream@GU?$char_traits@G@std@@@std@@7B@"}, {{ 0x8, 0x10}, "??_8?$basic_ostream@_WU?$char_traits@_W@std@@@std@@7B@"}, {{ 0x0, 0x0}, 0} }; static void test_vbtable_size_exports(void) { int i; const int *p_vbtable; int arch_idx = (sizeof(void*) == 8); for (i = 0; vbtable_size_exports_list[i].export_name; i++) { SET(p_vbtable, vbtable_size_exports_list[i].export_name); ok(p_vbtable[0] == 0, "vbtable[0] wrong, got 0x%x\n", p_vbtable[0]); ok(p_vbtable[1] == vbtable_size_exports_list[i].value[arch_idx], "%d: %s[1] wrong, got 0x%x\n", i, vbtable_size_exports_list[i].export_name, p_vbtable[1]); } } HANDLE _Pad__Launch_returned; _Pad pad; #ifdef __i386__ /* TODO: this should be a __thiscall function */ static unsigned int __stdcall vtbl_func__Go(void) #else static unsigned int __cdecl vtbl_func__Go(_Pad *this) #endif { DWORD ret; ret = WaitForSingleObject(_Pad__Launch_returned, 100); ok(ret == WAIT_TIMEOUT, "WiatForSingleObject returned %x\n", ret); ok(!pad.mtx->count, "pad.mtx.count = %d\n", pad.mtx->count); ok(!pad.launched, "pad.launched = %x\n", pad.launched); call_func1(p__Pad__Release, &pad); ok(pad.launched, "pad.launched = %x\n", pad.launched); ret = WaitForSingleObject(_Pad__Launch_returned, 100); ok(ret == WAIT_OBJECT_0, "WiatForSingleObject returned %x\n", ret); ok(pad.mtx->count == 1, "pad.mtx.count = %d\n", pad.mtx->count); return 0; } static void test__Pad(void) { _Pad pad_copy; _Thrd_t thrd; vtable_ptr pfunc = (vtable_ptr)&vtbl_func__Go; _Pad__Launch_returned = CreateEventW(NULL, FALSE, FALSE, NULL); pad.vtable = (void*)1; pad.cnd = (void*)2; pad.mtx = (void*)3; pad.launched = TRUE; memset(&pad_copy, 0, sizeof(pad_copy)); call_func2(p__Pad_copy_ctor, &pad_copy, &pad); ok(pad_copy.vtable != (void*)1, "pad_copy.vtable was not set\n"); ok(pad_copy.cnd == (void*)2, "pad_copy.cnd = %p\n", pad_copy.cnd); ok(pad_copy.mtx == (void*)3, "pad_copy.mtx = %p\n", pad_copy.mtx); ok(pad_copy.launched, "pad_copy.launched = %x\n", pad_copy.launched); memset(&pad_copy, 0xde, sizeof(pad_copy)); pad_copy.vtable = (void*)4; pad_copy.cnd = (void*)5; pad_copy.mtx = (void*)6; pad_copy.launched = FALSE; call_func2(p__Pad_op_assign, &pad_copy, &pad); ok(pad_copy.vtable == (void*)4, "pad_copy.vtable was set\n"); ok(pad_copy.cnd == (void*)2, "pad_copy.cnd = %p\n", pad_copy.cnd); ok(pad_copy.mtx == (void*)3, "pad_copy.mtx = %p\n", pad_copy.mtx); ok(pad_copy.launched, "pad_copy.launched = %x\n", pad_copy.launched); call_func1(p__Pad_ctor, &pad); call_func2(p__Pad_copy_ctor, &pad_copy, &pad); ok(pad.vtable == pad_copy.vtable, "pad.vtable = %p, pad_copy.vtable = %p\n", pad.vtable, pad_copy.vtable); ok(pad.cnd == pad_copy.cnd, "pad.cnd = %p, pad_copy.cnd = %p\n", pad.cnd, pad_copy.cnd); ok(pad.mtx == pad_copy.mtx, "pad.mtx = %p, pad_copy.mtx = %p\n", pad.mtx, pad_copy.mtx); ok(pad.launched == pad_copy.launched, "pad.launched = %x, pad_copy.launched = %x\n", pad.launched, pad_copy.launched); call_func1(p__Pad_dtor, &pad); /* call_func1(p__Pad_dtor, &pad_copy); - copy constructor is broken, this causes a crash */ memset(&pad, 0xfe, sizeof(pad)); call_func1(p__Pad_ctor, &pad); ok(!pad.launched, "pad.launched = %x\n", pad.launched); ok(pad.mtx->count == 1, "pad.mtx.count = %d\n", pad.mtx->count); pad.vtable = &pfunc; call_func2(p__Pad__Launch, &pad, &thrd); SetEvent(_Pad__Launch_returned); ok(!p__Thrd_join(thrd, NULL), "_Thrd_join failed\n"); call_func1(p__Pad_dtor, &pad); CloseHandle(_Pad__Launch_returned); } static void test_threads__Mtx(void) { void *mtx = NULL; p_threads__Mtx_new(&mtx); ok(mtx != NULL, "mtx == NULL\n"); p_threads__Mtx_lock(mtx); p_threads__Mtx_lock(mtx); p_threads__Mtx_unlock(mtx); p_threads__Mtx_unlock(mtx); p_threads__Mtx_unlock(mtx); p_threads__Mtx_delete(mtx); } static void test_vector_base_v4__Segment_index_of(void) { size_t i; size_t ret; struct { size_t x; size_t expect; } tests[] = { {0, 0}, {1, 0}, {2, 1}, {3, 1}, {4, 2}, {7, 2}, {8, 3}, {15, 3}, {16, 4}, {31, 4}, {32, 5}, {~0, 8*sizeof(void*)-1} }; for(i=0; idata + idx, src, sizeof(char)); } static void __thiscall queue_char__Copy_item( #ifndef __i386__ queue_base_v4 *this, #endif _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)); } static void __thiscall queue_char__Assign_and_destroy_item( #ifndef __i386__ queue_base_v4 *this, #endif 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)); } #ifndef __i386__ static _Page* __thiscall queue_char__Allocate_page(queue_base_v4 *this) #else static _Page* __thiscall queue_char__Allocate_page(void) #endif { CHECK_EXPECT(queue_char__Allocate_page); return malloc(sizeof(_Page) + sizeof(char[256])); } static void __thiscall queue_char__Deallocate_page( #ifndef __i386__ queue_base_v4 *this, #endif _Page *page) { CHECK_EXPECT2(queue_char__Deallocate_page); free(page); } static const void* queue_char_vtbl[] = { queue_char__Move_item, queue_char__Copy_item, queue_char__Assign_and_destroy_item, NULL, /* dtor */ queue_char__Allocate_page, 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* __cdecl concurrent_vector_int_alloc(vector_base_v4 *this, size_t n) { CHECK_EXPECT(concurrent_vector_int_alloc); vector_alloc_count++; return malloc(n*sizeof(int)); } static void __cdecl concurrent_vector_int_destroy(void *ptr, size_t n) { CHECK_EXPECT2(concurrent_vector_int_destroy); ok(vector_elem_count >= n, "invalid destroy\n"); vector_elem_count -= n; memset(ptr, 0xff, sizeof(int)*n); } static void concurrent_vector_int_ctor(vector_base_v4 *this) { memset(this, 0, sizeof(*this)); this->allocator = concurrent_vector_int_alloc; this->segment = &this->storage[0]; } static void concurrent_vector_int_dtor(vector_base_v4 *this) { size_t blocks; blocks = (size_t)call_func2(p_vector_base_v4__Internal_clear, this, concurrent_vector_int_destroy); while(this->first_block && blocks >= this->first_block) { vector_alloc_count--; free(this->segment[blocks - this->first_block]); blocks--; } call_func1(p_vector_base_v4_dtor, this); } static void __cdecl concurrent_vector_int_copy(void *dst, const void *src, size_t n) { CHECK_EXPECT2(concurrent_vector_int_copy); vector_elem_count += n; memcpy(dst, src, n*sizeof(int)); } 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); ok(queue.item_size == 0, "queue.item_size = %ld\n", (long)queue.item_size); call_func1(p_queue_base_v4_dtor, &queue); call_func2(p_queue_base_v4_ctor, &queue, 8); ok(queue.data != NULL, "queue.data = NULL\n"); ok(queue.alloc_count == 32, "queue.alloc_count = %ld\n", (long)queue.alloc_count); ok(queue.item_size == 8, "queue.item_size = %ld\n", (long)queue.item_size); call_func1(p_queue_base_v4_dtor, &queue); call_func2(p_queue_base_v4_ctor, &queue, 16); ok(queue.data != NULL, "queue.data = NULL\n"); ok(queue.alloc_count == 16, "queue.alloc_count = %ld\n", (long)queue.alloc_count); ok(queue.item_size == 16, "queue.item_size = %ld\n", (long)queue.item_size); b = (DWORD_PTR)call_func1(p_queue_base_v4__Internal_empty, &queue); ok(b, "queue is not empty\n"); size = (size_t)call_func1(p_queue_base_v4__Internal_size, &queue); ok(!size, "size = %ld\n", (long)size); call_func1(p_queue_base_v4_dtor, &queue); call_func2(p_queue_base_v4_ctor, &queue, 1); queue.vtable = (void*)&queue_char_vtbl; for(i=0; i<8; i++) { SET_EXPECT(queue_char__Allocate_page); SET_EXPECT(queue_char__Copy_item); c = 'a'+i; call_func2(p_queue_base_v4__Internal_push, &queue, &c); CHECK_CALLED(queue_char__Allocate_page); CHECK_CALLED(queue_char__Copy_item); b = (MSVCP_bool)(DWORD_PTR)call_func1(p_queue_base_v4__Internal_empty, &queue); ok(!b, "queue is empty\n"); size = (size_t)call_func1(p_queue_base_v4__Internal_size, &queue); ok(size == i+1, "size = %ld, expected %ld\n", (long)size, (long)i); } SET_EXPECT(queue_char__Copy_item); c = 'a'+i; call_func2(p_queue_base_v4__Internal_push, &queue, &c); CHECK_CALLED(queue_char__Copy_item); for(i=0; i<9; 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'+i, "got '%c', expected '%c'\n", c, 'a'+i); } b = (DWORD_PTR)call_func2(p_queue_base_v4__Internal_pop_if_present, &queue, &c); ok(!b, "pop returned true\n"); for(i=0; i<247; i++) { SET_EXPECT(queue_char__Copy_item); c = 'a'+i; call_func2(p_queue_base_v4__Internal_push, &queue, &c); CHECK_CALLED(queue_char__Copy_item); size = (size_t)call_func1(p_queue_base_v4__Internal_size, &queue); ok(size == i+1, "size = %ld, expected %ld\n", (long)size, (long)i); } SET_EXPECT(queue_char__Allocate_page); SET_EXPECT(queue_char__Copy_item); c = 'a'+i; call_func2(p_queue_base_v4__Internal_push, &queue, &c); CHECK_CALLED(queue_char__Allocate_page); CHECK_CALLED(queue_char__Copy_item); for(i=0; i<239; 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 == (char)('a'+i), "got '%c', expected '%c'\n", c, 'a'+i); } SET_EXPECT(queue_char__Assign_and_destroy_item); SET_EXPECT(queue_char__Deallocate_page); b = (DWORD_PTR)call_func2(p_queue_base_v4__Internal_pop_if_present, &queue, &c); CHECK_CALLED(queue_char__Assign_and_destroy_item); CHECK_CALLED(queue_char__Deallocate_page); ok(b, "pop returned false\n"); ok(c == (char)('a'+i), "got '%c', expected '%c'\n", c, 'a'+i); /* destructor doesn't clear the memory, _Internal_finish_clear needs to be called */ 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); /* 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); } static void test_vector_base_v4(void) { vector_base_v4 vector, v2; size_t idx, size; int *data; concurrent_vector_int_ctor(&vector); size = (size_t)call_func1(p_vector_base_v4__Internal_capacity, &vector); ok(size == 0, "size of vector got %ld expected 0\n", (long)size); SET_EXPECT(concurrent_vector_int_alloc); data = call_func3(p_vector_base_v4__Internal_push_back, &vector, sizeof(int), &idx); if(!data) { skip("_Internal_push_back not yet implemented\n"); return; } CHECK_CALLED(concurrent_vector_int_alloc); ok(data != NULL, "_Internal_push_back returned NULL\n"); ok(idx == 0, "idx got %ld expected %d\n", (long)idx, 0); vector_elem_count++; *data = 1; ok(data == vector.storage[0], "vector.storage[0] got %p expected %p\n", vector.storage[0], data); ok(vector.first_block == 1, "vector.first_block got %ld expected 1\n", (long)vector.first_block); ok(vector.early_size == 1, "vector.early_size got %ld expected 1\n", (long)vector.early_size); size = (size_t)call_func1(p_vector_base_v4__Internal_capacity, &vector); ok(size == 2, "size of vector got %ld expected 2\n", (long)size); data = call_func3(p_vector_base_v4__Internal_push_back, &vector, sizeof(int), &idx); ok(data != NULL, "_Internal_push_back returned NULL\n"); ok(idx == 1, "idx got %ld expected 1\n", (long)idx); vector_elem_count++; *data = 2; ok(vector.first_block == 1, "vector.first_block got %ld expected 1\n", (long)vector.first_block); ok(vector.early_size == 2, "vector.early_size got %ld expected 2\n", (long)vector.early_size); size = (size_t)call_func1(p_vector_base_v4__Internal_capacity, &vector); ok(size == 2, "size of vector got %ld expected 2\n", (long)size); SET_EXPECT(concurrent_vector_int_alloc); data = call_func3(p_vector_base_v4__Internal_push_back, &vector, sizeof(int), &idx); CHECK_CALLED(concurrent_vector_int_alloc); ok(data != NULL, "_Internal_push_back returned NULL\n"); ok(idx == 2, "idx got %ld expected 2\n", (long)idx); vector_elem_count++; *data = 3; ok(vector.first_block == 1, "vector.first_block got %ld expected 1\n", (long)vector.first_block); ok(vector.early_size == 3, "vector.early_size got %ld expected 3\n", (long)vector.early_size); size = (size_t)call_func1(p_vector_base_v4__Internal_capacity, &vector); ok(size == 4, "size of vector got %ld expected %d\n", (long)size, 4); data = call_func3(p_vector_base_v4__Internal_push_back, &vector, sizeof(int), &idx); ok(data != NULL, "_Internal_push_back returned NULL\n"); ok(idx == 3, "idx got %ld expected 3\n", (long)idx); vector_elem_count++; *data = 4; size = (size_t)call_func1(p_vector_base_v4__Internal_capacity, &vector); ok(size == 4, "size of vector got %ld expected 4\n", (long)size); SET_EXPECT(concurrent_vector_int_alloc); data = call_func3(p_vector_base_v4__Internal_push_back, &vector, sizeof(int), &idx); CHECK_CALLED(concurrent_vector_int_alloc); ok(data != NULL, "_Internal_push_back returned NULL\n"); ok(idx == 4, "idx got %ld expected 2\n", (long)idx); vector_elem_count++; *data = 5; size = (size_t)call_func1(p_vector_base_v4__Internal_capacity, &vector); ok(size == 8, "size of vector got %ld expected 8\n", (long)size); concurrent_vector_int_ctor(&v2); SET_EXPECT(concurrent_vector_int_alloc); SET_EXPECT(concurrent_vector_int_copy); call_func4(p_vector_base_v4__Internal_copy, &v2, &vector, sizeof(int), concurrent_vector_int_copy); CHECK_CALLED(concurrent_vector_int_alloc); CHECK_CALLED(concurrent_vector_int_copy); ok(v2.first_block == 3, "v2.first_block got %ld expected 3\n", (long)v2.first_block); ok(v2.early_size == 5, "v2.early_size got %ld expected 5\n", (long)v2.early_size); SET_EXPECT(concurrent_vector_int_destroy); size = (size_t)call_func2(p_vector_base_v4__Internal_clear, &v2, concurrent_vector_int_destroy); concurrent_vector_int_dtor(&v2); SET_EXPECT(concurrent_vector_int_destroy); size = (size_t)call_func2(p_vector_base_v4__Internal_clear, &vector, concurrent_vector_int_destroy); CHECK_CALLED(concurrent_vector_int_destroy); ok(size == 3, "_Internal_clear returned %ld\n", (long)size); ok(vector.first_block == 1, "vector.first_block got %ld expected 1\n", (long)vector.first_block); ok(vector.early_size == 0, "vector.early_size got %ld expected 0\n", (long)vector.early_size); concurrent_vector_int_dtor(&vector); ok(!vector_elem_count, "vector_elem_count = %d, expected 0\n", vector_elem_count); ok(!vector_alloc_count, "vector_alloc_count = %d, expected 0\n", vector_alloc_count); } 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(); test__Call_once(); test__Do_call(); test__Dtest(); test__Dscale(); test__FExp(); test_tr2_sys__File_size(); test_tr2_sys__Equivalent(); test_tr2_sys__Current_get(); test_tr2_sys__Current_set(); test_tr2_sys__Make_dir(); test_tr2_sys__Remove_dir(); test_tr2_sys__Copy_file(); test_tr2_sys__Rename(); test_tr2_sys__Statvfs(); test_tr2_sys__Stat(); test_tr2_sys__Last_write_time(); test_tr2_sys__dir_operation(); test_tr2_sys__Link(); test_tr2_sys__Symlink(); test_tr2_sys__Unlink(); test_thrd(); test_cnd(); test__Pad(); test_threads__Mtx(); test_vector_base_v4__Segment_index_of(); test_queue_base_v4(); test_vector_base_v4(); test_vbtable_size_exports(); free_expect_struct(); TlsFree(expect_idx); FreeLibrary(msvcp); }