Archive for January, 2008

Seminários OSR em casa

15 de January de 2008

Se um dos problemas que impediam você de fazer um treinamento especializado em desenvolvimento de device drivers na OSR era o fato de ter medinho de voar, então seus pobremas se acabaram-se. A OSR, depois de anos e anos de experiência ensinando a escrever drivers, agora investe nos Webinars. Essa novidade já está anunciada desde o dia 4 de janeiro, mas ainda causa surpresa quando comento com algumas pessoas. Assim, resolvi colocar esse post e tentar repassar a novidade para mais pessoas de uma só vez.

 

Mais barato?

A vantagem financeira está no fato de evitar de comprar as passagens aéreas e pagar a hospedagem de uma semana nos Estados Unidos. Tá, tudo bem, não é você quem vai pagar mesmo, mas pense que nem todos trabalham em empresas multi-nacionais com milhares de dólares destinados a treinamentos de funcionários. Quando fiz o treinamento na OSR, tudo foi pago pela empresa onde eu trabalhava, mas se eu colocar tudo na ponta do lápis, foram cerca de R$13000 de investimento para participar de um seminario de U$2350, que na cotação de hoje seriam traduzidos em aproximadamente R$4143, ou seja, aproximadamente um terço do valor total. Isso pode simplesmente ser o fator que vai impedir você de fazer o treinamento. Então, você já pode ir correndo dizer pro papai e pra mamãe que eles agora têm mais poder aquisitivo para treinar você. Mas não três vezes mais. Pelo que me parece, os Webinars são relativamente mais caros que os seminários convecionais. O seminário que participei teve duração de 32 horas e abordava o desenvolvimento de drivers de File System (um assunto um cadim avançado), enquanto O primeiro webinar oferecido pela OSR fará uma rápida introdução ao WDF durante 20 horas pelo mesmo preço.

Outras vantagens

Um outro ponto bastante relevante é o fato de não ter que se ausentar de sua casa ou da empresa que você trabalha durante o seminário. Algumas das pessoas com quem conversei a respeito, me disseram que um grande problema é o fato de ter que sair de casa durante uma semana inteira. Alguns deles têm filhos pequenos ou outros tantos motivos que você pode imaginar, mas creio que o motivo mais comum que pode prender o profissional, são os intermináveis pepinos inadiáveis que só você pode resolver. Bom pelo menos este webinar é composto por 5 aulas de 4 horas. Isso permite que você cuide de sua pequena hortinha de pepinos enquanto participa dos treinamentos.

Não é apenas um ppt bem caro

Ao contrário do que se pode imaginar, os seminários serão interativos utilizando conexões de duas vias onde o participante poderá, além de receber todas as instruções ao vivo, fazer perguntas e ainda receber todo o material impresso como nos outros seminários. O interessado no webinar fará o download da ferramenta que estabelece a conexão e participará de uma sessão de 15 minutos para testar o computador que será usado nas sessões, e assim, certificar-se de que o participante não terá qualquer problema durante o treinamento.

Agora, se sua empresa não quiser mesmo pagar um treinamento pra você, já fica pelo menos mais fácil pagar por você mesmo e poder usar isso como uma nova estrelinha em seu currículo.
Até mais!

CLEANUP e CLOSE

9 de January de 2008

Já escrevi um post que descreve os passos de como criar um driver bem simples. Este driver simplesmente mantém uma lista de strings que recebe via IRP’s de escrita e as devolve nas IRP’s de leitura. Muito bem, se você ainda não sabe o que é uma IRP, um outro post tenta explicar o que são as IRP’s e até descreve os passos necessários para utilizar o IRP Tracker para observar as IRP’s indo e vindo. Se fizermos um pequeno teste utilizando o IRP Tracker sobre o driver de exemplo que acabei de comentar, teremos uma saída semelhante a figura abaixo.


