O Sistema Operacional OpenVOS fornece uma Interface de Programação de Aplicação (API) de alto nível que, de modo geral, facilita a programação do sistema. Mas às vezes, torna-se muito fácil - porque uma simples chamada de sub-rotina para uma rotina s$... pode esconder muita complexidade.
Este é o primeiro de uma série irregular de postos a chamar sua atenção para tais armadilhas para que você possa evitá-las em seus projetos de aplicação.
Os males das mensagens da 25ª Linha
A capacidade de escrever uma mensagem para a 25ª linha (ou o que quer que seja o fundo) de um terminal permite que um usuário (ou um programa em execução) notifique outros usuários sobre condições incomuns. A interface da linha de comando é o comando send_message. O comando e os programas do usuário acabam invocando a subrotina s$send_message API. Argumentos a esta chamada fornecem o nome_de_utilizador de um receptor, o nome_do_módulo_alvo onde esse usuário pode estar logado, o texto de notificação e algumas bandeiras para modificar aspectos da operação. Chamadores privilegiados têm permissão para especificar o nome do remetente; caso contrário, o nome_de_usuário do processo de envio é o padrão.
Até agora, parece simples. Como a operação requer acesso ao terminal de propriedade de outro usuário, o kernel envia o pedido em uma fila de servidores para o processo TheOverseer no módulo alvo. Normalmente, o processo de envio espera então pelo status de entrega da mensagem, mas pode optar por não esperar por esta resposta.
TheOverseer processo para qualquer módulo mantém o controle de todos os processos de login e do dispositivo terminal usado por esses processos. Quando recebe uma solicitação para enviar uma mensagem, ele procura sua lista de processos e dispositivos, e para cada processo de nome_de_usuário que corresponda ao argumento nome_de_servidor, ele anexa uma porta ao dispositivo terminal do processo, abre a porta, escreve a mensagem na linha de notificação, fecha a porta, e desprende a porta. Se vários processos corresponderem ao argumento do nome_do_consecedor, este ciclo de anexar/abrir/escrever/fechar/apagar é repetido para cada um deles.
Certo - isto é um pouco mais complicado do que falamos pela primeira vez. Explorando melhor, descobrimos que qualquer módulo do sistema pode estar hospedando processos de login onde o terminal real é um dispositivo em outro sistema/módulo que usou o Open StrataLink (OSL) para fazer login em toda a rede (com o comando login -modulo). Agora, a operação aparentemente simples de anexar/abrir/escrever/fechar/apagar nesse terminal tem que envolver processos OSL e chamadas de procedimento remoto de rede para o módulo remoto, e é muito mais cara do que o manuseio no módulo.
A ampliação dos efeitos acontece quando o nome do usuário receptor é especificado como um nome estrela que pode corresponder a vários ou a todos os usuários do login. E é ainda ampliado se o módulo alvo também for especificado como um nome estelar. O pior caso seria enviar a mensagem ao usuário "*.*". (todos os usuários, todos os grupos) no módulo "*" (todos os módulos do sistema atual).
Implementação
s$expand_module_starname(target_module) => module_list; foreach module_name in module_list send_overseer_request(module_name, send_message_request_data) The message is sent via a server queue and OSL to TheOverseer process on that module. TheOverseer process on each receiving module then does: foreach terminal_process in TheOverseer’s list of login processes and sub-processes; if (terminal_process user_name matches receiver star name) if (messages_queued_for_device < 5) queue it for the login device else reject the request (e$too_many_terminal_messages)
Simultaneamente, utilize até 10 portos de cada vez para enviar qualquer fila mensagens para os terminais; Para cada mensagem para cada terminal Fixar porta Porta aberta s$control(...WRITE_SYSTEM_MESSAGE...) Fechar o porto Desprender o porto Este processamento é feito em modo no_wait_mode para cada terminal de modo que atrasos (como solicitações de E/S em toda a rede) afetam apenas os processamento de mensagens para aquele terminal. Se alguma mensagem não puder ser entregue em 300 segundos, ela é enxaguada.
Quando uma aplicação usa este mecanismo para relatar erros e uma enchente de erros aparece, a aplicação pode facilmente ficar atolada em relatórios, alternando entre esperar que outras mensagens sejam processadas e inundar os terminais dos usuários com mensagens que chegam muito rápido para serem compreendidas.
Evitar
Agora que você sabe o que está acontecendo nos bastidores, a orientação que posso lhe dar é:
- Cuidadosamente crie nomes de estrelas para nomes de usuários e nomes de módulos para garantir que você alcance apenas os usuários que devem receber a mensagem e nenhum outro. Por exemplo, John_Doe.* ou *.Operations ou John_Doe.SysAdmin.
- Considere a implementação de uma lista de usuários sem nome para notificar e enviar cada notificação separadamente.
- Coloque o detalhe das mensagens de erro em outro lugar (um log de erros, por exemplo) e use s$send_message para alertar apenas para a presença de erros.
- Limitar a freqüência das notificações a algo razoável (talvez não mais do que uma vez por minuto).
- Suprimir qualquer mensagem que seja a mesma que a última enviada. A nova mensagem apenas sobreporia a anterior.
Se você tiver qualquer outra sugestão, envie seus comentários para que outros os vejam.