msvcirt: Add implementation of streambuf locking.
[wine.git] / dlls / msvcirt / tests / msvcirt.c
blob3c2c5cef9ded541842b5a01a6db34dc3b63cf880
1 /*
2 * Copyright 2015 Iván Matellanes
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdio.h>
20 #include <windef.h>
21 #include <winbase.h>
22 #include "wine/test.h"
24 typedef void (*vtable_ptr)(void);
26 /* class streambuf */
27 typedef struct {
28 const vtable_ptr *vtable;
29 int allocated;
30 int unbuffered;
31 int unknown;
32 char *base;
33 char *ebuf;
34 char *pbase;
35 char *pptr;
36 char *epptr;
37 char *eback;
38 char *gptr;
39 char *egptr;
40 int do_lock;
41 CRITICAL_SECTION lock;
42 } streambuf;
44 #undef __thiscall
45 #ifdef __i386__
46 #define __thiscall __stdcall
47 #else
48 #define __thiscall __cdecl
49 #endif
51 /* streambuf */
52 static streambuf* (*__thiscall p_streambuf_reserve_ctor)(streambuf*, char*, int);
53 static streambuf* (*__thiscall p_streambuf_ctor)(streambuf*);
54 static void (*__thiscall p_streambuf_dtor)(streambuf*);
55 static int (*__thiscall p_streambuf_allocate)(streambuf*);
56 static void (*__thiscall p_streambuf_clrclock)(streambuf*);
57 static int (*__thiscall p_streambuf_doallocate)(streambuf*);
58 static void (*__thiscall p_streambuf_lock)(streambuf*);
59 static void (*__thiscall p_streambuf_setb)(streambuf*, char*, char*, int);
60 static void (*__thiscall p_streambuf_setlock)(streambuf*);
61 static streambuf* (*__thiscall p_streambuf_setbuf)(streambuf*, char*, int);
62 static void (*__thiscall p_streambuf_unlock)(streambuf*);
64 /* Emulate a __thiscall */
65 #ifdef __i386__
67 #include "pshpack1.h"
68 struct thiscall_thunk
70 BYTE pop_eax; /* popl %eax (ret addr) */
71 BYTE pop_edx; /* popl %edx (func) */
72 BYTE pop_ecx; /* popl %ecx (this) */
73 BYTE push_eax; /* pushl %eax */
74 WORD jmp_edx; /* jmp *%edx */
76 #include "poppack.h"
78 static void * (WINAPI *call_thiscall_func1)( void *func, void *this );
79 static void * (WINAPI *call_thiscall_func2)( void *func, void *this, const void *a );
80 static void * (WINAPI *call_thiscall_func3)( void *func, void *this, const void *a, const void *b );
81 static void * (WINAPI *call_thiscall_func4)( void *func, void *this, const void *a, const void *b,
82 const void *c );
83 static void * (WINAPI *call_thiscall_func5)( void *func, void *this, const void *a, const void *b,
84 const void *c, const void *d );
86 static void init_thiscall_thunk(void)
88 struct thiscall_thunk *thunk = VirtualAlloc( NULL, sizeof(*thunk),
89 MEM_COMMIT, PAGE_EXECUTE_READWRITE );
90 thunk->pop_eax = 0x58; /* popl %eax */
91 thunk->pop_edx = 0x5a; /* popl %edx */
92 thunk->pop_ecx = 0x59; /* popl %ecx */
93 thunk->push_eax = 0x50; /* pushl %eax */
94 thunk->jmp_edx = 0xe2ff; /* jmp *%edx */
95 call_thiscall_func1 = (void *)thunk;
96 call_thiscall_func2 = (void *)thunk;
97 call_thiscall_func3 = (void *)thunk;
98 call_thiscall_func4 = (void *)thunk;
99 call_thiscall_func5 = (void *)thunk;
102 #define call_func1(func,_this) call_thiscall_func1(func,_this)
103 #define call_func2(func,_this,a) call_thiscall_func2(func,_this,(const void*)(a))
104 #define call_func3(func,_this,a,b) call_thiscall_func3(func,_this,(const void*)(a),(const void*)(b))
105 #define call_func4(func,_this,a,b,c) call_thiscall_func4(func,_this,(const void*)(a),(const void*)(b), \
106 (const void*)(c))
107 #define call_func5(func,_this,a,b,c,d) call_thiscall_func5(func,_this,(const void*)(a),(const void*)(b), \
108 (const void*)(c), (const void *)(d))
110 #else
112 #define init_thiscall_thunk()
113 #define call_func1(func,_this) func(_this)
114 #define call_func2(func,_this,a) func(_this,a)
115 #define call_func3(func,_this,a,b) func(_this,a,b)
116 #define call_func4(func,_this,a,b,c) func(_this,a,b,c)
117 #define call_func5(func,_this,a,b,c,d) func(_this,a,b,c,d)
119 #endif /* __i386__ */
121 static HMODULE msvcirt;
122 #define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcirt,y)
123 #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0)
124 static BOOL init(void)
126 msvcirt = LoadLibraryA("msvcirt.dll");
127 if(!msvcirt) {
128 win_skip("msvcirt.dll not installed\n");
129 return FALSE;
132 if(sizeof(void*) == 8) { /* 64-bit initialization */
133 SET(p_streambuf_reserve_ctor, "??0streambuf@@IEAA@PEADH@Z");
134 SET(p_streambuf_ctor, "??0streambuf@@IEAA@XZ");
135 SET(p_streambuf_dtor, "??1streambuf@@UEAA@XZ");
136 SET(p_streambuf_allocate, "?allocate@streambuf@@IEAAHXZ");
137 SET(p_streambuf_clrclock, "?clrlock@streambuf@@QEAAXXZ");
138 SET(p_streambuf_doallocate, "?doallocate@streambuf@@MEAAHXZ");
139 SET(p_streambuf_lock, "?lock@streambuf@@QEAAXXZ");
140 SET(p_streambuf_setb, "?setb@streambuf@@IEAAXPEAD0H@Z");
141 SET(p_streambuf_setbuf, "?setbuf@streambuf@@UEAAPEAV1@PEADH@Z");
142 SET(p_streambuf_setlock, "?setlock@streambuf@@QEAAXXZ");
143 SET(p_streambuf_unlock, "?unlock@streambuf@@QEAAXXZ");
144 } else {
145 SET(p_streambuf_reserve_ctor, "??0streambuf@@IAE@PADH@Z");
146 SET(p_streambuf_ctor, "??0streambuf@@IAE@XZ");
147 SET(p_streambuf_dtor, "??1streambuf@@UAE@XZ");
148 SET(p_streambuf_allocate, "?allocate@streambuf@@IAEHXZ");
149 SET(p_streambuf_clrclock, "?clrlock@streambuf@@QAEXXZ");
150 SET(p_streambuf_doallocate, "?doallocate@streambuf@@MAEHXZ");
151 SET(p_streambuf_lock, "?lock@streambuf@@QAEXXZ");
152 SET(p_streambuf_setb, "?setb@streambuf@@IAEXPAD0H@Z");
153 SET(p_streambuf_setbuf, "?setbuf@streambuf@@UAEPAV1@PADH@Z");
154 SET(p_streambuf_setlock, "?setlock@streambuf@@QAEXXZ");
155 SET(p_streambuf_unlock, "?unlock@streambuf@@QAEXXZ");
158 init_thiscall_thunk();
159 return TRUE;
162 struct streambuf_lock_arg
164 streambuf *sb;
165 HANDLE lock[4];
166 HANDLE test[4];
169 static DWORD WINAPI lock_streambuf(void *arg)
171 struct streambuf_lock_arg *lock_arg = arg;
172 call_func1(p_streambuf_lock, lock_arg->sb);
173 SetEvent(lock_arg->lock[0]);
174 WaitForSingleObject(lock_arg->test[0], INFINITE);
175 call_func1(p_streambuf_lock, lock_arg->sb);
176 SetEvent(lock_arg->lock[1]);
177 WaitForSingleObject(lock_arg->test[1], INFINITE);
178 call_func1(p_streambuf_lock, lock_arg->sb);
179 SetEvent(lock_arg->lock[2]);
180 WaitForSingleObject(lock_arg->test[2], INFINITE);
181 call_func1(p_streambuf_unlock, lock_arg->sb);
182 SetEvent(lock_arg->lock[3]);
183 WaitForSingleObject(lock_arg->test[3], INFINITE);
184 call_func1(p_streambuf_unlock, lock_arg->sb);
185 return 0;
188 static void test_streambuf(void)
190 streambuf sb, sb2, *psb;
191 struct streambuf_lock_arg lock_arg;
192 HANDLE thread;
193 char reserve[16];
194 int ret, i;
195 BOOL locked;
197 memset(&sb, 0xab, sizeof(streambuf));
198 memset(&sb2, 0xab, sizeof(streambuf));
200 /* constructors */
201 call_func1(p_streambuf_ctor, &sb);
202 ok(sb.allocated == 0, "wrong allocate value, expected 0 got %d\n", sb.allocated);
203 ok(sb.unbuffered == 0, "wrong unbuffered value, expected 0 got %d\n", sb.unbuffered);
204 ok(sb.base == NULL, "wrong base pointer, expected %p got %p\n", NULL, sb.base);
205 ok(sb.ebuf == NULL, "wrong ebuf pointer, expected %p got %p\n", NULL, sb.ebuf);
206 ok(sb.lock.LockCount == -1, "wrong critical section state, expected -1 got %d\n", sb.lock.LockCount);
207 call_func3(p_streambuf_reserve_ctor, &sb2, reserve, 16);
208 ok(sb2.allocated == 0, "wrong allocate value, expected 0 got %d\n", sb2.allocated);
209 ok(sb2.unbuffered == 0, "wrong unbuffered value, expected 0 got %d\n", sb2.unbuffered);
210 ok(sb2.base == reserve, "wrong base pointer, expected %p got %p\n", reserve, sb2.base);
211 ok(sb2.ebuf == reserve+16, "wrong ebuf pointer, expected %p got %p\n", reserve+16, sb2.ebuf);
212 ok(sb.lock.LockCount == -1, "wrong critical section state, expected -1 got %d\n", sb.lock.LockCount);
214 /* setlock */
215 ok(sb.do_lock == -1, "expected do_lock value -1, got %d\n", sb.do_lock);
216 call_func1(p_streambuf_setlock, &sb);
217 ok(sb.do_lock == -2, "expected do_lock value -2, got %d\n", sb.do_lock);
218 call_func1(p_streambuf_setlock, &sb);
219 ok(sb.do_lock == -3, "expected do_lock value -3, got %d\n", sb.do_lock);
220 sb.do_lock = 3;
221 call_func1(p_streambuf_setlock, &sb);
222 ok(sb.do_lock == 2, "expected do_lock value 2, got %d\n", sb.do_lock);
224 /* clrlock */
225 sb.do_lock = -2;
226 call_func1(p_streambuf_clrclock, &sb);
227 ok(sb.do_lock == -1, "expected do_lock value -1, got %d\n", sb.do_lock);
228 call_func1(p_streambuf_clrclock, &sb);
229 ok(sb.do_lock == 0, "expected do_lock value 0, got %d\n", sb.do_lock);
230 call_func1(p_streambuf_clrclock, &sb);
231 ok(sb.do_lock == 1, "expected do_lock value 1, got %d\n", sb.do_lock);
232 call_func1(p_streambuf_clrclock, &sb);
233 ok(sb.do_lock == 1, "expected do_lock value 1, got %d\n", sb.do_lock);
235 /* lock/unlock */
236 lock_arg.sb = &sb;
237 for (i = 0; i < 4; i++) {
238 lock_arg.lock[i] = CreateEventW(NULL, FALSE, FALSE, NULL);
239 ok(lock_arg.lock[i] != NULL, "CreateEventW failed\n");
240 lock_arg.test[i] = CreateEventW(NULL, FALSE, FALSE, NULL);
241 ok(lock_arg.test[i] != NULL, "CreateEventW failed\n");
244 sb.do_lock = 0;
245 thread = CreateThread(NULL, 0, lock_streambuf, (void*)&lock_arg, 0, NULL);
246 ok(thread != NULL, "CreateThread failed\n");
247 WaitForSingleObject(lock_arg.lock[0], INFINITE);
248 locked = TryEnterCriticalSection(&sb.lock);
249 ok(locked != 0, "could not lock the streambuf\n");
250 LeaveCriticalSection(&sb.lock);
252 sb.do_lock = 1;
253 SetEvent(lock_arg.test[0]);
254 WaitForSingleObject(lock_arg.lock[1], INFINITE);
255 locked = TryEnterCriticalSection(&sb.lock);
256 ok(locked != 0, "could not lock the streambuf\n");
257 LeaveCriticalSection(&sb.lock);
259 sb.do_lock = -1;
260 SetEvent(lock_arg.test[1]);
261 WaitForSingleObject(lock_arg.lock[2], INFINITE);
262 locked = TryEnterCriticalSection(&sb.lock);
263 ok(locked == 0, "the streambuf was not locked before\n");
265 sb.do_lock = 0;
266 SetEvent(lock_arg.test[2]);
267 WaitForSingleObject(lock_arg.lock[3], INFINITE);
268 locked = TryEnterCriticalSection(&sb.lock);
269 ok(locked == 0, "the streambuf was not locked before\n");
270 sb.do_lock = -1;
272 /* setb */
273 call_func4(p_streambuf_setb, &sb, reserve, reserve+16, 0);
274 ok(sb.base == reserve, "wrong base pointer, expected %p got %p\n", reserve, sb.base);
275 ok(sb.ebuf == reserve+16, "wrong ebuf pointer, expected %p got %p\n", reserve+16, sb.ebuf);
276 call_func4(p_streambuf_setb, &sb, reserve, reserve+16, 4);
277 ok(sb.allocated == 4, "wrong allocate value, expected 4 got %d\n", sb.allocated);
278 sb.allocated = 0;
279 call_func4(p_streambuf_setb, &sb, NULL, NULL, 3);
280 ok(sb.allocated == 3, "wrong allocate value, expected 3 got %d\n", sb.allocated);
282 /* setbuf */
283 psb = call_func3(p_streambuf_setbuf, &sb, NULL, 5);
284 ok(psb == &sb, "wrong return value, expected %p got %p\n", &sb, psb);
285 ok(sb.allocated == 3, "wrong allocate value, expected 3 got %d\n", sb.allocated);
286 ok(sb.unbuffered == 1, "wrong unbuffered value, expected 1 got %d\n", sb.unbuffered);
287 ok(sb.base == NULL, "wrong base pointer, expected %p got %p\n", NULL, sb.base);
288 ok(sb.ebuf == NULL, "wrong ebuf pointer, expected %p got %p\n", NULL, sb.ebuf);
289 psb = call_func3(p_streambuf_setbuf, &sb, reserve, 0);
290 ok(psb == &sb, "wrong return value, expected %p got %p\n", &sb, psb);
291 ok(sb.unbuffered == 1, "wrong unbuffered value, expected 1 got %d\n", sb.unbuffered);
292 ok(sb.base == NULL, "wrong base pointer, expected %p got %p\n", NULL, sb.base);
293 ok(sb.ebuf == NULL, "wrong ebuf pointer, expected %p got %p\n", NULL, sb.ebuf);
294 psb = call_func3(p_streambuf_setbuf, &sb, reserve, 16);
295 ok(psb == &sb, "wrong return value, expected %p got %p\n", &sb, psb);
296 ok(sb.allocated == 3, "wrong allocate value, expected 3 got %d\n", sb.allocated);
297 ok(sb.unbuffered == 0, "wrong unbuffered value, expected 0 got %d\n", sb.unbuffered);
298 ok(sb.base == reserve, "wrong base pointer, expected %p got %p\n", reserve, sb.base);
299 ok(sb.ebuf == reserve+16, "wrong ebuf pointer, expected %p got %p\n", reserve+16, sb.ebuf);
300 psb = call_func3(p_streambuf_setbuf, &sb, NULL, 8);
301 ok(psb == NULL, "wrong return value, expected %p got %p\n", NULL, psb);
302 ok(sb.unbuffered == 0, "wrong unbuffered value, expected 0 got %d\n", sb.unbuffered);
303 ok(sb.base == reserve, "wrong base pointer, expected %p got %p\n", reserve, sb.base);
304 ok(sb.ebuf == reserve+16, "wrong ebuf pointer, expected %p got %p\n", reserve+16, sb.ebuf);
306 /* allocate */
307 ret = (int) call_func1(p_streambuf_allocate, &sb);
308 ok(ret == 0, "wrong return value, expected 0 got %d\n", ret);
309 sb.base = NULL;
310 ret = (int) call_func1(p_streambuf_allocate, &sb);
311 ok(ret == 1, "wrong return value, expected 1 got %d\n", ret);
312 ok(sb.allocated == 1, "wrong allocate value, expected 1 got %d\n", sb.allocated);
313 ok(sb.ebuf - sb.base == 512 , "wrong reserve area size, expected 512 got %p-%p\n", sb.ebuf, sb.base);
315 /* doallocate */
316 ret = (int) call_func1(p_streambuf_doallocate, &sb2);
317 ok(ret == 1, "doallocate failed, got %d\n", ret);
318 ok(sb2.allocated == 1, "wrong allocate value, expected 1 got %d\n", sb2.allocated);
319 ok(sb2.ebuf - sb2.base == 512 , "wrong reserve area size, expected 512 got %p-%p\n", sb2.ebuf, sb2.base);
321 SetEvent(lock_arg.test[3]);
322 WaitForSingleObject(thread, INFINITE);
324 call_func1(p_streambuf_dtor, &sb);
325 call_func1(p_streambuf_dtor, &sb2);
326 for (i = 0; i < 4; i++) {
327 CloseHandle(lock_arg.lock[i]);
328 CloseHandle(lock_arg.test[i]);
330 CloseHandle(thread);
333 START_TEST(msvcirt)
335 if(!init())
336 return;
338 test_streambuf();
340 FreeLibrary(msvcirt);