Podemos ver as todas as IRP’s que nosso device recebeu desde a IRP_MJ_CREATE até a IRP_MJ_CLOSE. Entre estas IRP’s notamos que algumas delas não foram completadas com sucesso. Como nenhuma rotina foi designada para tratar IRP_MJ_CLEANUP, estas IRP’s são terminam com STATUS_INVALID_DEVICE_REQUEST. Neste post vou comentar um pouco sobre a esta IRP e como seu device interage com os processos que obtiveram um handle para ele.

Para ver detalhes da IRP, dê um duplo clique sobre a linha da IRP no IRP Tracker para que a janela abaixo seja exibida. Nessa janela é possível ver, entre outros detalhes, o FileObject utilizado na IRP. Isso nos será útil neste post durante os testes.


Quando o IRP_MJ_CLEANUP ocorre?

O Object Manager envia uma IRP de CLEANUP a fim de notificar o driver de que o último handle para determinado FileObject foi fechado. Como alguns de vocês devem saber, quando uma aplicação usa o CreateFile para obter um handle para nosso device, isso resulta na criação de um FileObject. As operações subseqüentes utilizando este handle estarão vinculadas a este FileObject. Mais detalhes sobre isso neste post.

Um FileObject não tem uma relação direta com um handle. Um handle pode ser duplicado ou mesmo herdado do processo pai na criação de um novo processo. O resultado destas ações é ter vários handles que serão traduzidos para o mesmo FileObject. Desta forma, nem sempre quando uma aplicação chama a função CloseHandle, uma IRP de CLEANUP ou CLOSE é enviada ao driver.

Para acompanhar os passos abaixo, o código fonte do programa de exemplo está disponível para download ao final deste post. Este programa utiliza o driver de exemplo construído em outro post, o código fonte do driver pode ser baixado daqui. A partir dos fontes você pode compilar e instalar o driver de teste. Se você não sabe como fazer isso, este post pode te ajudar. Depois de instalar o driver de teste, seria interessante poder executar as chamadas abaixo com a ajuda de um depurador, e assim, poder observar os resultados no IRP Tracker a cada linha executada.

É importante ler os comentários do fonte abaixo. Fiquei com preguiça de duplicar essas informações aqui no post.

