PCW_CALLBACK fungsi panggilan balik (wdm.h)
Penyedia dapat secara opsional menerapkan PCW_CALLBACK
fungsi untuk menerima pemberitahuan ketika konsumen membuat permintaan seperti menghitung instans atau mengumpulkan data counterset. Pustaka Penghitung Kinerja (PERFLIB versi 2.0) memanggil PCW_CALLBACK
fungsi sebelum menyelesaikan permintaan konsumen.
Sintaks
PCW_CALLBACK PcwCallback;
NTSTATUS PcwCallback(
[in] PCW_CALLBACK_TYPE Type,
[in] PPCW_CALLBACK_INFORMATION Info,
[in, optional] PVOID Context
)
{...}
Parameter
[in] Type
Nilai enumerasi PCW_CALLBACK_TYPE yang menunjukkan mengapa panggilan balik dipanggil. Nilai yang mungkin adalah PcwCallbackAddCounter
, PcwCallbackRemoveCounter
, PcwCallbackEnumerateInstances
, dan PcwCallbackCollectData
.
[in] Info
Pointer ke serikat PCW_CALLBACK_INFORMATION yang menyediakan detail tentang mengapa panggilan balik penyedia dipanggil. Detailnya akan berada di bidang yang sesuai dengan Type
parameter . Misalnya, jika Type == PcwCallbackEnumerateInstances
maka detailnya akan ada di Info->EnumerateInstances
.
[in, optional] Context
Konteks panggilan balik yang disediakan oleh penyedia saat memanggil PcwRegister atau saat memanggil fungsi Register yang dihasilkan CTRPP (yang memanggil PcwRegister
).
Mengembalikan nilai
Fungsi PCW_CALLBACK
panggilan balik harus kembali STATUS_SUCCESS
jika panggilan balik selesai tanpa kesalahan, atau NTSTATUS
kode kesalahan sebaliknya. Perhatikan bahwa kode pengembalian ini hanya untuk tujuan informasi dan pemrosesan permintaan konsumen akan berlanjut bahkan jika panggilan balik mengembalikan kesalahan.
Keterangan
Penyedia counterset dapat menyediakan informasi kepada konsumen melalui dua sistem yang berbeda:
Penyedia dapat menggunakan
PcwCreateInstance
danPcwCloseInstance
untuk mempertahankan daftar instans yang tersedia dan data penghitung yang sesuai. Sistem ini mudah diterapkan tetapi terbatas pada fleksibilitas. Saat menggunakan sistem ini, penyedia tidak perlu menyediakan fungsi panggilan balik. Untuk informasi selengkapnya tentang sistem ini, lihat dokumentasi untuk PcwCreateInstance.Penyedia dapat menyediakan
PCW_CALLBACK
fungsi yang akan dipanggil oleh Pustaka Penghitung Kinerja sesuai kebutuhan untuk mengumpulkan data.
Implementasi panggilan balik harus aman untuk utas. Beberapa konsumen yang berbeda mungkin secara bersamaan meminta data dari penyedia pada utas yang berbeda.
Panggilan balik harus menangani PcwCallbackEnumerateInstances
jenis permintaan dan PcwCallbackCollectData
. Panggilan balik biasanya tidak perlu menangani jenis permintaan lain, tetapi dalam skenario kompleks panggilan balik mungkin juga menangani PcwCallbackAddCounter
dan PcwCallbackRemoveCounter
untuk mengoptimalkan pengumpulan data (yaitu untuk menonaktifkan pelacakan statistik ketika tidak ada kueri yang aktif).
Panggilan balik bertanggung jawab untuk menghasilkan Name
nilai dan Id
untuk instans counterset.
Nilai instans
Id
HARUS stabil dari waktu ke waktu (instans logis yang sama harus menggunakan nilai yang samaId
untuk semua pemanggilan panggilan balik), harus unik (misalnya jangan hanya menggunakan 0 untuk semua instans), dan harus kurang dari 0xFFFFFFFE (jangan gunakanPCW_ANY_INSTANCE_ID
). Jika memungkinkan, instansId
harus bermakna (misalnya, penghitung Proses mungkin menggunakan PID sebagaiId
) alih-alih arbitrer (misalnya nomor urut).Nilai instans
Name
HARUS stabil dari waktu ke waktu (instans logis yang sama harus menggunakan nilai yang samaName
untuk semua pemanggilan panggilan balik) dan HARUS unik. Jika counterset mendukung beberapa instans, instansName
tidak boleh kosong. Pencocokan string dilakukan menggunakan perbandingan yang tidak peka huruf besar/kecil, sehinggaName
nilai tidak boleh berbeda hanya menurut kasus.
Saat menangani PcwCallbackCollectData
permintaan, implementasi panggilan balik dasar hanya akan memanggil PcwAddInstance (atau fungsi AddXxx yang dihasilkan CTRPP) sekali untuk setiap instans counterset. Untuk informasi selengkapnya, lihat Fungsi AddXxx yang dihasilkan CTRPP.
Pengoptimalan berikut dapat digunakan dalam implementasi yang lebih canggih jika perlu:
Jika
Info->CollectData.CounterMask != (UINT64)-1
kemudian konsumen tidak memerlukan semua penghitung dalam counterset. Dalam hal ini, panggilan balik dapat mengoptimalkan pengumpulan data dengan meninggalkan nilai yang sesuai sebagai 0 di blok data penghitung.Jika
Info->CollectData.InstanceId != PCW_ANY_INSTANCE_ID
kemudian konsumen hanya menginginkan data tentang instans dengan yangInstanceId
sama denganCollectData.InstanceId
. Panggilan balik dapat mengoptimalkan pengumpulan data dengan melewatkan panggilan kePcwAddInstance
untuk instans dengan yang tidak cocokInstanceId
.Jika
Info->CollectData.InstanceMask != "*"
kemudian konsumen hanya menginginkan data tentang instans dengan yang cocok denganInstanceName
polaCollectData.InstanceMask
wildcard . Panggilan balik dapat mengoptimalkan pengumpulan data dengan melewatkan panggilan kePcwAddInstance
untuk instans dengan yang tidak cocokInstanceName
. Pencocokan wildcard sulit diimplementasikan dengan benar, sehingga pengoptimalan ini direkomendasikan hanya ketika pengumpulan data instans sangat mahal.
Dalam kebanyakan kasus, implementasi panggilan balik untuk PcwCallbackEnumerateInstances
permintaan akan identik dengan implementasi untuk PcwCallbackCollectData
. Panggilan balik dapat secara opsional mengoptimalkan pengumpulan data dengan menghilangkan data penghitung aktual dalam panggilan ke PcwAddInstance
(yaitu dengan meneruskan 0 dan NULL untuk Count
parameter dan Data
).
Implementasi panggilan balik dapat disusun sebagai berikut:
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;
}
Sebagian besar penyedia counterset menggunakan alat CTRPP untuk memproses manifes counterset mereka dan menghasilkan fungsi pembantu, termasuk pembungkus PcwRegister
fungsi (CTRPP menghasilkan deskriptor penghitung) dan PcwAddInstance
(CTRPP menghasilkan kode untuk membungkus struktur data penyedia ke dalam format yang diperlukan oleh PcwAddInstance
).
Sebagai referensi dalam contoh ini, berikut ini adalah fungsi Register yang dihasilkan CTRPP untuk KCS.man
manifes dari sampel KCS.
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);
}
Penyedia counterset mengimplementasikan PCW_CALLBACK
fungsi untuk menangani permintaan konsumen. Contoh kode berikut menunjukkan PCW_CALLBACK
fungsi bernama KcsGeometricWaveCallback
yang menghitung dan mengumpulkan data yang disimulasikan. (Perhatikan bahwa KcsAddGeometricWave
adalah fungsi pembantu yang dihasilkan CTRPP yang memanggil 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;
}
DriverEntry
Dalam rutinitas sampel KCS, KcsGeometricWaveCallback
fungsi ditentukan sebagai Callback
saat KcsRegisterGeometricWave
mendaftarkan counterset.
//
// Register Countersets during DriverEntry. (TODO: Unregister at driver unload.)
//
Status = KcsRegisterGeometricWave(KcsGeometricWaveCallback, NULL);
if (!NT_SUCCESS(Status)) {
return Status;
}
Persyaratan
Persyaratan | Nilai |
---|---|
Klien minimum yang didukung | Tersedia di Windows 7 dan versi Windows yang lebih baru. |
Target Platform | Desktop |
Header | wdm.h (termasuk Wdm.h, Ntddk.h) |
IRQL | IRQL <=APC_LEVEL |