ntoskrnl/tests: Open the test output file using a hardcoded path.
[wine.git] / dlls / ntoskrnl.exe / tests / driver.c
blob179d2d5e02d1621d87f1bb9d173e7a98afd980c0
1 /*
2 * ntoskrnl.exe testing framework
4 * Copyright 2015 Sebastian Lackner
5 * Copyright 2015 Michael Müller
6 * Copyright 2015 Christian Costa
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
24 #include <stdio.h>
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winternl.h"
31 #include "winioctl.h"
32 #include "ddk/ntddk.h"
33 #include "ddk/ntifs.h"
34 #include "ddk/wdm.h"
36 #include "driver.h"
38 #include "utils.h"
40 /* memcmp() isn't exported from ntoskrnl on i386 */
41 static int kmemcmp( const void *ptr1, const void *ptr2, size_t n )
43 const unsigned char *p1, *p2;
45 for (p1 = ptr1, p2 = ptr2; n; n--, p1++, p2++)
47 if (*p1 < *p2) return -1;
48 if (*p1 > *p2) return 1;
50 return 0;
53 static DRIVER_OBJECT *driver_obj;
54 static DEVICE_OBJECT *lower_device, *upper_device;
56 static POBJECT_TYPE *pExEventObjectType, *pIoFileObjectType, *pPsThreadType, *pIoDriverObjectType;
57 static PEPROCESS *pPsInitialSystemProcess;
58 static void *create_caller_thread;
60 static PETHREAD create_irp_thread;
62 NTSTATUS WINAPI ZwQueryInformationProcess(HANDLE,PROCESSINFOCLASS,void*,ULONG,ULONG*);
64 struct file_context
66 DWORD id;
67 ULONG namelen;
68 WCHAR name[10];
71 static void *get_proc_address(const char *name)
73 UNICODE_STRING name_u;
74 ANSI_STRING name_a;
75 NTSTATUS status;
76 void *ret;
78 RtlInitAnsiString(&name_a, name);
79 status = RtlAnsiStringToUnicodeString(&name_u, &name_a, TRUE);
80 ok (!status, "RtlAnsiStringToUnicodeString failed: %#x\n", status);
81 if (status) return NULL;
83 ret = MmGetSystemRoutineAddress(&name_u);
84 RtlFreeUnicodeString(&name_u);
85 return ret;
88 static FILE_OBJECT *last_created_file;
89 static unsigned int create_count, close_count;
91 static NTSTATUS WINAPI test_irp_struct_completion_routine(DEVICE_OBJECT *reserved, IRP *irp, void *context)
93 unsigned int *result = context;
95 *result = 1;
96 return STATUS_MORE_PROCESSING_REQUIRED;
99 static void test_irp_struct(IRP *irp, DEVICE_OBJECT *device)
101 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
102 unsigned int irp_completion_result;
104 ok(device == upper_device, "Expected device %p, got %p.\n", upper_device, device);
105 ok(last_created_file != NULL, "last_created_file = NULL\n");
106 ok(irpsp->FileObject == last_created_file, "FileObject != last_created_file\n");
107 ok(irpsp->DeviceObject == upper_device, "unexpected DeviceObject\n");
108 ok(irpsp->FileObject->DeviceObject == lower_device, "unexpected FileObject->DeviceObject\n");
109 ok(!irp->UserEvent, "UserEvent = %p\n", irp->UserEvent);
110 ok(irp->Tail.Overlay.Thread == (PETHREAD)KeGetCurrentThread(),
111 "IRP thread is not the current thread\n");
113 ok(IoGetRequestorProcess(irp) == IoGetCurrentProcess(), "processes didn't match\n");
115 irp = IoAllocateIrp(1, FALSE);
116 ok(irp->AllocationFlags == IRP_ALLOCATED_FIXED_SIZE, "Got unexpected irp->AllocationFlags %#x.\n",
117 irp->AllocationFlags);
118 ok(irp->CurrentLocation == 2,
119 "Got unexpected irp->CurrentLocation %u.\n", irp->CurrentLocation);
120 IoSetCompletionRoutine(irp, test_irp_struct_completion_routine, &irp_completion_result,
121 TRUE, TRUE, TRUE);
123 irp_completion_result = 0;
125 irp->IoStatus.Status = STATUS_SUCCESS;
126 --irp->CurrentLocation;
127 --irp->Tail.Overlay.CurrentStackLocation;
128 IoCompleteRequest(irp, IO_NO_INCREMENT);
129 ok(irp->CurrentLocation == 2,
130 "Got unexpected irp->CurrentLocation %u.\n", irp->CurrentLocation);
131 ok(irp_completion_result, "IRP completion was not called.\n");
133 --irp->CurrentLocation;
134 --irp->Tail.Overlay.CurrentStackLocation;
135 IoReuseIrp(irp, STATUS_UNSUCCESSFUL);
136 ok(irp->CurrentLocation == 2,
137 "Got unexpected irp->CurrentLocation %u.\n", irp->CurrentLocation);
138 ok(irp->AllocationFlags == IRP_ALLOCATED_FIXED_SIZE, "Got unexpected irp->AllocationFlags %#x.\n",
139 irp->AllocationFlags);
141 IoFreeIrp(irp);
144 static void test_mdl_map(void)
146 char buffer[20] = "test buffer";
147 void *addr;
148 MDL *mdl;
150 mdl = IoAllocateMdl(buffer, sizeof(buffer), FALSE, FALSE, NULL);
151 ok(mdl != NULL, "IoAllocateMdl failed\n");
153 MmProbeAndLockPages(mdl, KernelMode, IoReadAccess);
155 addr = MmMapLockedPagesSpecifyCache(mdl, KernelMode, MmCached, NULL, FALSE, NormalPagePriority);
156 todo_wine
157 ok(addr != NULL, "MmMapLockedPagesSpecifyCache failed\n");
159 MmUnmapLockedPages(addr, mdl);
161 IoFreeMdl(mdl);
164 static void test_init_funcs(void)
166 KTIMER timer, timer2;
168 KeInitializeTimerEx(&timer, NotificationTimer);
169 ok(timer.Header.Type == 8, "got: %u\n", timer.Header.Type);
170 ok(timer.Header.Size == 0 || timer.Header.Size == 10, "got: %u\n", timer.Header.Size);
171 ok(timer.Header.SignalState == 0, "got: %u\n", timer.Header.SignalState);
173 KeInitializeTimerEx(&timer2, SynchronizationTimer);
174 ok(timer2.Header.Type == 9, "got: %u\n", timer2.Header.Type);
175 ok(timer2.Header.Size == 0 || timer2.Header.Size == 10, "got: %u\n", timer2.Header.Size);
176 ok(timer2.Header.SignalState == 0, "got: %u\n", timer2.Header.SignalState);
179 static const WCHAR driver2_path[] =
180 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\WineTestDriver2";
182 static IMAGE_INFO test_image_info;
183 static int test_load_image_notify_count;
184 static WCHAR test_load_image_name[MAX_PATH];
186 static void WINAPI test_load_image_notify_routine(UNICODE_STRING *image_name, HANDLE process_id,
187 IMAGE_INFO *image_info)
189 if (test_load_image_notify_count == -1
190 || (image_name->Buffer && wcsstr(image_name->Buffer, L".tmp")))
192 ++test_load_image_notify_count;
193 test_image_info = *image_info;
194 wcscpy(test_load_image_name, image_name->Buffer);
198 static void test_load_driver(void)
200 char full_name_buffer[300];
201 OBJECT_NAME_INFORMATION *full_name = (OBJECT_NAME_INFORMATION *)full_name_buffer;
202 static WCHAR image_path_key_name[] = L"ImagePath";
203 RTL_QUERY_REGISTRY_TABLE query_table[2];
204 UNICODE_STRING name, image_path;
205 OBJECT_ATTRIBUTES attr;
206 IO_STATUS_BLOCK io;
207 NTSTATUS ret;
208 HANDLE file;
210 ret = PsSetLoadImageNotifyRoutine(test_load_image_notify_routine);
211 ok(ret == STATUS_SUCCESS, "Got unexpected status %#x.\n", ret);
213 /* Routine gets registered twice on Windows. */
214 ret = PsSetLoadImageNotifyRoutine(test_load_image_notify_routine);
215 ok(ret == STATUS_SUCCESS, "Got unexpected status %#x.\n", ret);
217 RtlInitUnicodeString(&image_path, NULL);
218 memset(query_table, 0, sizeof(query_table));
219 query_table[0].QueryRoutine = NULL;
220 query_table[0].Name = image_path_key_name;
221 query_table[0].EntryContext = &image_path;
222 query_table[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK;
223 query_table[0].DefaultType = REG_EXPAND_SZ << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT;
225 ret = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, driver2_path, query_table, NULL, NULL);
226 ok(ret == STATUS_SUCCESS, "Got unexpected status %#x.\n", ret);
227 ok(!!image_path.Buffer, "image_path.Buffer is NULL.\n");
229 /* The image path name in the registry may contain NT symlinks (e.g. DOS
230 * drives), which are resolved before the callback is called on Windows 10. */
231 InitializeObjectAttributes(&attr, &image_path, OBJ_KERNEL_HANDLE, NULL, NULL);
232 ret = ZwOpenFile(&file, SYNCHRONIZE, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT);
233 todo_wine ok(!ret, "Got unexpected status %#x.\n", ret);
234 if (!ret)
236 ret = ZwQueryObject(file, ObjectNameInformation, full_name_buffer, sizeof(full_name_buffer), NULL);
237 ok(!ret, "Got unexpected status %#x.\n", ret);
238 ZwClose(file);
241 RtlInitUnicodeString(&name, driver2_path);
243 ret = ZwLoadDriver(&name);
244 ok(!ret, "got %#x\n", ret);
246 ok(test_load_image_notify_count == 2, "Got unexpected test_load_image_notify_count %u.\n",
247 test_load_image_notify_count);
248 ok(test_image_info.ImageAddressingMode == IMAGE_ADDRESSING_MODE_32BIT,
249 "Got unexpected ImageAddressingMode %#x.\n", test_image_info.ImageAddressingMode);
250 ok(test_image_info.SystemModeImage,
251 "Got unexpected SystemModeImage %#x.\n", test_image_info.SystemModeImage);
252 ok(!wcscmp(test_load_image_name, image_path.Buffer) /* Win < 10 */
253 || !wcscmp(test_load_image_name, full_name->Name.Buffer),
254 "Expected image path name %ls, got %ls.\n", full_name->Name.Buffer, test_load_image_name);
256 test_load_image_notify_count = -1;
258 ret = ZwLoadDriver(&name);
259 ok(ret == STATUS_IMAGE_ALREADY_LOADED, "got %#x\n", ret);
261 ret = ZwUnloadDriver(&name);
262 ok(!ret, "got %#x\n", ret);
264 ret = PsRemoveLoadImageNotifyRoutine(test_load_image_notify_routine);
265 ok(ret == STATUS_SUCCESS, "Got unexpected status %#x.\n", ret);
266 ret = PsRemoveLoadImageNotifyRoutine(test_load_image_notify_routine);
267 ok(ret == STATUS_SUCCESS, "Got unexpected status %#x.\n", ret);
268 ret = PsRemoveLoadImageNotifyRoutine(test_load_image_notify_routine);
269 ok(ret == STATUS_PROCEDURE_NOT_FOUND, "Got unexpected status %#x.\n", ret);
271 ok(test_load_image_notify_count == -1, "Got unexpected test_load_image_notify_count %u.\n",
272 test_load_image_notify_count);
273 RtlFreeUnicodeString(&image_path);
276 static NTSTATUS wait_single(void *obj, ULONGLONG timeout)
278 LARGE_INTEGER integer;
280 integer.QuadPart = timeout;
281 return KeWaitForSingleObject(obj, Executive, KernelMode, FALSE, &integer);
284 static NTSTATUS wait_multiple(ULONG count, void *objs[], WAIT_TYPE wait_type, ULONGLONG timeout)
286 LARGE_INTEGER integer;
288 integer.QuadPart = timeout;
289 return KeWaitForMultipleObjects(count, objs, wait_type, Executive, KernelMode, FALSE, &integer, NULL);
292 static NTSTATUS wait_single_handle(HANDLE handle, ULONGLONG timeout)
294 LARGE_INTEGER integer;
296 integer.QuadPart = timeout;
297 return ZwWaitForSingleObject(handle, FALSE, &integer);
300 static void test_current_thread(BOOL is_system)
302 PROCESS_BASIC_INFORMATION info;
303 DISPATCHER_HEADER *header;
304 HANDLE process_handle, id;
305 PEPROCESS current;
306 PETHREAD thread;
307 NTSTATUS ret;
309 current = IoGetCurrentProcess();
310 ok(current != NULL, "Expected current process to be non-NULL\n");
312 header = (DISPATCHER_HEADER*)current;
313 ok(header->Type == 3, "header->Type != 3, = %u\n", header->Type);
314 ret = wait_single(current, 0);
315 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
317 if (is_system)
318 ok(current == *pPsInitialSystemProcess, "current != PsInitialSystemProcess\n");
319 else
320 ok(current != *pPsInitialSystemProcess, "current == PsInitialSystemProcess\n");
322 ok(PsGetProcessId(current) == PsGetCurrentProcessId(), "process IDs don't match\n");
323 ok(PsGetThreadProcessId((PETHREAD)KeGetCurrentThread()) == PsGetCurrentProcessId(), "process IDs don't match\n");
325 thread = PsGetCurrentThread();
326 ret = wait_single( thread, 0 );
327 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
329 ok(PsGetThreadId((PETHREAD)KeGetCurrentThread()) == PsGetCurrentThreadId(), "thread IDs don't match\n");
330 ok(PsIsSystemThread((PETHREAD)KeGetCurrentThread()) == is_system, "unexpected system thread\n");
331 if (!is_system)
333 ok(create_caller_thread == KeGetCurrentThread(), "thread is not create caller thread\n");
334 ok(create_irp_thread == (PETHREAD)KeGetCurrentThread(), "thread of create request is not current thread\n");
337 ret = ObOpenObjectByPointer(current, OBJ_KERNEL_HANDLE, NULL, PROCESS_QUERY_INFORMATION, NULL, KernelMode, &process_handle);
338 ok(!ret, "ObOpenObjectByPointer failed: %#x\n", ret);
340 ret = ZwQueryInformationProcess(process_handle, ProcessBasicInformation, &info, sizeof(info), NULL);
341 ok(!ret, "ZwQueryInformationProcess failed: %#x\n", ret);
343 id = PsGetProcessInheritedFromUniqueProcessId(current);
344 ok(id == (HANDLE)info.InheritedFromUniqueProcessId, "unexpected process id %p\n", id);
346 ret = ZwClose(process_handle);
347 ok(!ret, "ZwClose failed: %#x\n", ret);
350 static void test_critical_region(BOOL is_dispatcher)
352 BOOLEAN result;
354 KeEnterCriticalRegion();
355 KeEnterCriticalRegion();
357 result = KeAreApcsDisabled();
358 ok(result == TRUE, "KeAreApcsDisabled returned %x\n", result);
359 KeLeaveCriticalRegion();
361 result = KeAreApcsDisabled();
362 ok(result == TRUE, "KeAreApcsDisabled returned %x\n", result);
363 KeLeaveCriticalRegion();
365 result = KeAreApcsDisabled();
366 ok(result == is_dispatcher || broken(is_dispatcher && !result),
367 "KeAreApcsDisabled returned %x\n", result);
370 static void sleep_1ms(void)
372 LARGE_INTEGER timeout;
374 timeout.QuadPart = -1 * 10000;
375 KeDelayExecutionThread( KernelMode, FALSE, &timeout );
378 static void sleep(void)
380 LARGE_INTEGER timeout;
381 timeout.QuadPart = -20 * 10000;
382 KeDelayExecutionThread( KernelMode, FALSE, &timeout );
385 static HANDLE create_thread(PKSTART_ROUTINE proc, void *arg)
387 OBJECT_ATTRIBUTES attr = {0};
388 HANDLE thread;
389 NTSTATUS ret;
391 attr.Length = sizeof(attr);
392 attr.Attributes = OBJ_KERNEL_HANDLE;
393 ret = PsCreateSystemThread(&thread, THREAD_ALL_ACCESS, &attr, NULL, NULL, proc, arg);
394 ok(!ret, "got %#x\n", ret);
396 return thread;
399 static void join_thread(HANDLE thread)
401 NTSTATUS ret;
403 ret = ZwWaitForSingleObject(thread, FALSE, NULL);
404 ok(!ret, "got %#x\n", ret);
405 ret = ZwClose(thread);
406 ok(!ret, "got %#x\n", ret);
409 static void run_thread(PKSTART_ROUTINE proc, void *arg)
411 HANDLE thread = create_thread(proc, arg);
412 join_thread(thread);
415 static KMUTEX test_mutex;
417 static void WINAPI mutex_thread(void *arg)
419 NTSTATUS ret, expect = (NTSTATUS)(DWORD_PTR)arg;
421 ret = wait_single(&test_mutex, 0);
422 ok(ret == expect, "expected %#x, got %#x\n", expect, ret);
424 if (!ret) KeReleaseMutex(&test_mutex, FALSE);
425 PsTerminateSystemThread(STATUS_SUCCESS);
428 static KEVENT remove_lock_ready;
430 static void WINAPI remove_lock_thread(void *arg)
432 IO_REMOVE_LOCK *lock = arg;
433 NTSTATUS ret;
435 ret = IoAcquireRemoveLockEx(lock, NULL, "", 1, sizeof(IO_REMOVE_LOCK_COMMON_BLOCK));
436 ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
437 KeSetEvent(&remove_lock_ready, 0, FALSE);
439 IoReleaseRemoveLockAndWaitEx(lock, NULL, sizeof(IO_REMOVE_LOCK_COMMON_BLOCK));
440 PsTerminateSystemThread(STATUS_SUCCESS);
443 struct test_sync_dpc_context
445 BOOL called;
448 static void WINAPI test_sync_dpc(KDPC *dpc, void *context, void *system_argument1, void *system_argument2)
450 struct test_sync_dpc_context *c = context;
452 c->called = TRUE;
455 static void test_sync(void)
457 static const ULONG wine_tag = 0x454e4957; /* WINE */
458 struct test_sync_dpc_context dpc_context;
459 KEVENT manual_event, auto_event, *event;
460 KSEMAPHORE semaphore, semaphore2;
461 IO_REMOVE_LOCK remove_lock;
462 LARGE_INTEGER timeout;
463 OBJECT_ATTRIBUTES attr;
464 HANDLE handle, thread;
465 void *objs[2];
466 KTIMER timer;
467 NTSTATUS ret;
468 KDPC dpc;
469 int i;
471 KeInitializeEvent(&manual_event, NotificationEvent, FALSE);
473 ret = wait_single(&manual_event, 0);
474 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
476 ret = KeReadStateEvent(&manual_event);
477 ok(ret == 0, "got %d\n", ret);
479 KeSetEvent(&manual_event, 0, FALSE);
481 ret = KeReadStateEvent(&manual_event);
482 ok(ret == 1, "got %d\n", ret);
484 ret = wait_single(&manual_event, 0);
485 ok(ret == 0, "got %#x\n", ret);
487 ret = wait_single(&manual_event, 0);
488 ok(ret == 0, "got %#x\n", ret);
490 KeResetEvent(&manual_event);
492 ret = wait_single(&manual_event, 0);
493 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
495 KeInitializeEvent(&auto_event, SynchronizationEvent, FALSE);
497 ret = wait_single(&auto_event, 0);
498 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
500 KeSetEvent(&auto_event, 0, FALSE);
502 ret = wait_single(&auto_event, 0);
503 ok(ret == 0, "got %#x\n", ret);
505 ret = wait_single(&auto_event, 0);
506 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
508 KeInitializeEvent(&auto_event, SynchronizationEvent, TRUE);
510 ret = wait_single(&auto_event, 0);
511 ok(ret == 0, "got %#x\n", ret);
513 objs[0] = &manual_event;
514 objs[1] = &auto_event;
516 ret = wait_multiple(2, objs, WaitAny, 0);
517 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
519 KeSetEvent(&manual_event, 0, FALSE);
520 KeSetEvent(&auto_event, 0, FALSE);
522 ret = wait_multiple(2, objs, WaitAny, 0);
523 ok(ret == 0, "got %#x\n", ret);
525 ret = wait_single(&auto_event, 0);
526 ok(ret == 0, "got %#x\n", ret);
528 KeResetEvent(&manual_event);
529 KeSetEvent(&auto_event, 0, FALSE);
531 ret = wait_multiple(2, objs, WaitAny, 0);
532 ok(ret == 1, "got %#x\n", ret);
534 ret = wait_multiple(2, objs, WaitAny, 0);
535 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
537 KeSetEvent(&manual_event, 0, FALSE);
538 KeSetEvent(&auto_event, 0, FALSE);
540 ret = wait_multiple(2, objs, WaitAll, 0);
541 ok(ret == 0, "got %#x\n", ret);
543 ret = wait_multiple(2, objs, WaitAll, 0);
544 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
546 KeSetEvent(&auto_event, 0, FALSE);
547 KeResetEvent(&manual_event);
549 ret = wait_multiple(2, objs, WaitAll, 0);
550 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
552 ret = wait_single(&auto_event, 0);
553 ok(ret == 0, "got %#x\n", ret);
555 objs[0] = &auto_event;
556 objs[1] = &manual_event;
557 KeSetEvent(&manual_event, 0, FALSE);
558 KeSetEvent(&auto_event, 0, FALSE);
560 ret = wait_multiple(2, objs, WaitAny, 0);
561 ok(ret == 0, "got %#x\n", ret);
563 ret = wait_multiple(2, objs, WaitAny, 0);
564 ok(ret == 1, "got %#x\n", ret);
566 ret = wait_multiple(2, objs, WaitAny, 0);
567 ok(ret == 1, "got %#x\n", ret);
569 InitializeObjectAttributes(&attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
570 ret = ZwCreateEvent(&handle, SYNCHRONIZE, &attr, NotificationEvent, TRUE);
571 ok(!ret, "ZwCreateEvent failed: %#x\n", ret);
573 ret = ObReferenceObjectByHandle(handle, SYNCHRONIZE, *pExEventObjectType, KernelMode, (void **)&event, NULL);
574 ok(!ret, "ObReferenceObjectByHandle failed: %#x\n", ret);
577 ret = wait_single(event, 0);
578 ok(ret == 0, "got %#x\n", ret);
579 ret = KeReadStateEvent(event);
580 ok(ret == 1, "got %d\n", ret);
581 KeResetEvent(event);
582 ret = KeReadStateEvent(event);
583 ok(ret == 0, "got %d\n", ret);
584 ret = wait_single(event, 0);
585 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
586 ret = wait_single_handle(handle, 0);
587 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
589 KeSetEvent(event, 0, FALSE);
590 ret = wait_single(event, 0);
591 ok(ret == 0, "got %#x\n", ret);
592 ret = wait_single_handle(handle, 0);
593 ok(!ret, "got %#x\n", ret);
595 ZwClose(handle);
596 ObDereferenceObject(event);
598 event = IoCreateSynchronizationEvent(NULL, &handle);
599 ok(event != NULL, "IoCreateSynchronizationEvent failed\n");
601 ret = wait_single(event, 0);
602 ok(ret == 0, "got %#x\n", ret);
603 KeResetEvent(event);
604 ret = wait_single(event, 0);
605 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
606 ret = wait_single_handle(handle, 0);
607 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
609 ret = ZwSetEvent(handle, NULL);
610 ok(!ret, "NtSetEvent returned %#x\n", ret);
611 ret = wait_single(event, 0);
612 ok(ret == 0, "got %#x\n", ret);
613 ret = wait_single_handle(handle, 0);
614 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
616 KeSetEvent(event, 0, FALSE);
617 ret = wait_single_handle(handle, 0);
618 ok(!ret, "got %#x\n", ret);
619 ret = wait_single(event, 0);
620 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
622 ret = ZwClose(handle);
623 ok(!ret, "ZwClose returned %#x\n", ret);
625 /* test semaphores */
626 KeInitializeSemaphore(&semaphore, 0, 5);
628 ret = wait_single(&semaphore, 0);
629 ok(ret == STATUS_TIMEOUT, "got %u\n", ret);
631 ret = KeReleaseSemaphore(&semaphore, 0, 1, FALSE);
632 ok(ret == 0, "got prev %d\n", ret);
634 ret = KeReleaseSemaphore(&semaphore, 0, 2, FALSE);
635 ok(ret == 1, "got prev %d\n", ret);
637 ret = KeReleaseSemaphore(&semaphore, 0, 1, FALSE);
638 ok(ret == 3, "got prev %d\n", ret);
640 for (i = 0; i < 4; i++)
642 ret = wait_single(&semaphore, 0);
643 ok(ret == 0, "got %#x\n", ret);
646 ret = wait_single(&semaphore, 0);
647 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
649 KeInitializeSemaphore(&semaphore2, 3, 5);
651 ret = KeReleaseSemaphore(&semaphore2, 0, 1, FALSE);
652 ok(ret == 3, "got prev %d\n", ret);
654 for (i = 0; i < 4; i++)
656 ret = wait_single(&semaphore2, 0);
657 ok(ret == 0, "got %#x\n", ret);
660 objs[0] = &semaphore;
661 objs[1] = &semaphore2;
663 ret = wait_multiple(2, objs, WaitAny, 0);
664 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
666 KeReleaseSemaphore(&semaphore, 0, 1, FALSE);
667 KeReleaseSemaphore(&semaphore2, 0, 1, FALSE);
669 ret = wait_multiple(2, objs, WaitAny, 0);
670 ok(ret == 0, "got %#x\n", ret);
672 ret = wait_multiple(2, objs, WaitAny, 0);
673 ok(ret == 1, "got %#x\n", ret);
675 ret = wait_multiple(2, objs, WaitAny, 0);
676 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
678 KeReleaseSemaphore(&semaphore, 0, 1, FALSE);
679 KeReleaseSemaphore(&semaphore2, 0, 1, FALSE);
681 ret = wait_multiple(2, objs, WaitAll, 0);
682 ok(ret == 0, "got %#x\n", ret);
684 ret = wait_multiple(2, objs, WaitAny, 0);
685 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
687 /* test mutexes */
688 KeInitializeMutex(&test_mutex, 0);
690 for (i = 0; i < 10; i++)
692 ret = wait_single(&test_mutex, 0);
693 ok(ret == 0, "got %#x\n", ret);
696 for (i = 0; i < 10; i++)
698 ret = KeReleaseMutex(&test_mutex, FALSE);
699 ok(ret == i - 9, "expected %d, got %d\n", i - 9, ret);
702 run_thread(mutex_thread, (void *)0);
704 ret = wait_single(&test_mutex, 0);
705 ok(ret == 0, "got %#x\n", ret);
707 run_thread(mutex_thread, (void *)STATUS_TIMEOUT);
709 ret = KeReleaseMutex(&test_mutex, 0);
710 ok(ret == 0, "got %#x\n", ret);
712 run_thread(mutex_thread, (void *)0);
714 /* test timers */
715 KeInitializeTimerEx(&timer, NotificationTimer);
717 timeout.QuadPart = -20 * 10000;
718 KeSetTimerEx(&timer, timeout, 0, NULL);
720 ret = wait_single(&timer, 0);
721 ok(ret == WAIT_TIMEOUT, "got %#x\n", ret);
723 ret = wait_single(&timer, -40 * 10000);
724 ok(ret == 0, "got %#x\n", ret);
726 ret = wait_single(&timer, 0);
727 ok(ret == 0, "got %#x\n", ret);
729 KeCancelTimer(&timer);
730 KeInitializeTimerEx(&timer, SynchronizationTimer);
732 memset(&dpc_context, 0, sizeof(dpc_context));
733 KeInitializeDpc(&dpc, test_sync_dpc, &dpc_context);
735 KeSetTimerEx(&timer, timeout, 0, &dpc);
737 ret = wait_single(&timer, 0);
738 ok(ret == WAIT_TIMEOUT, "got %#x\n", ret);
739 ok(!dpc_context.called, "DPC was called unexpectedly.\n");
741 ret = wait_single(&timer, -40 * 10000);
742 ok(ret == 0, "got %#x\n", ret);
743 sleep_1ms();
744 ok(dpc_context.called, "DPC was not called.\n");
746 ret = wait_single(&timer, -40 * 10000);
747 ok(ret == WAIT_TIMEOUT, "got %#x\n", ret);
749 KeCancelTimer(&timer);
750 KeSetTimerEx(&timer, timeout, 20, NULL);
752 ret = wait_single(&timer, 0);
753 ok(ret == WAIT_TIMEOUT, "got %#x\n", ret);
755 ret = wait_single(&timer, -40 * 10000);
756 ok(ret == 0, "got %#x\n", ret);
758 ret = wait_single(&timer, 0);
759 ok(ret == WAIT_TIMEOUT, "got %#x\n", ret);
761 ret = wait_single(&timer, -40 * 10000);
762 ok(ret == 0, "got %#x\n", ret);
764 ret = wait_single(&timer, -40 * 10000);
765 ok(ret == 0, "got %#x\n", ret);
767 KeCancelTimer(&timer);
769 /* Test cancelling timer. */
770 dpc_context.called = 0;
771 KeSetTimerEx(&timer, timeout, 0, &dpc);
773 ret = wait_single(&timer, 0);
774 ok(ret == WAIT_TIMEOUT, "got %#x\n", ret);
775 ok(!dpc_context.called, "DPC was called.\n");
777 KeCancelTimer(&timer);
778 dpc_context.called = 0;
779 ret = wait_single(&timer, -40 * 10000);
780 ok(ret == WAIT_TIMEOUT, "got %#x\n", ret);
781 ok(!dpc_context.called, "DPC was called.\n");
783 KeSetTimerEx(&timer, timeout, 20, &dpc);
784 KeSetTimerEx(&timer, timeout, 0, &dpc);
785 ret = wait_single(&timer, 0);
786 ok(ret == WAIT_TIMEOUT, "got %#x\n", ret);
788 ret = wait_single(&timer, -40 * 10000);
789 ok(ret == 0, "got %#x\n", ret);
791 ret = wait_single(&timer, 0);
792 ok(ret == WAIT_TIMEOUT, "got %#x\n", ret);
794 ret = wait_single(&timer, -40 * 10000);
795 ok(ret == WAIT_TIMEOUT, "got %#x\n", ret);
797 ret = wait_single(&timer, -40 * 10000);
798 ok(ret == WAIT_TIMEOUT, "got %#x\n", ret);
800 KeCancelTimer(&timer);
801 /* Test reinitializing timer. */
802 KeSetTimerEx(&timer, timeout, 0, &dpc);
803 KeInitializeTimerEx(&timer, SynchronizationTimer);
804 dpc_context.called = 0;
805 ret = wait_single(&timer, -40 * 10000);
806 ok(ret == 0, "got %#x\n", ret);
807 sleep_1ms();
808 todo_wine ok(dpc_context.called, "DPC was not called.\n");
810 ret = wait_single(&timer, 0);
811 ok(ret == WAIT_TIMEOUT, "got %#x\n", ret);
812 sleep_1ms();
813 todo_wine ok(dpc_context.called, "DPC was not called.\n");
815 dpc_context.called = 0;
816 KeSetTimerEx(&timer, timeout, 0, &dpc);
817 ret = wait_single(&timer, -40 * 10000);
818 ok(ret == 0, "got %#x\n", ret);
819 sleep_1ms();
820 ok(dpc_context.called, "DPC was not called.\n");
822 KeCancelTimer(&timer);
823 /* remove locks */
825 IoInitializeRemoveLockEx(&remove_lock, wine_tag, 0, 0, sizeof(IO_REMOVE_LOCK_COMMON_BLOCK));
827 ret = IoAcquireRemoveLockEx(&remove_lock, NULL, "", 1, sizeof(IO_REMOVE_LOCK_COMMON_BLOCK));
828 ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
830 IoReleaseRemoveLockEx(&remove_lock, NULL, sizeof(IO_REMOVE_LOCK_COMMON_BLOCK));
832 ret = IoAcquireRemoveLockEx(&remove_lock, NULL, "", 1, sizeof(IO_REMOVE_LOCK_COMMON_BLOCK));
833 ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
835 ret = IoAcquireRemoveLockEx(&remove_lock, NULL, "", 1, sizeof(IO_REMOVE_LOCK_COMMON_BLOCK));
836 ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
838 KeInitializeEvent(&remove_lock_ready, SynchronizationEvent, FALSE);
839 thread = create_thread(remove_lock_thread, &remove_lock);
840 ret = wait_single(&remove_lock_ready, -1000 * 10000);
841 ok(!ret, "got %#x\n", ret);
842 ret = wait_single_handle(thread, -50 * 10000);
843 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
845 ret = IoAcquireRemoveLockEx(&remove_lock, NULL, "", 1, sizeof(IO_REMOVE_LOCK_COMMON_BLOCK));
846 ok(ret == STATUS_DELETE_PENDING, "got %#x\n", ret);
848 IoReleaseRemoveLockEx(&remove_lock, NULL, sizeof(IO_REMOVE_LOCK_COMMON_BLOCK));
849 ret = wait_single_handle(thread, 0);
850 ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
852 IoReleaseRemoveLockEx(&remove_lock, NULL, sizeof(IO_REMOVE_LOCK_COMMON_BLOCK));
853 ret = wait_single_handle(thread, -10000 * 10000);
854 ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
856 ret = IoAcquireRemoveLockEx(&remove_lock, NULL, "", 1, sizeof(IO_REMOVE_LOCK_COMMON_BLOCK));
857 ok(ret == STATUS_DELETE_PENDING, "got %#x\n", ret);
860 static void test_call_driver(DEVICE_OBJECT *device)
862 IO_STACK_LOCATION *irpsp;
863 IO_STATUS_BLOCK iosb;
864 IRP *irp = NULL;
865 KEVENT event;
866 NTSTATUS status;
868 iosb.Status = 0xdeadbeef;
869 iosb.Information = 0xdeadbeef;
870 irp = IoBuildAsynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &iosb);
871 ok(irp->UserIosb == &iosb, "unexpected UserIosb\n");
872 ok(!irp->Cancel, "Cancel = %x\n", irp->Cancel);
873 ok(!irp->CancelRoutine, "CancelRoutine = %x\n", irp->CancelRoutine);
874 ok(!irp->UserEvent, "UserEvent = %p\n", irp->UserEvent);
875 ok(irp->CurrentLocation == 2, "CurrentLocation = %u\n", irp->CurrentLocation);
876 ok(irp->Tail.Overlay.Thread == (PETHREAD)KeGetCurrentThread(),
877 "IRP thread is not the current thread\n");
878 ok(!irp->IoStatus.Status, "got status %#x\n", irp->IoStatus.Status);
879 ok(!irp->IoStatus.Information, "got information %#x\n", irp->IoStatus.Information);
880 ok(iosb.Status == 0xdeadbeef, "got status %#x\n", iosb.Status);
881 ok(iosb.Information == 0xdeadbeef, "got information %#x\n", iosb.Information);
883 irpsp = IoGetNextIrpStackLocation(irp);
884 ok(irpsp->MajorFunction == IRP_MJ_FLUSH_BUFFERS, "MajorFunction = %u\n", irpsp->MajorFunction);
885 ok(!irpsp->DeviceObject, "DeviceObject = %u\n", irpsp->DeviceObject);
886 ok(!irpsp->FileObject, "FileObject = %u\n", irpsp->FileObject);
887 ok(!irpsp->CompletionRoutine, "CompletionRoutine = %p\n", irpsp->CompletionRoutine);
889 status = IoCallDriver(device, irp);
890 ok(status == STATUS_PENDING, "IoCallDriver returned %#x\n", status);
891 ok(!irp->IoStatus.Status, "got status %#x\n", irp->IoStatus.Status);
892 ok(!irp->IoStatus.Information, "got information %#x\n", irp->IoStatus.Information);
893 ok(iosb.Status == 0xdeadbeef, "got status %#x\n", iosb.Status);
894 ok(iosb.Information == 0xdeadbeef, "got information %#x\n", iosb.Information);
896 irp->IoStatus.Status = STATUS_SUCCESS;
897 irp->IoStatus.Information = 123;
898 IoCompleteRequest(irp, IO_NO_INCREMENT);
899 ok(iosb.Status == STATUS_SUCCESS, "got status %#x\n", iosb.Status);
900 ok(iosb.Information == 123, "got information %#x\n", iosb.Information);
902 KeInitializeEvent(&event, NotificationEvent, FALSE);
904 irp = IoBuildSynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &event, &iosb);
905 ok(irp->UserIosb == &iosb, "unexpected UserIosb\n");
906 ok(!irp->Cancel, "Cancel = %x\n", irp->Cancel);
907 ok(!irp->CancelRoutine, "CancelRoutine = %x\n", irp->CancelRoutine);
908 ok(irp->UserEvent == &event, "UserEvent = %p\n", irp->UserEvent);
909 ok(irp->CurrentLocation == 2, "CurrentLocation = %u\n", irp->CurrentLocation);
910 ok(irp->Tail.Overlay.Thread == (PETHREAD)KeGetCurrentThread(),
911 "IRP thread is not the current thread\n");
913 irpsp = IoGetNextIrpStackLocation(irp);
914 ok(irpsp->MajorFunction == IRP_MJ_FLUSH_BUFFERS, "MajorFunction = %u\n", irpsp->MajorFunction);
915 ok(!irpsp->DeviceObject, "DeviceObject = %u\n", irpsp->DeviceObject);
916 ok(!irpsp->FileObject, "FileObject = %u\n", irpsp->FileObject);
917 ok(!irpsp->CompletionRoutine, "CompletionRoutine = %p\n", irpsp->CompletionRoutine);
919 status = wait_single(&event, 0);
920 ok(status == STATUS_TIMEOUT, "got %#x\n", status);
922 status = IoCallDriver(device, irp);
923 ok(status == STATUS_PENDING, "IoCallDriver returned %#x\n", status);
925 status = wait_single(&event, 0);
926 ok(status == STATUS_TIMEOUT, "got %#x\n", status);
928 irp->IoStatus.Status = STATUS_SUCCESS;
929 irp->IoStatus.Information = 0;
930 IoCompleteRequest(irp, IO_NO_INCREMENT);
932 status = wait_single(&event, 0);
933 ok(status == STATUS_SUCCESS, "got %#x\n", status);
936 static int cancel_cnt;
938 static void WINAPI cancel_irp(DEVICE_OBJECT *device, IRP *irp)
940 IoReleaseCancelSpinLock(irp->CancelIrql);
941 ok(irp->Cancel == TRUE, "Cancel = %x\n", irp->Cancel);
942 ok(!irp->CancelRoutine, "CancelRoutine = %p\n", irp->CancelRoutine);
943 irp->IoStatus.Status = STATUS_CANCELLED;
944 irp->IoStatus.Information = 0;
945 cancel_cnt++;
948 static void WINAPI cancel_ioctl_irp(DEVICE_OBJECT *device, IRP *irp)
950 IoReleaseCancelSpinLock(irp->CancelIrql);
951 irp->IoStatus.Status = STATUS_CANCELLED;
952 irp->IoStatus.Information = 0;
953 cancel_cnt++;
954 IoCompleteRequest(irp, IO_NO_INCREMENT);
957 static NTSTATUS WINAPI cancel_test_completion(DEVICE_OBJECT *device, IRP *irp, void *context)
959 ok(cancel_cnt == 1, "cancel_cnt = %d\n", cancel_cnt);
960 *(BOOL*)context = TRUE;
961 return STATUS_SUCCESS;
964 static void test_cancel_irp(DEVICE_OBJECT *device)
966 IO_STACK_LOCATION *irpsp;
967 IO_STATUS_BLOCK iosb;
968 IRP *irp = NULL;
969 BOOL completion_called;
970 BOOLEAN r;
971 NTSTATUS status;
973 /* cancel IRP with no cancel routine */
974 irp = IoBuildAsynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &iosb);
976 r = IoCancelIrp(irp);
977 ok(!r, "IoCancelIrp returned %x\n", r);
978 ok(irp->Cancel == TRUE, "Cancel = %x\n", irp->Cancel);
980 r = IoCancelIrp(irp);
981 ok(!r, "IoCancelIrp returned %x\n", r);
982 IoFreeIrp(irp);
984 irp = IoBuildAsynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &iosb);
986 /* cancel IRP with cancel routine */
987 status = IoCallDriver(device, irp);
988 ok(status == STATUS_PENDING, "IoCallDriver returned %#x\n", status);
990 ok(irp->CurrentLocation == 1, "CurrentLocation = %u\n", irp->CurrentLocation);
991 irpsp = IoGetCurrentIrpStackLocation(irp);
992 ok(irpsp->DeviceObject == device, "DeviceObject = %u\n", irpsp->DeviceObject);
994 IoSetCancelRoutine(irp, cancel_irp);
995 cancel_cnt = 0;
996 r = IoCancelIrp(irp);
997 ok(r == TRUE, "IoCancelIrp returned %x\n", r);
998 ok(irp->Cancel == TRUE, "Cancel = %x\n", irp->Cancel);
999 ok(cancel_cnt == 1, "cancel_cnt = %d\n", cancel_cnt);
1001 cancel_cnt = 0;
1002 r = IoCancelIrp(irp);
1003 ok(!r, "IoCancelIrp returned %x\n", r);
1004 ok(irp->Cancel == TRUE, "Cancel = %x\n", irp->Cancel);
1005 ok(!cancel_cnt, "cancel_cnt = %d\n", cancel_cnt);
1007 IoCompleteRequest(irp, IO_NO_INCREMENT);
1009 /* cancel IRP with cancel and completion routines with no SL_INVOKE_ON_ERROR */
1010 irp = IoBuildAsynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &iosb);
1011 IoSetCompletionRoutine(irp, cancel_test_completion, &completion_called, TRUE, FALSE, TRUE);
1013 status = IoCallDriver(device, irp);
1014 ok(status == STATUS_PENDING, "IoCallDriver returned %#x\n", status);
1016 IoSetCancelRoutine(irp, cancel_irp);
1017 cancel_cnt = 0;
1018 r = IoCancelIrp(irp);
1019 ok(r == TRUE, "IoCancelIrp returned %x\n", r);
1020 ok(cancel_cnt == 1, "cancel_cnt = %d\n", cancel_cnt);
1021 ok(irp->Cancel == TRUE, "Cancel = %x\n", irp->Cancel);
1023 completion_called = FALSE;
1024 IoCompleteRequest(irp, IO_NO_INCREMENT);
1025 ok(completion_called, "completion not called\n");
1027 /* cancel IRP with cancel and completion routines with no SL_INVOKE_ON_CANCEL flag */
1028 irp = IoBuildAsynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &iosb);
1029 IoSetCompletionRoutine(irp, cancel_test_completion, &completion_called, TRUE, TRUE, FALSE);
1031 status = IoCallDriver(device, irp);
1032 ok(status == STATUS_PENDING, "IoCallDriver returned %#x\n", status);
1034 IoSetCancelRoutine(irp, cancel_irp);
1035 cancel_cnt = 0;
1036 r = IoCancelIrp(irp);
1037 ok(r == TRUE, "IoCancelIrp returned %x\n", r);
1038 ok(irp->Cancel == TRUE, "Cancel = %x\n", irp->Cancel);
1039 ok(cancel_cnt == 1, "cancel_cnt = %d\n", cancel_cnt);
1041 completion_called = FALSE;
1042 IoCompleteRequest(irp, IO_NO_INCREMENT);
1043 ok(completion_called, "completion not called\n");
1045 /* cancel IRP with cancel and completion routines, but no SL_INVOKE_ON_ERROR nor SL_INVOKE_ON_CANCEL flag */
1046 irp = IoBuildAsynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &iosb);
1047 IoSetCompletionRoutine(irp, cancel_test_completion, &completion_called, TRUE, FALSE, FALSE);
1049 status = IoCallDriver(device, irp);
1050 ok(status == STATUS_PENDING, "IoCallDriver returned %#x\n", status);
1052 IoSetCancelRoutine(irp, cancel_irp);
1053 cancel_cnt = 0;
1054 r = IoCancelIrp(irp);
1055 ok(r == TRUE, "IoCancelIrp returned %x\n", r);
1056 ok(irp->Cancel == TRUE, "Cancel = %x\n", irp->Cancel);
1057 ok(cancel_cnt == 1, "cancel_cnt = %d\n", cancel_cnt);
1059 completion_called = FALSE;
1060 IoCompleteRequest(irp, IO_NO_INCREMENT);
1061 ok(!completion_called, "completion not called\n");
1064 static int callout_cnt;
1066 static void WINAPI callout(void *parameter)
1068 ok(parameter == (void*)0xdeadbeef, "parameter = %p\n", parameter);
1069 callout_cnt++;
1072 static void test_stack_callout(void)
1074 NTSTATUS (WINAPI *pKeExpandKernelStackAndCallout)(PEXPAND_STACK_CALLOUT,void*,SIZE_T);
1075 NTSTATUS (WINAPI *pKeExpandKernelStackAndCalloutEx)(PEXPAND_STACK_CALLOUT,void*,SIZE_T,BOOLEAN,void*);
1076 NTSTATUS ret;
1078 pKeExpandKernelStackAndCallout = get_proc_address("KeExpandKernelStackAndCallout");
1079 if (pKeExpandKernelStackAndCallout)
1081 callout_cnt = 0;
1082 ret = pKeExpandKernelStackAndCallout(callout, (void*)0xdeadbeef, 4096);
1083 ok(ret == STATUS_SUCCESS, "KeExpandKernelStackAndCallout failed: %#x\n", ret);
1084 ok(callout_cnt == 1, "callout_cnt = %u\n", callout_cnt);
1086 else win_skip("KeExpandKernelStackAndCallout is not available\n");
1088 pKeExpandKernelStackAndCalloutEx = get_proc_address("KeExpandKernelStackAndCalloutEx");
1089 if (pKeExpandKernelStackAndCalloutEx)
1091 callout_cnt = 0;
1092 ret = pKeExpandKernelStackAndCalloutEx(callout, (void*)0xdeadbeef, 4096, FALSE, NULL);
1093 ok(ret == STATUS_SUCCESS, "KeExpandKernelStackAndCalloutEx failed: %#x\n", ret);
1094 ok(callout_cnt == 1, "callout_cnt = %u\n", callout_cnt);
1096 else win_skip("KeExpandKernelStackAndCalloutEx is not available\n");
1099 static void test_lookaside_list(void)
1101 NPAGED_LOOKASIDE_LIST list;
1102 PAGED_LOOKASIDE_LIST paged_list;
1103 ULONG tag = 0x454e4957; /* WINE */
1105 ExInitializeNPagedLookasideList(&list, NULL, NULL, POOL_NX_ALLOCATION, LOOKASIDE_MINIMUM_BLOCK_SIZE, tag, 0);
1106 ok(list.L.Depth == 4, "Expected 4 got %u\n", list.L.Depth);
1107 ok(list.L.MaximumDepth == 256, "Expected 256 got %u\n", list.L.MaximumDepth);
1108 ok(list.L.TotalAllocates == 0, "Expected 0 got %u\n", list.L.TotalAllocates);
1109 ok(list.L.AllocateMisses == 0, "Expected 0 got %u\n", list.L.AllocateMisses);
1110 ok(list.L.TotalFrees == 0, "Expected 0 got %u\n", list.L.TotalFrees);
1111 ok(list.L.FreeMisses == 0, "Expected 0 got %u\n", list.L.FreeMisses);
1112 ok(list.L.Type == (NonPagedPool|POOL_NX_ALLOCATION),
1113 "Expected NonPagedPool|POOL_NX_ALLOCATION got %u\n", list.L.Type);
1114 ok(list.L.Tag == tag, "Expected %x got %x\n", tag, list.L.Tag);
1115 ok(list.L.Size == LOOKASIDE_MINIMUM_BLOCK_SIZE,
1116 "Expected %u got %u\n", LOOKASIDE_MINIMUM_BLOCK_SIZE, list.L.Size);
1117 ok(list.L.LastTotalAllocates == 0,"Expected 0 got %u\n", list.L.LastTotalAllocates);
1118 ok(list.L.LastAllocateMisses == 0,"Expected 0 got %u\n", list.L.LastAllocateMisses);
1119 ExDeleteNPagedLookasideList(&list);
1121 list.L.Depth = 0;
1122 ExInitializeNPagedLookasideList(&list, NULL, NULL, 0, LOOKASIDE_MINIMUM_BLOCK_SIZE, tag, 20);
1123 ok(list.L.Depth == 4, "Expected 4 got %u\n", list.L.Depth);
1124 ok(list.L.MaximumDepth == 256, "Expected 256 got %u\n", list.L.MaximumDepth);
1125 ok(list.L.Type == NonPagedPool, "Expected NonPagedPool got %u\n", list.L.Type);
1126 ExDeleteNPagedLookasideList(&list);
1128 ExInitializePagedLookasideList(&paged_list, NULL, NULL, POOL_NX_ALLOCATION, LOOKASIDE_MINIMUM_BLOCK_SIZE, tag, 0);
1129 ok(paged_list.L.Depth == 4, "Expected 4 got %u\n", paged_list.L.Depth);
1130 ok(paged_list.L.MaximumDepth == 256, "Expected 256 got %u\n", paged_list.L.MaximumDepth);
1131 ok(paged_list.L.TotalAllocates == 0, "Expected 0 got %u\n", paged_list.L.TotalAllocates);
1132 ok(paged_list.L.AllocateMisses == 0, "Expected 0 got %u\n", paged_list.L.AllocateMisses);
1133 ok(paged_list.L.TotalFrees == 0, "Expected 0 got %u\n", paged_list.L.TotalFrees);
1134 ok(paged_list.L.FreeMisses == 0, "Expected 0 got %u\n", paged_list.L.FreeMisses);
1135 ok(paged_list.L.Type == (PagedPool|POOL_NX_ALLOCATION),
1136 "Expected PagedPool|POOL_NX_ALLOCATION got %u\n", paged_list.L.Type);
1137 ok(paged_list.L.Tag == tag, "Expected %x got %x\n", tag, paged_list.L.Tag);
1138 ok(paged_list.L.Size == LOOKASIDE_MINIMUM_BLOCK_SIZE,
1139 "Expected %u got %u\n", LOOKASIDE_MINIMUM_BLOCK_SIZE, paged_list.L.Size);
1140 ok(paged_list.L.LastTotalAllocates == 0,"Expected 0 got %u\n", paged_list.L.LastTotalAllocates);
1141 ok(paged_list.L.LastAllocateMisses == 0,"Expected 0 got %u\n", paged_list.L.LastAllocateMisses);
1142 ExDeletePagedLookasideList(&paged_list);
1144 paged_list.L.Depth = 0;
1145 ExInitializePagedLookasideList(&paged_list, NULL, NULL, 0, LOOKASIDE_MINIMUM_BLOCK_SIZE, tag, 20);
1146 ok(paged_list.L.Depth == 4, "Expected 4 got %u\n", paged_list.L.Depth);
1147 ok(paged_list.L.MaximumDepth == 256, "Expected 256 got %u\n", paged_list.L.MaximumDepth);
1148 ok(paged_list.L.Type == PagedPool, "Expected PagedPool got %u\n", paged_list.L.Type);
1149 ExDeletePagedLookasideList(&paged_list);
1152 static void test_version(void)
1154 USHORT *pNtBuildNumber;
1155 ULONG build;
1157 pNtBuildNumber = get_proc_address("NtBuildNumber");
1158 ok(!!pNtBuildNumber, "Could not get pointer to NtBuildNumber\n");
1160 PsGetVersion(NULL, NULL, &build, NULL);
1161 ok(*pNtBuildNumber == build, "Expected build number %u, got %u\n", build, *pNtBuildNumber);
1164 static void WINAPI thread_proc(void *arg)
1166 PsTerminateSystemThread(STATUS_SUCCESS);
1169 static void test_ob_reference(void)
1171 POBJECT_TYPE (WINAPI *pObGetObjectType)(void*);
1172 OBJECT_ATTRIBUTES attr = { sizeof(attr) };
1173 HANDLE event_handle, file_handle, file_handle2, thread_handle, handle;
1174 DISPATCHER_HEADER *header;
1175 FILE_OBJECT *file;
1176 void *obj1, *obj2;
1177 POBJECT_TYPE obj1_type;
1178 UNICODE_STRING pathU;
1179 IO_STATUS_BLOCK io;
1180 NTSTATUS status;
1182 pObGetObjectType = get_proc_address("ObGetObjectType");
1183 if (!pObGetObjectType)
1184 win_skip("ObGetObjectType not found\n");
1186 InitializeObjectAttributes(&attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
1187 status = ZwCreateEvent(&event_handle, SYNCHRONIZE, &attr, NotificationEvent, TRUE);
1188 ok(!status, "ZwCreateEvent failed: %#x\n", status);
1190 RtlInitUnicodeString(&pathU, L"\\??\\C:\\windows\\winetest_ntoskrnl_file.tmp");
1191 attr.ObjectName = &pathU;
1192 attr.Attributes = OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE;
1193 status = ZwCreateFile(&file_handle, DELETE | FILE_WRITE_DATA | SYNCHRONIZE, &attr, &io, NULL, 0, 0, FILE_CREATE,
1194 FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
1195 ok(!status, "ZwCreateFile failed: %#x\n", status);
1197 status = ZwDuplicateObject(NtCurrentProcess(), file_handle, NtCurrentProcess(), &file_handle2,
1198 0, OBJ_KERNEL_HANDLE, DUPLICATE_SAME_ACCESS);
1199 ok(!status, "ZwDuplicateObject failed: %#x\n", status);
1201 InitializeObjectAttributes(&attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
1202 status = PsCreateSystemThread(&thread_handle, SYNCHRONIZE, &attr, NULL, NULL, thread_proc, NULL);
1203 ok(!status, "PsCreateSystemThread returned: %#x\n", status);
1205 status = ObReferenceObjectByHandle(NULL, SYNCHRONIZE, *pExEventObjectType, KernelMode, &obj1, NULL);
1206 ok(status == STATUS_INVALID_HANDLE, "ObReferenceObjectByHandle failed: %#x\n", status);
1208 status = ObReferenceObjectByHandle(event_handle, SYNCHRONIZE, *pIoFileObjectType, KernelMode, &obj1, NULL);
1209 ok(status == STATUS_OBJECT_TYPE_MISMATCH, "ObReferenceObjectByHandle returned: %#x\n", status);
1211 status = ObReferenceObjectByHandle(event_handle, SYNCHRONIZE, NULL, KernelMode, &obj1, NULL);
1212 ok(!status, "ObReferenceObjectByHandle failed: %#x\n", status);
1214 if (pObGetObjectType)
1216 obj1_type = pObGetObjectType(obj1);
1217 ok(obj1_type == *pExEventObjectType, "ObGetObjectType returned %p\n", obj1_type);
1220 if (sizeof(void *) != 4) /* avoid dealing with fastcall */
1222 ObfReferenceObject(obj1);
1223 ObDereferenceObject(obj1);
1226 status = ObReferenceObjectByHandle(event_handle, SYNCHRONIZE, *pIoFileObjectType, KernelMode, &obj2, NULL);
1227 ok(status == STATUS_OBJECT_TYPE_MISMATCH, "ObReferenceObjectByHandle returned: %#x\n", status);
1229 status = ObReferenceObjectByHandle(event_handle, SYNCHRONIZE, *pExEventObjectType, KernelMode, &obj2, NULL);
1230 ok(!status, "ObReferenceObjectByHandle failed: %#x\n", status);
1231 ok(obj1 == obj2, "obj1 != obj2\n");
1233 ObDereferenceObject(obj2);
1235 status = ObReferenceObjectByHandle(event_handle, SYNCHRONIZE, NULL, KernelMode, &obj2, NULL);
1236 ok(!status, "ObReferenceObjectByHandle failed: %#x\n", status);
1237 ok(obj1 == obj2, "obj1 != obj2\n");
1239 ObDereferenceObject(obj2);
1240 ObDereferenceObject(obj1);
1242 status = ObReferenceObjectByHandle(file_handle, SYNCHRONIZE, *pIoFileObjectType, KernelMode, &obj1, NULL);
1243 ok(!status, "ObReferenceObjectByHandle failed: %#x\n", status);
1245 status = ObReferenceObjectByHandle(file_handle2, SYNCHRONIZE, *pIoFileObjectType, KernelMode, &obj2, NULL);
1246 ok(!status, "ObReferenceObjectByHandle failed: %#x\n", status);
1247 ok(obj1 == obj2, "obj1 != obj2\n");
1249 file = obj1;
1250 ok(file->Type == 5, "Type = %u\n", file->Type);
1252 ObDereferenceObject(obj1);
1253 ObDereferenceObject(obj2);
1255 status = ObReferenceObjectByHandle(thread_handle, SYNCHRONIZE, *pPsThreadType, KernelMode, &obj1, NULL);
1256 ok(!status, "ObReferenceObjectByHandle failed: %#x\n", status);
1258 status = ObReferenceObjectByHandle(thread_handle, SYNCHRONIZE, *pPsThreadType, KernelMode, &obj2, NULL);
1259 ok(!status, "ObReferenceObjectByHandle failed: %#x\n", status);
1260 ok(obj1 == obj2, "obj1 != obj2\n");
1262 header = obj1;
1263 ok(header->Type == 6, "Type = %u\n", header->Type);
1265 status = wait_single(header, 0);
1266 ok(status == 0 || status == STATUS_TIMEOUT, "got %#x\n", status);
1268 ObDereferenceObject(obj2);
1270 status = ObOpenObjectByPointer(obj1, OBJ_KERNEL_HANDLE, NULL, 0, NULL, KernelMode, &handle);
1271 ok(status == STATUS_SUCCESS, "ObOpenObjectByPointer failed: %#x\n", status);
1273 status = ZwClose(handle);
1274 ok(!status, "ZwClose failed: %#x\n", status);
1276 status = ObReferenceObjectByHandle(thread_handle, SYNCHRONIZE, *pPsThreadType, KernelMode, &obj2, NULL);
1277 ok(!status, "ObReferenceObjectByHandle failed: %#x\n", status);
1278 ok(obj1 == obj2, "obj1 != obj2\n");
1279 ObDereferenceObject(obj2);
1281 status = ObOpenObjectByPointer(obj1, OBJ_KERNEL_HANDLE, NULL, 0, *pIoFileObjectType, KernelMode, &handle);
1282 ok(status == STATUS_OBJECT_TYPE_MISMATCH, "ObOpenObjectByPointer returned: %#x\n", status);
1284 ObDereferenceObject(obj1);
1286 status = ZwClose(thread_handle);
1287 ok(!status, "ZwClose failed: %#x\n", status);
1289 status = ZwClose(event_handle);
1290 ok(!status, "ZwClose failed: %#x\n", status);
1292 status = ZwClose(file_handle);
1293 ok(!status, "ZwClose failed: %#x\n", status);
1295 status = ZwClose(file_handle2);
1296 ok(!status, "ZwClose failed: %#x\n", status);
1299 static void check_resource_(int line, ERESOURCE *resource, ULONG exclusive_waiters,
1300 ULONG shared_waiters, BOOLEAN exclusive, ULONG shared_count)
1302 BOOLEAN ret;
1303 ULONG count;
1305 count = ExGetExclusiveWaiterCount(resource);
1306 ok_(__FILE__, line, count == exclusive_waiters,
1307 "expected %u exclusive waiters, got %u\n", exclusive_waiters, count);
1308 count = ExGetSharedWaiterCount(resource);
1309 ok_(__FILE__, line, count == shared_waiters,
1310 "expected %u shared waiters, got %u\n", shared_waiters, count);
1311 ret = ExIsResourceAcquiredExclusiveLite(resource);
1312 ok_(__FILE__, line, ret == exclusive,
1313 "expected exclusive %u, got %u\n", exclusive, ret);
1314 count = ExIsResourceAcquiredSharedLite(resource);
1315 ok_(__FILE__, line, count == shared_count,
1316 "expected shared %u, got %u\n", shared_count, count);
1318 #define check_resource(a,b,c,d,e) check_resource_(__LINE__,a,b,c,d,e)
1320 static KEVENT resource_shared_ready, resource_shared_done, resource_exclusive_ready, resource_exclusive_done;
1322 static void WINAPI resource_shared_thread(void *arg)
1324 ERESOURCE *resource = arg;
1325 BOOLEAN ret;
1327 check_resource(resource, 0, 0, FALSE, 0);
1329 ret = ExAcquireResourceSharedLite(resource, TRUE);
1330 ok(ret == TRUE, "got ret %u\n", ret);
1332 check_resource(resource, 0, 0, FALSE, 1);
1334 KeSetEvent(&resource_shared_ready, IO_NO_INCREMENT, FALSE);
1335 KeWaitForSingleObject(&resource_shared_done, Executive, KernelMode, FALSE, NULL);
1337 ExReleaseResourceForThreadLite(resource, (ULONG_PTR)PsGetCurrentThread());
1339 PsTerminateSystemThread(STATUS_SUCCESS);
1342 static void WINAPI resource_exclusive_thread(void *arg)
1344 ERESOURCE *resource = arg;
1345 BOOLEAN ret;
1347 check_resource(resource, 0, 0, FALSE, 0);
1349 ret = ExAcquireResourceExclusiveLite(resource, TRUE);
1350 ok(ret == TRUE, "got ret %u\n", ret);
1352 check_resource(resource, 0, 0, TRUE, 1);
1354 KeSetEvent(&resource_exclusive_ready, IO_NO_INCREMENT, FALSE);
1355 KeWaitForSingleObject(&resource_exclusive_done, Executive, KernelMode, FALSE, NULL);
1357 ExReleaseResourceForThreadLite(resource, (ULONG_PTR)PsGetCurrentThread());
1359 PsTerminateSystemThread(STATUS_SUCCESS);
1362 static void test_resource(void)
1364 ERESOURCE resource;
1365 NTSTATUS status;
1366 BOOLEAN ret;
1367 HANDLE thread, thread2;
1369 memset(&resource, 0xcc, sizeof(resource));
1371 status = ExInitializeResourceLite(&resource);
1372 ok(status == STATUS_SUCCESS, "got status %#x\n", status);
1373 check_resource(&resource, 0, 0, FALSE, 0);
1375 KeEnterCriticalRegion();
1377 ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
1378 ok(ret == TRUE, "got ret %u\n", ret);
1379 check_resource(&resource, 0, 0, TRUE, 1);
1381 ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
1382 ok(ret == TRUE, "got ret %u\n", ret);
1383 check_resource(&resource, 0, 0, TRUE, 2);
1385 ret = ExAcquireResourceSharedLite(&resource, FALSE);
1386 ok(ret == TRUE, "got ret %u\n", ret);
1387 check_resource(&resource, 0, 0, TRUE, 3);
1389 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1390 check_resource(&resource, 0, 0, TRUE, 2);
1392 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1393 check_resource(&resource, 0, 0, TRUE, 1);
1395 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1396 check_resource(&resource, 0, 0, FALSE, 0);
1398 ret = ExAcquireResourceSharedLite(&resource, FALSE);
1399 ok(ret == TRUE, "got ret %u\n", ret);
1400 check_resource(&resource, 0, 0, FALSE, 1);
1402 ret = ExAcquireResourceSharedLite(&resource, FALSE);
1403 ok(ret == TRUE, "got ret %u\n", ret);
1404 check_resource(&resource, 0, 0, FALSE, 2);
1406 ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
1407 ok(ret == FALSE, "got ret %u\n", ret);
1408 check_resource(&resource, 0, 0, FALSE, 2);
1410 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1411 check_resource(&resource, 0, 0, FALSE, 1);
1413 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1414 check_resource(&resource, 0, 0, FALSE, 0);
1416 ret = ExAcquireSharedStarveExclusive(&resource, FALSE);
1417 ok(ret == TRUE, "got ret %u\n", ret);
1418 check_resource(&resource, 0, 0, FALSE, 1);
1420 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1421 check_resource(&resource, 0, 0, FALSE, 0);
1423 ret = ExAcquireSharedWaitForExclusive(&resource, FALSE);
1424 ok(ret == TRUE, "got ret %u\n", ret);
1425 check_resource(&resource, 0, 0, FALSE, 1);
1427 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1428 check_resource(&resource, 0, 0, FALSE, 0);
1430 /* Do not acquire the resource ourselves, but spawn a shared thread holding it. */
1432 KeInitializeEvent(&resource_shared_ready, SynchronizationEvent, FALSE);
1433 KeInitializeEvent(&resource_shared_done, SynchronizationEvent, FALSE);
1434 thread = create_thread(resource_shared_thread, &resource);
1435 KeWaitForSingleObject(&resource_shared_ready, Executive, KernelMode, FALSE, NULL);
1436 check_resource(&resource, 0, 0, FALSE, 0);
1438 ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
1439 ok(ret == FALSE, "got ret %u\n", ret);
1441 ret = ExAcquireResourceSharedLite(&resource, FALSE);
1442 ok(ret == TRUE, "got ret %u\n", ret);
1443 check_resource(&resource, 0, 0, FALSE, 1);
1445 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1446 check_resource(&resource, 0, 0, FALSE, 0);
1448 ret = ExAcquireSharedStarveExclusive(&resource, FALSE);
1449 ok(ret == TRUE, "got ret %u\n", ret);
1450 check_resource(&resource, 0, 0, FALSE, 1);
1452 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1453 check_resource(&resource, 0, 0, FALSE, 0);
1455 ret = ExAcquireSharedWaitForExclusive(&resource, FALSE);
1456 ok(ret == TRUE, "got ret %u\n", ret);
1457 check_resource(&resource, 0, 0, FALSE, 1);
1459 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1460 check_resource(&resource, 0, 0, FALSE, 0);
1462 KeSetEvent(&resource_shared_done, IO_NO_INCREMENT, FALSE);
1463 join_thread(thread);
1464 check_resource(&resource, 0, 0, FALSE, 0);
1466 /* Acquire the resource as exclusive, and then spawn a shared thread. */
1468 ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
1469 ok(ret == TRUE, "got ret %u\n", ret);
1470 check_resource(&resource, 0, 0, TRUE, 1);
1472 thread = create_thread(resource_shared_thread, &resource);
1473 sleep();
1474 check_resource(&resource, 0, 1, TRUE, 1);
1476 ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
1477 ok(ret == TRUE, "got ret %u\n", ret);
1478 check_resource(&resource, 0, 1, TRUE, 2);
1480 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1481 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1482 KeWaitForSingleObject(&resource_shared_ready, Executive, KernelMode, FALSE, NULL);
1483 KeSetEvent(&resource_shared_done, IO_NO_INCREMENT, FALSE);
1484 join_thread(thread);
1485 check_resource(&resource, 0, 0, FALSE, 0);
1487 /* Do not acquire the resource ourselves, but spawn an exclusive thread holding it. */
1489 KeInitializeEvent(&resource_exclusive_ready, SynchronizationEvent, FALSE);
1490 KeInitializeEvent(&resource_exclusive_done, SynchronizationEvent, FALSE);
1491 thread = create_thread(resource_exclusive_thread, &resource);
1492 KeWaitForSingleObject(&resource_exclusive_ready, Executive, KernelMode, FALSE, NULL);
1493 check_resource(&resource, 0, 0, FALSE, 0);
1495 ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
1496 ok(ret == FALSE, "got ret %u\n", ret);
1497 check_resource(&resource, 0, 0, FALSE, 0);
1499 ret = ExAcquireResourceSharedLite(&resource, FALSE);
1500 ok(ret == FALSE, "got ret %u\n", ret);
1501 check_resource(&resource, 0, 0, FALSE, 0);
1503 ret = ExAcquireSharedStarveExclusive(&resource, FALSE);
1504 ok(ret == FALSE, "got ret %u\n", ret);
1505 check_resource(&resource, 0, 0, FALSE, 0);
1507 ret = ExAcquireSharedWaitForExclusive(&resource, FALSE);
1508 ok(ret == FALSE, "got ret %u\n", ret);
1509 check_resource(&resource, 0, 0, FALSE, 0);
1511 KeSetEvent(&resource_exclusive_done, IO_NO_INCREMENT, FALSE);
1512 join_thread(thread);
1513 check_resource(&resource, 0, 0, FALSE, 0);
1515 /* Acquire the resource as shared, and then spawn an exclusive waiter. */
1517 ret = ExAcquireResourceSharedLite(&resource, FALSE);
1518 ok(ret == TRUE, "got ret %u\n", ret);
1519 check_resource(&resource, 0, 0, FALSE, 1);
1521 thread = create_thread(resource_exclusive_thread, &resource);
1522 sleep();
1523 check_resource(&resource, 1, 0, FALSE, 1);
1525 ret = ExAcquireResourceSharedLite(&resource, FALSE);
1526 ok(ret == TRUE, "got ret %u\n", ret);
1527 check_resource(&resource, 1, 0, FALSE, 2);
1528 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1530 ret = ExAcquireSharedStarveExclusive(&resource, FALSE);
1531 ok(ret == TRUE, "got ret %u\n", ret);
1532 check_resource(&resource, 1, 0, FALSE, 2);
1533 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1535 ret = ExAcquireSharedWaitForExclusive(&resource, FALSE);
1536 ok(ret == FALSE, "got ret %u\n", ret);
1537 check_resource(&resource, 1, 0, FALSE, 1);
1539 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1540 KeWaitForSingleObject(&resource_exclusive_ready, Executive, KernelMode, FALSE, NULL);
1541 KeSetEvent(&resource_exclusive_done, IO_NO_INCREMENT, FALSE);
1542 join_thread(thread);
1543 check_resource(&resource, 0, 0, FALSE, 0);
1545 /* Spawn a shared and then exclusive waiter. */
1547 KeInitializeEvent(&resource_shared_ready, SynchronizationEvent, FALSE);
1548 KeInitializeEvent(&resource_shared_done, SynchronizationEvent, FALSE);
1549 thread = create_thread(resource_shared_thread, &resource);
1550 KeWaitForSingleObject(&resource_shared_ready, Executive, KernelMode, FALSE, NULL);
1551 check_resource(&resource, 0, 0, FALSE, 0);
1553 thread2 = create_thread(resource_exclusive_thread, &resource);
1554 sleep();
1555 check_resource(&resource, 1, 0, FALSE, 0);
1557 ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
1558 ok(ret == FALSE, "got ret %u\n", ret);
1559 check_resource(&resource, 1, 0, FALSE, 0);
1561 ret = ExAcquireResourceSharedLite(&resource, FALSE);
1562 ok(ret == FALSE, "got ret %u\n", ret);
1563 check_resource(&resource, 1, 0, FALSE, 0);
1565 ret = ExAcquireSharedStarveExclusive(&resource, FALSE);
1566 ok(ret == TRUE, "got ret %u\n", ret);
1567 check_resource(&resource, 1, 0, FALSE, 1);
1568 ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
1570 ret = ExAcquireSharedWaitForExclusive(&resource, FALSE);
1571 ok(ret == FALSE, "got ret %u\n", ret);
1572 check_resource(&resource, 1, 0, FALSE, 0);
1574 KeSetEvent(&resource_shared_done, IO_NO_INCREMENT, FALSE);
1575 join_thread(thread);
1576 KeWaitForSingleObject(&resource_exclusive_ready, Executive, KernelMode, FALSE, NULL);
1577 KeSetEvent(&resource_exclusive_done, IO_NO_INCREMENT, FALSE);
1578 join_thread(thread2);
1579 check_resource(&resource, 0, 0, FALSE, 0);
1581 KeLeaveCriticalRegion();
1583 status = ExDeleteResourceLite(&resource);
1584 ok(status == STATUS_SUCCESS, "got status %#x\n", status);
1587 static void test_lookup_thread(void)
1589 NTSTATUS status;
1590 PETHREAD thread = NULL;
1592 status = PsLookupThreadByThreadId(PsGetCurrentThreadId(), &thread);
1593 ok(!status, "PsLookupThreadByThreadId failed: %#x\n", status);
1594 ok((PKTHREAD)thread == KeGetCurrentThread(), "thread != KeGetCurrentThread\n");
1595 if (thread) ObDereferenceObject(thread);
1597 status = PsLookupThreadByThreadId(NULL, &thread);
1598 ok(status == STATUS_INVALID_CID || broken(status == STATUS_INVALID_PARAMETER) /* winxp */,
1599 "PsLookupThreadByThreadId returned %#x\n", status);
1602 static void test_stack_limits(void)
1604 ULONG_PTR low = 0, high = 0;
1606 IoGetStackLimits(&low, &high);
1607 ok(low, "low = 0\n");
1608 ok(low < high, "low >= high\n");
1609 ok(low < (ULONG_PTR)&low && (ULONG_PTR)&low < high, "stack variable is not in stack limits\n");
1612 static unsigned int got_completion;
1614 static NTSTATUS WINAPI completion_cb(DEVICE_OBJECT *device, IRP *irp, void *context)
1616 ok(device == context, "Got device %p; expected %p.\n", device, context);
1617 ++got_completion;
1618 return STATUS_SUCCESS;
1621 static void test_completion(void)
1623 IO_STATUS_BLOCK io;
1624 NTSTATUS ret;
1625 KEVENT event;
1626 IRP *irp;
1628 KeInitializeEvent(&event, NotificationEvent, FALSE);
1630 irp = IoBuildDeviceIoControlRequest(IOCTL_WINETEST_COMPLETION, upper_device,
1631 NULL, 0, NULL, 0, FALSE, &event, &io);
1633 IoSetCompletionRoutine(irp, completion_cb, NULL, TRUE, TRUE, TRUE);
1634 ret = IoCallDriver(upper_device, irp);
1635 ok(ret == STATUS_SUCCESS, "IoCallDriver returned %#x\n", ret);
1636 ok(got_completion == 2, "got %u calls to completion routine\n", got_completion);
1639 static void test_IoAttachDeviceToDeviceStack(void)
1641 DEVICE_OBJECT *dev1, *dev2, *dev3, *ret;
1642 NTSTATUS status;
1644 status = IoCreateDevice(driver_obj, 0, NULL, FILE_DEVICE_UNKNOWN,
1645 FILE_DEVICE_SECURE_OPEN, FALSE, &dev1);
1646 ok(status == STATUS_SUCCESS, "IoCreateDevice failed\n");
1647 status = IoCreateDevice(driver_obj, 0, NULL, FILE_DEVICE_UNKNOWN,
1648 FILE_DEVICE_SECURE_OPEN, FALSE, &dev2);
1649 ok(status == STATUS_SUCCESS, "IoCreateDevice failed\n");
1650 status = IoCreateDevice(driver_obj, 0, NULL, FILE_DEVICE_UNKNOWN,
1651 FILE_DEVICE_SECURE_OPEN, FALSE, &dev3);
1652 ok(status == STATUS_SUCCESS, "IoCreateDevice failed\n");
1654 /* TODO: initialize devices properly */
1655 dev1->Flags &= ~DO_DEVICE_INITIALIZING;
1656 dev2->Flags &= ~DO_DEVICE_INITIALIZING;
1658 ret = IoAttachDeviceToDeviceStack(dev2, dev1);
1659 ok(ret == dev1, "IoAttachDeviceToDeviceStack returned %p, expected %p\n", ret, dev1);
1660 ok(dev1->AttachedDevice == dev2, "dev1->AttachedDevice = %p, expected %p\n",
1661 dev1->AttachedDevice, dev2);
1662 ok(!dev2->AttachedDevice, "dev2->AttachedDevice = %p\n", dev2->AttachedDevice);
1663 ok(dev1->StackSize == 1, "dev1->StackSize = %d\n", dev1->StackSize);
1664 ok(dev2->StackSize == 2, "dev2->StackSize = %d\n", dev2->StackSize);
1666 ret = IoAttachDeviceToDeviceStack(dev3, dev1);
1667 ok(ret == dev2, "IoAttachDeviceToDeviceStack returned %p, expected %p\n", ret, dev2);
1668 ok(dev1->AttachedDevice == dev2, "dev1->AttachedDevice = %p, expected %p\n",
1669 dev1->AttachedDevice, dev2);
1670 ok(dev2->AttachedDevice == dev3, "dev2->AttachedDevice = %p, expected %p\n",
1671 dev2->AttachedDevice, dev3);
1672 ok(!dev3->AttachedDevice, "dev3->AttachedDevice = %p\n", dev3->AttachedDevice);
1673 ok(dev1->StackSize == 1, "dev1->StackSize = %d\n", dev1->StackSize);
1674 ok(dev2->StackSize == 2, "dev2->StackSize = %d\n", dev2->StackSize);
1675 ok(dev3->StackSize == 3, "dev3->StackSize = %d\n", dev3->StackSize);
1677 IoDetachDevice(dev1);
1678 ok(!dev1->AttachedDevice, "dev1->AttachedDevice = %p\n", dev1->AttachedDevice);
1679 ok(dev2->AttachedDevice == dev3, "dev2->AttachedDevice = %p\n", dev2->AttachedDevice);
1681 IoDetachDevice(dev2);
1682 ok(!dev2->AttachedDevice, "dev2->AttachedDevice = %p\n", dev2->AttachedDevice);
1683 ok(dev1->StackSize == 1, "dev1->StackSize = %d\n", dev1->StackSize);
1684 ok(dev2->StackSize == 2, "dev2->StackSize = %d\n", dev2->StackSize);
1685 ok(dev3->StackSize == 3, "dev3->StackSize = %d\n", dev3->StackSize);
1687 IoDeleteDevice(dev1);
1688 IoDeleteDevice(dev2);
1689 IoDeleteDevice(dev3);
1692 static void test_object_name(void)
1694 static const WCHAR event_nameW[] = L"\\wine_test_event";
1695 static const WCHAR device_nameW[] = L"\\Device\\WineTestDriver";
1696 char buffer[1024];
1697 OBJECT_NAME_INFORMATION *name = (OBJECT_NAME_INFORMATION *)buffer;
1698 OBJECT_ATTRIBUTES attr;
1699 UNICODE_STRING string;
1700 ULONG ret_size;
1701 HANDLE handle;
1702 KEVENT *event;
1703 NTSTATUS ret;
1705 ret_size = 0;
1706 ret = ObQueryNameString(lower_device, name, 0, &ret_size);
1707 ok(ret == STATUS_INFO_LENGTH_MISMATCH, "got status %#x\n", ret);
1708 ok(ret_size == sizeof(*name) + sizeof(device_nameW), "got size %u\n", ret_size);
1710 ret_size = 0;
1711 ret = ObQueryNameString(lower_device, name, sizeof(buffer), &ret_size);
1712 ok(!ret, "got status %#x\n", ret);
1713 ok(!wcscmp(name->Name.Buffer, device_nameW), "got name %ls\n", name->Name.Buffer);
1714 ok(ret_size == sizeof(*name) + sizeof(device_nameW), "got size %u\n", ret_size);
1715 ok(name->Name.Length == wcslen(device_nameW) * sizeof(WCHAR), "got length %u\n", name->Name.Length);
1716 ok(name->Name.MaximumLength == sizeof(device_nameW), "got maximum length %u\n", name->Name.MaximumLength);
1718 event = IoCreateSynchronizationEvent(NULL, &handle);
1719 ok(!!event, "failed to create event\n");
1721 ret_size = 0;
1722 ret = ObQueryNameString(event, name, sizeof(buffer), &ret_size);
1723 ok(!ret, "got status %#x\n", ret);
1724 ok(!name->Name.Buffer, "got name %ls\n", name->Name.Buffer);
1725 ok(ret_size == sizeof(*name), "got size %u\n", ret_size);
1726 ok(!name->Name.Length, "got length %u\n", name->Name.Length);
1727 ok(!name->Name.MaximumLength, "got maximum length %u\n", name->Name.MaximumLength);
1729 ret = ZwClose(handle);
1730 ok(!ret, "got status %#x\n", ret);
1732 RtlInitUnicodeString(&string, event_nameW);
1733 InitializeObjectAttributes(&attr, &string, OBJ_KERNEL_HANDLE, NULL, NULL);
1734 ret = ZwCreateEvent(&handle, 0, &attr, NotificationEvent, TRUE);
1735 ok(!ret, "got status %#x\n", ret);
1736 ret = ObReferenceObjectByHandle(handle, 0, *pExEventObjectType, KernelMode, (void **)&event, NULL);
1737 ok(!ret, "got status %#x\n", ret);
1739 ret_size = 0;
1740 ret = ObQueryNameString(event, name, sizeof(buffer), &ret_size);
1741 ok(!ret, "got status %#x\n", ret);
1742 ok(!wcscmp(name->Name.Buffer, event_nameW), "got name %ls\n", name->Name.Buffer);
1743 ok(ret_size == sizeof(*name) + sizeof(event_nameW), "got size %u\n", ret_size);
1744 ok(name->Name.Length == wcslen(event_nameW) * sizeof(WCHAR), "got length %u\n", name->Name.Length);
1745 ok(name->Name.MaximumLength == sizeof(event_nameW), "got maximum length %u\n", name->Name.MaximumLength);
1747 ObDereferenceObject(event);
1748 ret = ZwClose(handle);
1749 ok(!ret, "got status %#x\n", ret);
1751 ret_size = 0;
1752 ret = ObQueryNameString(KeGetCurrentThread(), name, sizeof(buffer), &ret_size);
1753 ok(!ret, "got status %#x\n", ret);
1754 ok(!name->Name.Buffer, "got name %ls\n", name->Name.Buffer);
1755 ok(ret_size == sizeof(*name), "got size %u\n", ret_size);
1756 ok(!name->Name.Length, "got length %u\n", name->Name.Length);
1757 ok(!name->Name.MaximumLength, "got maximum length %u\n", name->Name.MaximumLength);
1759 ret_size = 0;
1760 ret = ObQueryNameString(IoGetCurrentProcess(), name, sizeof(buffer), &ret_size);
1761 ok(!ret, "got status %#x\n", ret);
1762 ok(!name->Name.Buffer, "got name %ls\n", name->Name.Buffer);
1763 ok(ret_size == sizeof(*name), "got size %u\n", ret_size);
1764 ok(!name->Name.Length, "got length %u\n", name->Name.Length);
1765 ok(!name->Name.MaximumLength, "got maximum length %u\n", name->Name.MaximumLength);
1768 static PIO_WORKITEM main_test_work_item;
1770 static void WINAPI main_test_task(DEVICE_OBJECT *device, void *context)
1772 IRP *irp = context;
1773 void *buffer = irp->AssociatedIrp.SystemBuffer;
1775 IoFreeWorkItem(main_test_work_item);
1776 main_test_work_item = NULL;
1778 test_current_thread(TRUE);
1779 test_critical_region(FALSE);
1780 test_call_driver(device);
1781 test_cancel_irp(device);
1782 test_stack_limits();
1783 test_completion();
1785 /* print process report */
1786 if (winetest_debug)
1788 kprintf("%04x:ntoskrnl: %d tests executed (%d marked as todo, %d %s), %d skipped.\n",
1789 PsGetCurrentProcessId(), successes + failures + todo_successes + todo_failures,
1790 todo_successes, failures + todo_failures,
1791 (failures + todo_failures != 1) ? "failures" : "failure", skipped );
1793 ZwClose(okfile);
1795 *((LONG *)buffer) = failures;
1796 irp->IoStatus.Status = STATUS_SUCCESS;
1797 irp->IoStatus.Information = sizeof(failures);
1798 IoCompleteRequest(irp, IO_NO_INCREMENT);
1801 #if defined(__i386__) || defined(__x86_64__)
1802 static void test_executable_pool(void)
1804 static const unsigned char bytes[] =
1805 { 0xb8, 0xef, 0xbe, 0xad, 0xde, 0xc3 }; /* mov $0xdeadbeef,%eax ; ret */
1806 static const ULONG tag = 0x74736574; /* test */
1807 int (*func)(void);
1808 int ret;
1810 func = ExAllocatePoolWithTag(NonPagedPool, sizeof(bytes), tag);
1811 ok(!!func, "Got NULL memory.\n");
1813 memcpy(func, bytes, sizeof(bytes));
1814 ret = func();
1815 ok(ret == 0xdeadbeef, "Got %#x.\n", ret);
1817 ExFreePoolWithTag(func, tag);
1819 #endif
1821 static void test_affinity(void)
1823 KAFFINITY (WINAPI *pKeSetSystemAffinityThreadEx)(KAFFINITY affinity);
1824 void (WINAPI *pKeRevertToUserAffinityThreadEx)(KAFFINITY affinity);
1825 ULONG (WINAPI *pKeQueryActiveProcessorCountEx)(USHORT);
1826 KAFFINITY (WINAPI *pKeQueryActiveProcessors)(void);
1827 KAFFINITY mask, mask_all_cpus;
1828 ULONG cpu_count, count;
1830 pKeQueryActiveProcessorCountEx = get_proc_address("KeQueryActiveProcessorCountEx");
1831 if (!pKeQueryActiveProcessorCountEx)
1833 win_skip("KeQueryActiveProcessorCountEx is not available.\n");
1834 return;
1837 pKeQueryActiveProcessors = get_proc_address("KeQueryActiveProcessors");
1838 ok(!!pKeQueryActiveProcessors, "KeQueryActiveProcessors is not available.\n");
1840 pKeSetSystemAffinityThreadEx = get_proc_address("KeSetSystemAffinityThreadEx");
1841 ok(!!pKeSetSystemAffinityThreadEx, "KeSetSystemAffinityThreadEx is not available.\n");
1843 pKeRevertToUserAffinityThreadEx = get_proc_address("KeRevertToUserAffinityThreadEx");
1844 ok(!!pKeRevertToUserAffinityThreadEx, "KeRevertToUserAffinityThreadEx is not available.\n");
1846 count = pKeQueryActiveProcessorCountEx(1);
1847 todo_wine ok(!count, "Got unexpected count %u.\n", count);
1849 cpu_count = pKeQueryActiveProcessorCountEx(0);
1850 ok(cpu_count, "Got unexpected cpu_count %u.\n", cpu_count);
1852 count = pKeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
1853 ok(count == cpu_count, "Got unexpected count %u.\n", count);
1855 mask_all_cpus = ~((~0u) << cpu_count);
1857 mask = pKeQueryActiveProcessors();
1858 ok(mask == mask_all_cpus, "Got unexpected mask %#lx.\n", mask);
1860 pKeRevertToUserAffinityThreadEx(0x2);
1862 mask = pKeSetSystemAffinityThreadEx(0);
1863 ok(!mask, "Got unexpected mask %#lx.\n", mask);
1865 pKeRevertToUserAffinityThreadEx(0x2);
1867 mask = pKeSetSystemAffinityThreadEx(0x1);
1868 ok(mask == 0x2, "Got unexpected mask %#lx.\n", mask);
1870 mask = pKeSetSystemAffinityThreadEx(~(KAFFINITY)0);
1871 ok(mask == 0x1, "Got unexpected mask %#lx.\n", mask);
1873 pKeRevertToUserAffinityThreadEx(~(KAFFINITY)0);
1874 mask = pKeSetSystemAffinityThreadEx(0x1);
1875 ok(mask == mask_all_cpus, "Got unexpected mask %#lx.\n", mask);
1877 pKeRevertToUserAffinityThreadEx(0);
1879 mask = pKeSetSystemAffinityThreadEx(0x1);
1880 ok(!mask, "Got unexpected mask %#lx.\n", mask);
1882 KeRevertToUserAffinityThread();
1884 mask = pKeSetSystemAffinityThreadEx(0x1);
1885 ok(!mask, "Got unexpected mask %#lx.\n", mask);
1887 KeRevertToUserAffinityThread();
1890 struct test_dpc_func_context
1892 volatile LONG call_count;
1893 volatile LONG selected_count;
1894 volatile DEFERRED_REVERSE_BARRIER sync_barrier_start_value, sync_barrier_mid_value, sync_barrier_end_value;
1895 volatile LONG done_barrier_start_value;
1898 static BOOLEAN (WINAPI *pKeSignalCallDpcSynchronize)(void *barrier);
1899 static void (WINAPI *pKeSignalCallDpcDone)(void *barrier);
1901 static void WINAPI test_dpc_func(PKDPC Dpc, void *context, void *cpu_count,
1902 void *reverse_barrier)
1904 DEFERRED_REVERSE_BARRIER *barrier = reverse_barrier;
1905 struct test_dpc_func_context *data = context;
1907 InterlockedIncrement(&data->call_count);
1909 InterlockedCompareExchange((volatile LONG*)&data->sync_barrier_start_value.Barrier,
1910 *(volatile LONG *)&barrier->Barrier, 0);
1911 InterlockedCompareExchange((volatile LONG*)&data->sync_barrier_start_value.TotalProcessors,
1912 *(volatile LONG *)&barrier->TotalProcessors, 0);
1914 if (pKeSignalCallDpcSynchronize(reverse_barrier))
1915 InterlockedIncrement(&data->selected_count);
1917 InterlockedCompareExchange((volatile LONG*)&data->sync_barrier_mid_value.Barrier,
1918 *(volatile LONG *)&barrier->Barrier, 0);
1919 InterlockedCompareExchange((volatile LONG*)&data->sync_barrier_mid_value.TotalProcessors,
1920 *(volatile LONG *)&barrier->TotalProcessors, 0);
1922 data->done_barrier_start_value = *(volatile LONG *)cpu_count;
1924 if (pKeSignalCallDpcSynchronize(reverse_barrier))
1925 InterlockedIncrement(&data->selected_count);
1927 pKeSignalCallDpcSynchronize(reverse_barrier);
1928 pKeSignalCallDpcSynchronize(reverse_barrier);
1930 InterlockedCompareExchange((volatile LONG*)&data->sync_barrier_end_value.Barrier,
1931 *(volatile LONG *)&barrier->Barrier, 0);
1932 InterlockedCompareExchange((volatile LONG*)&data->sync_barrier_end_value.TotalProcessors,
1933 *(volatile LONG *)&barrier->TotalProcessors, 0);
1935 pKeSignalCallDpcDone(cpu_count);
1938 static void test_dpc(void)
1940 void (WINAPI *pKeGenericCallDpc)(PKDEFERRED_ROUTINE routine, void *context);
1941 struct test_dpc_func_context data;
1942 KAFFINITY cpu_mask;
1943 ULONG cpu_count;
1945 pKeGenericCallDpc = get_proc_address("KeGenericCallDpc");
1946 if (!pKeGenericCallDpc)
1948 win_skip("KeGenericCallDpc is not available.\n");
1949 return;
1952 pKeSignalCallDpcDone = get_proc_address("KeSignalCallDpcDone");
1953 ok(!!pKeSignalCallDpcDone, "KeSignalCallDpcDone is not available.\n");
1954 pKeSignalCallDpcSynchronize = get_proc_address("KeSignalCallDpcSynchronize");
1955 ok(!!pKeSignalCallDpcSynchronize, "KeSignalCallDpcSynchronize is not available.\n");
1958 cpu_mask = KeQueryActiveProcessors();
1959 cpu_count = 0;
1960 while (cpu_mask)
1962 if (cpu_mask & 1)
1963 ++cpu_count;
1965 cpu_mask >>= 1;
1968 memset(&data, 0, sizeof(data));
1970 KeSetSystemAffinityThread(0x1);
1972 pKeGenericCallDpc(test_dpc_func, &data);
1973 ok(data.call_count == cpu_count, "Got unexpected call_count %u.\n", data.call_count);
1974 ok(data.selected_count == 2, "Got unexpected selected_count %u.\n", data.selected_count);
1975 ok(data.sync_barrier_start_value.Barrier == cpu_count,
1976 "Got unexpected sync_barrier_start_value.Barrier %d.\n",
1977 data.sync_barrier_start_value.Barrier);
1978 ok(data.sync_barrier_start_value.TotalProcessors == cpu_count,
1979 "Got unexpected sync_barrier_start_value.TotalProcessors %d.\n",
1980 data.sync_barrier_start_value.TotalProcessors);
1982 ok(data.sync_barrier_mid_value.Barrier == (0x80000000 | cpu_count),
1983 "Got unexpected sync_barrier_mid_value.Barrier %d.\n",
1984 data.sync_barrier_mid_value.Barrier);
1985 ok(data.sync_barrier_mid_value.TotalProcessors == cpu_count,
1986 "Got unexpected sync_barrier_mid_value.TotalProcessors %d.\n",
1987 data.sync_barrier_mid_value.TotalProcessors);
1989 ok(data.sync_barrier_end_value.Barrier == cpu_count,
1990 "Got unexpected sync_barrier_end_value.Barrier %d.\n",
1991 data.sync_barrier_end_value.Barrier);
1992 ok(data.sync_barrier_end_value.TotalProcessors == cpu_count,
1993 "Got unexpected sync_barrier_end_value.TotalProcessors %d.\n",
1994 data.sync_barrier_end_value.TotalProcessors);
1996 ok(data.done_barrier_start_value == cpu_count, "Got unexpected done_barrier_start_value %d.\n", data.done_barrier_start_value);
1998 KeRevertToUserAffinityThread();
2001 static void test_process_memory(const struct test_input *test_input)
2003 NTSTATUS (WINAPI *pMmCopyVirtualMemory)(PEPROCESS fromprocess, void *fromaddress, PEPROCESS toprocess,
2004 void *toaddress, SIZE_T bufsize, KPROCESSOR_MODE mode, SIZE_T *copied);
2005 char buffer[sizeof(teststr)];
2006 ULONG64 modified_value;
2007 PEPROCESS process;
2008 KAPC_STATE state;
2009 NTSTATUS status;
2010 SIZE_T size;
2011 BYTE *base;
2013 pMmCopyVirtualMemory = get_proc_address("MmCopyVirtualMemory");
2015 status = PsLookupProcessByProcessId((HANDLE)(ULONG_PTR)test_input->process_id, &process);
2016 ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
2018 if (status)
2019 return;
2021 if (0) /* Crashes on Windows. */
2022 PsGetProcessSectionBaseAddress(NULL);
2024 base = PsGetProcessSectionBaseAddress(process);
2025 ok(!!base, "Got NULL base address.\n");
2027 ok(process == PsGetCurrentProcess(), "Got unexpected process %p, PsGetCurrentProcess() %p.\n",
2028 process, PsGetCurrentProcess());
2030 modified_value = 0xdeadbeeffeedcafe;
2031 if (pMmCopyVirtualMemory)
2033 size = 0xdeadbeef;
2034 status = pMmCopyVirtualMemory(process, base + test_input->teststr_offset, PsGetCurrentProcess(),
2035 buffer, sizeof(buffer), UserMode, &size);
2036 todo_wine ok(status == STATUS_ACCESS_VIOLATION, "Got unexpected status %#x.\n", status);
2037 ok(!size, "Got unexpected size %#lx.\n", size);
2039 memset(buffer, 0, sizeof(buffer));
2040 size = 0xdeadbeef;
2041 if (0) /* Passing NULL for the copied size address hangs Windows. */
2042 pMmCopyVirtualMemory(process, base + test_input->teststr_offset, PsGetCurrentProcess(),
2043 buffer, sizeof(buffer), KernelMode, NULL);
2044 status = pMmCopyVirtualMemory(process, base + test_input->teststr_offset, PsGetCurrentProcess(),
2045 buffer, sizeof(buffer), KernelMode, &size);
2046 todo_wine ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
2047 todo_wine ok(size == sizeof(buffer), "Got unexpected size %lu.\n", size);
2048 todo_wine ok(!strcmp(buffer, teststr), "Got unexpected test string.\n");
2050 else
2052 win_skip("MmCopyVirtualMemory is not available.\n");
2055 if (!test_input->running_under_wine)
2057 KeStackAttachProcess((PKPROCESS)process, &state);
2058 todo_wine ok(!strcmp(teststr, (char *)(base + test_input->teststr_offset)),
2059 "Strings do not match.\n");
2060 *test_input->modified_value = modified_value;
2061 KeUnstackDetachProcess(&state);
2063 ObDereferenceObject(process);
2066 static void test_permanence(void)
2068 OBJECT_ATTRIBUTES attr;
2069 HANDLE handle, handle2;
2070 UNICODE_STRING str;
2071 NTSTATUS status;
2073 RtlInitUnicodeString(&str, L"\\BaseNamedObjects\\wine_test_dir");
2074 InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
2075 status = ZwCreateDirectoryObject( &handle, GENERIC_ALL, &attr );
2076 ok(!status, "got %#x\n", status);
2077 status = ZwClose( handle );
2078 ok(!status, "got %#x\n", status);
2079 status = ZwOpenDirectoryObject( &handle, 0, &attr );
2080 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "got %#x\n", status);
2082 attr.Attributes = OBJ_PERMANENT;
2083 status = ZwCreateDirectoryObject( &handle, GENERIC_ALL, &attr );
2084 ok(!status, "got %#x\n", status);
2085 status = ZwClose( handle );
2086 ok(!status, "got %#x\n", status);
2088 attr.Attributes = 0;
2089 status = ZwOpenDirectoryObject( &handle, 0, &attr );
2090 ok(!status, "got %#x\n", status);
2091 status = ZwMakeTemporaryObject( handle );
2092 ok(!status, "got %#x\n", status);
2093 status = ZwMakeTemporaryObject( handle );
2094 ok(!status, "got %#x\n", status);
2095 status = ZwClose( handle );
2096 ok(!status, "got %#x\n", status);
2097 status = ZwOpenDirectoryObject( &handle, 0, &attr );
2098 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "got %#x\n", status);
2100 status = ZwCreateDirectoryObject( &handle, GENERIC_ALL, &attr );
2101 ok(!status, "got %#x\n", status);
2102 attr.Attributes = OBJ_PERMANENT;
2103 status = ZwOpenDirectoryObject( &handle2, 0, &attr );
2104 ok(status == STATUS_SUCCESS, "got %#x\n", status);
2105 status = ZwClose( handle2 );
2106 ok(!status, "got %#x\n", status);
2107 status = ZwClose( handle );
2108 ok(!status, "got %#x\n", status);
2109 attr.Attributes = 0;
2110 status = ZwOpenDirectoryObject( &handle, 0, &attr );
2111 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "got %#x\n", status);
2114 static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *stack)
2116 ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength;
2117 void *buffer = irp->AssociatedIrp.SystemBuffer;
2118 struct test_input *test_input = (struct test_input *)buffer;
2119 OBJECT_ATTRIBUTES attr = {0};
2120 UNICODE_STRING pathU;
2121 IO_STATUS_BLOCK io;
2123 if (!buffer)
2124 return STATUS_ACCESS_VIOLATION;
2125 if (length < sizeof(failures))
2126 return STATUS_BUFFER_TOO_SMALL;
2128 attr.Length = sizeof(attr);
2129 RtlInitUnicodeString(&pathU, L"\\??\\C:\\windows\\winetest_ntoskrnl_okfile");
2130 running_under_wine = test_input->running_under_wine;
2131 winetest_debug = test_input->winetest_debug;
2132 winetest_report_success = test_input->winetest_report_success;
2133 attr.ObjectName = &pathU;
2134 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE; /* needed to be accessible from system threads */
2135 ZwOpenFile(&okfile, FILE_APPEND_DATA | SYNCHRONIZE, &attr, &io,
2136 FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
2138 pExEventObjectType = get_proc_address("ExEventObjectType");
2139 ok(!!pExEventObjectType, "ExEventObjectType not found\n");
2141 pIoFileObjectType = get_proc_address("IoFileObjectType");
2142 ok(!!pIoFileObjectType, "IofileObjectType not found\n");
2144 pPsThreadType = get_proc_address("PsThreadType");
2145 ok(!!pPsThreadType, "IofileObjectType not found\n");
2147 pPsInitialSystemProcess = get_proc_address("PsInitialSystemProcess");
2148 ok(!!pPsInitialSystemProcess, "PsInitialSystemProcess not found\n");
2150 test_irp_struct(irp, device);
2151 test_current_thread(FALSE);
2152 test_critical_region(TRUE);
2153 test_mdl_map();
2154 test_init_funcs();
2155 test_load_driver();
2156 test_sync();
2157 test_version();
2158 test_stack_callout();
2159 test_lookaside_list();
2160 test_ob_reference();
2161 test_resource();
2162 test_lookup_thread();
2163 test_IoAttachDeviceToDeviceStack();
2164 test_object_name();
2165 #if defined(__i386__) || defined(__x86_64__)
2166 test_executable_pool();
2167 #endif
2168 test_affinity();
2169 test_dpc();
2170 test_process_memory(test_input);
2171 test_permanence();
2173 if (main_test_work_item) return STATUS_UNEXPECTED_IO_ERROR;
2175 main_test_work_item = IoAllocateWorkItem(lower_device);
2176 ok(main_test_work_item != NULL, "main_test_work_item = NULL\n");
2178 IoMarkIrpPending(irp);
2179 IoQueueWorkItem(main_test_work_item, main_test_task, DelayedWorkQueue, irp);
2181 return STATUS_PENDING;
2184 static NTSTATUS test_basic_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info)
2186 ULONG length = min(stack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(teststr));
2187 char *buffer = irp->AssociatedIrp.SystemBuffer;
2189 if (!buffer)
2190 return STATUS_ACCESS_VIOLATION;
2192 memcpy(buffer, teststr, length);
2193 *info = length;
2195 return STATUS_SUCCESS;
2198 static NTSTATUS get_dword(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info, DWORD value)
2200 ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength;
2201 char *buffer = irp->AssociatedIrp.SystemBuffer;
2203 if (!buffer)
2204 return STATUS_ACCESS_VIOLATION;
2206 if (length < sizeof(DWORD))
2207 return STATUS_BUFFER_TOO_SMALL;
2209 *(DWORD*)buffer = value;
2210 *info = sizeof(DWORD);
2211 return STATUS_SUCCESS;
2214 static NTSTATUS get_fscontext(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info)
2216 ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength;
2217 char *buffer = irp->AssociatedIrp.SystemBuffer;
2218 struct file_context *context = stack->FileObject->FsContext;
2220 if (!buffer)
2221 return STATUS_ACCESS_VIOLATION;
2223 if (length < sizeof(DWORD))
2224 return STATUS_BUFFER_TOO_SMALL;
2226 *(DWORD*)buffer = context->id;
2227 *info = sizeof(DWORD);
2228 return STATUS_SUCCESS;
2231 static NTSTATUS return_status(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info)
2233 char *buffer = irp->AssociatedIrp.SystemBuffer;
2234 NTSTATUS ret;
2236 if (!buffer)
2237 return STATUS_ACCESS_VIOLATION;
2239 if (stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(DWORD)
2240 || stack->Parameters.DeviceIoControl.OutputBufferLength < 3)
2241 return STATUS_BUFFER_TOO_SMALL;
2243 ret = *(DWORD *)irp->AssociatedIrp.SystemBuffer;
2244 memcpy(buffer, "ghi", 3);
2245 *info = 3;
2246 return ret;
2249 static NTSTATUS test_load_driver_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info)
2251 BOOL *load = irp->AssociatedIrp.SystemBuffer;
2252 UNICODE_STRING name;
2254 if (!load)
2255 return STATUS_ACCESS_VIOLATION;
2257 *info = 0;
2259 RtlInitUnicodeString(&name, driver2_path);
2260 if (*load)
2261 return ZwLoadDriver(&name);
2262 else
2263 return ZwUnloadDriver(&name);
2266 static NTSTATUS test_mismatched_status_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info)
2268 ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength;
2269 char *buffer = irp->UserBuffer;
2271 if (!buffer)
2273 irp->IoStatus.Status = STATUS_ACCESS_VIOLATION;
2274 IoCompleteRequest(irp, IO_NO_INCREMENT);
2275 return STATUS_ACCESS_VIOLATION;
2278 if (length < sizeof(teststr))
2280 irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
2281 IoCompleteRequest(irp, IO_NO_INCREMENT);
2282 return STATUS_BUFFER_TOO_SMALL;
2285 memcpy(buffer, teststr, sizeof(teststr));
2287 /* This is deliberate; some broken drivers do this */
2288 *info = 0;
2289 irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
2290 IoCompleteRequest(irp, IO_NO_INCREMENT);
2291 return STATUS_SUCCESS;
2294 static NTSTATUS test_completion_ioctl(DEVICE_OBJECT *device, IRP *irp)
2296 if (device == upper_device)
2298 IoCopyCurrentIrpStackLocationToNext(irp);
2299 IoSetCompletionRoutine(irp, completion_cb, upper_device, TRUE, TRUE, TRUE);
2300 return IoCallDriver(lower_device, irp);
2302 else
2304 ok(device == lower_device, "Got wrong device.\n");
2305 irp->IoStatus.Status = STATUS_SUCCESS;
2306 IoCompleteRequest(irp, IO_NO_INCREMENT);
2307 return STATUS_SUCCESS;
2311 static NTSTATUS WINAPI driver_Create(DEVICE_OBJECT *device, IRP *irp)
2313 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
2314 struct file_context *context = ExAllocatePool(PagedPool, sizeof(*context));
2316 if (!context)
2318 irp->IoStatus.Status = STATUS_NO_MEMORY;
2319 IoCompleteRequest(irp, IO_NO_INCREMENT);
2320 return STATUS_NO_MEMORY;
2323 context->id = ++create_count;
2324 context->namelen = min(irpsp->FileObject->FileName.Length, sizeof(context->name));
2325 memcpy(context->name, irpsp->FileObject->FileName.Buffer, context->namelen);
2326 irpsp->FileObject->FsContext = context;
2328 last_created_file = irpsp->FileObject;
2329 create_caller_thread = KeGetCurrentThread();
2330 create_irp_thread = irp->Tail.Overlay.Thread;
2332 irp->IoStatus.Status = STATUS_SUCCESS;
2333 IoCompleteRequest(irp, IO_NO_INCREMENT);
2334 return STATUS_SUCCESS;
2337 static NTSTATUS WINAPI driver_IoControl(DEVICE_OBJECT *device, IRP *irp)
2339 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
2340 NTSTATUS status = STATUS_NOT_SUPPORTED;
2342 switch (stack->Parameters.DeviceIoControl.IoControlCode)
2344 case IOCTL_WINETEST_BASIC_IOCTL:
2345 status = test_basic_ioctl(irp, stack, &irp->IoStatus.Information);
2346 break;
2347 case IOCTL_WINETEST_MAIN_TEST:
2348 status = main_test(device, irp, stack);
2349 break;
2350 case IOCTL_WINETEST_LOAD_DRIVER:
2351 status = test_load_driver_ioctl(irp, stack, &irp->IoStatus.Information);
2352 break;
2353 case IOCTL_WINETEST_RESET_CANCEL:
2354 cancel_cnt = 0;
2355 status = STATUS_SUCCESS;
2356 break;
2357 case IOCTL_WINETEST_TEST_CANCEL:
2358 IoSetCancelRoutine(irp, cancel_ioctl_irp);
2359 IoMarkIrpPending(irp);
2360 return STATUS_PENDING;
2361 case IOCTL_WINETEST_GET_CANCEL_COUNT:
2362 status = get_dword(irp, stack, &irp->IoStatus.Information, cancel_cnt);
2363 break;
2364 case IOCTL_WINETEST_GET_CREATE_COUNT:
2365 status = get_dword(irp, stack, &irp->IoStatus.Information, create_count);
2366 break;
2367 case IOCTL_WINETEST_GET_CLOSE_COUNT:
2368 status = get_dword(irp, stack, &irp->IoStatus.Information, close_count);
2369 break;
2370 case IOCTL_WINETEST_GET_FSCONTEXT:
2371 status = get_fscontext(irp, stack, &irp->IoStatus.Information);
2372 break;
2373 case IOCTL_WINETEST_RETURN_STATUS:
2374 status = return_status(irp, stack, &irp->IoStatus.Information);
2375 break;
2376 case IOCTL_WINETEST_DETACH:
2377 IoDetachDevice(lower_device);
2378 status = STATUS_SUCCESS;
2379 break;
2380 case IOCTL_WINETEST_MISMATCHED_STATUS:
2381 return test_mismatched_status_ioctl(irp, stack, &irp->IoStatus.Information);
2382 case IOCTL_WINETEST_COMPLETION:
2383 return test_completion_ioctl(device, irp);
2384 default:
2385 break;
2388 if (status != STATUS_PENDING)
2390 irp->IoStatus.Status = status;
2391 IoCompleteRequest(irp, IO_NO_INCREMENT);
2393 return status;
2396 static NTSTATUS WINAPI driver_FlushBuffers(DEVICE_OBJECT *device, IRP *irp)
2398 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
2399 ok(device == lower_device, "Expected device %p, got %p.\n", lower_device, device);
2400 ok(irpsp->DeviceObject == device, "device != DeviceObject\n");
2401 ok(irp->Tail.Overlay.Thread == (PETHREAD)KeGetCurrentThread(),
2402 "IRP thread is not the current thread\n");
2403 IoMarkIrpPending(irp);
2404 return STATUS_PENDING;
2407 static BOOL compare_file_name(const struct file_context *context, const WCHAR *expect)
2409 return context->namelen == wcslen(expect) * sizeof(WCHAR)
2410 && !kmemcmp(context->name, expect, context->namelen);
2413 static NTSTATUS WINAPI driver_QueryInformation(DEVICE_OBJECT *device, IRP *irp)
2415 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
2416 NTSTATUS ret;
2418 switch (stack->Parameters.QueryFile.FileInformationClass)
2420 case FileNameInformation:
2422 const struct file_context *context = stack->FileObject->FsContext;
2423 FILE_NAME_INFORMATION *info = irp->AssociatedIrp.SystemBuffer;
2424 ULONG len;
2426 if (stack->Parameters.QueryFile.Length < sizeof(*info))
2428 ret = STATUS_INFO_LENGTH_MISMATCH;
2429 break;
2432 if (compare_file_name(context, L"\\notimpl"))
2434 ret = STATUS_NOT_IMPLEMENTED;
2435 break;
2437 else if (compare_file_name(context, L""))
2439 ret = STATUS_INVALID_DEVICE_REQUEST;
2440 break;
2442 else if (compare_file_name(context, L"\\badparam"))
2444 ret = STATUS_INVALID_PARAMETER;
2445 break;
2447 else if (compare_file_name(context, L"\\genfail"))
2449 ret = STATUS_UNSUCCESSFUL;
2450 break;
2452 else if (compare_file_name(context, L"\\badtype"))
2454 ret = STATUS_OBJECT_TYPE_MISMATCH;
2455 break;
2458 len = stack->Parameters.QueryFile.Length - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2459 if (len < context->namelen)
2460 ret = STATUS_BUFFER_OVERFLOW;
2461 else
2463 len = context->namelen;
2464 ret = STATUS_SUCCESS;
2466 irp->IoStatus.Information = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + len;
2467 info->FileNameLength = context->namelen;
2468 memcpy(info->FileName, context->name, len);
2469 break;
2472 default:
2473 ret = STATUS_NOT_IMPLEMENTED;
2474 break;
2477 irp->IoStatus.Status = ret;
2478 IoCompleteRequest(irp, IO_NO_INCREMENT);
2479 return ret;
2482 static NTSTATUS WINAPI driver_QueryVolumeInformation(DEVICE_OBJECT *device, IRP *irp)
2484 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
2485 ULONG length = stack->Parameters.QueryVolume.Length;
2486 NTSTATUS ret;
2488 switch (stack->Parameters.QueryVolume.FsInformationClass)
2490 case FileFsVolumeInformation:
2492 FILE_FS_VOLUME_INFORMATION *info = irp->AssociatedIrp.SystemBuffer;
2493 static const WCHAR label[] = L"WineTestDriver";
2494 ULONG serial = 0xdeadbeef;
2496 if (length < sizeof(FILE_FS_VOLUME_INFORMATION))
2498 ret = STATUS_INFO_LENGTH_MISMATCH;
2499 break;
2502 info->VolumeCreationTime.QuadPart = 0;
2503 info->VolumeSerialNumber = serial;
2504 info->VolumeLabelLength = min( lstrlenW(label) * sizeof(WCHAR),
2505 length - offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) );
2506 info->SupportsObjects = TRUE;
2507 memcpy( info->VolumeLabel, label, info->VolumeLabelLength );
2509 irp->IoStatus.Information = offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) + info->VolumeLabelLength;
2510 ret = STATUS_SUCCESS;
2511 break;
2513 default:
2514 ret = STATUS_NOT_IMPLEMENTED;
2515 break;
2518 irp->IoStatus.Status = ret;
2519 IoCompleteRequest(irp, IO_NO_INCREMENT);
2520 return ret;
2523 static NTSTATUS WINAPI driver_Close(DEVICE_OBJECT *device, IRP *irp)
2525 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
2526 ++close_count;
2527 if (stack->FileObject->FsContext)
2528 ExFreePool(stack->FileObject->FsContext);
2529 irp->IoStatus.Status = STATUS_SUCCESS;
2530 IoCompleteRequest(irp, IO_NO_INCREMENT);
2531 return STATUS_SUCCESS;
2534 static VOID WINAPI driver_Unload(DRIVER_OBJECT *driver)
2536 UNICODE_STRING linkW;
2538 DbgPrint("unloading driver\n");
2540 RtlInitUnicodeString(&linkW, L"\\DosDevices\\WineTestDriver");
2541 IoDeleteSymbolicLink(&linkW);
2543 IoDeleteDevice(upper_device);
2544 IoDeleteDevice(lower_device);
2547 NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, PUNICODE_STRING registry)
2549 UNICODE_STRING nameW, linkW;
2550 NTSTATUS status;
2551 void *obj;
2553 DbgPrint("loading driver\n");
2555 driver_obj = driver;
2557 /* Allow unloading of the driver */
2558 driver->DriverUnload = driver_Unload;
2560 /* Set driver functions */
2561 driver->MajorFunction[IRP_MJ_CREATE] = driver_Create;
2562 driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_IoControl;
2563 driver->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = driver_FlushBuffers;
2564 driver->MajorFunction[IRP_MJ_QUERY_INFORMATION] = driver_QueryInformation;
2565 driver->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = driver_QueryVolumeInformation;
2566 driver->MajorFunction[IRP_MJ_CLOSE] = driver_Close;
2568 RtlInitUnicodeString(&nameW, L"IoDriverObjectType");
2569 pIoDriverObjectType = MmGetSystemRoutineAddress(&nameW);
2571 RtlInitUnicodeString(&nameW, L"\\Driver\\WineTestDriver");
2572 if ((status = ObReferenceObjectByName(&nameW, 0, NULL, 0, *pIoDriverObjectType, KernelMode, NULL, &obj)))
2573 return status;
2574 if (obj != driver)
2576 ObDereferenceObject(obj);
2577 return STATUS_UNSUCCESSFUL;
2579 ObDereferenceObject(obj);
2581 RtlInitUnicodeString(&nameW, L"\\Device\\WineTestDriver");
2582 RtlInitUnicodeString(&linkW, L"\\DosDevices\\WineTestDriver");
2584 if (!(status = IoCreateDevice(driver, 0, &nameW, FILE_DEVICE_UNKNOWN,
2585 FILE_DEVICE_SECURE_OPEN, FALSE, &lower_device)))
2587 status = IoCreateSymbolicLink(&linkW, &nameW);
2588 lower_device->Flags &= ~DO_DEVICE_INITIALIZING;
2591 if (!status)
2593 RtlInitUnicodeString(&nameW, L"\\Device\\WineTestUpper");
2595 status = IoCreateDevice(driver, 0, &nameW, FILE_DEVICE_UNKNOWN,
2596 FILE_DEVICE_SECURE_OPEN, FALSE, &upper_device);
2599 if (!status)
2601 IoAttachDeviceToDeviceStack(upper_device, lower_device);
2602 upper_device->Flags &= ~DO_DEVICE_INITIALIZING;
2605 return status;