1c2c66affSColin Finck /*
2c2c66affSColin Finck * Unit test suite for thread functions.
3c2c66affSColin Finck *
4c2c66affSColin Finck * Copyright 2002 Geoffrey Hausheer
5c2c66affSColin Finck *
6c2c66affSColin Finck * This library is free software; you can redistribute it and/or
7c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public
8c2c66affSColin Finck * License as published by the Free Software Foundation; either
9c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version.
10c2c66affSColin Finck *
11c2c66affSColin Finck * This library is distributed in the hope that it will be useful,
12c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of
13c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14c2c66affSColin Finck * Lesser General Public License for more details.
15c2c66affSColin Finck *
16c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public
17c2c66affSColin Finck * License along with this library; if not, write to the Free Software
18c2c66affSColin Finck * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19c2c66affSColin Finck */
20c2c66affSColin Finck
21*ed41a4deSAmine Khaldi #include <assert.h>
22*ed41a4deSAmine Khaldi #include <stdarg.h>
23*ed41a4deSAmine Khaldi #include <stdio.h>
24*ed41a4deSAmine Khaldi
25*ed41a4deSAmine Khaldi /* the tests intentionally pass invalid pointers and need an exception handler */
26*ed41a4deSAmine Khaldi #define WINE_NO_INLINE_STRING
27*ed41a4deSAmine Khaldi
28*ed41a4deSAmine Khaldi #include <ntstatus.h>
29*ed41a4deSAmine Khaldi #define WIN32_NO_STATUS
30*ed41a4deSAmine Khaldi #include <windef.h>
31*ed41a4deSAmine Khaldi #include <winbase.h>
32*ed41a4deSAmine Khaldi #include <winnt.h>
33*ed41a4deSAmine Khaldi #include <winerror.h>
34*ed41a4deSAmine Khaldi #include <winnls.h>
35*ed41a4deSAmine Khaldi #include <winternl.h>
36*ed41a4deSAmine Khaldi #include "wine/test.h"
37c2c66affSColin Finck
38c2c66affSColin Finck /* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
39c2c66affSColin Finck #define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff)
40c2c66affSColin Finck
41c2c66affSColin Finck /* Specify the number of simultaneous threads to test */
42c2c66affSColin Finck #define NUM_THREADS 4
43c2c66affSColin Finck /* Specify whether to test the extended priorities for Win2k/XP */
44c2c66affSColin Finck #define USE_EXTENDED_PRIORITIES 0
45c2c66affSColin Finck /* Specify whether to test the stack allocation in CreateThread */
46c2c66affSColin Finck #define CHECK_STACK 0
47c2c66affSColin Finck
48c2c66affSColin Finck /* Set CHECK_STACK to 1 if you want to try to test the stack-limit from
49c2c66affSColin Finck CreateThread. So far I have been unable to make this work, and
50c2c66affSColin Finck I am in doubt as to how portable it is. Also, according to MSDN,
51c2c66affSColin Finck you shouldn't mix C-run-time-libraries (i.e. alloca) with CreateThread.
52c2c66affSColin Finck Anyhow, the check is currently commented out
53c2c66affSColin Finck */
54c2c66affSColin Finck #if CHECK_STACK
55c2c66affSColin Finck # ifdef __try
56c2c66affSColin Finck # define __TRY __try
57c2c66affSColin Finck # define __EXCEPT __except
58c2c66affSColin Finck # define __ENDTRY
59c2c66affSColin Finck # else
60c2c66affSColin Finck # include "wine/exception.h"
61c2c66affSColin Finck # endif
62c2c66affSColin Finck #endif
63c2c66affSColin Finck
64c2c66affSColin Finck #ifdef __i386__
65c2c66affSColin Finck #define ARCH "x86"
66c2c66affSColin Finck #elif defined __x86_64__
67c2c66affSColin Finck #define ARCH "amd64"
68c2c66affSColin Finck #elif defined __arm__
69c2c66affSColin Finck #define ARCH "arm"
70c2c66affSColin Finck #elif defined __aarch64__
71c2c66affSColin Finck #define ARCH "arm64"
72c2c66affSColin Finck #else
73c2c66affSColin Finck #define ARCH "none"
74c2c66affSColin Finck #endif
75c2c66affSColin Finck
76c2c66affSColin Finck static BOOL (WINAPI *pGetThreadPriorityBoost)(HANDLE,PBOOL);
77c2c66affSColin Finck static HANDLE (WINAPI *pOpenThread)(DWORD,BOOL,DWORD);
78c2c66affSColin Finck static BOOL (WINAPI *pQueueUserWorkItem)(LPTHREAD_START_ROUTINE,PVOID,ULONG);
79c2c66affSColin Finck static DWORD (WINAPI *pSetThreadIdealProcessor)(HANDLE,DWORD);
80c2c66affSColin Finck static BOOL (WINAPI *pSetThreadPriorityBoost)(HANDLE,BOOL);
81c2c66affSColin Finck static BOOL (WINAPI *pRegisterWaitForSingleObject)(PHANDLE,HANDLE,WAITORTIMERCALLBACK,PVOID,ULONG,ULONG);
82c2c66affSColin Finck static BOOL (WINAPI *pUnregisterWait)(HANDLE);
83c2c66affSColin Finck static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
84c2c66affSColin Finck static BOOL (WINAPI *pSetThreadErrorMode)(DWORD,PDWORD);
85c2c66affSColin Finck static DWORD (WINAPI *pGetThreadErrorMode)(void);
86c2c66affSColin Finck static DWORD (WINAPI *pRtlGetThreadErrorMode)(void);
87c2c66affSColin Finck static BOOL (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
88c2c66affSColin Finck static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
89c2c66affSColin Finck static BOOL (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
90c2c66affSColin Finck static BOOL (WINAPI *pGetCurrentActCtx)(HANDLE *);
91c2c66affSColin Finck static void (WINAPI *pReleaseActCtx)(HANDLE);
92c2c66affSColin Finck static PTP_POOL (WINAPI *pCreateThreadpool)(PVOID);
93c2c66affSColin Finck static void (WINAPI *pCloseThreadpool)(PTP_POOL);
94c2c66affSColin Finck static PTP_WORK (WINAPI *pCreateThreadpoolWork)(PTP_WORK_CALLBACK,PVOID,PTP_CALLBACK_ENVIRON);
95c2c66affSColin Finck static void (WINAPI *pSubmitThreadpoolWork)(PTP_WORK);
96c2c66affSColin Finck static void (WINAPI *pWaitForThreadpoolWorkCallbacks)(PTP_WORK,BOOL);
97c2c66affSColin Finck static void (WINAPI *pCloseThreadpoolWork)(PTP_WORK);
98c2c66affSColin Finck static NTSTATUS (WINAPI *pNtQueryInformationThread)(HANDLE,THREADINFOCLASS,PVOID,ULONG,PULONG);
99c2c66affSColin Finck static BOOL (WINAPI *pGetThreadGroupAffinity)(HANDLE,GROUP_AFFINITY*);
100c2c66affSColin Finck static BOOL (WINAPI *pSetThreadGroupAffinity)(HANDLE,const GROUP_AFFINITY*,GROUP_AFFINITY*);
101c2c66affSColin Finck static NTSTATUS (WINAPI *pNtSetInformationThread)(HANDLE,THREADINFOCLASS,LPCVOID,ULONG);
102c2c66affSColin Finck static NTSTATUS (WINAPI *pNtSetLdtEntries)(ULONG,ULONG,ULONG,ULONG,ULONG,ULONG);
103c2c66affSColin Finck
create_target_process(const char * arg)104c2c66affSColin Finck static HANDLE create_target_process(const char *arg)
105c2c66affSColin Finck {
106c2c66affSColin Finck char **argv;
107c2c66affSColin Finck char cmdline[MAX_PATH];
108c2c66affSColin Finck PROCESS_INFORMATION pi;
109c2c66affSColin Finck BOOL ret;
110c2c66affSColin Finck STARTUPINFOA si = { 0 };
111c2c66affSColin Finck si.cb = sizeof(si);
112c2c66affSColin Finck
113c2c66affSColin Finck winetest_get_mainargs( &argv );
114c2c66affSColin Finck sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg);
115c2c66affSColin Finck ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
116c2c66affSColin Finck ok(ret, "error: %u\n", GetLastError());
117c2c66affSColin Finck ret = CloseHandle(pi.hThread);
118c2c66affSColin Finck ok(ret, "error %u\n", GetLastError());
119c2c66affSColin Finck return pi.hProcess;
120c2c66affSColin Finck }
121c2c66affSColin Finck
122c2c66affSColin Finck /* Functions not tested yet:
123c2c66affSColin Finck AttachThreadInput
124c2c66affSColin Finck SetThreadContext
125c2c66affSColin Finck SwitchToThread
126c2c66affSColin Finck
127c2c66affSColin Finck In addition there are no checks that the inheritance works properly in
128c2c66affSColin Finck CreateThread
129c2c66affSColin Finck */
130c2c66affSColin Finck
131c2c66affSColin Finck /* Functions to ensure that from a group of threads, only one executes
132c2c66affSColin Finck certain chunks of code at a time, and we know which one is executing
133c2c66affSColin Finck it. It basically makes multithreaded execution linear, which defeats
134c2c66affSColin Finck the purpose of multiple threads, but makes testing easy. */
135c2c66affSColin Finck static HANDLE start_event, stop_event;
136c2c66affSColin Finck static LONG num_synced;
137c2c66affSColin Finck
init_thread_sync_helpers(void)138c2c66affSColin Finck static void init_thread_sync_helpers(void)
139c2c66affSColin Finck {
140c2c66affSColin Finck start_event = CreateEventW(NULL, TRUE, FALSE, NULL);
141c2c66affSColin Finck ok(start_event != NULL, "CreateEvent failed\n");
142c2c66affSColin Finck stop_event = CreateEventW(NULL, TRUE, FALSE, NULL);
143c2c66affSColin Finck ok(stop_event != NULL, "CreateEvent failed\n");
144c2c66affSColin Finck num_synced = -1;
145c2c66affSColin Finck }
146c2c66affSColin Finck
sync_threads_and_run_one(DWORD sync_id,DWORD my_id)147c2c66affSColin Finck static BOOL sync_threads_and_run_one(DWORD sync_id, DWORD my_id)
148c2c66affSColin Finck {
149c2c66affSColin Finck LONG num = InterlockedIncrement(&num_synced);
150c2c66affSColin Finck assert(-1 <= num && num <= 1);
151c2c66affSColin Finck if (num == 1)
152c2c66affSColin Finck {
153c2c66affSColin Finck ResetEvent( stop_event );
154c2c66affSColin Finck SetEvent( start_event );
155c2c66affSColin Finck }
156c2c66affSColin Finck else
157c2c66affSColin Finck {
158c2c66affSColin Finck DWORD ret = WaitForSingleObject(start_event, 10000);
159c2c66affSColin Finck ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed %x\n",ret);
160c2c66affSColin Finck }
161c2c66affSColin Finck return sync_id == my_id;
162c2c66affSColin Finck }
163c2c66affSColin Finck
resync_after_run(void)164c2c66affSColin Finck static void resync_after_run(void)
165c2c66affSColin Finck {
166c2c66affSColin Finck LONG num = InterlockedDecrement(&num_synced);
167c2c66affSColin Finck assert(-1 <= num && num <= 1);
168c2c66affSColin Finck if (num == -1)
169c2c66affSColin Finck {
170c2c66affSColin Finck ResetEvent( start_event );
171c2c66affSColin Finck SetEvent( stop_event );
172c2c66affSColin Finck }
173c2c66affSColin Finck else
174c2c66affSColin Finck {
175c2c66affSColin Finck DWORD ret = WaitForSingleObject(stop_event, 10000);
176c2c66affSColin Finck ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
177c2c66affSColin Finck }
178c2c66affSColin Finck }
179c2c66affSColin Finck
cleanup_thread_sync_helpers(void)180c2c66affSColin Finck static void cleanup_thread_sync_helpers(void)
181c2c66affSColin Finck {
182c2c66affSColin Finck CloseHandle(start_event);
183c2c66affSColin Finck CloseHandle(stop_event);
184c2c66affSColin Finck }
185c2c66affSColin Finck
186c2c66affSColin Finck static DWORD tlsIndex;
187c2c66affSColin Finck
188c2c66affSColin Finck typedef struct {
189c2c66affSColin Finck int threadnum;
190c2c66affSColin Finck HANDLE *event;
191c2c66affSColin Finck DWORD *threadmem;
192c2c66affSColin Finck } t1Struct;
193c2c66affSColin Finck
194c2c66affSColin Finck /* WinME supports OpenThread but doesn't know about access restrictions so
195c2c66affSColin Finck we require them to be either completely ignored or always obeyed.
196c2c66affSColin Finck */
197c2c66affSColin Finck static INT obeying_ars = 0; /* -1 == no, 0 == dunno yet, 1 == yes */
198c2c66affSColin Finck #define obey_ar(x) \
199c2c66affSColin Finck (obeying_ars == 0 \
200c2c66affSColin Finck ? ((x) \
201c2c66affSColin Finck ? (obeying_ars = +1) \
202c2c66affSColin Finck : ((obeying_ars = -1), \
203c2c66affSColin Finck trace("not restricted, assuming consistent behaviour\n"))) \
204c2c66affSColin Finck : (obeying_ars < 0) \
205c2c66affSColin Finck ? ok(!(x), "access restrictions obeyed\n") \
206c2c66affSColin Finck : ok( (x), "access restrictions not obeyed\n"))
207c2c66affSColin Finck
208c2c66affSColin Finck /* Basic test that simultaneous threads can access shared memory,
209c2c66affSColin Finck that the thread local storage routines work correctly, and that
210c2c66affSColin Finck threads actually run concurrently
211c2c66affSColin Finck */
threadFunc1(LPVOID p)212c2c66affSColin Finck static DWORD WINAPI threadFunc1(LPVOID p)
213c2c66affSColin Finck {
214c2c66affSColin Finck t1Struct *tstruct = p;
215c2c66affSColin Finck int i;
216c2c66affSColin Finck /* write our thread # into shared memory */
217c2c66affSColin Finck tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId();
218c2c66affSColin Finck ok(TlsSetValue(tlsIndex,(LPVOID)(INT_PTR)(tstruct->threadnum+1))!=0,
219c2c66affSColin Finck "TlsSetValue failed\n");
220c2c66affSColin Finck /* The threads synchronize before terminating. This is done by
221c2c66affSColin Finck Signaling an event, and waiting for all events to occur
222c2c66affSColin Finck */
223c2c66affSColin Finck SetEvent(tstruct->event[tstruct->threadnum]);
224c2c66affSColin Finck WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE);
225c2c66affSColin Finck /* Double check that all threads really did run by validating that
226c2c66affSColin Finck they have all written to the shared memory. There should be no race
227c2c66affSColin Finck here, since all threads were synchronized after the write.*/
228c2c66affSColin Finck for (i = 0; i < NUM_THREADS; i++)
229c2c66affSColin Finck ok(tstruct->threadmem[i] != 0, "expected threadmem[%d] != 0\n", i);
230c2c66affSColin Finck
231c2c66affSColin Finck /* lstrlenA contains an exception handler so this makes sure exceptions work in threads */
232c2c66affSColin Finck ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
233c2c66affSColin Finck
234c2c66affSColin Finck /* Check that no one changed our tls memory */
235c2c66affSColin Finck ok((INT_PTR)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
236c2c66affSColin Finck "TlsGetValue failed\n");
237c2c66affSColin Finck return NUM_THREADS+tstruct->threadnum;
238c2c66affSColin Finck }
239c2c66affSColin Finck
threadFunc2(LPVOID p)240c2c66affSColin Finck static DWORD WINAPI threadFunc2(LPVOID p)
241c2c66affSColin Finck {
242c2c66affSColin Finck return 99;
243c2c66affSColin Finck }
244c2c66affSColin Finck
threadFunc3(LPVOID p)245c2c66affSColin Finck static DWORD WINAPI threadFunc3(LPVOID p)
246c2c66affSColin Finck {
247c2c66affSColin Finck HANDLE thread;
248c2c66affSColin Finck thread=GetCurrentThread();
249c2c66affSColin Finck SuspendThread(thread);
250c2c66affSColin Finck return 99;
251c2c66affSColin Finck }
252c2c66affSColin Finck
threadFunc4(LPVOID p)253c2c66affSColin Finck static DWORD WINAPI threadFunc4(LPVOID p)
254c2c66affSColin Finck {
255c2c66affSColin Finck HANDLE event = p;
256c2c66affSColin Finck if(event != NULL) {
257c2c66affSColin Finck SetEvent(event);
258c2c66affSColin Finck }
259c2c66affSColin Finck Sleep(99000);
260c2c66affSColin Finck return 0;
261c2c66affSColin Finck }
262c2c66affSColin Finck
263c2c66affSColin Finck #if CHECK_STACK
threadFunc5(LPVOID p)264c2c66affSColin Finck static DWORD WINAPI threadFunc5(LPVOID p)
265c2c66affSColin Finck {
266c2c66affSColin Finck DWORD *exitCode = p;
267c2c66affSColin Finck SYSTEM_INFO sysInfo;
268c2c66affSColin Finck sysInfo.dwPageSize=0;
269c2c66affSColin Finck GetSystemInfo(&sysInfo);
270c2c66affSColin Finck *exitCode=0;
271c2c66affSColin Finck __TRY
272c2c66affSColin Finck {
273c2c66affSColin Finck alloca(2*sysInfo.dwPageSize);
274c2c66affSColin Finck }
275c2c66affSColin Finck __EXCEPT(1) {
276c2c66affSColin Finck *exitCode=1;
277c2c66affSColin Finck }
278c2c66affSColin Finck __ENDTRY
279c2c66affSColin Finck return 0;
280c2c66affSColin Finck }
281c2c66affSColin Finck #endif
282c2c66affSColin Finck
threadFunc_SetEvent(LPVOID p)283c2c66affSColin Finck static DWORD WINAPI threadFunc_SetEvent(LPVOID p)
284c2c66affSColin Finck {
285c2c66affSColin Finck SetEvent(p);
286c2c66affSColin Finck return 0;
287c2c66affSColin Finck }
288c2c66affSColin Finck
threadFunc_CloseHandle(LPVOID p)289c2c66affSColin Finck static DWORD WINAPI threadFunc_CloseHandle(LPVOID p)
290c2c66affSColin Finck {
291c2c66affSColin Finck CloseHandle(p);
292c2c66affSColin Finck return 0;
293c2c66affSColin Finck }
294c2c66affSColin Finck
295c2c66affSColin Finck struct thread_actctx_param
296c2c66affSColin Finck {
297c2c66affSColin Finck HANDLE thread_context;
298c2c66affSColin Finck HANDLE handle;
299c2c66affSColin Finck };
300c2c66affSColin Finck
thread_actctx_func(void * p)301c2c66affSColin Finck static DWORD WINAPI thread_actctx_func(void *p)
302c2c66affSColin Finck {
303c2c66affSColin Finck struct thread_actctx_param *param = (struct thread_actctx_param*)p;
304c2c66affSColin Finck HANDLE cur;
305c2c66affSColin Finck BOOL ret;
306c2c66affSColin Finck
307c2c66affSColin Finck cur = (void*)0xdeadbeef;
308c2c66affSColin Finck ret = pGetCurrentActCtx(&cur);
309c2c66affSColin Finck ok(ret, "thread GetCurrentActCtx failed, %u\n", GetLastError());
310c2c66affSColin Finck ok(cur == param->handle, "got %p, expected %p\n", cur, param->handle);
311c2c66affSColin Finck param->thread_context = cur;
312c2c66affSColin Finck
313c2c66affSColin Finck return 0;
314c2c66affSColin Finck }
315c2c66affSColin Finck
create_function_addr_events(HANDLE events[2])316c2c66affSColin Finck static void create_function_addr_events(HANDLE events[2])
317c2c66affSColin Finck {
318c2c66affSColin Finck char buffer[256];
319c2c66affSColin Finck
320c2c66affSColin Finck sprintf(buffer, "threadFunc_SetEvent %p", threadFunc_SetEvent);
321c2c66affSColin Finck events[0] = CreateEventA(NULL, FALSE, FALSE, buffer);
322c2c66affSColin Finck
323c2c66affSColin Finck sprintf(buffer, "threadFunc_CloseHandle %p", threadFunc_CloseHandle);
324c2c66affSColin Finck events[1] = CreateEventA(NULL, FALSE, FALSE, buffer);
325c2c66affSColin Finck }
326c2c66affSColin Finck
327c2c66affSColin Finck /* check CreateRemoteThread */
test_CreateRemoteThread(void)328c2c66affSColin Finck static VOID test_CreateRemoteThread(void)
329c2c66affSColin Finck {
330c2c66affSColin Finck HANDLE hProcess, hThread, hEvent, hRemoteEvent;
331c2c66affSColin Finck DWORD tid, ret, exitcode;
332c2c66affSColin Finck HANDLE hAddrEvents[2];
333c2c66affSColin Finck
334c2c66affSColin Finck hProcess = create_target_process("sleep");
335c2c66affSColin Finck ok(hProcess != NULL, "Can't start process\n");
336c2c66affSColin Finck
337c2c66affSColin Finck /* ensure threadFunc_SetEvent & threadFunc_CloseHandle are the same
338c2c66affSColin Finck * address as in the child process */
339c2c66affSColin Finck create_function_addr_events(hAddrEvents);
340c2c66affSColin Finck ret = WaitForMultipleObjects(2, hAddrEvents, TRUE, 5000);
341c2c66affSColin Finck if (ret == WAIT_TIMEOUT)
342c2c66affSColin Finck {
343c2c66affSColin Finck skip("child process wasn't mapped at same address, so can't do CreateRemoteThread tests.\n");
344c2c66affSColin Finck return;
345c2c66affSColin Finck }
346c2c66affSColin Finck ok(ret == WAIT_OBJECT_0 || broken(ret == WAIT_OBJECT_0+1 /* nt4,w2k */), "WaitForAllObjects 2 events %d\n", ret);
347c2c66affSColin Finck
348c2c66affSColin Finck hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
349c2c66affSColin Finck ok(hEvent != NULL, "Can't create event, err=%u\n", GetLastError());
350c2c66affSColin Finck ret = DuplicateHandle(GetCurrentProcess(), hEvent, hProcess, &hRemoteEvent,
351c2c66affSColin Finck 0, FALSE, DUPLICATE_SAME_ACCESS);
352c2c66affSColin Finck ok(ret != 0, "DuplicateHandle failed, err=%u\n", GetLastError());
353c2c66affSColin Finck
354c2c66affSColin Finck /* create suspended remote thread with entry point SetEvent() */
355c2c66affSColin Finck SetLastError(0xdeadbeef);
356c2c66affSColin Finck hThread = CreateRemoteThread(hProcess, NULL, 0, threadFunc_SetEvent,
357c2c66affSColin Finck hRemoteEvent, CREATE_SUSPENDED, &tid);
358c2c66affSColin Finck if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
359c2c66affSColin Finck {
360c2c66affSColin Finck win_skip("CreateRemoteThread is not implemented\n");
361c2c66affSColin Finck goto cleanup;
362c2c66affSColin Finck }
363c2c66affSColin Finck ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
364c2c66affSColin Finck ok(tid != 0, "null tid\n");
365c2c66affSColin Finck ret = SuspendThread(hThread);
366c2c66affSColin Finck ok(ret == 1, "ret=%u, err=%u\n", ret, GetLastError());
367c2c66affSColin Finck ret = ResumeThread(hThread);
368c2c66affSColin Finck ok(ret == 2, "ret=%u, err=%u\n", ret, GetLastError());
369c2c66affSColin Finck
370c2c66affSColin Finck /* thread still suspended, so wait times out */
371c2c66affSColin Finck ret = WaitForSingleObject(hEvent, 1000);
372c2c66affSColin Finck ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%u\n", ret);
373c2c66affSColin Finck
374c2c66affSColin Finck ret = ResumeThread(hThread);
375c2c66affSColin Finck ok(ret == 1, "ret=%u, err=%u\n", ret, GetLastError());
376c2c66affSColin Finck
377c2c66affSColin Finck /* wait that doesn't time out */
378c2c66affSColin Finck ret = WaitForSingleObject(hEvent, 1000);
379c2c66affSColin Finck ok(ret == WAIT_OBJECT_0, "object not signaled, ret=%u\n", ret);
380c2c66affSColin Finck
381c2c66affSColin Finck /* wait for thread end */
382c2c66affSColin Finck ret = WaitForSingleObject(hThread, 1000);
383c2c66affSColin Finck ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%u\n", ret);
384c2c66affSColin Finck CloseHandle(hThread);
385c2c66affSColin Finck
386c2c66affSColin Finck /* create and wait for remote thread with entry point CloseHandle() */
387c2c66affSColin Finck hThread = CreateRemoteThread(hProcess, NULL, 0,
388c2c66affSColin Finck threadFunc_CloseHandle,
389c2c66affSColin Finck hRemoteEvent, 0, &tid);
390c2c66affSColin Finck ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
391c2c66affSColin Finck ret = WaitForSingleObject(hThread, 1000);
392c2c66affSColin Finck ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%u\n", ret);
393c2c66affSColin Finck CloseHandle(hThread);
394c2c66affSColin Finck
395c2c66affSColin Finck /* create remote thread with entry point SetEvent() */
396c2c66affSColin Finck hThread = CreateRemoteThread(hProcess, NULL, 0,
397c2c66affSColin Finck threadFunc_SetEvent,
398c2c66affSColin Finck hRemoteEvent, 0, &tid);
399c2c66affSColin Finck ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
400c2c66affSColin Finck
401c2c66affSColin Finck /* closed handle, so wait times out */
402c2c66affSColin Finck ret = WaitForSingleObject(hEvent, 1000);
403c2c66affSColin Finck ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%u\n", ret);
404c2c66affSColin Finck
405c2c66affSColin Finck /* check that remote SetEvent() failed */
406c2c66affSColin Finck ret = GetExitCodeThread(hThread, &exitcode);
407c2c66affSColin Finck ok(ret != 0, "GetExitCodeThread failed, err=%u\n", GetLastError());
408c2c66affSColin Finck if (ret) ok(exitcode == 0, "SetEvent succeeded, expected to fail\n");
409c2c66affSColin Finck CloseHandle(hThread);
410c2c66affSColin Finck
411c2c66affSColin Finck cleanup:
412c2c66affSColin Finck TerminateProcess(hProcess, 0);
413c2c66affSColin Finck CloseHandle(hEvent);
414c2c66affSColin Finck CloseHandle(hProcess);
415c2c66affSColin Finck }
416c2c66affSColin Finck
417c2c66affSColin Finck /* Check basic functionality of CreateThread and Tls* functions */
test_CreateThread_basic(void)418c2c66affSColin Finck static VOID test_CreateThread_basic(void)
419c2c66affSColin Finck {
420c2c66affSColin Finck HANDLE thread[NUM_THREADS],event[NUM_THREADS];
421c2c66affSColin Finck DWORD threadid[NUM_THREADS],curthreadId;
422c2c66affSColin Finck DWORD threadmem[NUM_THREADS];
423c2c66affSColin Finck DWORD exitCode;
424c2c66affSColin Finck t1Struct tstruct[NUM_THREADS];
425c2c66affSColin Finck int error;
426c2c66affSColin Finck DWORD i,j;
427c2c66affSColin Finck DWORD GLE, ret;
428c2c66affSColin Finck DWORD tid;
429c2c66affSColin Finck BOOL bRet;
430c2c66affSColin Finck
431c2c66affSColin Finck /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */
432c2c66affSColin Finck ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
433c2c66affSColin Finck
434c2c66affSColin Finck /* Retrieve current Thread ID for later comparisons */
435c2c66affSColin Finck curthreadId=GetCurrentThreadId();
436c2c66affSColin Finck /* Allocate some local storage */
437c2c66affSColin Finck ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed\n");
438c2c66affSColin Finck /* Create events for thread synchronization */
439c2c66affSColin Finck for(i=0;i<NUM_THREADS;i++) {
440c2c66affSColin Finck threadmem[i]=0;
441c2c66affSColin Finck /* Note that it doesn't matter what type of event we choose here. This
442c2c66affSColin Finck test isn't trying to thoroughly test events
443c2c66affSColin Finck */
444c2c66affSColin Finck event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
445c2c66affSColin Finck tstruct[i].threadnum=i;
446c2c66affSColin Finck tstruct[i].threadmem=threadmem;
447c2c66affSColin Finck tstruct[i].event=event;
448c2c66affSColin Finck }
449c2c66affSColin Finck
450c2c66affSColin Finck /* Test that passing arguments to threads works okay */
451c2c66affSColin Finck for(i=0;i<NUM_THREADS;i++) {
452c2c66affSColin Finck thread[i] = CreateThread(NULL,0,threadFunc1,
453c2c66affSColin Finck &tstruct[i],0,&threadid[i]);
454c2c66affSColin Finck ok(thread[i]!=NULL,"Create Thread failed\n");
455c2c66affSColin Finck }
456c2c66affSColin Finck /* Test that the threads actually complete */
457c2c66affSColin Finck for(i=0;i<NUM_THREADS;i++) {
458c2c66affSColin Finck error=WaitForSingleObject(thread[i],5000);
459c2c66affSColin Finck ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit\n");
460c2c66affSColin Finck if(error!=WAIT_OBJECT_0) {
461c2c66affSColin Finck TerminateThread(thread[i],i+NUM_THREADS);
462c2c66affSColin Finck }
463c2c66affSColin Finck ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code\n");
464c2c66affSColin Finck ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code\n");
465c2c66affSColin Finck }
466c2c66affSColin Finck /* Test that each thread executed in its parent's address space
467c2c66affSColin Finck (it was able to change threadmem and pass that change back to its parent)
468c2c66affSColin Finck and that each thread id was independent). Note that we prove that the
469c2c66affSColin Finck threads actually execute concurrently by having them block on each other
470c2c66affSColin Finck in threadFunc1
471c2c66affSColin Finck */
472c2c66affSColin Finck for(i=0;i<NUM_THREADS;i++) {
473c2c66affSColin Finck error=0;
474c2c66affSColin Finck for(j=i+1;j<NUM_THREADS;j++) {
475c2c66affSColin Finck if (threadmem[i]==threadmem[j]) {
476c2c66affSColin Finck error=1;
477c2c66affSColin Finck }
478c2c66affSColin Finck }
479c2c66affSColin Finck ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId,
480c2c66affSColin Finck "Thread did not execute successfully\n");
481c2c66affSColin Finck ok(CloseHandle(thread[i])!=0,"CloseHandle failed\n");
482c2c66affSColin Finck }
483c2c66affSColin Finck
484c2c66affSColin Finck SetLastError(0xCAFEF00D);
485c2c66affSColin Finck bRet = TlsFree(tlsIndex);
486c2c66affSColin Finck ok(bRet, "TlsFree failed: %08x\n", GetLastError());
487c2c66affSColin Finck ok(GetLastError()==0xCAFEF00D,
488c2c66affSColin Finck "GetLastError: expected 0xCAFEF00D, got %08x\n", GetLastError());
489c2c66affSColin Finck
490c2c66affSColin Finck /* Test freeing an already freed TLS index */
491c2c66affSColin Finck SetLastError(0xCAFEF00D);
492c2c66affSColin Finck ok(TlsFree(tlsIndex)==0,"TlsFree succeeded\n");
493c2c66affSColin Finck ok(GetLastError()==ERROR_INVALID_PARAMETER,
494c2c66affSColin Finck "GetLastError: expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
495c2c66affSColin Finck
496c2c66affSColin Finck /* Test how passing NULL as a pointer to threadid works */
497c2c66affSColin Finck SetLastError(0xFACEaBAD);
498c2c66affSColin Finck thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,&tid);
499c2c66affSColin Finck GLE = GetLastError();
500c2c66affSColin Finck if (thread[0]) { /* NT */
501c2c66affSColin Finck ok(GLE==0xFACEaBAD, "CreateThread set last error to %d, expected 4207848365\n", GLE);
502c2c66affSColin Finck ret = WaitForSingleObject(thread[0],100);
503c2c66affSColin Finck ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
504c2c66affSColin Finck ret = GetExitCodeThread(thread[0],&exitCode);
505c2c66affSColin Finck ok(ret!=0, "GetExitCodeThread returned %d (expected nonzero)\n", ret);
506c2c66affSColin Finck ok(exitCode==99, "threadFunc2 exited with code: %d (expected 99)\n", exitCode);
507c2c66affSColin Finck ok(CloseHandle(thread[0])!=0,"Error closing thread handle\n");
508c2c66affSColin Finck }
509c2c66affSColin Finck else { /* 9x */
510c2c66affSColin Finck ok(GLE==ERROR_INVALID_PARAMETER, "CreateThread set last error to %d, expected 87\n", GLE);
511c2c66affSColin Finck }
512c2c66affSColin Finck }
513c2c66affSColin Finck
514c2c66affSColin Finck /* Check that using the CREATE_SUSPENDED flag works */
test_CreateThread_suspended(void)515c2c66affSColin Finck static VOID test_CreateThread_suspended(void)
516c2c66affSColin Finck {
517c2c66affSColin Finck HANDLE thread;
518c2c66affSColin Finck DWORD threadId;
519c2c66affSColin Finck DWORD suspend_count;
520c2c66affSColin Finck int error;
521c2c66affSColin Finck
522c2c66affSColin Finck thread = CreateThread(NULL,0,threadFunc2,NULL,
523c2c66affSColin Finck CREATE_SUSPENDED,&threadId);
524c2c66affSColin Finck ok(thread!=NULL,"Create Thread failed\n");
525c2c66affSColin Finck /* Check that the thread is suspended */
526c2c66affSColin Finck ok(SuspendThread(thread)==1,"Thread did not start suspended\n");
527c2c66affSColin Finck ok(ResumeThread(thread)==2,"Resume thread returned an invalid value\n");
528c2c66affSColin Finck /* Check that resume thread didn't actually start the thread. I can't think
529c2c66affSColin Finck of a better way of checking this than just waiting. I am not sure if this
530c2c66affSColin Finck will work on slow computers.
531c2c66affSColin Finck */
532c2c66affSColin Finck ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT,
533c2c66affSColin Finck "ResumeThread should not have actually started the thread\n");
534c2c66affSColin Finck /* Now actually resume the thread and make sure that it actually completes*/
535c2c66affSColin Finck ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
536c2c66affSColin Finck ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
537c2c66affSColin Finck "Thread did not resume\n");
538c2c66affSColin Finck if(error!=WAIT_OBJECT_0) {
539c2c66affSColin Finck TerminateThread(thread,1);
540c2c66affSColin Finck }
541c2c66affSColin Finck
542c2c66affSColin Finck suspend_count = SuspendThread(thread);
543c2c66affSColin Finck ok(suspend_count == -1, "SuspendThread returned %d, expected -1\n", suspend_count);
544c2c66affSColin Finck
545c2c66affSColin Finck suspend_count = ResumeThread(thread);
546c2c66affSColin Finck ok(suspend_count == 0 ||
547c2c66affSColin Finck broken(suspend_count == -1), /* win9x */
548c2c66affSColin Finck "ResumeThread returned %d, expected 0\n", suspend_count);
549c2c66affSColin Finck
550c2c66affSColin Finck ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
551c2c66affSColin Finck }
552c2c66affSColin Finck
553c2c66affSColin Finck /* Check that SuspendThread and ResumeThread work */
test_SuspendThread(void)554c2c66affSColin Finck static VOID test_SuspendThread(void)
555c2c66affSColin Finck {
556c2c66affSColin Finck HANDLE thread,access_thread;
557c2c66affSColin Finck DWORD threadId,exitCode,error;
558c2c66affSColin Finck int i;
559c2c66affSColin Finck
560c2c66affSColin Finck thread = CreateThread(NULL,0,threadFunc3,NULL,
561c2c66affSColin Finck 0,&threadId);
562c2c66affSColin Finck ok(thread!=NULL,"Create Thread failed\n");
563c2c66affSColin Finck /* Check that the thread is suspended */
564c2c66affSColin Finck /* Note that this is a polling method, and there is a race between
565c2c66affSColin Finck SuspendThread being called (in the child, and the loop below timing out,
566c2c66affSColin Finck so the test could fail on a heavily loaded or slow computer.
567c2c66affSColin Finck */
568c2c66affSColin Finck error=0;
569c2c66affSColin Finck for(i=0;error==0 && i<100;i++) {
570c2c66affSColin Finck error=SuspendThread(thread);
571c2c66affSColin Finck ResumeThread(thread);
572c2c66affSColin Finck if(error==0) {
573c2c66affSColin Finck Sleep(50);
574c2c66affSColin Finck i++;
575c2c66affSColin Finck }
576c2c66affSColin Finck }
577c2c66affSColin Finck ok(error==1,"SuspendThread did not work\n");
578c2c66affSColin Finck /* check that access restrictions are obeyed */
579c2c66affSColin Finck if (pOpenThread) {
580c2c66affSColin Finck access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 & (~THREAD_SUSPEND_RESUME),
581c2c66affSColin Finck 0,threadId);
582c2c66affSColin Finck ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
583c2c66affSColin Finck if (access_thread!=NULL) {
584c2c66affSColin Finck obey_ar(SuspendThread(access_thread)==~0U);
585c2c66affSColin Finck obey_ar(ResumeThread(access_thread)==~0U);
586c2c66affSColin Finck ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
587c2c66affSColin Finck }
588c2c66affSColin Finck }
589c2c66affSColin Finck /* Double check that the thread really is suspended */
590c2c66affSColin Finck ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE,
591c2c66affSColin Finck "Thread did not really suspend\n");
592c2c66affSColin Finck /* Resume the thread, and make sure it actually completes */
593c2c66affSColin Finck ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
594c2c66affSColin Finck ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
595c2c66affSColin Finck "Thread did not resume\n");
596c2c66affSColin Finck if(error!=WAIT_OBJECT_0) {
597c2c66affSColin Finck TerminateThread(thread,1);
598c2c66affSColin Finck }
599c2c66affSColin Finck /* Trying to suspend a terminated thread should fail */
600c2c66affSColin Finck error=SuspendThread(thread);
601c2c66affSColin Finck ok(error==~0U, "wrong return code: %d\n", error);
602c2c66affSColin Finck ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %d\n", GetLastError());
603c2c66affSColin Finck
604c2c66affSColin Finck ok(CloseHandle(thread)!=0,"CloseHandle Failed\n");
605c2c66affSColin Finck }
606c2c66affSColin Finck
607c2c66affSColin Finck /* Check that TerminateThread works properly
608c2c66affSColin Finck */
test_TerminateThread(void)609c2c66affSColin Finck static VOID test_TerminateThread(void)
610c2c66affSColin Finck {
611c2c66affSColin Finck HANDLE thread,access_thread,event;
612c2c66affSColin Finck DWORD threadId,exitCode;
613c2c66affSColin Finck event=CreateEventA(NULL,TRUE,FALSE,NULL);
614c2c66affSColin Finck thread = CreateThread(NULL,0,threadFunc4,event,0,&threadId);
615c2c66affSColin Finck ok(thread!=NULL,"Create Thread failed\n");
616c2c66affSColin Finck /* TerminateThread has a race condition in Wine. If the thread is terminated
617c2c66affSColin Finck before it starts, it leaves a process behind. Therefore, we wait for the
618c2c66affSColin Finck thread to signal that it has started. There is no easy way to force the
619c2c66affSColin Finck race to occur, so we don't try to find it.
620c2c66affSColin Finck */
621c2c66affSColin Finck ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
622c2c66affSColin Finck "TerminateThread didn't work\n");
623c2c66affSColin Finck /* check that access restrictions are obeyed */
624c2c66affSColin Finck if (pOpenThread) {
625c2c66affSColin Finck access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 & (~THREAD_TERMINATE),
626c2c66affSColin Finck 0,threadId);
627c2c66affSColin Finck ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
628c2c66affSColin Finck if (access_thread!=NULL) {
629c2c66affSColin Finck obey_ar(TerminateThread(access_thread,99)==0);
630c2c66affSColin Finck ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
631c2c66affSColin Finck }
632c2c66affSColin Finck }
633c2c66affSColin Finck /* terminate a job and make sure it terminates */
634c2c66affSColin Finck ok(TerminateThread(thread,99)!=0,"TerminateThread failed\n");
635c2c66affSColin Finck ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
636c2c66affSColin Finck "TerminateThread didn't work\n");
637c2c66affSColin Finck ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
638c2c66affSColin Finck "TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
639c2c66affSColin Finck ok(exitCode==99, "TerminateThread returned invalid exit code\n");
640c2c66affSColin Finck ok(CloseHandle(thread)!=0,"Error Closing thread handle\n");
641c2c66affSColin Finck }
642c2c66affSColin Finck
643c2c66affSColin Finck /* Check if CreateThread obeys the specified stack size. This code does
644c2c66affSColin Finck not work properly, and is currently disabled
645c2c66affSColin Finck */
test_CreateThread_stack(void)646c2c66affSColin Finck static VOID test_CreateThread_stack(void)
647c2c66affSColin Finck {
648c2c66affSColin Finck #if CHECK_STACK
649c2c66affSColin Finck /* The only way I know of to test the stack size is to use alloca
650c2c66affSColin Finck and __try/__except. However, this is probably not portable,
651c2c66affSColin Finck and I couldn't get it to work under Wine anyhow. However, here
652c2c66affSColin Finck is the code which should allow for testing that CreateThread
653c2c66affSColin Finck respects the stack-size limit
654c2c66affSColin Finck */
655c2c66affSColin Finck HANDLE thread;
656c2c66affSColin Finck DWORD threadId,exitCode;
657c2c66affSColin Finck
658c2c66affSColin Finck SYSTEM_INFO sysInfo;
659c2c66affSColin Finck sysInfo.dwPageSize=0;
660c2c66affSColin Finck GetSystemInfo(&sysInfo);
661c2c66affSColin Finck ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
662c2c66affSColin Finck thread = CreateThread(NULL,sysInfo.dwPageSize,
663c2c66affSColin Finck threadFunc5,&exitCode,
664c2c66affSColin Finck 0,&threadId);
665c2c66affSColin Finck ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
666c2c66affSColin Finck "TerminateThread didn't work\n");
667c2c66affSColin Finck ok(exitCode==1,"CreateThread did not obey stack-size-limit\n");
668c2c66affSColin Finck ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
669c2c66affSColin Finck #endif
670c2c66affSColin Finck }
671c2c66affSColin Finck
672c2c66affSColin Finck /* Check whether setting/retrieving thread priorities works */
test_thread_priority(void)673c2c66affSColin Finck static VOID test_thread_priority(void)
674c2c66affSColin Finck {
675c2c66affSColin Finck HANDLE curthread,access_thread;
676c2c66affSColin Finck DWORD curthreadId,exitCode;
677c2c66affSColin Finck int min_priority=-2,max_priority=2;
678c2c66affSColin Finck BOOL disabled,rc;
679c2c66affSColin Finck int i;
680c2c66affSColin Finck
681c2c66affSColin Finck curthread=GetCurrentThread();
682c2c66affSColin Finck curthreadId=GetCurrentThreadId();
683c2c66affSColin Finck /* Check thread priority */
684c2c66affSColin Finck /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
685c2c66affSColin Finck is -2 to 2. However, even on a real Win2k system, using thread
686c2c66affSColin Finck priorities beyond the -2 to 2 range does not work. If you want to try
687c2c66affSColin Finck anyway, enable USE_EXTENDED_PRIORITIES
688c2c66affSColin Finck */
689c2c66affSColin Finck ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
690c2c66affSColin Finck "GetThreadPriority Failed\n");
691c2c66affSColin Finck
692c2c66affSColin Finck if (pOpenThread) {
693c2c66affSColin Finck /* check that access control is obeyed */
694c2c66affSColin Finck access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 &
695c2c66affSColin Finck (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
696c2c66affSColin Finck 0,curthreadId);
697c2c66affSColin Finck ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
698c2c66affSColin Finck if (access_thread!=NULL) {
699c2c66affSColin Finck obey_ar(SetThreadPriority(access_thread,1)==0);
700c2c66affSColin Finck obey_ar(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN);
701c2c66affSColin Finck obey_ar(GetExitCodeThread(access_thread,&exitCode)==0);
702c2c66affSColin Finck ok(CloseHandle(access_thread),"Error Closing thread handle\n");
703c2c66affSColin Finck }
704c2c66affSColin Finck }
705c2c66affSColin Finck #if USE_EXTENDED_PRIORITIES
706c2c66affSColin Finck min_priority=-7; max_priority=6;
707c2c66affSColin Finck #endif
708c2c66affSColin Finck for(i=min_priority;i<=max_priority;i++) {
709c2c66affSColin Finck ok(SetThreadPriority(curthread,i)!=0,
710c2c66affSColin Finck "SetThreadPriority Failed for priority: %d\n",i);
711c2c66affSColin Finck ok(GetThreadPriority(curthread)==i,
712c2c66affSColin Finck "GetThreadPriority Failed for priority: %d\n",i);
713c2c66affSColin Finck }
714c2c66affSColin Finck ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0,
715c2c66affSColin Finck "SetThreadPriority Failed\n");
716c2c66affSColin Finck ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
717c2c66affSColin Finck "GetThreadPriority Failed\n");
718c2c66affSColin Finck ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
719c2c66affSColin Finck "SetThreadPriority Failed\n");
720c2c66affSColin Finck ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
721c2c66affSColin Finck "GetThreadPriority Failed\n");
722c2c66affSColin Finck ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed\n");
723c2c66affSColin Finck
724c2c66affSColin Finck /* Check that the thread priority is not changed if SetThreadPriority
725c2c66affSColin Finck is called with a value outside of the max/min range */
726c2c66affSColin Finck SetThreadPriority(curthread,min_priority);
727c2c66affSColin Finck SetLastError(0xdeadbeef);
728c2c66affSColin Finck rc = SetThreadPriority(curthread,min_priority-1);
729c2c66affSColin Finck
730c2c66affSColin Finck ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
731c2c66affSColin Finck ok(GetLastError() == ERROR_INVALID_PARAMETER ||
732c2c66affSColin Finck GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */,
733c2c66affSColin Finck "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
734c2c66affSColin Finck GetLastError());
735c2c66affSColin Finck ok(GetThreadPriority(curthread)==min_priority,
736c2c66affSColin Finck "GetThreadPriority didn't return min_priority\n");
737c2c66affSColin Finck
738c2c66affSColin Finck SetThreadPriority(curthread,max_priority);
739c2c66affSColin Finck SetLastError(0xdeadbeef);
740c2c66affSColin Finck rc = SetThreadPriority(curthread,max_priority+1);
741c2c66affSColin Finck
742c2c66affSColin Finck ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
743c2c66affSColin Finck ok(GetLastError() == ERROR_INVALID_PARAMETER ||
744c2c66affSColin Finck GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */,
745c2c66affSColin Finck "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
746c2c66affSColin Finck GetLastError());
747c2c66affSColin Finck ok(GetThreadPriority(curthread)==max_priority,
748c2c66affSColin Finck "GetThreadPriority didn't return max_priority\n");
749c2c66affSColin Finck
750c2c66affSColin Finck /* Check thread priority boost */
751c2c66affSColin Finck if (!pGetThreadPriorityBoost || !pSetThreadPriorityBoost)
752c2c66affSColin Finck return; /* Win9x */
753c2c66affSColin Finck
754c2c66affSColin Finck SetLastError(0xdeadbeef);
755c2c66affSColin Finck rc=pGetThreadPriorityBoost(curthread,&disabled);
756c2c66affSColin Finck if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
757c2c66affSColin Finck {
758c2c66affSColin Finck win_skip("GetThreadPriorityBoost is not implemented on WinME\n");
759c2c66affSColin Finck return;
760c2c66affSColin Finck }
761c2c66affSColin Finck
762c2c66affSColin Finck ok(rc!=0,"error=%d\n",GetLastError());
763c2c66affSColin Finck
764c2c66affSColin Finck if (pOpenThread) {
765c2c66affSColin Finck /* check that access control is obeyed */
766c2c66affSColin Finck access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 &
767c2c66affSColin Finck (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
768c2c66affSColin Finck 0,curthreadId);
769c2c66affSColin Finck ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
770c2c66affSColin Finck if (access_thread!=NULL) {
771c2c66affSColin Finck todo_wine obey_ar(pSetThreadPriorityBoost(access_thread,1)==0);
772c2c66affSColin Finck todo_wine obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0);
773c2c66affSColin Finck ok(CloseHandle(access_thread),"Error Closing thread handle\n");
774c2c66affSColin Finck }
775c2c66affSColin Finck }
776c2c66affSColin Finck
777c2c66affSColin Finck rc = pSetThreadPriorityBoost(curthread,1);
778c2c66affSColin Finck ok( rc != 0, "error=%d\n",GetLastError());
779c2c66affSColin Finck todo_wine {
780c2c66affSColin Finck rc=pGetThreadPriorityBoost(curthread,&disabled);
781c2c66affSColin Finck ok(rc!=0 && disabled==1,
782c2c66affSColin Finck "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
783c2c66affSColin Finck }
784c2c66affSColin Finck
785c2c66affSColin Finck rc = pSetThreadPriorityBoost(curthread,0);
786c2c66affSColin Finck ok( rc != 0, "error=%d\n",GetLastError());
787c2c66affSColin Finck rc=pGetThreadPriorityBoost(curthread,&disabled);
788c2c66affSColin Finck ok(rc!=0 && disabled==0,
789c2c66affSColin Finck "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
790c2c66affSColin Finck }
791c2c66affSColin Finck
792c2c66affSColin Finck /* check the GetThreadTimes function */
test_GetThreadTimes(void)793c2c66affSColin Finck static VOID test_GetThreadTimes(void)
794c2c66affSColin Finck {
795c2c66affSColin Finck HANDLE thread,access_thread=NULL;
796c2c66affSColin Finck FILETIME creationTime,exitTime,kernelTime,userTime;
797c2c66affSColin Finck DWORD threadId;
798c2c66affSColin Finck int error;
799c2c66affSColin Finck
800c2c66affSColin Finck thread = CreateThread(NULL,0,threadFunc2,NULL,
801c2c66affSColin Finck CREATE_SUSPENDED,&threadId);
802c2c66affSColin Finck
803c2c66affSColin Finck ok(thread!=NULL,"Create Thread failed\n");
804c2c66affSColin Finck /* check that access control is obeyed */
805c2c66affSColin Finck if (pOpenThread) {
806c2c66affSColin Finck access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 &
807c2c66affSColin Finck (~THREAD_QUERY_INFORMATION), 0,threadId);
808c2c66affSColin Finck ok(access_thread!=NULL,
809c2c66affSColin Finck "OpenThread returned an invalid handle\n");
810c2c66affSColin Finck }
811c2c66affSColin Finck ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
812c2c66affSColin Finck ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
813c2c66affSColin Finck "ResumeThread didn't work\n");
814c2c66affSColin Finck creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
815c2c66affSColin Finck exitTime.dwLowDateTime=99; exitTime.dwHighDateTime=99;
816c2c66affSColin Finck kernelTime.dwLowDateTime=99; kernelTime.dwHighDateTime=99;
817c2c66affSColin Finck userTime.dwLowDateTime=99; userTime.dwHighDateTime=99;
818c2c66affSColin Finck /* GetThreadTimes should set all of the parameters passed to it */
819c2c66affSColin Finck error=GetThreadTimes(thread,&creationTime,&exitTime,
820c2c66affSColin Finck &kernelTime,&userTime);
821c2c66affSColin Finck
822c2c66affSColin Finck if (error == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
823c2c66affSColin Finck win_skip("GetThreadTimes is not implemented\n");
824c2c66affSColin Finck else {
825c2c66affSColin Finck ok(error!=0,"GetThreadTimes failed\n");
826c2c66affSColin Finck ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
827c2c66affSColin Finck "creationTime was invalid\n");
828c2c66affSColin Finck ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
829c2c66affSColin Finck "exitTime was invalid\n");
830c2c66affSColin Finck ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
831c2c66affSColin Finck "kernelTimewas invalid\n");
832c2c66affSColin Finck ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
833c2c66affSColin Finck "userTime was invalid\n");
834c2c66affSColin Finck ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
835c2c66affSColin Finck if(access_thread!=NULL)
836c2c66affSColin Finck {
837c2c66affSColin Finck error=GetThreadTimes(access_thread,&creationTime,&exitTime,
838c2c66affSColin Finck &kernelTime,&userTime);
839c2c66affSColin Finck obey_ar(error==0);
840c2c66affSColin Finck }
841c2c66affSColin Finck }
842c2c66affSColin Finck if(access_thread!=NULL) {
843c2c66affSColin Finck ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
844c2c66affSColin Finck }
845c2c66affSColin Finck }
846c2c66affSColin Finck
847c2c66affSColin Finck /* Check the processor affinity functions */
848c2c66affSColin Finck /* NOTE: These functions should also be checked that they obey access control
849c2c66affSColin Finck */
test_thread_processor(void)850c2c66affSColin Finck static VOID test_thread_processor(void)
851c2c66affSColin Finck {
852c2c66affSColin Finck HANDLE curthread,curproc;
853c2c66affSColin Finck DWORD_PTR processMask,systemMask,retMask;
854c2c66affSColin Finck SYSTEM_INFO sysInfo;
855c2c66affSColin Finck int error=0;
856c2c66affSColin Finck BOOL is_wow64;
857c2c66affSColin Finck
858c2c66affSColin Finck if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
859c2c66affSColin Finck
860c2c66affSColin Finck sysInfo.dwNumberOfProcessors=0;
861c2c66affSColin Finck GetSystemInfo(&sysInfo);
862c2c66affSColin Finck ok(sysInfo.dwNumberOfProcessors>0,
863c2c66affSColin Finck "GetSystemInfo failed to return a valid # of processors\n");
864c2c66affSColin Finck /* Use the current Thread/process for all tests */
865c2c66affSColin Finck curthread=GetCurrentThread();
866c2c66affSColin Finck ok(curthread!=NULL,"GetCurrentThread failed\n");
867c2c66affSColin Finck curproc=GetCurrentProcess();
868c2c66affSColin Finck ok(curproc!=NULL,"GetCurrentProcess failed\n");
869c2c66affSColin Finck /* Check the Affinity Mask functions */
870c2c66affSColin Finck ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
871c2c66affSColin Finck "GetProcessAffinityMask failed\n");
872c2c66affSColin Finck ok(SetThreadAffinityMask(curthread,processMask)==processMask,
873c2c66affSColin Finck "SetThreadAffinityMask failed\n");
874c2c66affSColin Finck ok(SetThreadAffinityMask(curthread,processMask+1)==0,
875c2c66affSColin Finck "SetThreadAffinityMask passed for an illegal processor\n");
876c2c66affSColin Finck /* NOTE: Pre-Vista does not recognize the "all processors" flag (all bits set) */
877c2c66affSColin Finck retMask = SetThreadAffinityMask(curthread,~0);
878c2c66affSColin Finck ok(broken(retMask==0) || retMask==processMask,
879c2c66affSColin Finck "SetThreadAffinityMask(thread,-1) failed to request all processors.\n");
880c2c66affSColin Finck
881c2c66affSColin Finck if (retMask == processMask)
882c2c66affSColin Finck {
883c2c66affSColin Finck /* Show that the "all processors" flag is handled in ntdll */
884c2c66affSColin Finck DWORD_PTR mask = ~0u;
885c2c66affSColin Finck NTSTATUS status = pNtSetInformationThread(curthread, ThreadAffinityMask, &mask, sizeof(mask));
886c2c66affSColin Finck ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS in NtSetInformationThread, got %x\n", status);
887c2c66affSColin Finck }
888c2c66affSColin Finck
889c2c66affSColin Finck if (retMask == processMask && sizeof(ULONG_PTR) > sizeof(ULONG))
890c2c66affSColin Finck {
891c2c66affSColin Finck /* only the low 32-bits matter */
892c2c66affSColin Finck retMask = SetThreadAffinityMask(curthread,~(ULONG_PTR)0);
893c2c66affSColin Finck ok(retMask == processMask, "SetThreadAffinityMask failed\n");
894c2c66affSColin Finck retMask = SetThreadAffinityMask(curthread,~(ULONG_PTR)0 >> 3);
895c2c66affSColin Finck ok(retMask == processMask, "SetThreadAffinityMask failed\n");
896c2c66affSColin Finck }
897c2c66affSColin Finck /* NOTE: This only works on WinNT/2000/XP) */
898c2c66affSColin Finck if (pSetThreadIdealProcessor)
899c2c66affSColin Finck {
900c2c66affSColin Finck SetLastError(0xdeadbeef);
901c2c66affSColin Finck error=pSetThreadIdealProcessor(curthread,0);
902c2c66affSColin Finck if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
903c2c66affSColin Finck {
904c2c66affSColin Finck ok(error!=-1, "SetThreadIdealProcessor failed\n");
905c2c66affSColin Finck
906c2c66affSColin Finck if (is_wow64)
907c2c66affSColin Finck {
908c2c66affSColin Finck SetLastError(0xdeadbeef);
909c2c66affSColin Finck error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
910c2c66affSColin Finck todo_wine
911c2c66affSColin Finck ok(error!=-1, "SetThreadIdealProcessor failed for %u on Wow64\n", MAXIMUM_PROCESSORS+1);
912c2c66affSColin Finck
913c2c66affSColin Finck SetLastError(0xdeadbeef);
914c2c66affSColin Finck error=pSetThreadIdealProcessor(curthread,65);
915c2c66affSColin Finck ok(error==-1, "SetThreadIdealProcessor succeeded with an illegal processor #\n");
916c2c66affSColin Finck ok(GetLastError()==ERROR_INVALID_PARAMETER,
917c2c66affSColin Finck "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
918c2c66affSColin Finck }
919c2c66affSColin Finck else
920c2c66affSColin Finck {
921c2c66affSColin Finck SetLastError(0xdeadbeef);
922c2c66affSColin Finck error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
923c2c66affSColin Finck ok(error==-1, "SetThreadIdealProcessor succeeded with an illegal processor #\n");
924c2c66affSColin Finck ok(GetLastError()==ERROR_INVALID_PARAMETER,
925c2c66affSColin Finck "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
926c2c66affSColin Finck }
927c2c66affSColin Finck
928c2c66affSColin Finck error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
929c2c66affSColin Finck ok(error!=-1, "SetThreadIdealProcessor failed\n");
930c2c66affSColin Finck }
931c2c66affSColin Finck else
932c2c66affSColin Finck win_skip("SetThreadIdealProcessor is not implemented\n");
933c2c66affSColin Finck }
934c2c66affSColin Finck
935c2c66affSColin Finck if (pGetThreadGroupAffinity && pSetThreadGroupAffinity)
936c2c66affSColin Finck {
937c2c66affSColin Finck GROUP_AFFINITY affinity, affinity_new;
938c2c66affSColin Finck NTSTATUS status;
939c2c66affSColin Finck
940c2c66affSColin Finck memset(&affinity, 0, sizeof(affinity));
941c2c66affSColin Finck ok(pGetThreadGroupAffinity(curthread, &affinity), "GetThreadGroupAffinity failed\n");
942c2c66affSColin Finck
943c2c66affSColin Finck SetLastError(0xdeadbeef);
944c2c66affSColin Finck ok(!pGetThreadGroupAffinity(curthread, NULL), "GetThreadGroupAffinity succeeded\n");
945c2c66affSColin Finck ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_NOACCESS), /* Win 7 and 8 */
946c2c66affSColin Finck "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
947c2c66affSColin Finck ok(affinity.Group == 0, "Expected group 0 got %u\n", affinity.Group);
948c2c66affSColin Finck
949c2c66affSColin Finck memset(&affinity_new, 0, sizeof(affinity_new));
950c2c66affSColin Finck affinity_new.Group = 0;
951c2c66affSColin Finck affinity_new.Mask = affinity.Mask;
952c2c66affSColin Finck ok(pSetThreadGroupAffinity(curthread, &affinity_new, &affinity), "SetThreadGroupAffinity failed\n");
953c2c66affSColin Finck ok(affinity_new.Mask == affinity.Mask, "Expected old affinity mask %lx, got %lx\n",
954c2c66affSColin Finck affinity_new.Mask, affinity.Mask);
955c2c66affSColin Finck
956c2c66affSColin Finck /* show that the "all processors" flag is not supported for SetThreadGroupAffinity */
957c2c66affSColin Finck affinity_new.Group = 0;
958c2c66affSColin Finck affinity_new.Mask = ~0u;
959c2c66affSColin Finck SetLastError(0xdeadbeef);
960c2c66affSColin Finck ok(!pSetThreadGroupAffinity(curthread, &affinity_new, NULL), "SetThreadGroupAffinity succeeded\n");
961c2c66affSColin Finck ok(GetLastError() == ERROR_INVALID_PARAMETER,
962c2c66affSColin Finck "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
963c2c66affSColin Finck
964c2c66affSColin Finck affinity_new.Group = 1; /* assumes that you have less than 64 logical processors */
965c2c66affSColin Finck affinity_new.Mask = 0x1;
966c2c66affSColin Finck SetLastError(0xdeadbeef);
967c2c66affSColin Finck ok(!pSetThreadGroupAffinity(curthread, &affinity_new, NULL), "SetThreadGroupAffinity succeeded\n");
968c2c66affSColin Finck ok(GetLastError() == ERROR_INVALID_PARAMETER,
969c2c66affSColin Finck "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
970c2c66affSColin Finck
971c2c66affSColin Finck SetLastError(0xdeadbeef);
972c2c66affSColin Finck ok(!pSetThreadGroupAffinity(curthread, NULL, NULL), "SetThreadGroupAffinity succeeded\n");
973c2c66affSColin Finck ok(GetLastError() == ERROR_NOACCESS,
974c2c66affSColin Finck "Expected ERROR_NOACCESS, got %d\n", GetLastError());
975c2c66affSColin Finck
976c2c66affSColin Finck /* show that the access violation was detected in ntdll */
977c2c66affSColin Finck status = pNtSetInformationThread(curthread, ThreadGroupInformation, NULL, sizeof(affinity_new));
978c2c66affSColin Finck ok(status == STATUS_ACCESS_VIOLATION,
979c2c66affSColin Finck "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status);
980c2c66affSColin Finck
981c2c66affSColin Finck /* restore original mask */
982c2c66affSColin Finck affinity_new.Group = 0;
983c2c66affSColin Finck affinity_new.Mask = affinity.Mask;
984c2c66affSColin Finck SetLastError(0xdeadbeef);
985c2c66affSColin Finck ok(pSetThreadGroupAffinity(curthread, &affinity_new, &affinity), "SetThreadGroupAffinity failed\n");
986c2c66affSColin Finck ok(affinity_new.Mask == affinity.Mask, "Expected old affinity mask %lx, got %lx\n",
987c2c66affSColin Finck affinity_new.Mask, affinity.Mask);
988c2c66affSColin Finck }
989c2c66affSColin Finck else
990c2c66affSColin Finck win_skip("Get/SetThreadGroupAffinity not available\n");
991c2c66affSColin Finck }
992c2c66affSColin Finck
test_GetThreadExitCode(void)993c2c66affSColin Finck static VOID test_GetThreadExitCode(void)
994c2c66affSColin Finck {
995c2c66affSColin Finck DWORD exitCode, threadid;
996c2c66affSColin Finck DWORD GLE, ret;
997c2c66affSColin Finck HANDLE thread;
998c2c66affSColin Finck
999c2c66affSColin Finck ret = GetExitCodeThread((HANDLE)0x2bad2bad,&exitCode);
1000c2c66affSColin Finck ok(ret==0, "GetExitCodeThread returned non zero value: %d\n", ret);
1001c2c66affSColin Finck GLE = GetLastError();
1002c2c66affSColin Finck ok(GLE==ERROR_INVALID_HANDLE, "GetLastError returned %d (expected 6)\n", GLE);
1003c2c66affSColin Finck
1004c2c66affSColin Finck thread = CreateThread(NULL,0,threadFunc2,NULL,0,&threadid);
1005c2c66affSColin Finck ret = WaitForSingleObject(thread,100);
1006c2c66affSColin Finck ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
1007c2c66affSColin Finck ret = GetExitCodeThread(thread,&exitCode);
1008c2c66affSColin Finck ok(ret==exitCode || ret==1,
1009c2c66affSColin Finck "GetExitCodeThread returned %d (expected 1 or %d)\n", ret, exitCode);
1010c2c66affSColin Finck ok(exitCode==99, "threadFunc2 exited with code %d (expected 99)\n", exitCode);
1011c2c66affSColin Finck ok(CloseHandle(thread)!=0,"Error closing thread handle\n");
1012c2c66affSColin Finck }
1013c2c66affSColin Finck
1014c2c66affSColin Finck #ifdef __i386__
1015c2c66affSColin Finck
1016c2c66affSColin Finck static int test_value = 0;
1017c2c66affSColin Finck static HANDLE event;
1018c2c66affSColin Finck
set_test_val(int val)1019c2c66affSColin Finck static void WINAPI set_test_val( int val )
1020c2c66affSColin Finck {
1021c2c66affSColin Finck test_value += val;
1022c2c66affSColin Finck ExitThread(0);
1023c2c66affSColin Finck }
1024c2c66affSColin Finck
threadFunc6(LPVOID p)1025c2c66affSColin Finck static DWORD WINAPI threadFunc6(LPVOID p)
1026c2c66affSColin Finck {
1027c2c66affSColin Finck SetEvent( event );
1028c2c66affSColin Finck Sleep( 1000 );
1029c2c66affSColin Finck test_value *= (int)p;
1030c2c66affSColin Finck return 0;
1031c2c66affSColin Finck }
1032c2c66affSColin Finck
test_SetThreadContext(void)1033c2c66affSColin Finck static void test_SetThreadContext(void)
1034c2c66affSColin Finck {
1035c2c66affSColin Finck CONTEXT ctx;
1036c2c66affSColin Finck int *stack;
1037c2c66affSColin Finck HANDLE thread;
1038c2c66affSColin Finck DWORD threadid;
1039c2c66affSColin Finck DWORD prevcount;
1040c2c66affSColin Finck BOOL ret;
1041c2c66affSColin Finck
1042c2c66affSColin Finck SetLastError(0xdeadbeef);
1043c2c66affSColin Finck event = CreateEventW( NULL, TRUE, FALSE, NULL );
1044c2c66affSColin Finck thread = CreateThread( NULL, 0, threadFunc6, (void *)2, 0, &threadid );
1045c2c66affSColin Finck ok( thread != NULL, "CreateThread failed : (%d)\n", GetLastError() );
1046c2c66affSColin Finck if (!thread)
1047c2c66affSColin Finck {
1048c2c66affSColin Finck trace("Thread creation failed, skipping rest of test\n");
1049c2c66affSColin Finck return;
1050c2c66affSColin Finck }
1051c2c66affSColin Finck WaitForSingleObject( event, INFINITE );
1052c2c66affSColin Finck SuspendThread( thread );
1053c2c66affSColin Finck CloseHandle( event );
1054c2c66affSColin Finck
1055c2c66affSColin Finck ctx.ContextFlags = CONTEXT_FULL;
1056c2c66affSColin Finck SetLastError(0xdeadbeef);
1057c2c66affSColin Finck ret = GetThreadContext( thread, &ctx );
1058c2c66affSColin Finck ok( ret, "GetThreadContext failed : (%u)\n", GetLastError() );
1059c2c66affSColin Finck
1060c2c66affSColin Finck if (ret)
1061c2c66affSColin Finck {
1062c2c66affSColin Finck /* simulate a call to set_test_val(10) */
1063c2c66affSColin Finck stack = (int *)ctx.Esp;
1064c2c66affSColin Finck stack[-1] = 10;
1065c2c66affSColin Finck stack[-2] = ctx.Eip;
1066c2c66affSColin Finck ctx.Esp -= 2 * sizeof(int *);
1067c2c66affSColin Finck ctx.Eip = (DWORD)set_test_val;
1068c2c66affSColin Finck SetLastError(0xdeadbeef);
1069c2c66affSColin Finck ret = SetThreadContext( thread, &ctx );
1070c2c66affSColin Finck ok( ret, "SetThreadContext failed : (%d)\n", GetLastError() );
1071c2c66affSColin Finck }
1072c2c66affSColin Finck
1073c2c66affSColin Finck SetLastError(0xdeadbeef);
1074c2c66affSColin Finck prevcount = ResumeThread( thread );
1075c2c66affSColin Finck ok ( prevcount == 1, "Previous suspend count (%d) instead of 1, last error : (%d)\n",
1076c2c66affSColin Finck prevcount, GetLastError() );
1077c2c66affSColin Finck
1078c2c66affSColin Finck WaitForSingleObject( thread, INFINITE );
1079c2c66affSColin Finck ok( test_value == 10, "test_value %d\n", test_value );
1080c2c66affSColin Finck
1081c2c66affSColin Finck ctx.ContextFlags = CONTEXT_FULL;
1082c2c66affSColin Finck SetLastError(0xdeadbeef);
1083c2c66affSColin Finck ret = GetThreadContext( thread, &ctx );
1084c2c66affSColin Finck ok( (!ret && ((GetLastError() == ERROR_GEN_FAILURE) || (GetLastError() == ERROR_ACCESS_DENIED))) ||
1085c2c66affSColin Finck (!ret && broken(GetLastError() == ERROR_INVALID_HANDLE)) || /* win2k */
1086c2c66affSColin Finck broken(ret), /* 32bit application on NT 5.x 64bit */
1087c2c66affSColin Finck "got %d with %u (expected FALSE with ERROR_GEN_FAILURE or ERROR_ACCESS_DENIED)\n",
1088c2c66affSColin Finck ret, GetLastError() );
1089c2c66affSColin Finck
1090c2c66affSColin Finck SetLastError(0xdeadbeef);
1091c2c66affSColin Finck ret = SetThreadContext( thread, &ctx );
1092c2c66affSColin Finck ok( (!ret && ((GetLastError() == ERROR_GEN_FAILURE) || (GetLastError() == ERROR_ACCESS_DENIED))) ||
1093c2c66affSColin Finck (!ret && broken(GetLastError() == ERROR_INVALID_HANDLE)) || /* win2k */
1094c2c66affSColin Finck broken(ret), /* 32bit application on NT 5.x 64bit */
1095c2c66affSColin Finck "got %d with %u (expected FALSE with ERROR_GEN_FAILURE or ERROR_ACCESS_DENIED)\n",
1096c2c66affSColin Finck ret, GetLastError() );
1097c2c66affSColin Finck
1098c2c66affSColin Finck CloseHandle( thread );
1099c2c66affSColin Finck }
1100c2c66affSColin Finck
test_GetThreadSelectorEntry(void)1101c2c66affSColin Finck static void test_GetThreadSelectorEntry(void)
1102c2c66affSColin Finck {
1103c2c66affSColin Finck LDT_ENTRY entry;
1104c2c66affSColin Finck CONTEXT ctx;
1105c2c66affSColin Finck DWORD limit;
1106c2c66affSColin Finck void *base;
1107c2c66affSColin Finck BOOL ret;
1108c2c66affSColin Finck
1109c2c66affSColin Finck memset(&ctx, 0x11, sizeof(ctx));
1110c2c66affSColin Finck ctx.ContextFlags = CONTEXT_SEGMENTS | CONTEXT_CONTROL;
1111c2c66affSColin Finck ret = GetThreadContext(GetCurrentThread(), &ctx);
1112c2c66affSColin Finck ok(ret, "GetThreadContext error %u\n", GetLastError());
1113c2c66affSColin Finck ok(!HIWORD(ctx.SegCs), "expected HIWORD(SegCs) == 0, got %u\n", ctx.SegCs);
1114c2c66affSColin Finck ok(!HIWORD(ctx.SegDs), "expected HIWORD(SegDs) == 0, got %u\n", ctx.SegDs);
1115c2c66affSColin Finck ok(!HIWORD(ctx.SegFs), "expected HIWORD(SegFs) == 0, got %u\n", ctx.SegFs);
1116c2c66affSColin Finck
1117c2c66affSColin Finck ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegCs, &entry);
1118c2c66affSColin Finck ok(ret, "GetThreadSelectorEntry(SegCs) error %u\n", GetLastError());
1119c2c66affSColin Finck ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegDs, &entry);
1120c2c66affSColin Finck ok(ret, "GetThreadSelectorEntry(SegDs) error %u\n", GetLastError());
1121c2c66affSColin Finck
1122c2c66affSColin Finck memset(&entry, 0x11, sizeof(entry));
1123c2c66affSColin Finck ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegFs, &entry);
1124c2c66affSColin Finck ok(ret, "GetThreadSelectorEntry(SegFs) error %u\n", GetLastError());
1125c2c66affSColin Finck entry.HighWord.Bits.Type &= ~1; /* ignore accessed bit */
1126c2c66affSColin Finck
1127c2c66affSColin Finck base = (void *)((entry.HighWord.Bits.BaseHi << 24) | (entry.HighWord.Bits.BaseMid << 16) | entry.BaseLow);
1128c2c66affSColin Finck limit = (entry.HighWord.Bits.LimitHi << 16) | entry.LimitLow;
1129c2c66affSColin Finck
1130c2c66affSColin Finck ok(base == NtCurrentTeb(), "expected %p, got %p\n", NtCurrentTeb(), base);
1131c2c66affSColin Finck ok(limit == 0x0fff || limit == 0x4000, "expected 0x0fff or 0x4000, got %#x\n", limit);
1132c2c66affSColin Finck ok(entry.HighWord.Bits.Type == 0x12, "expected 0x12, got %#x\n", entry.HighWord.Bits.Type);
1133c2c66affSColin Finck ok(entry.HighWord.Bits.Dpl == 3, "expected 3, got %u\n", entry.HighWord.Bits.Dpl);
1134c2c66affSColin Finck ok(entry.HighWord.Bits.Pres == 1, "expected 1, got %u\n", entry.HighWord.Bits.Pres);
1135c2c66affSColin Finck ok(entry.HighWord.Bits.Sys == 0, "expected 0, got %u\n", entry.HighWord.Bits.Sys);
1136c2c66affSColin Finck ok(entry.HighWord.Bits.Reserved_0 == 0, "expected 0, got %u\n", entry.HighWord.Bits.Reserved_0);
1137c2c66affSColin Finck ok(entry.HighWord.Bits.Default_Big == 1, "expected 1, got %u\n", entry.HighWord.Bits.Default_Big);
1138c2c66affSColin Finck ok(entry.HighWord.Bits.Granularity == 0, "expected 0, got %u\n", entry.HighWord.Bits.Granularity);
1139c2c66affSColin Finck }
1140c2c66affSColin Finck
test_NtSetLdtEntries(void)1141c2c66affSColin Finck static void test_NtSetLdtEntries(void)
1142c2c66affSColin Finck {
1143c2c66affSColin Finck THREAD_DESCRIPTOR_INFORMATION tdi;
1144c2c66affSColin Finck LDT_ENTRY ds_entry;
1145c2c66affSColin Finck CONTEXT ctx;
1146c2c66affSColin Finck DWORD ret;
1147c2c66affSColin Finck union
1148c2c66affSColin Finck {
1149c2c66affSColin Finck LDT_ENTRY entry;
1150c2c66affSColin Finck DWORD dw[2];
1151c2c66affSColin Finck } sel;
1152c2c66affSColin Finck
1153c2c66affSColin Finck if (!pNtSetLdtEntries)
1154c2c66affSColin Finck {
1155c2c66affSColin Finck win_skip("NtSetLdtEntries is not available on this platform\n");
1156c2c66affSColin Finck return;
1157c2c66affSColin Finck }
1158c2c66affSColin Finck
1159c2c66affSColin Finck if (pNtSetLdtEntries(0, 0, 0, 0, 0, 0) == STATUS_NOT_IMPLEMENTED) /* WoW64 */
1160c2c66affSColin Finck {
1161c2c66affSColin Finck win_skip("NtSetLdtEntries is not implemented on this platform\n");
1162c2c66affSColin Finck return;
1163c2c66affSColin Finck }
1164c2c66affSColin Finck
1165c2c66affSColin Finck ret = pNtSetLdtEntries(0, 0, 0, 0, 0, 0);
1166c2c66affSColin Finck ok(!ret, "NtSetLdtEntries failed: %08x\n", ret);
1167c2c66affSColin Finck
1168c2c66affSColin Finck ctx.ContextFlags = CONTEXT_SEGMENTS;
1169c2c66affSColin Finck ret = GetThreadContext(GetCurrentThread(), &ctx);
1170c2c66affSColin Finck ok(ret, "GetThreadContext failed\n");
1171c2c66affSColin Finck
1172c2c66affSColin Finck tdi.Selector = ctx.SegDs;
1173c2c66affSColin Finck ret = pNtQueryInformationThread(GetCurrentThread(), ThreadDescriptorTableEntry, &tdi, sizeof(tdi), &ret);
1174c2c66affSColin Finck ok(!ret, "NtQueryInformationThread failed: %08x\n", ret);
1175c2c66affSColin Finck ds_entry = tdi.Entry;
1176c2c66affSColin Finck
1177c2c66affSColin Finck tdi.Selector = 0x000f;
1178c2c66affSColin Finck ret = pNtQueryInformationThread(GetCurrentThread(), ThreadDescriptorTableEntry, &tdi, sizeof(tdi), &ret);
1179c2c66affSColin Finck ok(ret == STATUS_ACCESS_VIOLATION, "got %08x\n", ret);
1180c2c66affSColin Finck
1181c2c66affSColin Finck tdi.Selector = 0x001f;
1182c2c66affSColin Finck ret = pNtQueryInformationThread(GetCurrentThread(), ThreadDescriptorTableEntry, &tdi, sizeof(tdi), &ret);
1183c2c66affSColin Finck ok(ret == STATUS_ACCESS_VIOLATION, "NtQueryInformationThread returned %08x\n", ret);
1184c2c66affSColin Finck
1185c2c66affSColin Finck ret = GetThreadSelectorEntry(GetCurrentThread(), 0x000f, &sel.entry);
1186c2c66affSColin Finck ok(!ret, "GetThreadSelectorEntry should fail\n");
1187c2c66affSColin Finck
1188c2c66affSColin Finck ret = GetThreadSelectorEntry(GetCurrentThread(), 0x001f, &sel.entry);
1189c2c66affSColin Finck ok(!ret, "GetThreadSelectorEntry should fail\n");
1190c2c66affSColin Finck
1191c2c66affSColin Finck memset(&sel.entry, 0x9a, sizeof(sel.entry));
1192c2c66affSColin Finck ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegDs, &sel.entry);
1193c2c66affSColin Finck ok(ret, "GetThreadSelectorEntry failed\n");
1194c2c66affSColin Finck ok(!memcmp(&ds_entry, &sel.entry, sizeof(ds_entry)), "entries do not match\n");
1195c2c66affSColin Finck
1196c2c66affSColin Finck ret = pNtSetLdtEntries(0x000f, sel.dw[0], sel.dw[1], 0x001f, sel.dw[0], sel.dw[1]);
1197c2c66affSColin Finck ok(!ret || broken(ret == STATUS_INVALID_LDT_DESCRIPTOR) /*XP*/, "NtSetLdtEntries failed: %08x\n", ret);
1198c2c66affSColin Finck
1199c2c66affSColin Finck if (!ret)
1200c2c66affSColin Finck {
1201c2c66affSColin Finck memset(&sel.entry, 0x9a, sizeof(sel.entry));
1202c2c66affSColin Finck ret = GetThreadSelectorEntry(GetCurrentThread(), 0x000f, &sel.entry);
1203c2c66affSColin Finck ok(ret, "GetThreadSelectorEntry failed\n");
1204c2c66affSColin Finck ok(!memcmp(&ds_entry, &sel.entry, sizeof(ds_entry)), "entries do not match\n");
1205c2c66affSColin Finck
1206c2c66affSColin Finck memset(&sel.entry, 0x9a, sizeof(sel.entry));
1207c2c66affSColin Finck ret = GetThreadSelectorEntry(GetCurrentThread(), 0x001f, &sel.entry);
1208c2c66affSColin Finck ok(ret, "GetThreadSelectorEntry failed\n");
1209c2c66affSColin Finck ok(!memcmp(&ds_entry, &sel.entry, sizeof(ds_entry)), "entries do not match\n");
1210c2c66affSColin Finck }
1211c2c66affSColin Finck }
1212c2c66affSColin Finck
1213c2c66affSColin Finck #endif /* __i386__ */
1214c2c66affSColin Finck
1215c2c66affSColin Finck static HANDLE finish_event;
1216c2c66affSColin Finck static LONG times_executed;
1217c2c66affSColin Finck
work_function(void * p)1218c2c66affSColin Finck static DWORD CALLBACK work_function(void *p)
1219c2c66affSColin Finck {
1220c2c66affSColin Finck LONG executed = InterlockedIncrement(×_executed);
1221c2c66affSColin Finck
1222c2c66affSColin Finck if (executed == 100)
1223c2c66affSColin Finck SetEvent(finish_event);
1224c2c66affSColin Finck return 0;
1225c2c66affSColin Finck }
1226c2c66affSColin Finck
test_QueueUserWorkItem(void)1227c2c66affSColin Finck static void test_QueueUserWorkItem(void)
1228c2c66affSColin Finck {
1229c2c66affSColin Finck INT_PTR i;
1230c2c66affSColin Finck DWORD wait_result;
1231c2c66affSColin Finck DWORD before, after;
1232c2c66affSColin Finck
1233c2c66affSColin Finck /* QueueUserWorkItem not present on win9x */
1234c2c66affSColin Finck if (!pQueueUserWorkItem) return;
1235c2c66affSColin Finck
1236c2c66affSColin Finck finish_event = CreateEventW(NULL, TRUE, FALSE, NULL);
1237c2c66affSColin Finck
1238c2c66affSColin Finck before = GetTickCount();
1239c2c66affSColin Finck
1240c2c66affSColin Finck for (i = 0; i < 100; i++)
1241c2c66affSColin Finck {
1242c2c66affSColin Finck BOOL ret = pQueueUserWorkItem(work_function, (void *)i, WT_EXECUTEDEFAULT);
1243c2c66affSColin Finck ok(ret, "QueueUserWorkItem failed with error %d\n", GetLastError());
1244c2c66affSColin Finck }
1245c2c66affSColin Finck
1246c2c66affSColin Finck wait_result = WaitForSingleObject(finish_event, 10000);
1247c2c66affSColin Finck
1248c2c66affSColin Finck after = GetTickCount();
1249c2c66affSColin Finck trace("100 QueueUserWorkItem calls took %dms\n", after - before);
1250c2c66affSColin Finck ok(wait_result == WAIT_OBJECT_0, "wait failed with error 0x%x\n", wait_result);
1251c2c66affSColin Finck
1252c2c66affSColin Finck ok(times_executed == 100, "didn't execute all of the work items\n");
1253c2c66affSColin Finck }
1254c2c66affSColin Finck
signaled_function(PVOID p,BOOLEAN TimerOrWaitFired)1255c2c66affSColin Finck static void CALLBACK signaled_function(PVOID p, BOOLEAN TimerOrWaitFired)
1256c2c66affSColin Finck {
1257c2c66affSColin Finck HANDLE event = p;
1258c2c66affSColin Finck SetEvent(event);
1259c2c66affSColin Finck ok(!TimerOrWaitFired, "wait shouldn't have timed out\n");
1260c2c66affSColin Finck }
1261c2c66affSColin Finck
timeout_function(PVOID p,BOOLEAN TimerOrWaitFired)1262c2c66affSColin Finck static void CALLBACK timeout_function(PVOID p, BOOLEAN TimerOrWaitFired)
1263c2c66affSColin Finck {
1264c2c66affSColin Finck HANDLE event = p;
1265c2c66affSColin Finck SetEvent(event);
1266c2c66affSColin Finck ok(TimerOrWaitFired, "wait should have timed out\n");
1267c2c66affSColin Finck }
1268c2c66affSColin Finck
test_RegisterWaitForSingleObject(void)1269c2c66affSColin Finck static void test_RegisterWaitForSingleObject(void)
1270c2c66affSColin Finck {
1271c2c66affSColin Finck BOOL ret;
1272c2c66affSColin Finck HANDLE wait_handle;
1273c2c66affSColin Finck HANDLE handle;
1274c2c66affSColin Finck HANDLE complete_event;
1275c2c66affSColin Finck
1276c2c66affSColin Finck if (!pRegisterWaitForSingleObject || !pUnregisterWait)
1277c2c66affSColin Finck {
1278c2c66affSColin Finck win_skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n");
1279c2c66affSColin Finck return;
1280c2c66affSColin Finck }
1281c2c66affSColin Finck
1282c2c66affSColin Finck /* test signaled case */
1283c2c66affSColin Finck
1284c2c66affSColin Finck handle = CreateEventW(NULL, TRUE, TRUE, NULL);
1285c2c66affSColin Finck complete_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1286c2c66affSColin Finck
1287c2c66affSColin Finck ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
1288c2c66affSColin Finck ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1289c2c66affSColin Finck
1290c2c66affSColin Finck WaitForSingleObject(complete_event, INFINITE);
1291c2c66affSColin Finck /* give worker thread chance to complete */
1292c2c66affSColin Finck Sleep(100);
1293c2c66affSColin Finck
1294c2c66affSColin Finck ret = pUnregisterWait(wait_handle);
1295c2c66affSColin Finck ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
1296c2c66affSColin Finck
1297c2c66affSColin Finck /* test cancel case */
1298c2c66affSColin Finck
1299c2c66affSColin Finck ResetEvent(handle);
1300c2c66affSColin Finck
1301c2c66affSColin Finck ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
1302c2c66affSColin Finck ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1303c2c66affSColin Finck
1304c2c66affSColin Finck ret = pUnregisterWait(wait_handle);
1305c2c66affSColin Finck ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
1306c2c66affSColin Finck
1307c2c66affSColin Finck /* test timeout case */
1308c2c66affSColin Finck
1309c2c66affSColin Finck ret = pRegisterWaitForSingleObject(&wait_handle, handle, timeout_function, complete_event, 0, WT_EXECUTEONLYONCE);
1310c2c66affSColin Finck ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
1311c2c66affSColin Finck
1312c2c66affSColin Finck WaitForSingleObject(complete_event, INFINITE);
1313c2c66affSColin Finck /* give worker thread chance to complete */
1314c2c66affSColin Finck Sleep(100);
1315c2c66affSColin Finck
1316c2c66affSColin Finck ret = pUnregisterWait(wait_handle);
1317c2c66affSColin Finck ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
1318c2c66affSColin Finck
1319c2c66affSColin Finck SetLastError(0xdeadbeef);
1320c2c66affSColin Finck ret = pUnregisterWait(NULL);
1321c2c66affSColin Finck ok(!ret, "Expected UnregisterWait to fail\n");
1322c2c66affSColin Finck ok(GetLastError() == ERROR_INVALID_HANDLE,
1323c2c66affSColin Finck "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
1324c2c66affSColin Finck }
1325c2c66affSColin Finck
1326c2c66affSColin Finck static DWORD LS_main;
1327c2c66affSColin Finck static DWORD LS_index0, LS_index1;
1328c2c66affSColin Finck static DWORD LS_OutOfIndexesValue;
1329c2c66affSColin Finck
1330c2c66affSColin Finck /* Function pointers to the FLS/TLS functions to test in LS_ThreadProc() */
1331c2c66affSColin Finck static DWORD (WINAPI *LS_AllocFunc)(void);
1332c2c66affSColin Finck static PVOID (WINAPI *LS_GetValueFunc)(DWORD);
1333c2c66affSColin Finck static BOOL (WINAPI *LS_SetValueFunc)(DWORD, PVOID);
1334c2c66affSColin Finck static BOOL (WINAPI *LS_FreeFunc)(DWORD);
1335c2c66affSColin Finck
1336c2c66affSColin Finck /* Names of the functions tested in LS_ThreadProc(), for error messages */
1337c2c66affSColin Finck static const char* LS_AllocFuncName = "";
1338c2c66affSColin Finck static const char* LS_GetValueFuncName = "";
1339c2c66affSColin Finck static const char* LS_SetValueFuncName = "";
1340c2c66affSColin Finck static const char* LS_FreeFuncName = "";
1341c2c66affSColin Finck
1342c2c66affSColin Finck /* FLS entry points, dynamically loaded in platforms that support them */
1343c2c66affSColin Finck static DWORD (WINAPI *pFlsAlloc)(PFLS_CALLBACK_FUNCTION);
1344c2c66affSColin Finck static BOOL (WINAPI *pFlsFree)(DWORD);
1345c2c66affSColin Finck static PVOID (WINAPI *pFlsGetValue)(DWORD);
1346c2c66affSColin Finck static BOOL (WINAPI *pFlsSetValue)(DWORD,PVOID);
1347c2c66affSColin Finck
1348c2c66affSColin Finck /* A thunk function to make FlsAlloc compatible with the signature of TlsAlloc */
FLS_AllocFuncThunk(void)1349c2c66affSColin Finck static DWORD WINAPI FLS_AllocFuncThunk(void)
1350c2c66affSColin Finck {
1351c2c66affSColin Finck return pFlsAlloc(NULL);
1352c2c66affSColin Finck }
1353c2c66affSColin Finck
LS_InheritanceProc(LPVOID p)1354c2c66affSColin Finck static DWORD WINAPI LS_InheritanceProc(LPVOID p)
1355c2c66affSColin Finck {
1356c2c66affSColin Finck /* We should NOT inherit the FLS/TLS values from our parent or from the
1357c2c66affSColin Finck main thread. */
1358c2c66affSColin Finck LPVOID val;
1359c2c66affSColin Finck
1360c2c66affSColin Finck val = LS_GetValueFunc(LS_main);
1361c2c66affSColin Finck ok(val == NULL, "%s inheritance failed\n", LS_GetValueFuncName);
1362c2c66affSColin Finck
1363c2c66affSColin Finck val = LS_GetValueFunc(LS_index0);
1364c2c66affSColin Finck ok(val == NULL, "%s inheritance failed\n", LS_GetValueFuncName);
1365c2c66affSColin Finck
1366c2c66affSColin Finck val = LS_GetValueFunc(LS_index1);
1367c2c66affSColin Finck ok(val == NULL, "%s inheritance failed\n", LS_GetValueFuncName);
1368c2c66affSColin Finck
1369c2c66affSColin Finck return 0;
1370c2c66affSColin Finck }
1371c2c66affSColin Finck
1372c2c66affSColin Finck /* Basic FLS/TLS usage test. Make sure we can create slots and the values we
1373c2c66affSColin Finck store in them are separate among threads. Also test FLS/TLS value
1374c2c66affSColin Finck inheritance with LS_InheritanceProc. */
LS_ThreadProc(LPVOID p)1375c2c66affSColin Finck static DWORD WINAPI LS_ThreadProc(LPVOID p)
1376c2c66affSColin Finck {
1377c2c66affSColin Finck LONG_PTR id = (LONG_PTR) p;
1378c2c66affSColin Finck LPVOID val;
1379c2c66affSColin Finck BOOL ret;
1380c2c66affSColin Finck
1381c2c66affSColin Finck if (sync_threads_and_run_one(0, id))
1382c2c66affSColin Finck {
1383c2c66affSColin Finck LS_index0 = LS_AllocFunc();
1384c2c66affSColin Finck ok(LS_index0 != LS_OutOfIndexesValue, "%s failed\n", LS_AllocFuncName);
1385c2c66affSColin Finck }
1386c2c66affSColin Finck resync_after_run();
1387c2c66affSColin Finck
1388c2c66affSColin Finck if (sync_threads_and_run_one(1, id))
1389c2c66affSColin Finck {
1390c2c66affSColin Finck LS_index1 = LS_AllocFunc();
1391c2c66affSColin Finck ok(LS_index1 != LS_OutOfIndexesValue, "%s failed\n", LS_AllocFuncName);
1392c2c66affSColin Finck
1393c2c66affSColin Finck /* Slot indices should be different even if created in different
1394c2c66affSColin Finck threads. */
1395c2c66affSColin Finck ok(LS_index0 != LS_index1, "%s failed\n", LS_AllocFuncName);
1396c2c66affSColin Finck
1397c2c66affSColin Finck /* Both slots should be initialized to NULL */
1398*ed41a4deSAmine Khaldi SetLastError(0xdeadbeef);
1399c2c66affSColin Finck val = LS_GetValueFunc(LS_index0);
1400c2c66affSColin Finck ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1401c2c66affSColin Finck ok(val == NULL, "Slot not initialized correctly\n");
1402c2c66affSColin Finck
1403*ed41a4deSAmine Khaldi SetLastError(0xdeadbeef);
1404c2c66affSColin Finck val = LS_GetValueFunc(LS_index1);
1405c2c66affSColin Finck ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1406c2c66affSColin Finck ok(val == NULL, "Slot not initialized correctly\n");
1407c2c66affSColin Finck }
1408c2c66affSColin Finck resync_after_run();
1409c2c66affSColin Finck
1410c2c66affSColin Finck if (sync_threads_and_run_one(0, id))
1411c2c66affSColin Finck {
1412*ed41a4deSAmine Khaldi SetLastError(0xdeadbeef);
1413c2c66affSColin Finck val = LS_GetValueFunc(LS_index0);
1414c2c66affSColin Finck ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1415c2c66affSColin Finck ok(val == NULL, "Slot not initialized correctly\n");
1416c2c66affSColin Finck
1417*ed41a4deSAmine Khaldi SetLastError(0xdeadbeef);
1418c2c66affSColin Finck val = LS_GetValueFunc(LS_index1);
1419c2c66affSColin Finck ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1420c2c66affSColin Finck ok(val == NULL, "Slot not initialized correctly\n");
1421c2c66affSColin Finck
1422c2c66affSColin Finck ret = LS_SetValueFunc(LS_index0, (LPVOID) 1);
1423c2c66affSColin Finck ok(ret, "%s failed\n", LS_SetValueFuncName);
1424c2c66affSColin Finck
1425c2c66affSColin Finck ret = LS_SetValueFunc(LS_index1, (LPVOID) 2);
1426c2c66affSColin Finck ok(ret, "%s failed\n", LS_SetValueFuncName);
1427c2c66affSColin Finck
1428*ed41a4deSAmine Khaldi SetLastError(0xdeadbeef);
1429c2c66affSColin Finck val = LS_GetValueFunc(LS_index0);
1430c2c66affSColin Finck ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1431c2c66affSColin Finck ok(val == (LPVOID) 1, "Slot not initialized correctly\n");
1432c2c66affSColin Finck
1433*ed41a4deSAmine Khaldi SetLastError(0xdeadbeef);
1434c2c66affSColin Finck val = LS_GetValueFunc(LS_index1);
1435c2c66affSColin Finck ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1436c2c66affSColin Finck ok(val == (LPVOID) 2, "Slot not initialized correctly\n");
1437c2c66affSColin Finck }
1438c2c66affSColin Finck resync_after_run();
1439c2c66affSColin Finck
1440c2c66affSColin Finck if (sync_threads_and_run_one(1, id))
1441c2c66affSColin Finck {
1442c2c66affSColin Finck val = LS_GetValueFunc(LS_index0);
1443c2c66affSColin Finck ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1444c2c66affSColin Finck ok(val == NULL, "Slot not initialized correctly\n");
1445c2c66affSColin Finck
1446c2c66affSColin Finck val = LS_GetValueFunc(LS_index1);
1447c2c66affSColin Finck ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1448c2c66affSColin Finck ok(val == NULL, "Slot not initialized correctly\n");
1449c2c66affSColin Finck
1450c2c66affSColin Finck ret = LS_SetValueFunc(LS_index0, (LPVOID) 3);
1451c2c66affSColin Finck ok(ret, "%s failed\n", LS_SetValueFuncName);
1452c2c66affSColin Finck
1453c2c66affSColin Finck ret = LS_SetValueFunc(LS_index1, (LPVOID) 4);
1454c2c66affSColin Finck ok(ret, "%s failed\n", LS_SetValueFuncName);
1455c2c66affSColin Finck
1456c2c66affSColin Finck val = LS_GetValueFunc(LS_index0);
1457c2c66affSColin Finck ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1458c2c66affSColin Finck ok(val == (LPVOID) 3, "Slot not initialized correctly\n");
1459c2c66affSColin Finck
1460c2c66affSColin Finck val = LS_GetValueFunc(LS_index1);
1461c2c66affSColin Finck ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1462c2c66affSColin Finck ok(val == (LPVOID) 4, "Slot not initialized correctly\n");
1463c2c66affSColin Finck }
1464c2c66affSColin Finck resync_after_run();
1465c2c66affSColin Finck
1466c2c66affSColin Finck if (sync_threads_and_run_one(0, id))
1467c2c66affSColin Finck {
1468c2c66affSColin Finck HANDLE thread;
1469c2c66affSColin Finck DWORD waitret, tid;
1470c2c66affSColin Finck
1471c2c66affSColin Finck val = LS_GetValueFunc(LS_index0);
1472c2c66affSColin Finck ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1473c2c66affSColin Finck ok(val == (LPVOID) 1, "Slot not initialized correctly\n");
1474c2c66affSColin Finck
1475c2c66affSColin Finck val = LS_GetValueFunc(LS_index1);
1476c2c66affSColin Finck ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName);
1477c2c66affSColin Finck ok(val == (LPVOID) 2, "Slot not initialized correctly\n");
1478c2c66affSColin Finck
1479c2c66affSColin Finck thread = CreateThread(NULL, 0, LS_InheritanceProc, 0, 0, &tid);
1480c2c66affSColin Finck ok(thread != NULL, "CreateThread failed\n");
1481c2c66affSColin Finck waitret = WaitForSingleObject(thread, 60000);
1482c2c66affSColin Finck ok(waitret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
1483c2c66affSColin Finck CloseHandle(thread);
1484c2c66affSColin Finck
1485c2c66affSColin Finck ret = LS_FreeFunc(LS_index0);
1486c2c66affSColin Finck ok(ret, "%s failed\n", LS_FreeFuncName);
1487c2c66affSColin Finck }
1488c2c66affSColin Finck resync_after_run();
1489c2c66affSColin Finck
1490c2c66affSColin Finck if (sync_threads_and_run_one(1, id))
1491c2c66affSColin Finck {
1492c2c66affSColin Finck ret = LS_FreeFunc(LS_index1);
1493c2c66affSColin Finck ok(ret, "%s failed\n", LS_FreeFuncName);
1494c2c66affSColin Finck }
1495c2c66affSColin Finck resync_after_run();
1496c2c66affSColin Finck
1497c2c66affSColin Finck return 0;
1498c2c66affSColin Finck }
1499c2c66affSColin Finck
run_LS_tests(void)1500c2c66affSColin Finck static void run_LS_tests(void)
1501c2c66affSColin Finck {
1502c2c66affSColin Finck HANDLE threads[2];
1503c2c66affSColin Finck LONG_PTR i;
1504c2c66affSColin Finck DWORD ret;
1505c2c66affSColin Finck BOOL suc;
1506c2c66affSColin Finck
1507c2c66affSColin Finck init_thread_sync_helpers();
1508c2c66affSColin Finck
1509c2c66affSColin Finck /* Allocate a slot in the main thread to test for inheritance. */
1510c2c66affSColin Finck LS_main = LS_AllocFunc();
1511c2c66affSColin Finck ok(LS_main != LS_OutOfIndexesValue, "%s failed\n", LS_AllocFuncName);
1512c2c66affSColin Finck suc = LS_SetValueFunc(LS_main, (LPVOID) 4114);
1513c2c66affSColin Finck ok(suc, "%s failed\n", LS_SetValueFuncName);
1514c2c66affSColin Finck
1515c2c66affSColin Finck for (i = 0; i < 2; ++i)
1516c2c66affSColin Finck {
1517c2c66affSColin Finck DWORD tid;
1518c2c66affSColin Finck
1519c2c66affSColin Finck threads[i] = CreateThread(NULL, 0, LS_ThreadProc, (LPVOID) i, 0, &tid);
1520c2c66affSColin Finck ok(threads[i] != NULL, "CreateThread failed\n");
1521c2c66affSColin Finck }
1522c2c66affSColin Finck
1523c2c66affSColin Finck ret = WaitForMultipleObjects(2, threads, TRUE, 60000);
1524c2c66affSColin Finck ok(ret == WAIT_OBJECT_0 || broken(ret == WAIT_OBJECT_0+1 /* nt4,w2k */), "WaitForAllObjects 2 threads %d\n",ret);
1525c2c66affSColin Finck
1526c2c66affSColin Finck for (i = 0; i < 2; ++i)
1527c2c66affSColin Finck CloseHandle(threads[i]);
1528c2c66affSColin Finck
1529c2c66affSColin Finck suc = LS_FreeFunc(LS_main);
1530c2c66affSColin Finck ok(suc, "%s failed\n", LS_FreeFuncName);
1531c2c66affSColin Finck cleanup_thread_sync_helpers();
1532c2c66affSColin Finck }
1533c2c66affSColin Finck
test_TLS(void)1534c2c66affSColin Finck static void test_TLS(void)
1535c2c66affSColin Finck {
1536c2c66affSColin Finck LS_OutOfIndexesValue = TLS_OUT_OF_INDEXES;
1537c2c66affSColin Finck
1538c2c66affSColin Finck LS_AllocFunc = &TlsAlloc;
1539c2c66affSColin Finck LS_GetValueFunc = &TlsGetValue;
1540c2c66affSColin Finck LS_SetValueFunc = &TlsSetValue;
1541c2c66affSColin Finck LS_FreeFunc = &TlsFree;
1542c2c66affSColin Finck
1543c2c66affSColin Finck LS_AllocFuncName = "TlsAlloc";
1544c2c66affSColin Finck LS_GetValueFuncName = "TlsGetValue";
1545c2c66affSColin Finck LS_SetValueFuncName = "TlsSetValue";
1546c2c66affSColin Finck LS_FreeFuncName = "TlsFree";
1547c2c66affSColin Finck
1548c2c66affSColin Finck run_LS_tests();
1549c2c66affSColin Finck }
1550c2c66affSColin Finck
test_FLS(void)1551c2c66affSColin Finck static void test_FLS(void)
1552c2c66affSColin Finck {
1553c2c66affSColin Finck if (!pFlsAlloc || !pFlsFree || !pFlsGetValue || !pFlsSetValue)
1554c2c66affSColin Finck {
1555c2c66affSColin Finck win_skip("Fiber Local Storage not supported\n");
1556c2c66affSColin Finck return;
1557c2c66affSColin Finck }
1558c2c66affSColin Finck
1559c2c66affSColin Finck LS_OutOfIndexesValue = FLS_OUT_OF_INDEXES;
1560c2c66affSColin Finck
1561c2c66affSColin Finck LS_AllocFunc = &FLS_AllocFuncThunk;
1562c2c66affSColin Finck LS_GetValueFunc = pFlsGetValue;
1563c2c66affSColin Finck LS_SetValueFunc = pFlsSetValue;
1564c2c66affSColin Finck LS_FreeFunc = pFlsFree;
1565c2c66affSColin Finck
1566c2c66affSColin Finck LS_AllocFuncName = "FlsAlloc";
1567c2c66affSColin Finck LS_GetValueFuncName = "FlsGetValue";
1568c2c66affSColin Finck LS_SetValueFuncName = "FlsSetValue";
1569c2c66affSColin Finck LS_FreeFuncName = "FlsFree";
1570c2c66affSColin Finck
1571c2c66affSColin Finck run_LS_tests();
1572c2c66affSColin Finck }
1573c2c66affSColin Finck
test_ThreadErrorMode(void)1574c2c66affSColin Finck static void test_ThreadErrorMode(void)
1575c2c66affSColin Finck {
1576c2c66affSColin Finck DWORD oldmode;
1577c2c66affSColin Finck DWORD mode;
1578c2c66affSColin Finck DWORD rtlmode;
1579c2c66affSColin Finck BOOL ret;
1580c2c66affSColin Finck
1581c2c66affSColin Finck if (!pSetThreadErrorMode || !pGetThreadErrorMode)
1582c2c66affSColin Finck {
1583c2c66affSColin Finck win_skip("SetThreadErrorMode and/or GetThreadErrorMode unavailable (added in Windows 7)\n");
1584c2c66affSColin Finck return;
1585c2c66affSColin Finck }
1586c2c66affSColin Finck
1587c2c66affSColin Finck if (!pRtlGetThreadErrorMode) {
1588c2c66affSColin Finck win_skip("RtlGetThreadErrorMode not available\n");
1589c2c66affSColin Finck return;
1590c2c66affSColin Finck }
1591c2c66affSColin Finck
1592c2c66affSColin Finck oldmode = pGetThreadErrorMode();
1593c2c66affSColin Finck
1594c2c66affSColin Finck ret = pSetThreadErrorMode(0, &mode);
1595c2c66affSColin Finck ok(ret, "SetThreadErrorMode failed\n");
1596c2c66affSColin Finck ok(mode == oldmode,
1597c2c66affSColin Finck "SetThreadErrorMode returned old mode 0x%x, expected 0x%x\n",
1598c2c66affSColin Finck mode, oldmode);
1599c2c66affSColin Finck mode = pGetThreadErrorMode();
1600c2c66affSColin Finck ok(mode == 0, "GetThreadErrorMode returned mode 0x%x, expected 0\n", mode);
1601c2c66affSColin Finck rtlmode = pRtlGetThreadErrorMode();
1602c2c66affSColin Finck ok(rtlmode == 0,
1603c2c66affSColin Finck "RtlGetThreadErrorMode returned mode 0x%x, expected 0\n", mode);
1604c2c66affSColin Finck
1605c2c66affSColin Finck ret = pSetThreadErrorMode(SEM_FAILCRITICALERRORS, &mode);
1606c2c66affSColin Finck ok(ret, "SetThreadErrorMode failed\n");
1607c2c66affSColin Finck ok(mode == 0,
1608c2c66affSColin Finck "SetThreadErrorMode returned old mode 0x%x, expected 0\n", mode);
1609c2c66affSColin Finck mode = pGetThreadErrorMode();
1610c2c66affSColin Finck ok(mode == SEM_FAILCRITICALERRORS,
1611c2c66affSColin Finck "GetThreadErrorMode returned mode 0x%x, expected SEM_FAILCRITICALERRORS\n",
1612c2c66affSColin Finck mode);
1613c2c66affSColin Finck rtlmode = pRtlGetThreadErrorMode();
1614c2c66affSColin Finck ok(rtlmode == 0x10,
1615c2c66affSColin Finck "RtlGetThreadErrorMode returned mode 0x%x, expected 0x10\n", mode);
1616c2c66affSColin Finck
1617c2c66affSColin Finck ret = pSetThreadErrorMode(SEM_NOGPFAULTERRORBOX, &mode);
1618c2c66affSColin Finck ok(ret, "SetThreadErrorMode failed\n");
1619c2c66affSColin Finck ok(mode == SEM_FAILCRITICALERRORS,
1620c2c66affSColin Finck "SetThreadErrorMode returned old mode 0x%x, expected SEM_FAILCRITICALERRORS\n",
1621c2c66affSColin Finck mode);
1622c2c66affSColin Finck mode = pGetThreadErrorMode();
1623c2c66affSColin Finck ok(mode == SEM_NOGPFAULTERRORBOX,
1624c2c66affSColin Finck "GetThreadErrorMode returned mode 0x%x, expected SEM_NOGPFAULTERRORBOX\n",
1625c2c66affSColin Finck mode);
1626c2c66affSColin Finck rtlmode = pRtlGetThreadErrorMode();
1627c2c66affSColin Finck ok(rtlmode == 0x20,
1628c2c66affSColin Finck "RtlGetThreadErrorMode returned mode 0x%x, expected 0x20\n", mode);
1629c2c66affSColin Finck
1630c2c66affSColin Finck ret = pSetThreadErrorMode(SEM_NOOPENFILEERRORBOX, NULL);
1631c2c66affSColin Finck ok(ret, "SetThreadErrorMode failed\n");
1632c2c66affSColin Finck mode = pGetThreadErrorMode();
1633c2c66affSColin Finck ok(mode == SEM_NOOPENFILEERRORBOX,
1634c2c66affSColin Finck "GetThreadErrorMode returned mode 0x%x, expected SEM_NOOPENFILEERRORBOX\n",
1635c2c66affSColin Finck mode);
1636c2c66affSColin Finck rtlmode = pRtlGetThreadErrorMode();
1637c2c66affSColin Finck ok(rtlmode == 0x40,
1638c2c66affSColin Finck "RtlGetThreadErrorMode returned mode 0x%x, expected 0x40\n", rtlmode);
1639c2c66affSColin Finck
1640c2c66affSColin Finck for (mode = 1; mode; mode <<= 1)
1641c2c66affSColin Finck {
1642c2c66affSColin Finck ret = pSetThreadErrorMode(mode, NULL);
1643c2c66affSColin Finck if (mode & (SEM_FAILCRITICALERRORS |
1644c2c66affSColin Finck SEM_NOGPFAULTERRORBOX |
1645c2c66affSColin Finck SEM_NOOPENFILEERRORBOX))
1646c2c66affSColin Finck {
1647c2c66affSColin Finck ok(ret,
1648c2c66affSColin Finck "SetThreadErrorMode(0x%x,NULL) failed with error %d\n",
1649c2c66affSColin Finck mode, GetLastError());
1650c2c66affSColin Finck }
1651c2c66affSColin Finck else
1652c2c66affSColin Finck {
1653c2c66affSColin Finck DWORD GLE = GetLastError();
1654c2c66affSColin Finck ok(!ret,
1655c2c66affSColin Finck "SetThreadErrorMode(0x%x,NULL) succeeded, expected failure\n",
1656c2c66affSColin Finck mode);
1657c2c66affSColin Finck ok(GLE == ERROR_INVALID_PARAMETER,
1658c2c66affSColin Finck "SetThreadErrorMode(0x%x,NULL) failed with %d, "
1659c2c66affSColin Finck "expected ERROR_INVALID_PARAMETER\n",
1660c2c66affSColin Finck mode, GLE);
1661c2c66affSColin Finck }
1662c2c66affSColin Finck }
1663c2c66affSColin Finck
1664c2c66affSColin Finck pSetThreadErrorMode(oldmode, NULL);
1665c2c66affSColin Finck }
1666c2c66affSColin Finck
1667c2c66affSColin Finck #if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || (defined(_MSC_VER) && defined(__i386__))
set_fpu_cw(WORD cw)1668c2c66affSColin Finck static inline void set_fpu_cw(WORD cw)
1669c2c66affSColin Finck {
1670c2c66affSColin Finck #ifdef _MSC_VER
1671c2c66affSColin Finck __asm { fnclex }
1672c2c66affSColin Finck __asm { fldcw [cw] }
1673c2c66affSColin Finck #else
1674c2c66affSColin Finck __asm__ volatile ("fnclex; fldcw %0" : : "m" (cw));
1675c2c66affSColin Finck #endif
1676c2c66affSColin Finck }
1677c2c66affSColin Finck
get_fpu_cw(void)1678c2c66affSColin Finck static inline WORD get_fpu_cw(void)
1679c2c66affSColin Finck {
1680c2c66affSColin Finck WORD cw = 0;
1681c2c66affSColin Finck #ifdef _MSC_VER
1682c2c66affSColin Finck __asm { fnstcw [cw] }
1683c2c66affSColin Finck #else
1684c2c66affSColin Finck __asm__ volatile ("fnstcw %0" : "=m" (cw));
1685c2c66affSColin Finck #endif
1686c2c66affSColin Finck return cw;
1687c2c66affSColin Finck }
1688c2c66affSColin Finck
1689c2c66affSColin Finck struct fpu_thread_ctx
1690c2c66affSColin Finck {
1691c2c66affSColin Finck WORD cw;
1692c2c66affSColin Finck HANDLE finished;
1693c2c66affSColin Finck };
1694c2c66affSColin Finck
fpu_thread(void * param)1695c2c66affSColin Finck static DWORD WINAPI fpu_thread(void *param)
1696c2c66affSColin Finck {
1697c2c66affSColin Finck struct fpu_thread_ctx *ctx = param;
1698c2c66affSColin Finck BOOL ret;
1699c2c66affSColin Finck
1700c2c66affSColin Finck ctx->cw = get_fpu_cw();
1701c2c66affSColin Finck
1702c2c66affSColin Finck ret = SetEvent(ctx->finished);
1703c2c66affSColin Finck ok(ret, "SetEvent failed, last error %#x.\n", GetLastError());
1704c2c66affSColin Finck
1705c2c66affSColin Finck return 0;
1706c2c66affSColin Finck }
1707c2c66affSColin Finck
get_thread_fpu_cw(void)1708c2c66affSColin Finck static WORD get_thread_fpu_cw(void)
1709c2c66affSColin Finck {
1710c2c66affSColin Finck struct fpu_thread_ctx ctx;
1711c2c66affSColin Finck DWORD tid, res;
1712c2c66affSColin Finck HANDLE thread;
1713c2c66affSColin Finck
1714c2c66affSColin Finck ctx.finished = CreateEventW(NULL, FALSE, FALSE, NULL);
1715c2c66affSColin Finck ok(!!ctx.finished, "Failed to create event, last error %#x.\n", GetLastError());
1716c2c66affSColin Finck
1717c2c66affSColin Finck thread = CreateThread(NULL, 0, fpu_thread, &ctx, 0, &tid);
1718c2c66affSColin Finck ok(!!thread, "Failed to create thread, last error %#x.\n", GetLastError());
1719c2c66affSColin Finck
1720c2c66affSColin Finck res = WaitForSingleObject(ctx.finished, INFINITE);
1721c2c66affSColin Finck ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
1722c2c66affSColin Finck
1723c2c66affSColin Finck res = CloseHandle(ctx.finished);
1724c2c66affSColin Finck ok(!!res, "Failed to close event handle, last error %#x.\n", GetLastError());
1725c2c66affSColin Finck
1726*ed41a4deSAmine Khaldi CloseHandle(thread);
1727c2c66affSColin Finck return ctx.cw;
1728c2c66affSColin Finck }
1729c2c66affSColin Finck
test_thread_fpu_cw(void)1730c2c66affSColin Finck static void test_thread_fpu_cw(void)
1731c2c66affSColin Finck {
1732c2c66affSColin Finck WORD initial_cw, cw;
1733c2c66affSColin Finck
1734c2c66affSColin Finck initial_cw = get_fpu_cw();
1735c2c66affSColin Finck ok(initial_cw == 0x27f, "Expected FPU control word 0x27f, got %#x.\n", initial_cw);
1736c2c66affSColin Finck
1737c2c66affSColin Finck cw = get_thread_fpu_cw();
1738c2c66affSColin Finck ok(cw == 0x27f, "Expected FPU control word 0x27f, got %#x.\n", cw);
1739c2c66affSColin Finck
1740c2c66affSColin Finck set_fpu_cw(0xf60);
1741c2c66affSColin Finck cw = get_fpu_cw();
1742c2c66affSColin Finck ok(cw == 0xf60, "Expected FPU control word 0xf60, got %#x.\n", cw);
1743c2c66affSColin Finck
1744c2c66affSColin Finck cw = get_thread_fpu_cw();
1745c2c66affSColin Finck ok(cw == 0x27f, "Expected FPU control word 0x27f, got %#x.\n", cw);
1746c2c66affSColin Finck
1747c2c66affSColin Finck cw = get_fpu_cw();
1748c2c66affSColin Finck ok(cw == 0xf60, "Expected FPU control word 0xf60, got %#x.\n", cw);
1749c2c66affSColin Finck
1750c2c66affSColin Finck set_fpu_cw(initial_cw);
1751c2c66affSColin Finck cw = get_fpu_cw();
1752c2c66affSColin Finck ok(cw == initial_cw, "Expected FPU control word %#x, got %#x.\n", initial_cw, cw);
1753c2c66affSColin Finck }
1754c2c66affSColin Finck #endif
1755c2c66affSColin Finck
1756c2c66affSColin Finck static const char manifest_dep[] =
1757c2c66affSColin Finck "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
1758c2c66affSColin Finck "<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
1759c2c66affSColin Finck " <file name=\"testdep.dll\" />"
1760c2c66affSColin Finck "</assembly>";
1761c2c66affSColin Finck
1762c2c66affSColin Finck static const char manifest_main[] =
1763c2c66affSColin Finck "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
1764c2c66affSColin Finck "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
1765c2c66affSColin Finck "<dependency>"
1766c2c66affSColin Finck " <dependentAssembly>"
1767c2c66affSColin Finck " <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
1768c2c66affSColin Finck " </dependentAssembly>"
1769c2c66affSColin Finck "</dependency>"
1770c2c66affSColin Finck "</assembly>";
1771c2c66affSColin Finck
create_manifest_file(const char * filename,const char * manifest)1772c2c66affSColin Finck static void create_manifest_file(const char *filename, const char *manifest)
1773c2c66affSColin Finck {
1774c2c66affSColin Finck WCHAR path[MAX_PATH];
1775c2c66affSColin Finck HANDLE file;
1776c2c66affSColin Finck DWORD size;
1777c2c66affSColin Finck
1778c2c66affSColin Finck MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
1779c2c66affSColin Finck file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1780c2c66affSColin Finck ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
1781c2c66affSColin Finck WriteFile(file, manifest, strlen(manifest), &size, NULL);
1782c2c66affSColin Finck CloseHandle(file);
1783c2c66affSColin Finck }
1784c2c66affSColin Finck
test_create(const char * file)1785c2c66affSColin Finck static HANDLE test_create(const char *file)
1786c2c66affSColin Finck {
1787c2c66affSColin Finck WCHAR path[MAX_PATH];
1788c2c66affSColin Finck ACTCTXW actctx;
1789c2c66affSColin Finck HANDLE handle;
1790c2c66affSColin Finck
1791c2c66affSColin Finck MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
1792c2c66affSColin Finck memset(&actctx, 0, sizeof(ACTCTXW));
1793c2c66affSColin Finck actctx.cbSize = sizeof(ACTCTXW);
1794c2c66affSColin Finck actctx.lpSource = path;
1795c2c66affSColin Finck
1796c2c66affSColin Finck handle = pCreateActCtxW(&actctx);
1797c2c66affSColin Finck ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
1798c2c66affSColin Finck
1799c2c66affSColin Finck ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
1800c2c66affSColin Finck ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
1801c2c66affSColin Finck ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
1802c2c66affSColin Finck ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
1803c2c66affSColin Finck ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
1804c2c66affSColin Finck ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
1805c2c66affSColin Finck ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
1806c2c66affSColin Finck ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
1807c2c66affSColin Finck ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
1808c2c66affSColin Finck
1809c2c66affSColin Finck return handle;
1810c2c66affSColin Finck }
1811c2c66affSColin Finck
test_thread_actctx(void)1812c2c66affSColin Finck static void test_thread_actctx(void)
1813c2c66affSColin Finck {
1814c2c66affSColin Finck struct thread_actctx_param param;
1815c2c66affSColin Finck HANDLE thread, handle, context;
1816c2c66affSColin Finck ULONG_PTR cookie;
1817c2c66affSColin Finck DWORD tid, ret;
1818c2c66affSColin Finck BOOL b;
1819c2c66affSColin Finck
1820c2c66affSColin Finck if (!pActivateActCtx)
1821c2c66affSColin Finck {
1822c2c66affSColin Finck win_skip("skipping activation context tests\n");
1823c2c66affSColin Finck return;
1824c2c66affSColin Finck }
1825c2c66affSColin Finck
1826c2c66affSColin Finck create_manifest_file("testdep1.manifest", manifest_dep);
1827c2c66affSColin Finck create_manifest_file("main.manifest", manifest_main);
1828c2c66affSColin Finck
1829c2c66affSColin Finck context = test_create("main.manifest");
1830c2c66affSColin Finck DeleteFileA("testdep1.manifest");
1831c2c66affSColin Finck DeleteFileA("main.manifest");
1832c2c66affSColin Finck
1833c2c66affSColin Finck handle = (void*)0xdeadbeef;
1834c2c66affSColin Finck b = pGetCurrentActCtx(&handle);
1835c2c66affSColin Finck ok(b, "GetCurrentActCtx failed: %u\n", GetLastError());
1836c2c66affSColin Finck ok(handle == 0, "active context %p\n", handle);
1837c2c66affSColin Finck
1838c2c66affSColin Finck /* without active context */
1839c2c66affSColin Finck param.thread_context = (void*)0xdeadbeef;
1840c2c66affSColin Finck param.handle = NULL;
1841c2c66affSColin Finck thread = CreateThread(NULL, 0, thread_actctx_func, ¶m, 0, &tid);
1842c2c66affSColin Finck ok(thread != NULL, "failed, got %u\n", GetLastError());
1843c2c66affSColin Finck
1844c2c66affSColin Finck ret = WaitForSingleObject(thread, 1000);
1845c2c66affSColin Finck ok(ret == WAIT_OBJECT_0, "wait timeout\n");
1846c2c66affSColin Finck ok(param.thread_context == NULL, "got wrong thread context %p\n", param.thread_context);
1847c2c66affSColin Finck CloseHandle(thread);
1848c2c66affSColin Finck
1849c2c66affSColin Finck b = pActivateActCtx(context, &cookie);
1850c2c66affSColin Finck ok(b, "activation failed: %u\n", GetLastError());
1851c2c66affSColin Finck
1852c2c66affSColin Finck handle = 0;
1853c2c66affSColin Finck b = pGetCurrentActCtx(&handle);
1854c2c66affSColin Finck ok(b, "GetCurrentActCtx failed: %u\n", GetLastError());
1855c2c66affSColin Finck ok(handle != 0, "no active context\n");
1856c2c66affSColin Finck pReleaseActCtx(handle);
1857c2c66affSColin Finck
1858c2c66affSColin Finck param.handle = NULL;
1859c2c66affSColin Finck b = pGetCurrentActCtx(¶m.handle);
1860c2c66affSColin Finck ok(b && param.handle != NULL, "failed to get context, %u\n", GetLastError());
1861c2c66affSColin Finck
1862c2c66affSColin Finck param.thread_context = (void*)0xdeadbeef;
1863c2c66affSColin Finck thread = CreateThread(NULL, 0, thread_actctx_func, ¶m, 0, &tid);
1864c2c66affSColin Finck ok(thread != NULL, "failed, got %u\n", GetLastError());
1865c2c66affSColin Finck
1866c2c66affSColin Finck ret = WaitForSingleObject(thread, 1000);
1867c2c66affSColin Finck ok(ret == WAIT_OBJECT_0, "wait timeout\n");
1868c2c66affSColin Finck ok(param.thread_context == context, "got wrong thread context %p, %p\n", param.thread_context, context);
1869c2c66affSColin Finck pReleaseActCtx(param.thread_context);
1870c2c66affSColin Finck CloseHandle(thread);
1871c2c66affSColin Finck
1872c2c66affSColin Finck /* similar test for CreateRemoteThread() */
1873c2c66affSColin Finck param.thread_context = (void*)0xdeadbeef;
1874c2c66affSColin Finck thread = CreateRemoteThread(GetCurrentProcess(), NULL, 0, thread_actctx_func, ¶m, 0, &tid);
1875c2c66affSColin Finck ok(thread != NULL, "failed, got %u\n", GetLastError());
1876c2c66affSColin Finck
1877c2c66affSColin Finck ret = WaitForSingleObject(thread, 1000);
1878c2c66affSColin Finck ok(ret == WAIT_OBJECT_0, "wait timeout\n");
1879c2c66affSColin Finck ok(param.thread_context == context, "got wrong thread context %p, %p\n", param.thread_context, context);
1880c2c66affSColin Finck pReleaseActCtx(param.thread_context);
1881c2c66affSColin Finck CloseHandle(thread);
1882c2c66affSColin Finck
1883c2c66affSColin Finck pReleaseActCtx(param.handle);
1884c2c66affSColin Finck
1885c2c66affSColin Finck b = pDeactivateActCtx(0, cookie);
1886c2c66affSColin Finck ok(b, "DeactivateActCtx failed: %u\n", GetLastError());
1887c2c66affSColin Finck pReleaseActCtx(context);
1888c2c66affSColin Finck }
1889c2c66affSColin Finck
1890c2c66affSColin Finck
threadpool_workcallback(PTP_CALLBACK_INSTANCE instance,void * context,PTP_WORK work)1891c2c66affSColin Finck static void WINAPI threadpool_workcallback(PTP_CALLBACK_INSTANCE instance, void *context, PTP_WORK work) {
1892c2c66affSColin Finck int *foo = (int*)context;
1893c2c66affSColin Finck
1894c2c66affSColin Finck (*foo)++;
1895c2c66affSColin Finck }
1896c2c66affSColin Finck
1897c2c66affSColin Finck
test_threadpool(void)1898c2c66affSColin Finck static void test_threadpool(void)
1899c2c66affSColin Finck {
1900c2c66affSColin Finck PTP_POOL pool;
1901c2c66affSColin Finck PTP_WORK work;
1902c2c66affSColin Finck int workcalled = 0;
1903c2c66affSColin Finck
1904c2c66affSColin Finck if (!pCreateThreadpool) {
1905c2c66affSColin Finck win_skip("thread pool apis not supported.\n");
1906c2c66affSColin Finck return;
1907c2c66affSColin Finck }
1908c2c66affSColin Finck
1909c2c66affSColin Finck work = pCreateThreadpoolWork(threadpool_workcallback, &workcalled, NULL);
1910c2c66affSColin Finck ok (work != NULL, "Error %d in CreateThreadpoolWork\n", GetLastError());
1911c2c66affSColin Finck pSubmitThreadpoolWork(work);
1912c2c66affSColin Finck pWaitForThreadpoolWorkCallbacks(work, FALSE);
1913c2c66affSColin Finck pCloseThreadpoolWork(work);
1914c2c66affSColin Finck
1915c2c66affSColin Finck ok (workcalled == 1, "expected work to be called once, got %d\n", workcalled);
1916c2c66affSColin Finck
1917c2c66affSColin Finck pool = pCreateThreadpool(NULL);
1918c2c66affSColin Finck ok (pool != NULL, "CreateThreadpool failed\n");
1919c2c66affSColin Finck pCloseThreadpool(pool);
1920c2c66affSColin Finck }
1921c2c66affSColin Finck
test_reserved_tls(void)1922c2c66affSColin Finck static void test_reserved_tls(void)
1923c2c66affSColin Finck {
1924c2c66affSColin Finck void *val;
1925c2c66affSColin Finck DWORD tls;
1926c2c66affSColin Finck BOOL ret;
1927c2c66affSColin Finck
1928c2c66affSColin Finck /* This seems to be a WinXP SP2+ feature. */
1929c2c66affSColin Finck if(!pIsWow64Process) {
1930c2c66affSColin Finck win_skip("Skipping reserved TLS slot on too old Windows.\n");
1931c2c66affSColin Finck return;
1932c2c66affSColin Finck }
1933c2c66affSColin Finck
1934c2c66affSColin Finck val = TlsGetValue(0);
1935c2c66affSColin Finck ok(!val, "TlsGetValue(0) = %p\n", val);
1936c2c66affSColin Finck
1937c2c66affSColin Finck /* Also make sure that there is a TLS allocated. */
1938c2c66affSColin Finck tls = TlsAlloc();
1939c2c66affSColin Finck ok(tls && tls != TLS_OUT_OF_INDEXES, "tls = %x\n", tls);
1940c2c66affSColin Finck TlsSetValue(tls, (void*)1);
1941c2c66affSColin Finck
1942c2c66affSColin Finck val = TlsGetValue(0);
1943c2c66affSColin Finck ok(!val, "TlsGetValue(0) = %p\n", val);
1944c2c66affSColin Finck
1945c2c66affSColin Finck TlsFree(tls);
1946c2c66affSColin Finck
1947c2c66affSColin Finck /* The following is too ugly to be run by default */
1948c2c66affSColin Finck if(0) {
1949c2c66affSColin Finck /* Set TLS index 0 value and see that this works and doesn't cause problems
1950c2c66affSColin Finck * for remaining tests. */
1951c2c66affSColin Finck ret = TlsSetValue(0, (void*)1);
1952c2c66affSColin Finck ok(ret, "TlsSetValue(0, 1) failed: %u\n", GetLastError());
1953c2c66affSColin Finck
1954c2c66affSColin Finck val = TlsGetValue(0);
1955c2c66affSColin Finck ok(val == (void*)1, "TlsGetValue(0) = %p\n", val);
1956c2c66affSColin Finck }
1957c2c66affSColin Finck }
1958c2c66affSColin Finck
test_thread_info(void)1959c2c66affSColin Finck static void test_thread_info(void)
1960c2c66affSColin Finck {
1961c2c66affSColin Finck char buf[4096];
1962c2c66affSColin Finck static const ULONG info_size[] =
1963c2c66affSColin Finck {
1964c2c66affSColin Finck sizeof(THREAD_BASIC_INFORMATION), /* ThreadBasicInformation */
1965c2c66affSColin Finck sizeof(KERNEL_USER_TIMES), /* ThreadTimes */
1966c2c66affSColin Finck sizeof(ULONG), /* ThreadPriority */
1967c2c66affSColin Finck sizeof(ULONG), /* ThreadBasePriority */
1968c2c66affSColin Finck sizeof(ULONG_PTR), /* ThreadAffinityMask */
1969c2c66affSColin Finck sizeof(HANDLE), /* ThreadImpersonationToken */
1970c2c66affSColin Finck sizeof(THREAD_DESCRIPTOR_INFORMATION), /* ThreadDescriptorTableEntry */
1971c2c66affSColin Finck sizeof(BOOLEAN), /* ThreadEnableAlignmentFaultFixup */
1972c2c66affSColin Finck 0, /* ThreadEventPair_Reusable */
1973c2c66affSColin Finck sizeof(ULONG_PTR), /* ThreadQuerySetWin32StartAddress */
1974c2c66affSColin Finck sizeof(ULONG), /* ThreadZeroTlsCell */
1975c2c66affSColin Finck sizeof(LARGE_INTEGER), /* ThreadPerformanceCount */
1976c2c66affSColin Finck sizeof(ULONG), /* ThreadAmILastThread */
1977c2c66affSColin Finck sizeof(ULONG), /* ThreadIdealProcessor */
1978c2c66affSColin Finck sizeof(ULONG), /* ThreadPriorityBoost */
1979c2c66affSColin Finck sizeof(ULONG_PTR), /* ThreadSetTlsArrayAddress */
1980c2c66affSColin Finck sizeof(ULONG), /* ThreadIsIoPending */
1981c2c66affSColin Finck sizeof(BOOLEAN), /* ThreadHideFromDebugger */
1982c2c66affSColin Finck /* FIXME: Add remaining classes */
1983c2c66affSColin Finck };
1984c2c66affSColin Finck HANDLE thread;
1985c2c66affSColin Finck ULONG i, status, ret_len;
1986c2c66affSColin Finck
1987c2c66affSColin Finck if (!pOpenThread)
1988c2c66affSColin Finck {
1989c2c66affSColin Finck win_skip("OpenThread is not available on this platform\n");
1990c2c66affSColin Finck return;
1991c2c66affSColin Finck }
1992c2c66affSColin Finck
1993c2c66affSColin Finck if (!pNtQueryInformationThread)
1994c2c66affSColin Finck {
1995c2c66affSColin Finck win_skip("NtQueryInformationThread is not available on this platform\n");
1996c2c66affSColin Finck return;
1997c2c66affSColin Finck }
1998c2c66affSColin Finck
1999c2c66affSColin Finck thread = pOpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentThreadId());
2000c2c66affSColin Finck if (!thread)
2001c2c66affSColin Finck {
2002c2c66affSColin Finck win_skip("THREAD_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
2003c2c66affSColin Finck return;
2004c2c66affSColin Finck }
2005c2c66affSColin Finck
2006c2c66affSColin Finck for (i = 0; i < sizeof(info_size)/sizeof(info_size[0]); i++)
2007c2c66affSColin Finck {
2008c2c66affSColin Finck memset(buf, 0, sizeof(buf));
2009c2c66affSColin Finck
2010c2c66affSColin Finck #ifdef __i386__
2011c2c66affSColin Finck if (i == ThreadDescriptorTableEntry)
2012c2c66affSColin Finck {
2013c2c66affSColin Finck CONTEXT ctx;
2014c2c66affSColin Finck THREAD_DESCRIPTOR_INFORMATION *tdi = (void *)buf;
2015c2c66affSColin Finck
2016c2c66affSColin Finck ctx.ContextFlags = CONTEXT_SEGMENTS;
2017c2c66affSColin Finck GetThreadContext(GetCurrentThread(), &ctx);
2018c2c66affSColin Finck tdi->Selector = ctx.SegDs;
2019c2c66affSColin Finck }
2020c2c66affSColin Finck #endif
2021c2c66affSColin Finck ret_len = 0;
2022c2c66affSColin Finck status = pNtQueryInformationThread(thread, i, buf, info_size[i], &ret_len);
2023c2c66affSColin Finck if (status == STATUS_NOT_IMPLEMENTED) continue;
2024c2c66affSColin Finck if (status == STATUS_INVALID_INFO_CLASS) continue;
2025c2c66affSColin Finck if (status == STATUS_UNSUCCESSFUL) continue;
2026c2c66affSColin Finck
2027c2c66affSColin Finck switch (i)
2028c2c66affSColin Finck {
2029c2c66affSColin Finck case ThreadBasicInformation:
2030c2c66affSColin Finck case ThreadAmILastThread:
2031c2c66affSColin Finck case ThreadPriorityBoost:
2032c2c66affSColin Finck ok(status == STATUS_SUCCESS, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
2033c2c66affSColin Finck break;
2034c2c66affSColin Finck
2035c2c66affSColin Finck #ifdef __i386__
2036c2c66affSColin Finck case ThreadDescriptorTableEntry:
2037c2c66affSColin Finck ok(status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_DENIED) /* testbot VM is broken */,
2038c2c66affSColin Finck "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
2039c2c66affSColin Finck break;
2040c2c66affSColin Finck #endif
2041c2c66affSColin Finck
2042c2c66affSColin Finck case ThreadTimes:
2043c2c66affSColin Finck todo_wine
2044c2c66affSColin Finck ok(status == STATUS_SUCCESS, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
2045c2c66affSColin Finck break;
2046c2c66affSColin Finck
2047c2c66affSColin Finck case ThreadAffinityMask:
2048c2c66affSColin Finck case ThreadQuerySetWin32StartAddress:
2049c2c66affSColin Finck case ThreadIsIoPending:
2050c2c66affSColin Finck todo_wine
2051c2c66affSColin Finck ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
2052c2c66affSColin Finck break;
2053c2c66affSColin Finck
2054c2c66affSColin Finck default:
2055c2c66affSColin Finck ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
2056c2c66affSColin Finck break;
2057c2c66affSColin Finck }
2058c2c66affSColin Finck }
2059c2c66affSColin Finck
2060c2c66affSColin Finck CloseHandle(thread);
2061c2c66affSColin Finck }
2062c2c66affSColin Finck
init_funcs(void)2063c2c66affSColin Finck static void init_funcs(void)
2064c2c66affSColin Finck {
2065c2c66affSColin Finck HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
2066c2c66affSColin Finck HMODULE ntdll = GetModuleHandleA("ntdll.dll");
2067c2c66affSColin Finck
2068c2c66affSColin Finck /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
2069c2c66affSColin Finck so that the compile passes */
2070c2c66affSColin Finck
2071c2c66affSColin Finck #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
2072c2c66affSColin Finck X(GetThreadPriorityBoost);
2073c2c66affSColin Finck X(OpenThread);
2074c2c66affSColin Finck X(QueueUserWorkItem);
2075c2c66affSColin Finck X(SetThreadIdealProcessor);
2076c2c66affSColin Finck X(SetThreadPriorityBoost);
2077c2c66affSColin Finck X(RegisterWaitForSingleObject);
2078c2c66affSColin Finck X(UnregisterWait);
2079c2c66affSColin Finck X(IsWow64Process);
2080c2c66affSColin Finck X(SetThreadErrorMode);
2081c2c66affSColin Finck X(GetThreadErrorMode);
2082c2c66affSColin Finck X(ActivateActCtx);
2083c2c66affSColin Finck X(CreateActCtxW);
2084c2c66affSColin Finck X(DeactivateActCtx);
2085c2c66affSColin Finck X(GetCurrentActCtx);
2086c2c66affSColin Finck X(ReleaseActCtx);
2087c2c66affSColin Finck
2088c2c66affSColin Finck X(CreateThreadpool);
2089c2c66affSColin Finck X(CloseThreadpool);
2090c2c66affSColin Finck X(CreateThreadpoolWork);
2091c2c66affSColin Finck X(SubmitThreadpoolWork);
2092c2c66affSColin Finck X(WaitForThreadpoolWorkCallbacks);
2093c2c66affSColin Finck X(CloseThreadpoolWork);
2094c2c66affSColin Finck
2095c2c66affSColin Finck X(GetThreadGroupAffinity);
2096c2c66affSColin Finck X(SetThreadGroupAffinity);
2097c2c66affSColin Finck
2098c2c66affSColin Finck X(FlsAlloc);
2099c2c66affSColin Finck X(FlsFree);
2100c2c66affSColin Finck X(FlsSetValue);
2101c2c66affSColin Finck X(FlsGetValue);
2102c2c66affSColin Finck #undef X
2103c2c66affSColin Finck
2104c2c66affSColin Finck #define X(f) p##f = (void*)GetProcAddress(ntdll, #f)
2105c2c66affSColin Finck if (ntdll)
2106c2c66affSColin Finck {
2107c2c66affSColin Finck X(NtQueryInformationThread);
2108c2c66affSColin Finck X(RtlGetThreadErrorMode);
2109c2c66affSColin Finck X(NtSetInformationThread);
2110c2c66affSColin Finck X(NtSetLdtEntries);
2111c2c66affSColin Finck }
2112c2c66affSColin Finck #undef X
2113c2c66affSColin Finck }
2114c2c66affSColin Finck
START_TEST(thread)2115c2c66affSColin Finck START_TEST(thread)
2116c2c66affSColin Finck {
2117c2c66affSColin Finck int argc;
2118c2c66affSColin Finck char **argv;
2119c2c66affSColin Finck argc = winetest_get_mainargs( &argv );
2120c2c66affSColin Finck
2121c2c66affSColin Finck init_funcs();
2122c2c66affSColin Finck
2123c2c66affSColin Finck if (argc >= 3)
2124c2c66affSColin Finck {
2125c2c66affSColin Finck if (!strcmp(argv[2], "sleep"))
2126c2c66affSColin Finck {
2127c2c66affSColin Finck HANDLE hAddrEvents[2];
2128c2c66affSColin Finck create_function_addr_events(hAddrEvents);
2129c2c66affSColin Finck SetEvent(hAddrEvents[0]);
2130c2c66affSColin Finck SetEvent(hAddrEvents[1]);
2131c2c66affSColin Finck Sleep(5000); /* spawned process runs for at most 5 seconds */
2132c2c66affSColin Finck return;
2133c2c66affSColin Finck }
2134c2c66affSColin Finck while (1)
2135c2c66affSColin Finck {
2136c2c66affSColin Finck HANDLE hThread;
2137c2c66affSColin Finck DWORD tid;
2138c2c66affSColin Finck hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, &tid);
2139c2c66affSColin Finck ok(hThread != NULL, "CreateThread failed, error %u\n",
2140c2c66affSColin Finck GetLastError());
2141c2c66affSColin Finck ok(WaitForSingleObject(hThread, 200) == WAIT_OBJECT_0,
2142c2c66affSColin Finck "Thread did not exit in time\n");
2143c2c66affSColin Finck if (hThread == NULL) break;
2144c2c66affSColin Finck CloseHandle(hThread);
2145c2c66affSColin Finck }
2146c2c66affSColin Finck return;
2147c2c66affSColin Finck }
2148c2c66affSColin Finck
2149c2c66affSColin Finck test_thread_info();
2150c2c66affSColin Finck test_reserved_tls();
2151c2c66affSColin Finck test_CreateRemoteThread();
2152c2c66affSColin Finck test_CreateThread_basic();
2153c2c66affSColin Finck test_CreateThread_suspended();
2154c2c66affSColin Finck test_SuspendThread();
2155c2c66affSColin Finck test_TerminateThread();
2156c2c66affSColin Finck test_CreateThread_stack();
2157c2c66affSColin Finck test_thread_priority();
2158c2c66affSColin Finck test_GetThreadTimes();
2159c2c66affSColin Finck test_thread_processor();
2160c2c66affSColin Finck test_GetThreadExitCode();
2161c2c66affSColin Finck #ifdef __i386__
2162c2c66affSColin Finck test_SetThreadContext();
2163c2c66affSColin Finck test_GetThreadSelectorEntry();
2164c2c66affSColin Finck test_NtSetLdtEntries();
2165c2c66affSColin Finck #endif
2166c2c66affSColin Finck test_QueueUserWorkItem();
2167c2c66affSColin Finck test_RegisterWaitForSingleObject();
2168c2c66affSColin Finck test_TLS();
2169c2c66affSColin Finck test_FLS();
2170c2c66affSColin Finck test_ThreadErrorMode();
2171c2c66affSColin Finck #if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || (defined(_MSC_VER) && defined(__i386__))
2172c2c66affSColin Finck test_thread_fpu_cw();
2173c2c66affSColin Finck #endif
2174c2c66affSColin Finck test_thread_actctx();
2175c2c66affSColin Finck
2176c2c66affSColin Finck test_threadpool();
2177c2c66affSColin Finck }
2178