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 dan PcwCloseInstance 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 sama Id untuk semua pemanggilan panggilan balik), harus unik (misalnya jangan hanya menggunakan 0 untuk semua instans), dan harus kurang dari 0xFFFFFFFE (jangan gunakan PCW_ANY_INSTANCE_ID). Jika memungkinkan, instans Id harus bermakna (misalnya, penghitung Proses mungkin menggunakan PID sebagai Id) alih-alih arbitrer (misalnya nomor urut).

  • Nilai instans Name HARUS stabil dari waktu ke waktu (instans logis yang sama harus menggunakan nilai yang sama Name untuk semua pemanggilan panggilan balik) dan HARUS unik. Jika counterset mendukung beberapa instans, instans Name tidak boleh kosong. Pencocokan string dilakukan menggunakan perbandingan yang tidak peka huruf besar/kecil, sehingga Name 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 yang InstanceId sama dengan CollectData.InstanceId. Panggilan balik dapat mengoptimalkan pengumpulan data dengan melewatkan panggilan ke PcwAddInstance untuk instans dengan yang tidak cocok InstanceId.

  • Jika Info->CollectData.InstanceMask != "*" kemudian konsumen hanya menginginkan data tentang instans dengan yang cocok dengan InstanceName pola CollectData.InstanceMaskwildcard . Panggilan balik dapat mengoptimalkan pengumpulan data dengan melewatkan panggilan ke PcwAddInstance untuk instans dengan yang tidak cocok InstanceName. 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

Lihat juga

PcwRegister

PcwAddInstance

PcwCreateInstance

PCW_CALLBACK_TYPE

PCW_CALLBACK_INFORMATION

CTRPP

Pustaka Penghitung Kinerja (PERFLIB versi 2.0)