/****
***     main
**
**      Espero que todos saibam que este é o ponto
**      de entrada de uma aplicação. Caso contrário,
**      você pode estar se preciptando em ler um blog
**      de driver para Windows.
*/
int main(int argc, char* argv[])
{
    HANDLE  h1, h3, h3;
    CHAR    szBuffer[100];
    DWORD   dwBytes;
 
    //-f--> Aqui estamos abrindo o primeiro handle
    //      para o nosso device. Este é o passo 1
    //      no IRP Tracker. Verifique o valor do
    //      FileObject para poder comparar em operações
    //      futuras.
    h1 = CreateFile("\\\\.\\EchoDevice",
                    GENERIC_ALL,
                    0,
                    NULL,
                    OPEN_EXISTING,
                    0,
                    NULL);
 
    //-f--> Aqui estamos abrindo o segundo handle
    //      para o nosso device. Este é o passo 2
    //      no IRP Tracker. Verifique o valor do
    //      FileObject para poder comparar em operações
    //      futuras.
    h3 = CreateFile("\\\\.\\EchoDevice",
                    GENERIC_ALL,
                    0,
                    NULL,
                    OPEN_EXISTING,
                    0,
                    NULL);
 
    //-f--> Aqui lançaremos uma IRP_MJ_READ para o
    //      primeiro FileObject obtido. Passo 3 no
    //      IRP Tracker. Note que o primeiro FileObject
    //      é utilizado nesta IRP.
    ReadFile(h1,
             szBuffer,
             sizeof(szBuffer),
             &dwBytes,
             NULL);
 
    //-f--> Aqui lançaremos uma IRP_MJ_READ para o
    //      segundo FileObject obtido. Passo 4 no
    //      IRP Tracker. Note que o segundo FileObject
    //      é utilizado nesta IRP.
    ReadFile(h3,
             szBuffer,
             sizeof(szBuffer),
             &dwBytes,
             NULL);
 
    //-f--> A duplicação de handle não é notificada
    //      ao driver. Apenas o Object Manager sabe
    //      disso. Não existe nenhum passo correspondente
    //      no IRP Tracker.
    DuplicateHandle(GetCurrentProcess(),
                    h1,
                    GetCurrentProcess(),
                    &h3,
                    0,
                    FALSE,
                    DUPLICATE_SAME_ACCESS);
 
    //-f--> Como o terceiro handle foi obtido atravéz de
    //      uma duplicação do primeiro, o FileObject
    //      correspondente é o mesmo do primeiro handle.
    //      Passo 5 no IRP Tracker. Note que o primeiro
    //      FileObject é utilizado nesta IRP.
    ReadFile(h3,
             szBuffer,
             sizeof(szBuffer),
             &dwBytes,
             NULL);
 
    //-f--> Como temos dois handles para o primeiro FileObject,
    //      fechar um deles não implicará em nenhuma notificação
    //      ao nosso device. Não existe passo correspondente no
    //      IRP Tracker.
    CloseHandle(h1);
 
    //-f--> Este handle não foi duplicado, assim, quando o fecharmos,
    //      uma IRP_MJ_CLEANUP seguido de uma IRP_MJ_CLOSE serão
    //      enviadas ao driver. Passo 6 no IRP Tracker.
    CloseHandle(h3);
 
    //-f--> Fechando este handle, teremos o mesmo comportamento
    //      observado no fechamento do handle h3. Do ponto de
    //      vista do driver, o primeiro FileObject será destruído
    //      agora. Passo 7 no IRP Tracker.
    CloseHandle(h3);
 
    //-f--> E todos viveram felizes para sempre.
    return 0;
}

Obter um handle para um objeto nos assegura que este objeto será válido enquanto não fecharmos o handle. Um objeto só pode ser destruído pelo sistema depois que todos os handles para ele forem fechados. Para isso, o Object Manager mantém dois contadores, o ProcessHandleCount e o SystemHandleCount. O primeiro deles mantém a quantidade de handles abertos para um objeto em um determinado processo. O outro mantém a soma de todos os ProcessHandleCount para o objeto no sistema. Estes contadores são decrementados à medida que os handles são fechados. Quando chegam a zero, uma IRP_MJ_CLEANUP é gerada.

Normalmente a IRP_MJ_CLEANUP nos serve como evento para cancelar qualquer operação assincrona relativa ao FileObject que está sendo finalizado. IRP’s são ligadas às threads que às lançaram e qualquer IRP assincrona deveria ser devidamente cancelada neste momento.

Então para quê serve o IRP_MJ_CLOSE?

Além dos contadores de referência acima citados, existe também o ObjectReferenceCount, que além de ser incrementado quando um novo handle é obtido, também é incrementado quando uma referência de kernel é feita utilizando funções do tipo ObReferenceObject por exemplo. Estas chamadas incrementam o ObjectReferenceCount sem que um novo handle seja gerado. Para quem conhece COM, esta chamada tem o comportamento semelhante ao AddRef. Isso permite que o objeto se mantenha válido para o kernel, mesmo depois que todos os handles para ele foram destruídos. Enfim, quando este contador chegar a zero, então a IRP_MJ_CLOSE é enviada.

Um driver pode associar estruturas de dados a um determinado FileObject utilizando os pointeiros FsContext e FsContext2 conforme eu já comentei neste outro post. Estas estruturas só poderão ser desalocadas quando recebermos o IRP_MJ_CLOSE.

Operações após o IRP_MJ_CLEANUP

Quando recebemos uma IRP_MJ_CLEANUP, não significa que o fim está próximo. Outros componentes do kernel podem lançar novas IRP’s de leitura ou escrita mesmo depois deste evento. Sem falar das IRP_MJ_INTERNAL_DEVICE_CONTROL que podem ser trocadas entre drivers.

