/* * PROJECT: ReactOS kernel-mode tests * LICENSE: GPLv2+ - See COPYING in the top level directory * PURPOSE: Kernel-Mode Test Suite Mutant/Mutex test * PROGRAMMER: Thomas Faber */ #include #define ULONGS_PER_POINTER (sizeof(PVOID) / sizeof(ULONG)) #define MUTANT_SIZE (2 + 6 * ULONGS_PER_POINTER) C_ASSERT(sizeof(DISPATCHER_HEADER) == 8 + 2 * sizeof(PVOID)); C_ASSERT(sizeof(KMUTANT) == sizeof(DISPATCHER_HEADER) + 3 * sizeof(PVOID) + sizeof(PVOID)); C_ASSERT(sizeof(KMUTANT) == MUTANT_SIZE * sizeof(ULONG)); #define CheckMutex(Mutex, Held, New, ExpectedApcDisable) do { \ PKTHREAD Thread = KeGetCurrentThread(); \ ok_eq_uint((Mutex)->Header.Type, MutantObject); \ ok_eq_uint((Mutex)->Header.Abandoned, 0x55); \ ok_eq_uint((Mutex)->Header.Size, MUTANT_SIZE); \ ok_eq_uint((Mutex)->Header.DpcActive, 0x55); \ ok_eq_pointer((Mutex)->Header.WaitListHead.Flink, \ &(Mutex)->Header.WaitListHead); \ ok_eq_pointer((Mutex)->Header.WaitListHead.Blink, \ &(Mutex)->Header.WaitListHead); \ if (Held) \ { \ ok_eq_long((Mutex)->Header.SignalState, 0); \ ok_eq_pointer((Mutex)->MutantListEntry.Flink, &Thread->MutantListHead); \ ok_eq_pointer((Mutex)->MutantListEntry.Blink, &Thread->MutantListHead); \ ok_eq_pointer(Thread->MutantListHead.Flink, &(Mutex)->MutantListEntry); \ ok_eq_pointer(Thread->MutantListHead.Blink, &(Mutex)->MutantListEntry); \ ok_eq_pointer((Mutex)->OwnerThread, Thread); \ } \ else \ { \ ok_eq_long((Mutex)->Header.SignalState, 1); \ if (New) \ { \ ok_eq_pointer((Mutex)->MutantListEntry.Flink, \ (PVOID)0x5555555555555555ULL); \ ok_eq_pointer((Mutex)->MutantListEntry.Blink, \ (PVOID)0x5555555555555555ULL); \ } \ ok_eq_pointer(Thread->MutantListHead.Flink, &Thread->MutantListHead); \ ok_eq_pointer(Thread->MutantListHead.Blink, &Thread->MutantListHead); \ ok_eq_pointer((Mutex)->OwnerThread, NULL); \ } \ ok_eq_uint((Mutex)->Abandoned, 0); \ ok_eq_uint((Mutex)->ApcDisable, ExpectedApcDisable); \ } while (0) #define CheckApcs(KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, Irql) do \ { \ ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled); \ ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled); \ ok_eq_bool(KeAreAllApcsDisabled(), AllApcsDisabled); \ ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled); \ ok_irql(Irql); \ } while (0) static VOID TestMutant(VOID) { NTSTATUS Status; KMUTANT Mutant; LONG State; PKTHREAD Thread = KeGetCurrentThread(); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); RtlFillMemory(&Mutant, sizeof(Mutant), 0x55); KeInitializeMutant(&Mutant, FALSE); CheckMutex(&Mutant, FALSE, TRUE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); RtlFillMemory(&Mutant, sizeof(Mutant), 0x55); KeInitializeMutant(&Mutant, TRUE); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); CheckMutex(&Mutant, TRUE, TRUE, 0); State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE); ok_eq_long(State, 0); CheckMutex(&Mutant, FALSE, FALSE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); /* Acquire and release */ Status = KeWaitForSingleObject(&Mutant, Executive, KernelMode, FALSE, NULL); ok_eq_hex(Status, STATUS_SUCCESS); CheckMutex(&Mutant, TRUE, TRUE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE); ok_eq_long(State, 0); CheckMutex(&Mutant, FALSE, FALSE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); } static VOID TestMutex(VOID) { NTSTATUS Status; KMUTEX Mutex; LONG State; PKTHREAD Thread = KeGetCurrentThread(); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); RtlFillMemory(&Mutex, sizeof(Mutex), 0x55); KeInitializeMutex(&Mutex, 0); CheckMutex(&Mutex, FALSE, TRUE, 1); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); RtlFillMemory(&Mutex, sizeof(Mutex), 0x55); KeInitializeMutex(&Mutex, 123); CheckMutex(&Mutex, FALSE, TRUE, 1); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); Status = KeWaitForSingleObject(&Mutex, Executive, KernelMode, FALSE, NULL); ok_eq_hex(Status, STATUS_SUCCESS); CheckMutex(&Mutex, TRUE, FALSE, 1); CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL); State = KeReleaseMutex(&Mutex, FALSE); ok_eq_long(State, 0); CheckMutex(&Mutex, FALSE, FALSE, 1); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); } START_TEST(KeMutex) { TestMutant(); TestMutex(); }