/* * 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 static _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) BOOLEAN (NTAPI *pKeAreAllApcsDisabled)(VOID); #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, State, 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 ((State) <= 0) \ { \ ok_eq_long((Mutex)->Header.SignalState, State); \ 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, State); \ 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); \ if (pKeAreAllApcsDisabled) \ ok_eq_bool(pKeAreAllApcsDisabled(), AllApcsDisabled); \ ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled); \ ok_irql(Irql); \ } while (0) static VOID TestMutant(VOID) { NTSTATUS Status; KMUTANT Mutant; LONG State; LONG i; PKTHREAD Thread = KeGetCurrentThread(); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); RtlFillMemory(&Mutant, sizeof(Mutant), 0x55); KeInitializeMutant(&Mutant, FALSE); CheckMutex(&Mutant, 1L, TRUE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); RtlFillMemory(&Mutant, sizeof(Mutant), 0x55); KeInitializeMutant(&Mutant, TRUE); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); CheckMutex(&Mutant, 0L, TRUE, 0); State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE); ok_eq_long(State, 0L); CheckMutex(&Mutant, 1L, 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, 0L, TRUE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE); ok_eq_long(State, 0L); CheckMutex(&Mutant, 1L, FALSE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); /* Acquire recursively */ for (i = 0; i < 8; i++) { KmtStartSeh() Status = KeWaitForSingleObject(&Mutant, Executive, KernelMode, FALSE, NULL); KmtEndSeh(STATUS_SUCCESS); ok_eq_hex(Status, STATUS_SUCCESS); CheckMutex(&Mutant, -i, FALSE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); } for (i = 0; i < 7; i++) { KmtStartSeh() State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE); KmtEndSeh(STATUS_SUCCESS); ok_eq_long(State, -7L + i); CheckMutex(&Mutant, -6L + i, FALSE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); } State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE); ok_eq_long(State, 0L); CheckMutex(&Mutant, 1L, FALSE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); /* Pretend to acquire it recursively -MINLONG times */ KmtStartSeh() Status = KeWaitForSingleObject(&Mutant, Executive, KernelMode, FALSE, NULL); KmtEndSeh(STATUS_SUCCESS); ok_eq_hex(Status, STATUS_SUCCESS); CheckMutex(&Mutant, 0L, FALSE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); Mutant.Header.SignalState = MINLONG + 1; KmtStartSeh() Status = KeWaitForSingleObject(&Mutant, Executive, KernelMode, FALSE, NULL); KmtEndSeh(STATUS_SUCCESS); ok_eq_hex(Status, STATUS_SUCCESS); CheckMutex(&Mutant, (LONG)MINLONG, FALSE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); KmtStartSeh() KeWaitForSingleObject(&Mutant, Executive, KernelMode, FALSE, NULL); KmtEndSeh(STATUS_MUTANT_LIMIT_EXCEEDED); CheckMutex(&Mutant, (LONG)MINLONG, FALSE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE); ok_eq_long(State, (LONG)MINLONG); CheckMutex(&Mutant, (LONG)MINLONG + 1L, FALSE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); Mutant.Header.SignalState = -1; State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE); ok_eq_long(State, -1L); CheckMutex(&Mutant, 0L, FALSE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE); ok_eq_long(State, 0L); CheckMutex(&Mutant, 1L, FALSE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); /* Now release it once too often */ KmtStartSeh() KeReleaseMutant(&Mutant, 1, FALSE, FALSE); KmtEndSeh(STATUS_MUTANT_NOT_OWNED); CheckMutex(&Mutant, 1L, FALSE, 0); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); } static VOID TestMutex(VOID) { NTSTATUS Status; KMUTEX Mutex; LONG State; LONG i; PKTHREAD Thread = KeGetCurrentThread(); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); RtlFillMemory(&Mutex, sizeof(Mutex), 0x55); KeInitializeMutex(&Mutex, 0); CheckMutex(&Mutex, 1L, TRUE, 1); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); RtlFillMemory(&Mutex, sizeof(Mutex), 0x55); KeInitializeMutex(&Mutex, 123); CheckMutex(&Mutex, 1L, TRUE, 1); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); /* Acquire and release */ Status = KeWaitForSingleObject(&Mutex, Executive, KernelMode, FALSE, NULL); ok_eq_hex(Status, STATUS_SUCCESS); CheckMutex(&Mutex, 0L, FALSE, 1); CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL); State = KeReleaseMutex(&Mutex, FALSE); ok_eq_long(State, 0L); CheckMutex(&Mutex, 1L, FALSE, 1); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); /* Acquire recursively */ for (i = 0; i < 8; i++) { KmtStartSeh() Status = KeWaitForSingleObject(&Mutex, Executive, KernelMode, FALSE, NULL); KmtEndSeh(STATUS_SUCCESS); ok_eq_hex(Status, STATUS_SUCCESS); CheckMutex(&Mutex, -i, FALSE, 1); CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL); } for (i = 0; i < 7; i++) { KmtStartSeh() State = KeReleaseMutex(&Mutex, FALSE); KmtEndSeh(STATUS_SUCCESS); ok_eq_long(State, -7L + i); CheckMutex(&Mutex, -6L + i, FALSE, 1); CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL); } State = KeReleaseMutex(&Mutex, FALSE); ok_eq_long(State, 0L); CheckMutex(&Mutex, 1L, FALSE, 1); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); /* Pretend to acquire it recursively -MINLONG times */ KmtStartSeh() Status = KeWaitForSingleObject(&Mutex, Executive, KernelMode, FALSE, NULL); KmtEndSeh(STATUS_SUCCESS); ok_eq_hex(Status, STATUS_SUCCESS); CheckMutex(&Mutex, 0L, FALSE, 1); CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL); Mutex.Header.SignalState = MINLONG + 1; KmtStartSeh() Status = KeWaitForSingleObject(&Mutex, Executive, KernelMode, FALSE, NULL); KmtEndSeh(STATUS_SUCCESS); ok_eq_hex(Status, STATUS_SUCCESS); CheckMutex(&Mutex, (LONG)MINLONG, FALSE, 1); CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL); KmtStartSeh() KeWaitForSingleObject(&Mutex, Executive, KernelMode, FALSE, NULL); KmtEndSeh(STATUS_MUTANT_LIMIT_EXCEEDED); CheckMutex(&Mutex, (LONG)MINLONG, FALSE, 1); CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL); State = KeReleaseMutex(&Mutex, FALSE); ok_eq_long(State, (LONG)MINLONG); CheckMutex(&Mutex, (LONG)MINLONG + 1L, FALSE, 1); CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL); Mutex.Header.SignalState = -1; State = KeReleaseMutex(&Mutex, FALSE); ok_eq_long(State, -1L); CheckMutex(&Mutex, 0L, FALSE, 1); CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL); State = KeReleaseMutex(&Mutex, FALSE); ok_eq_long(State, 0L); CheckMutex(&Mutex, 1L, FALSE, 1); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); /* Now release it once too often */ KmtStartSeh() KeReleaseMutex(&Mutex, FALSE); KmtEndSeh(STATUS_MUTANT_NOT_OWNED); CheckMutex(&Mutex, 1L, FALSE, 1); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); } START_TEST(KeMutex) { pKeAreAllApcsDisabled = KmtGetSystemRoutineAddress(L"KeAreAllApcsDisabled"); if (skip(pKeAreAllApcsDisabled != NULL, "KeAreAllApcsDisabled unavailable\n")) { /* We can live without this function here */ } TestMutant(); TestMutex(); }