Rotinas de bloqueio do Windows Sockets 1.1 e EINPROGRESS

Um dos principais problemas na portabilidade de aplicativos de um ambiente berkeley sockets para um ambiente do Windows envolve o bloqueio; ou seja, invocar uma função que não retorna até que a operação associada seja concluída. Um problema surge quando a operação leva um tempo arbitrariamente longo para ser concluída: um exemplo é uma função recv , que pode ser bloqueada até que os dados sejam recebidos do sistema par. O comportamento padrão no modelo Berkeley Sockets é que um soquete opere no modo de bloqueio, a menos que o programador solicite explicitamente que as operações sejam tratadas como não desbloqueio. Os ambientes do Windows Sockets 1.1 não puderam assumir o agendamento preemptivo. Portanto, foi altamente recomendável que os programadores usem as operações não desbloqueadas (assíncronas), se possível, com o Windows Sockets 1.1. Como isso nem sempre foi possível, as instalações de pseudo-bloqueio descritas a seguir foram fornecidas.

Observação

O Windows Sockets 2 é executado apenas em sistemas operacionais preemptivos de 32 bits em que os deadlocks não são um problema. As práticas de programação recomendadas para o Windows Sockets 1.1 não são necessárias no Windows Sockets 2.

 

Mesmo em um soquete de bloqueio, algumas funções – bind, getsockopt e getpeername , por exemplo – são concluídas imediatamente. Não há diferença entre um bloqueio e uma operação sem bloqueio para essas funções. Outras operações, como recv, podem ser concluídas imediatamente ou levar um tempo arbitrário para serem concluídas, dependendo de várias condições de transporte. Quando aplicadas a um soquete de bloqueio, essas operações são chamadas de operações de bloqueio. As seguintes funções podem bloquear:

Com o Windows Sockets 1.1 de 16 bits, uma operação de bloqueio que não pode ser concluída imediatamente é tratada pelo pseudo-bloqueio da seguinte maneira.

O provedor de serviços inicia a operação e, em seguida, insere um loop no qual envia todas as mensagens do Windows (gerando o processador para outro thread, se necessário) e, em seguida, verifica a conclusão da função do Windows Sockets. Se a função tiver sido concluída ou se WSACancelBlockingCall tiver sido invocado, a função de bloqueio será concluída com um resultado apropriado.

Um provedor de serviços deve permitir a instalação de uma função de gancho de bloqueio que não processa mensagens para evitar a possibilidade de reentrante de mensagens enquanto uma operação de bloqueio está pendente. A função de gancho de bloqueio mais simples retornaria FALSE. Se uma DLL do Windows Sockets depender de mensagens para operação interna, ela poderá executar PeekMessage(hMyWnd...) antes de executar o gancho de bloqueio de aplicativo para que ele possa obter suas mensagens sem afetar o restante do sistema.

Em um ambiente windows sockets 1.1 de 16 bits, se uma mensagem do Windows for recebida para um processo para o qual uma operação de bloqueio está em andamento, há o risco de que o aplicativo tente emitir outra chamada do Windows Sockets. Devido à dificuldade de gerenciar essa condição com segurança, o Windows Sockets 1.1 não dá suporte a esse comportamento de aplicativo. Um aplicativo não tem permissão para fazer mais de uma chamada de função aninhada do Windows Sockets. Somente uma chamada de função pendente é permitida para uma tarefa específica. As únicas exceções são duas funções fornecidas para ajudar o programador nessa situação: WSAIsBlocking e WSACancelBlockingCall.

A função WSAIsBlocking pode ser chamada a qualquer momento para determinar se uma chamada do Windows Sockets 1.1 de bloqueio está ou não em andamento. Da mesma forma, a função WSACancelBlockingCall pode ser chamada a qualquer momento para cancelar uma chamada de bloqueio em andamento. Qualquer outro aninhamento de funções do Windows Sockets falha com o erro WSAEINPROGRESS.

Deve-se enfatizar que essa restrição se aplica a operações de bloqueio e não bloqueio. Para aplicativos do Windows Sockets 2 que negociam a versão 2.0 ou superior no momento da chamada ao WSAStartup, nenhuma restrição ao aninhamento de operações é encerrada. As operações podem se tornar aninhadas em circunstâncias raras, como durante um retorno de chamada de aceitação condicional WSAAccept ou se um provedor de serviços, por sua vez, invocar uma função do Windows Sockets 2.

Embora esse mecanismo seja suficiente para aplicativos simples, ele não pode dar suporte aos requisitos complexos de expedição de mensagens de aplicativos mais avançados (por exemplo, aqueles que usam o modelo MDI). Para esses aplicativos, a API do Windows Sockets inclui a função WSASetBlockingHook, que permite que o aplicativo especifique uma rotina especial que pode ser chamada em vez da rotina de expedição de mensagens padrão descrita na discussão anterior.

O provedor do Windows Sockets chamará o gancho de bloqueio somente se todos os itens a seguir forem verdadeiros:

  • A rotina é definida como sendo capaz de bloquear.
  • O soquete especificado é um soquete de bloqueio.
  • A solicitação não pode ser concluída imediatamente.

Um soquete é definido como bloqueio por padrão, mas a função ioctlsocket com a função FIONBIO IOCTL ou WSAAsyncSelect pode definir um soquete como modo sem bloqueio.

O gancho de bloqueio nunca é chamado e o aplicativo não precisa se preocupar com os problemas de reentrância que o gancho de bloqueio pode introduzir, se um aplicativo seguir estas diretrizes:

  • Ele usa apenas soquetes sem bloqueio.
  • Ele usa as rotinas WSAAsyncSelect e/ou WSAAsyncGetXByY em vez de selecionar e as rotinas getXbyY .

Se um aplicativo Windows Sockets 1.1 invocar uma operação assíncrona ou sem bloqueio que usa um ponteiro para um objeto de memória (um buffer ou uma variável global, por exemplo) como um argumento, é responsabilidade do aplicativo garantir que o objeto esteja disponível para o Windows Sockets durante toda a operação. O aplicativo não deve invocar nenhuma função do Windows que possa afetar o mapeamento ou a viabilidade de endereço da memória envolvida.