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->EnumerateInstances
sind.
[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 Name
Id
von Werten für die Countersetinstanzen verantwortlich.
Instanzwerte
Id
MÜSSEN im Laufe der Zeit stabil sein (dieselbe logische instance sollte denselbenId
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 instanceId
sinnvoll sein (z. B. kann eine Prozesszählermenge eine PID alsId
) anstelle von willkürlich (z. B. eine Sequenznummer) verwenden.Instanzwerte
Name
MÜSSEN im Laufe der Zeit stabil sein (die gleiche logische instance sollte denselbenName
Wert für alle Aufrufe des Rückrufs verwenden) und MÜSSEN eindeutig sein. Wenn der Indikatorsatz mehrere Instanzen unterstützt, sollte die instanceName
nicht leer sein. Der Zeichenfolgenabgleich erfolgt mithilfe eines Vergleichs ohne Berücksichtigung der Groß-/Kleinschreibung, sodassName
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 einemInstanceId
-Wert benötigt, derCollectData.InstanceId
gleich ist. Der Rückruf kann die Datensammlung optimieren, indem der AufrufPcwAddInstance
von für Instanzen mit nicht übereinstimmendemInstanceId
übersprungen wird.Wenn
Info->CollectData.InstanceMask != "*"
der Consumer nur Daten zu Instanzen mit einemInstanceName
möchte, das dem Wildcardmuster vonCollectData.InstanceMask
entspricht. Der Rückruf kann die Datensammlung optimieren, indem der AufrufPcwAddInstance
von für Instanzen mit nicht übereinstimmendemInstanceName
ü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 PcwCallbackCollectData
identisch. 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 PcwAddInstance
erforderliche 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 |