Freigeben über


PCW_CALLBACK Rückruffunktion (wdm.h)

Anbieter können optional eine PCW_CALLBACK Funktion implementieren, um Benachrichtigungen zu empfangen, wenn Consumer Anforderungen stellen, z. B. das Aufzählen von Instanzen oder das Sammeln von Countersetdaten. Die Leistungsindikatorbibliothek (PERFLIB Version 2.0) ruft die PCW_CALLBACK Funktion auf, bevor die Anforderung des Consumers abgeschlossen wird.

Syntax

PCW_CALLBACK PcwCallback;

NTSTATUS PcwCallback(
  [in]           PCW_CALLBACK_TYPE Type,
  [in]           PPCW_CALLBACK_INFORMATION Info,
  [in, optional] PVOID Context
)
{...}

Parameter

[in] Type

Ein PCW_CALLBACK_TYPE Enumerationswert, der angibt, warum der Rückruf aufgerufen wurde. Mögliche Werte sind PcwCallbackAddCounter, PcwCallbackRemoveCounter, PcwCallbackEnumerateInstances und PcwCallbackCollectData.

[in] Info

Ein Zeiger auf einen PCW_CALLBACK_INFORMATION Union, der Details dazu liefert, warum der Anbieterrückruf aufgerufen wurde. Die Details werden in dem Feld angezeigt, das dem Type Parameter entspricht. Wenn die Details z. Type == PcwCallbackEnumerateInstances B. in Info->EnumerateInstancessind.

[in, optional] Context

Der Rückrufkontext, der vom Anbieter beim Aufrufen von PcwRegister oder beim Aufrufen der von CTRPP generierten Register-Funktion (die aufruft PcwRegister) bereitgestellt wurde.

Rückgabewert

Die PCW_CALLBACK Rückruffunktion sollte zurückgeben STATUS_SUCCESS , wenn der Rückruf ohne Fehler abgeschlossen wurde, oder andernfalls einen NTSTATUS Fehlercode. Beachten Sie, dass dieser Rückgabecode nur zu Informationszwecken dient und dass die Verarbeitung der Anforderung des Consumers auch dann fortgesetzt wird, wenn der Rückruf einen Fehler zurückgibt.

Hinweise

Counterset-Anbieter können dem Verbraucher Informationen über zwei verschiedene Systeme bereitstellen:

  • Der Anbieter kann und PcwCloseInstance verwendenPcwCreateInstance, um eine Liste der verfügbaren Instanzen und die entsprechenden Zählerdaten zu verwalten. Dieses System ist einfach zu implementieren, aber begrenzt in der Flexibilität. Bei Verwendung dieses Systems muss der Anbieter keine Rückruffunktion bereitstellen. Weitere Informationen zu diesem System finden Sie in der Dokumentation zu PcwCreateInstance.

  • Der Anbieter kann eine PCW_CALLBACK Funktion bereitstellen, die von der Leistungsindikatorbibliothek bei Bedarf zum Sammeln von Daten aufgerufen wird.

Die Rückrufimplementierung muss threadsicher sein. Mehrere verschiedene Consumer können gleichzeitig Daten vom Anbieter in verschiedenen Threads anfordern.

Der Rückruf muss die Anforderungstypen PcwCallbackEnumerateInstances und PcwCallbackCollectData verarbeiten. Der Rückruf muss in der Regel keine anderen Anforderungstypen verarbeiten, aber in komplexen Szenarien kann der Rückruf auch verarbeiten PcwCallbackAddCounter und PcwCallbackRemoveCounter die Datensammlung optimieren (d. h. um die Statistiknachverfolgung zu deaktivieren, wenn keine Abfragen aktiv sind).

Der Rückruf ist für das Generieren und NameId von Werten für die Countersetinstanzen verantwortlich.

  • Instanzwerte Id MÜSSEN im Laufe der Zeit stabil sein (dieselbe logische instance sollte denselben Id Wert für alle Aufrufe des Rückrufs verwenden), eindeutig sein (z. B. verwenden Sie nicht einfach 0 für alle Instanzen), und sie sollten kleiner als 0xFFFFFFFE sein (nicht verwendenPCW_ANY_INSTANCE_ID). Wenn möglich, sollte die instance Id sinnvoll sein (z. B. kann eine Prozesszählermenge eine PID als Id) anstelle von willkürlich (z. B. eine Sequenznummer) verwenden.

  • Instanzwerte Name MÜSSEN im Laufe der Zeit stabil sein (die gleiche logische instance sollte denselben Name Wert für alle Aufrufe des Rückrufs verwenden) und MÜSSEN eindeutig sein. Wenn der Indikatorsatz mehrere Instanzen unterstützt, sollte die instance Name nicht leer sein. Der Zeichenfolgenabgleich erfolgt mithilfe eines Vergleichs ohne Berücksichtigung der Groß-/Kleinschreibung, sodass Name sich die Werte nicht nur nach Groß-/Kleinschreibung unterscheiden sollten.

