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(&times_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, &param, 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(&param.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, &param, 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, &param, 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