Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Opcionalmente, os provedores podem implementar uma PCW_CALLBACK função para receber notificações quando os consumidores fazem solicitações, como enumerar instâncias ou coletar dados de contraconjunto. A Biblioteca de Contadores de Desempenho (PERFLIB versão 2.0) chama a PCW_CALLBACK função antes de concluir a solicitação do consumidor.
Sintaxe
PCW_CALLBACK PcwCallback;
NTSTATUS PcwCallback(
[in] PCW_CALLBACK_TYPE Type,
[in] PPCW_CALLBACK_INFORMATION Info,
[in, optional] PVOID Context
)
{...}
Parâmetros
[in] Type
Um PCW_CALLBACK_TYPE valor de enumeração que indica por que o retorno de chamada foi invocado. Os valores possíveis são PcwCallbackAddCounter, PcwCallbackRemoveCounter, PcwCallbackEnumerateInstances e PcwCallbackCollectData.
[in] Info
Um ponteiro para uma união PCW_CALLBACK_INFORMATION que fornece detalhes sobre por que o retorno de chamada do provedor foi invocado. Os detalhes estarão no campo correspondente ao Type parâmetro . Por exemplo, se Type == PcwCallbackEnumerateInstances os detalhes estiverem em Info->EnumerateInstances.
[in, optional] Context
O contexto de retorno de chamada fornecido pelo provedor ao chamar PcwRegister ou ao chamar a função Register gerada por CTRPP (que invoca PcwRegister).
Retornar valor
A PCW_CALLBACK função de retorno de chamada deverá retornar STATUS_SUCCESS se o retorno de chamada for concluído sem erros ou se um NTSTATUS código de erro for o contrário. Observe que esse código de retorno é apenas para fins informativos e que o processamento da solicitação do consumidor continuará mesmo que o retorno de chamada retorne um erro.
Comentários
Os provedores de contraconjunto podem fornecer informações ao consumidor por meio de dois sistemas diferentes:
O provedor pode usar
PcwCreateInstanceePcwCloseInstancepara manter uma lista de instâncias disponíveis e os dados de contador correspondentes. Esse sistema é simples de implementar, mas limitado em flexibilidade. Ao usar esse sistema, o provedor não precisa fornecer uma função de retorno de chamada. Para obter mais informações sobre esse sistema, consulte a documentação de PcwCreateInstance.O provedor pode fornecer uma
PCW_CALLBACKfunção que será invocada pela Biblioteca de Contadores de Desempenho conforme necessário para coletar dados.
A implementação do retorno de chamada deve ser thread-safe. Vários consumidores diferentes podem solicitar dados simultaneamente do provedor em threads diferentes.
O retorno de chamada deve lidar com os PcwCallbackEnumerateInstances tipos de solicitação e PcwCallbackCollectData . O retorno de chamada geralmente não precisa lidar com outros tipos de solicitação, mas em cenários complexos o retorno de chamada também pode manipular PcwCallbackAddCounter e PcwCallbackRemoveCounter otimizar a coleta de dados (ou seja, para desabilitar o acompanhamento de estatísticas quando nenhuma consulta estiver ativa).
O retorno de chamada é responsável por gerar Name valores e Id para as instâncias de contador.
Os valores de instância
IdDEVEM ser estáveis ao longo do tempo (a mesma instância lógica deve usar o mesmoIdvalor para todas as invocações do retorno de chamada), deve ser exclusivo (por exemplo, não use apenas 0 para todas as instâncias) e deve ser menor que 0xFFFFFFFE (não usePCW_ANY_INSTANCE_ID). Quando possível, a instânciaIddeve ser significativa (por exemplo, um contador de processo pode usar um PID como oId) em vez de arbitrário (por exemplo, um número de sequência).Os valores de instância
NameDEVEM ser estáveis ao longo do tempo (a mesma instância lógica deve usar o mesmoNamevalor para todas as invocações do retorno de chamada) e DEVE ser exclusiva. Se o contador der suporte a várias instâncias, a instânciaNamenão deverá estar em branco. A correspondência de cadeia de caracteres é feita usando uma comparação que não diferencia maiúsculas de minúsculas, portantoName, os valores não devem ser diferentes apenas por maiúsculas e minúsculas.
Ao lidar com PcwCallbackCollectData solicitações, uma implementação de retorno de chamada básica simplesmente invocará PcwAddInstance (ou a função AddXxx gerada por CTRPP) uma vez para cada instância de contador. Para obter mais informações, consulte Função AddXxx gerada por CTRPP.
As seguintes otimizações podem ser usadas em implementações mais avançadas quando necessário:
Se
Info->CollectData.CounterMask != (UINT64)-1o consumidor não precisar de todos os contadores no contador. Nesse caso, o retorno de chamada pode otimizar a coleta de dados deixando os valores correspondentes como 0 no bloco de dados do contador.Se
Info->CollectData.InstanceId != PCW_ANY_INSTANCE_IDo consumidor quiser apenas dados sobre instâncias com umInstanceIdigual aCollectData.InstanceId. O retorno de chamada pode otimizar a coleta de dados ignorando a chamada paraPcwAddInstancepara instâncias com não correspondentesInstanceId.Se
Info->CollectData.InstanceMask != "*"o consumidor quiser apenas dados sobre instâncias com umInstanceNameque corresponda ao padrão curinga deCollectData.InstanceMask. O retorno de chamada pode otimizar a coleta de dados ignorando a chamada paraPcwAddInstancepara instâncias com não correspondentesInstanceName. A correspondência de caracteres curinga é difícil de implementar corretamente, portanto, essa otimização é recomendada somente quando a coleta de dados de instância é muito cara.
Na maioria dos casos, a implementação de retorno de chamada para uma PcwCallbackEnumerateInstances solicitação será idêntica à implementação de um PcwCallbackCollectData. Opcionalmente, o retorno de chamada pode otimizar a coleta de dados omitindo os dados reais do contador na chamada para PcwAddInstance (ou seja, passando 0 e NULL para os Count parâmetros e Data ).
Uma implementação de retorno de chamada pode ser estruturada da seguinte maneira:
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;
}
A maioria dos provedores de contraconjunto usa a ferramenta CTRPP para processar seu manifesto de contraconjunto e gerar funções auxiliares, incluindo o encapsulamento PcwRegister de funções (CTRPP gera os descritores de contador) e PcwAddInstance (CTRPP gera código para encapsular as estruturas de dados do provedor no formato exigido por PcwAddInstance).
Para referência neste exemplo, veja a seguir a função Register gerada por CTRPP para o KCS.man manifesto do exemplo 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);
}
O provedor de contadores implementa a PCW_CALLBACK função para lidar com solicitações do consumidor. O exemplo de código a seguir mostra uma PCW_CALLBACK função chamada KcsGeometricWaveCallback que enumera e coleta dados simulados. (Observe que KcsAddGeometricWave é uma função auxiliar gerada por CTRPP que chama 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 Na rotina do exemplo de KCS, a KcsGeometricWaveCallback função é especificada como o Callback quando KcsRegisterGeometricWave registra o contador.
//
// Register Countersets during DriverEntry. (TODO: Unregister at driver unload.)
//
Status = KcsRegisterGeometricWave(KcsGeometricWaveCallback, NULL);
if (!NT_SUCCESS(Status)) {
return Status;
}
Requisitos
| Requisito | Valor |
|---|---|
| Cliente mínimo com suporte | Disponível no Windows 7 e versões posteriores do Windows. |
| Plataforma de Destino | Área de Trabalho |
| Cabeçalho | wdm.h (include Wdm.h, Ntddk.h) |
| IRQL | IRQL <=APC_LEVEL |