Bei der Verarbeitung von PcwCallbackCollectData Anforderungen ruft eine einfache Rückrufimplementierung pcwAddInstance (oder die von CTRPP generierte AddXxx-Funktion) einfach einmal für jede Counterset-instance auf. Weitere Informationen finden Sie unter Von CTRPP generierte AddXxx-Funktion.

Die folgenden Optimierungen können bei Bedarf in erweiterten Implementierungen verwendet werden:

  • Wenn Info->CollectData.CounterMask != (UINT64)-1 dann benötigt der Consumer nicht alle Leistungsindikatoren in der Counterset. In diesem Fall kann der Rückruf die Datensammlung optimieren, indem die entsprechenden Werte im Zählerdatenblock als 0 belassen werden.

  • Wenn Info->CollectData.InstanceId != PCW_ANY_INSTANCE_ID der Consumer nur Daten zu -Instanzen mit einem InstanceId -Wert benötigt, der CollectData.InstanceIdgleich ist. Der Rückruf kann die Datensammlung optimieren, indem der Aufruf PcwAddInstance von für Instanzen mit nicht übereinstimmendem InstanceIdübersprungen wird.

  • Wenn Info->CollectData.InstanceMask != "*" der Consumer nur Daten zu Instanzen mit einem InstanceName möchte, das dem Wildcardmuster von CollectData.InstanceMaskentspricht. Der Rückruf kann die Datensammlung optimieren, indem der Aufruf PcwAddInstance von für Instanzen mit nicht übereinstimmendem InstanceNameübersprungen wird. Die richtige Implementierung des Wildcardabgleichs ist schwierig, sodass diese Optimierung nur dann empfohlen wird, wenn instance Datenerfassung sehr teuer ist.

In den meisten Fällen ist die Rückrufimplementierung für eine PcwCallbackEnumerateInstances Anforderung mit der Implementierung für eine PcwCallbackCollectDataidentisch. Der Rückruf kann optional die Datensammlung optimieren, indem die tatsächlichen Zählerdaten im Aufruf PcwAddInstance von weggelassen werden (d. h. durch Übergeben von 0 und NULL für die Count Parameter und Data ).

Eine Rückrufimplementierung kann wie folgt strukturiert sein:

NTSTATUS NTAPI
MyProviderCallback(
    _In_ PCW_CALLBACK_TYPE Type,
    _In_ PPCW_CALLBACK_INFORMATION Info,
    _In_opt_ PVOID Context)
{
    PCW_MASK_INFORMATION* MaskInfo;
    PAGED_CODE();

    switch (Type)
    {
    case PcwCallbackCollectData:
        MaskInfo = &Info->CollectData;
        break;

    case PcwCallbackEnumerateInstances:
        MaskInfo = &Info->EnumerateInstances;
        break;

    case PcwCallbackAddCounter:
        // Optional (for optimizing data collection):
        // InterlockedIncrement(&CollectionEnableCount);
        return STATUS_SUCCESS; // Normally no action needed.

    case PcwCallbackRemoveCounter:
        // Optional (for optimizing data collection):
        // InterlockedDecrement(&CollectionEnableCount);
        return STATUS_SUCCESS; // Normally no action needed.
    }

    // Common code for CollectData and EnumerateInstances.
    // Note that this code needs to be thread-safe, as multiple
    // threads might invoke this callback at the same time.

    for (Instance : InstanceList) { // Pseudocode, need thread-safe enumeration
        NTSTATUS Status;

        // Optional optimization:
        // if (MaskInfo->InstanceId != PCW_ANY_INSTANCE_ID && Instance->Id != MaskInfo->InstanceId) {
        //     continue;
        // }

        // Note that in most cases, you'll use a CTRPP-generated Add wrapper instead of directly
        // calling PcwAddInstance.
        Status = PcwAddInstance(MaskInfo->Buffer,
                                &Instance->Name,
                                Instance->Id,
                                1, // Number of items in PcwData array
                                &Instance->PcwData);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }
    }

    return STATUS_SUCCESS;
}

Die meisten Countersetanbieter verwenden das CTRPP-Tool , um ihr Countersetmanifest zu verarbeiten und Hilfsfunktionen zu generieren, einschließlich Funktionsumbruch PcwRegister (CTRPP generiert die Indikatorendeskriptoren) und PcwAddInstance (CTRPP generiert Code zum Umschließen der Datenstrukturen des Anbieters in das von PcwAddInstanceerforderliche Format).

Als Referenz in diesem Beispiel ist die von CTRPP generierte Register-Funktion für das KCS.man Manifest aus dem KCS-Beispiel aufgeführt.

