ntdll: Improve stub of NtQueryEaFile.
[wine.git] / dlls / ntdll / tests / thread.c
blob3086247d5f4609178789ee683d8b52b31bb596de
1 /*
2 * Unit test suite for ntdll thread functions
4 * Copyright 2021 Paul Gofman for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "ntdll_test.h"
24 static NTSTATUS (WINAPI *pNtCreateThreadEx)( HANDLE *, ACCESS_MASK, OBJECT_ATTRIBUTES *,
25 HANDLE, PRTL_THREAD_START_ROUTINE, void *,
26 ULONG, ULONG_PTR, SIZE_T, SIZE_T, PS_ATTRIBUTE_LIST * );
28 static void init_function_pointers(void)
30 HMODULE hntdll = GetModuleHandleA( "ntdll.dll" );
31 #define GET_FUNC(name) p##name = (void *)GetProcAddress( hntdll, #name );
32 GET_FUNC( NtCreateThreadEx );
33 #undef GET_FUNC
36 static void CALLBACK test_NtCreateThreadEx_proc(void *param)
40 static void test_dbg_hidden_thread_creation(void)
42 RTL_USER_PROCESS_PARAMETERS *params;
43 PS_CREATE_INFO create_info;
44 PS_ATTRIBUTE_LIST ps_attr;
45 WCHAR path[MAX_PATH + 4];
46 HANDLE process, thread;
47 UNICODE_STRING imageW;
48 BOOLEAN dbg_hidden;
49 NTSTATUS status;
51 if (!pNtCreateThreadEx)
53 win_skip( "NtCreateThreadEx is not available.\n" );
54 return;
57 status = pNtCreateThreadEx( &thread, THREAD_ALL_ACCESS, NULL, GetCurrentProcess(), test_NtCreateThreadEx_proc,
58 NULL, THREAD_CREATE_FLAGS_CREATE_SUSPENDED, 0, 0, 0, NULL );
59 ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status );
61 dbg_hidden = 0xcc;
62 status = NtQueryInformationThread( thread, ThreadHideFromDebugger, &dbg_hidden, sizeof(dbg_hidden), NULL );
63 ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status );
64 ok( !dbg_hidden, "Got unexpected dbg_hidden %#x.\n", dbg_hidden );
66 status = NtResumeThread( thread, NULL );
67 ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status );
68 WaitForSingleObject( thread, INFINITE );
69 CloseHandle( thread );
71 status = pNtCreateThreadEx( &thread, THREAD_ALL_ACCESS, NULL, GetCurrentProcess(), test_NtCreateThreadEx_proc,
72 NULL, THREAD_CREATE_FLAGS_CREATE_SUSPENDED | THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER,
73 0, 0, 0, NULL );
74 ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status );
76 dbg_hidden = 0xcc;
77 status = NtQueryInformationThread( thread, ThreadHideFromDebugger, &dbg_hidden, sizeof(dbg_hidden), NULL );
78 ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status );
79 ok( dbg_hidden == 1, "Got unexpected dbg_hidden %#x.\n", dbg_hidden );
81 status = NtResumeThread( thread, NULL );
82 ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status );
83 WaitForSingleObject( thread, INFINITE );
84 CloseHandle( thread );
86 lstrcpyW( path, L"\\??\\" );
87 GetModuleFileNameW( NULL, path + 4, MAX_PATH );
89 RtlInitUnicodeString( &imageW, path );
91 memset( &ps_attr, 0, sizeof(ps_attr) );
92 ps_attr.Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME;
93 ps_attr.Attributes[0].Size = lstrlenW(path) * sizeof(WCHAR);
94 ps_attr.Attributes[0].ValuePtr = path;
95 ps_attr.TotalLength = sizeof(ps_attr);
97 status = RtlCreateProcessParametersEx( &params, &imageW, NULL, NULL,
98 NULL, NULL, NULL, NULL,
99 NULL, NULL, PROCESS_PARAMS_FLAG_NORMALIZED );
100 ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status );
102 /* NtCreateUserProcess() may return STATUS_INVALID_PARAMETER with some uninitialized data in create_info. */
103 memset( &create_info, 0, sizeof(create_info) );
104 create_info.Size = sizeof(create_info);
106 status = NtCreateUserProcess( &process, &thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS,
107 NULL, NULL, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED
108 | THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER, params,
109 &create_info, &ps_attr );
110 ok( status == STATUS_INVALID_PARAMETER, "Got unexpected status %#lx.\n", status );
111 status = NtCreateUserProcess( &process, &thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS,
112 NULL, NULL, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED, params,
113 &create_info, &ps_attr );
114 ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status );
115 status = NtTerminateProcess( process, 0 );
116 ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status );
117 CloseHandle( process );
118 CloseHandle( thread );
121 struct unique_teb_thread_args
123 TEB *teb;
124 HANDLE running_event;
125 HANDLE quit_event;
128 static void CALLBACK test_unique_teb_proc(void *param)
130 struct unique_teb_thread_args *args = param;
131 args->teb = NtCurrentTeb();
132 SetEvent( args->running_event );
133 WaitForSingleObject( args->quit_event, INFINITE );
136 static void test_unique_teb(void)
138 HANDLE threads[2], running_events[2];
139 struct unique_teb_thread_args args1, args2;
140 NTSTATUS status;
142 if (!pNtCreateThreadEx)
144 win_skip( "NtCreateThreadEx is not available.\n" );
145 return;
148 args1.running_event = running_events[0] = CreateEventW( NULL, FALSE, FALSE, NULL );
149 ok( args1.running_event != NULL, "CreateEventW failed %lu.\n", GetLastError() );
151 args2.running_event = running_events[1] = CreateEventW( NULL, FALSE, FALSE, NULL );
152 ok( args2.running_event != NULL, "CreateEventW failed %lu.\n", GetLastError() );
154 args1.quit_event = args2.quit_event = CreateEventW( NULL, TRUE, FALSE, NULL );
155 ok( args1.quit_event != NULL, "CreateEventW failed %lu.\n", GetLastError() );
157 status = pNtCreateThreadEx( &threads[0], THREAD_ALL_ACCESS, NULL, GetCurrentProcess(), test_unique_teb_proc,
158 &args1, 0, 0, 0, 0, NULL );
159 ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status );
161 status = pNtCreateThreadEx( &threads[1], THREAD_ALL_ACCESS, NULL, GetCurrentProcess(), test_unique_teb_proc,
162 &args2, 0, 0, 0, 0, NULL );
163 ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status );
165 WaitForMultipleObjects( 2, running_events, TRUE, INFINITE );
166 SetEvent( args1.quit_event );
168 WaitForMultipleObjects( 2, threads, TRUE, INFINITE );
169 CloseHandle( threads[0] );
170 CloseHandle( threads[1] );
171 CloseHandle( args1.running_event );
172 CloseHandle( args2.running_event );
173 CloseHandle( args1.quit_event );
175 ok( NtCurrentTeb() != args1.teb, "Multiple threads have TEB %p.\n", args1.teb );
176 ok( NtCurrentTeb() != args2.teb, "Multiple threads have TEB %p.\n", args2.teb );
177 ok( args1.teb != args2.teb, "Multiple threads have TEB %p.\n", args1.teb );
180 START_TEST(thread)
182 init_function_pointers();
184 test_dbg_hidden_thread_creation();
185 test_unique_teb();