NTSTATUS PhpServiceNonPollThreadStart( _In_ PVOID Parameter ) { ULONG result; SC_HANDLE scManagerHandle; LPENUM_SERVICE_STATUS_PROCESS services; ULONG numberOfServices; ULONG i; PLIST_ENTRY listEntry; PPHP_SERVICE_NOTIFY_CONTEXT notifyContext; if (!NT_SUCCESS(NtCreateEvent(&PhpNonPollEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE))) { PhpNonPollActive = FALSE; PhpNonPollGate = 1; return STATUS_UNSUCCESSFUL; } while (TRUE) { scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); if (!scManagerHandle) goto ErrorExit; InitializeListHead(&PhpNonPollServiceListHead); InitializeListHead(&PhpNonPollServicePendingListHead); if (!(services = PhEnumServices(scManagerHandle, 0, 0, &numberOfServices))) goto ErrorExit; for (i = 0; i < numberOfServices; i++) { SC_HANDLE serviceHandle; if (serviceHandle = OpenService(scManagerHandle, services[i].lpServiceName, SERVICE_QUERY_STATUS)) { notifyContext = PhAllocate(sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); memset(notifyContext, 0, sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); notifyContext->ServiceHandle = serviceHandle; notifyContext->State = SnNotify; InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry); } } PhFree(services); notifyContext = PhAllocate(sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); memset(notifyContext, 0, sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); notifyContext->ServiceHandle = scManagerHandle; notifyContext->IsServiceManager = TRUE; notifyContext->State = SnNotify; InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry); while (TRUE) { BOOLEAN lagging = FALSE; listEntry = PhpNonPollServicePendingListHead.Flink; while (listEntry != &PhpNonPollServicePendingListHead) { notifyContext = CONTAINING_RECORD(listEntry, PHP_SERVICE_NOTIFY_CONTEXT, ListEntry); listEntry = listEntry->Flink; switch (notifyContext->State) { case SnNone: break; case SnAdding: notifyContext->ServiceHandle = OpenService(scManagerHandle, notifyContext->ServiceName->Buffer, SERVICE_QUERY_STATUS); if (!notifyContext->ServiceHandle) { RemoveEntryList(¬ifyContext->ListEntry); PhpDestroyServiceNotifyContext(notifyContext); continue; } PhClearReference(¬ifyContext->ServiceName); notifyContext->State = SnNotify; goto NotifyCase; case SnRemoving: RemoveEntryList(¬ifyContext->ListEntry); PhpDestroyServiceNotifyContext(notifyContext); break; case SnNotify: NotifyCase: memset(¬ifyContext->Buffer, 0, sizeof(SERVICE_NOTIFY)); notifyContext->Buffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE; notifyContext->Buffer.pfnNotifyCallback = PhpServiceNonPollScNotifyCallback; notifyContext->Buffer.pContext = notifyContext; result = NotifyServiceStatusChangeW_I( notifyContext->ServiceHandle, notifyContext->IsServiceManager ? (SERVICE_NOTIFY_CREATED | SERVICE_NOTIFY_DELETED) : (SERVICE_NOTIFY_STOPPED | SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_STOP_PENDING | SERVICE_NOTIFY_RUNNING | SERVICE_NOTIFY_CONTINUE_PENDING | SERVICE_NOTIFY_PAUSE_PENDING | SERVICE_NOTIFY_PAUSED | SERVICE_NOTIFY_DELETE_PENDING), ¬ifyContext->Buffer ); switch (result) { case ERROR_SUCCESS: notifyContext->State = SnNone; RemoveEntryList(¬ifyContext->ListEntry); InsertTailList(&PhpNonPollServiceListHead, ¬ifyContext->ListEntry); break; case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING: // We are lagging behind. Re-open the handle to the SCM as soon as possible. lagging = TRUE; break; case ERROR_SERVICE_MARKED_FOR_DELETE: default: RemoveEntryList(¬ifyContext->ListEntry); PhpDestroyServiceNotifyContext(notifyContext); break; } break; } } while (NtWaitForSingleObject(PhpNonPollEventHandle, TRUE, NULL) != STATUS_WAIT_0) NOTHING; if (lagging) break; } // Execute all pending callbacks. NtTestAlert(); listEntry = PhpNonPollServiceListHead.Flink; while (listEntry != &PhpNonPollServiceListHead) { notifyContext = CONTAINING_RECORD(listEntry, PHP_SERVICE_NOTIFY_CONTEXT, ListEntry); listEntry = listEntry->Flink; PhpDestroyServiceNotifyContext(notifyContext); } listEntry = PhpNonPollServicePendingListHead.Flink; while (listEntry != &PhpNonPollServicePendingListHead) { notifyContext = CONTAINING_RECORD(listEntry, PHP_SERVICE_NOTIFY_CONTEXT, ListEntry); listEntry = listEntry->Flink; PhpDestroyServiceNotifyContext(notifyContext); } CloseServiceHandle(scManagerHandle); } NtClose(PhpNonPollEventHandle); return STATUS_SUCCESS; ErrorExit: PhpNonPollActive = FALSE; PhpNonPollGate = 1; NtClose(PhpNonPollEventHandle); return STATUS_UNSUCCESSFUL; }
void main( int argc, char *argv[] ) { NTSTATUS status; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE BaseHandle; HANDLE EventHandle; PIO_APC_ROUTINE ApcRoutine; // // Process args // KeyName.MaximumLength = WORK_SIZE; KeyName.Length = 0L; KeyName.Buffer = &(workbuffer[0]); processargs(argc, argv); // // Set up and open KeyPath // printf("rtnotify: starting\n"); InitializeObjectAttributes( &ObjectAttributes, &KeyName, 0, (HANDLE)NULL, NULL ); ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE; status = NtOpenKey( &BaseHandle, KEY_NOTIFY, &ObjectAttributes ); if (!NT_SUCCESS(status)) { printf("rtnotify: t0: %08lx\n", status); exit(1); } EventHandle = (HANDLE)NULL; if (UseEvent == TRUE) { status = NtCreateEvent( &EventHandle, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, NULL, NotificationEvent, FALSE ); if (!NT_SUCCESS(status)) { printf("rtnotify: t1: %08lx\n", status); exit(1); } } ApcRoutine = NULL; if (UseApc) { ApcRoutine = ApcTest; } printf("rtnotify:\n"); printf("\tUseEvent = %08lx\n", UseEvent); printf("\tApcRoutine = %08lx\n", ApcRoutine); printf("\tHold = %08lx\n", Hold); printf("\tFilter = %08lx\n", Filter); printf("\tWatchTree = %08lx\n", WatchTree); while (TRUE) { ApcSeen = FALSE; printf("\nCallCount = %dt\n", CallCount); CallCount++; status = NtNotifyChangeKey( BaseHandle, EventHandle, ApcRoutine, (PVOID)1992, // arbitrary context value &RtIoStatusBlock, Filter, WatchTree, NULL, 0, ! Hold ); exit(0); if ( ! NT_SUCCESS(status)) { printf("rtnotify: t2: %08lx\n", status); exit(1); } if (Hold) { printf("rtnotify: Synchronous Status = %08lx\n", RtIoStatusBlock.Status); } if (UseEvent) { status = NtWaitForSingleObject( EventHandle, TRUE, NULL ); if (!NT_SUCCESS(status)) { printf("rtnotify: t3: status = %08lx\n", status); exit(1); } printf("rtnotify: Event Status = %08lx\n", RtIoStatusBlock.Status); } if (UseApc) { while ((volatile)ApcSeen == FALSE) { NtTestAlert(); } } } NtClose(BaseHandle); exit(0); }