EXTERN_C FORCEINLINE NTSTATUS
KcsRegisterGeometricWave(
    __in_opt PPCW_CALLBACK Callback,
    __in_opt PVOID CallbackContext
    )
{
    PCW_REGISTRATION_INFORMATION RegInfo;
    UNICODE_STRING Name = RTL_CONSTANT_STRING(L"Geometric Waves");
    PCW_COUNTER_DESCRIPTOR Descriptors[] = {
        { 1, 0, FIELD_OFFSET(GEOMETRIC_WAVE_VALUES, Triangle), RTL_FIELD_SIZE(GEOMETRIC_WAVE_VALUES, Triangle)},
        { 2, 0, FIELD_OFFSET(GEOMETRIC_WAVE_VALUES, Square), RTL_FIELD_SIZE(GEOMETRIC_WAVE_VALUES, Square)},
    };

    PAGED_CODE();

    RtlZeroMemory(&RegInfo, sizeof RegInfo);

    RegInfo.Version = PCW_CURRENT_VERSION;
    RegInfo.Counters = Descriptors;
    RegInfo.CounterCount = RTL_NUMBER_OF(Descriptors);
    RegInfo.Callback = Callback;
    RegInfo.CallbackContext = CallbackContext;
    RegInfo.Name = &Name;

    return PcwRegister(&KcsGeometricWave, &RegInfo);
}

Der Countersetanbieter implementiert die PCW_CALLBACK -Funktion, um Consumeranforderungen zu verarbeiten. Das folgende Codebeispiel zeigt eine PCW_CALLBACK Funktion namens KcsGeometricWaveCallback , die simulierte Daten aufzählt und sammelt. (Beachten Sie, dass KcsAddGeometricWave eine von CTRPP generierte Hilfsfunktion ist, die aufruft PcwAddInstance.)

NTSTATUS
KcsAddGeometricInstance (
    _In_ PPCW_BUFFER Buffer,
    _In_ PCWSTR Name,
    _In_ ULONG Id,
    _In_ ULONG MinimalValue,
    _In_ ULONG Amplitude
    )
{
    ULONG Index;
    LARGE_INTEGER Timestamp;
    UNICODE_STRING UnicodeName;
    GEOMETRIC_WAVE_VALUES Values;

    PAGED_CODE();

    KeQuerySystemTime(&Timestamp);

    Index = (Timestamp.QuadPart / 10000000) % 10;

    Values.Triangle = MinimalValue + Amplitude * abs(5 - Index) / 5;
    Values.Square = MinimalValue + Amplitude * (Index < 5);

    RtlInitUnicodeString(&UnicodeName, Name);

    return KcsAddGeometricWave(Buffer, &UnicodeName, Id, &Values);
}

NTSTATUS NTAPI
KcsGeometricWaveCallback (
    __in PCW_CALLBACK_TYPE Type,
    __in PPCW_CALLBACK_INFORMATION Info,
    __in_opt PVOID Context
    )
{
    NTSTATUS Status;
    UNICODE_STRING UnicodeName;

    UNREFERENCED_PARAMETER(Context);

    PAGED_CODE();

    switch (Type) {
    case PcwCallbackEnumerateInstances:

        //
        // Instances are being enumerated, so we add them without values.
        //

        RtlInitUnicodeString(&UnicodeName, L"Small Wave");
        Status = KcsAddGeometricWave(Info->EnumerateInstances.Buffer,
                                     &UnicodeName,
                                     0,
                                     NULL);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }

        RtlInitUnicodeString(&UnicodeName, L"Medium Wave");
        Status = KcsAddGeometricWave(Info->EnumerateInstances.Buffer,
                                     &UnicodeName,
                                     1,
                                     NULL);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }

        RtlInitUnicodeString(&UnicodeName, L"Large Wave");
        Status = KcsAddGeometricWave(Info->EnumerateInstances.Buffer,
                                     &UnicodeName,
                                     2,
                                     NULL);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }

        break;

 case PcwCallbackCollectData:

        //
        // Add values for 3 instances of Geometric Wave Counterset.
        //

        Status = KcsAddGeometricInstance(Info->CollectData.Buffer,
                                         L"Small Wave",
                                         0,
                                         40,
                                         20);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }

        Status = KcsAddGeometricInstance(Info->CollectData.Buffer,
                                         L"Medium Wave",
                                         1,
                                         30,
                                         40);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }

        Status = KcsAddGeometricInstance(Info->CollectData.Buffer,
                                         L"Large Wave",
                                         2,
                                         20,
                                         60);
        if (!NT_SUCCESS(Status)) {
            return Status;
        }

        break;
    }

    return STATUS_SUCCESS;
}

In der DriverEntry Routine des KCS-Beispiels wird die KcsGeometricWaveCallback Funktion als Callback angegeben, wenn KcsRegisterGeometricWave die Zählermenge registriert wird.

    //
    // Register Countersets during DriverEntry. (TODO: Unregister at driver unload.)
    //

    Status = KcsRegisterGeometricWave(KcsGeometricWaveCallback, NULL);
    if (!NT_SUCCESS(Status)) {
        return Status;
    }

Anforderungen

Anforderung Wert
Unterstützte Mindestversion (Client) Verfügbar in Windows 7 und späteren Windows-Versionen.
Zielplattform Desktop
Kopfzeile wdm.h (include Wdm.h, Ntddk.h)
IRQL IRQL <=APC_LEVEL

Weitere Informationen

PcwRegister

PcwAddInstance

PcwCreateInstance

PCW_CALLBACK_TYPE

PCW_CALLBACK_INFORMATION

CTRPP

Leistungsindikatorbibliothek (PERFLIB Version 2.0)