Um cenário muito comum no desenvolvimento de File Systems é justamente quando uma refêrencia de um FileObject que é mantida pelo Cache Manager. Mesmo quando todos os handles forem fechados pelas aplicações, o sistema ainda retém esta refêrencia antecipando que alguma aplicação pode querer abrir o mesmo arquivo novamente. O Cache Manager possui system threads que realizam a então chamada “Escrita retardada”. Este recurso concentra várias escritas a um arquivo em uma única operação posterior a fim de diminuir o número de acessos a disco, assim ganhando performance. É muito comum tais escritas serem realizadas depois que o arquivo teve todos os seus handles fechados por aplicações, e assim temos escritas depois do IRP_MJ_CLEANUP.

No final de tudo isso, espero mais uma vez ter mais ajudado que atrapalhado. Assuntos referentes a Cache Manager, Memory Manager e File Systems não são muito triviais, mas são interessantes o suficiente para ler a respeito e entender o que o sistema faz antes de falar que tudo é uma porcaria.

Até a próxima!

TestCleanup.zip

E o pulso ainda pulsa

4 de January de 2008

Antes de completar três meses sem qualquer sinal de vida, aqui estou a dar uma espiada no que ocorre na blogosfera. Este final de ano foi realmente corrido. Como já devem saber, minha ida para IBM contribuiu um pouco para esta minha ausência. Tudo bem, a faculdade também ajudou bastante, no finalzinho do ano reservei um tempo para mim mesmo e fui dar uma passeada na praia. Mas vamos deixar de conversa mole e ir ao que interessa.

Neste post, de volta ao mundo dos vivos, vou comentar apenas pequenas coisas e deixar para depois (mas ainda para esta vida) um post mais elaborado, como os que vocês estão acostumados a ver por aqui.

Debug em Free

Uma das coisas que tive que aprender a conviver na IBM é a depurar o driver que escrevemos sempre com o Build Free, ou seja, com otimizações e tudo mais que uma compilação release merece. Eu bem que tentei relutar dizendo que é importante que tenhamos uma versão checked para testes e que seria valioso poder rodar nosso driver com todos os ASSERT‘s ligados e verificando qualquer coisa fora do normal que possa ocorrer. Mas acreditem, não é fácil convencer este povo que entre Indianos e Norte-Americanos já estão acostumados com essa situação. Foi procurando boas justificativas para termos uma versão checked utilizável que encontrei este post. Pois é, as justificativas são realmente muito boas, mas ainda defendo que deveriamos ter uma versão checked. Estou preparando um post que fala um pouco sobre isso.

Por falar em saber inglês

Alguns posts antes deste, eu falei do MSDN traduzido para algumas linguas, incluindo o português. O recado foi que, dá pra se virar um pouquinho sem saber inglês, mas se você ainda não sabe e pretende desenvolver drivers para viver, então trate de aprender o quanto antes. Me lembrei deste post hoje quando numa pesquisa do Google um link foi especialmente gratificante.

Dicas do IoGetDeviceObjectPointer

Bom, se alguém conseguiu pegar alguma dica, por favor me passe. Se um dia eu resolver aprender uma terceira lingua, agora já tenho uma candidata.

Ano novo cara nova

Era para ter acontecido antes, mas infelizmente o tempo é curto para muitas pessoas. Coloquei em prova as habilidades de web designer do meu irmão para dar um tapa no layout do meu blog. Está ficando muito bom, mas ainda não tenho nada de concreto para mostrar. Estarei migrando para o WordPress em pouco tempo. Uma boa parte do trabalho já foi feito, mas ainda há muito a ser feito. Minha principal intenção em migrar para o WordPress é poder utilizar um destes plug-ins que permitem que eu tenha o mesmo post tanto em inglês como em português. Bom, um dos poucos que testamos ainda deu problema. Mas vamos chegar lá.

Até mais mais…