OS "Sivelkiriya": um exemplo de construção de um programa

Olá, Habr.

Este post continua o ciclo de publicações sobre o projeto Sivelkiriya OS. O primeiro artigo do ciclo forneceu uma descrição geral do conceito, o segundo explicou por que era necessário e de que forma o produto podia ver a luz, o terceiro descreveu as soluções arquitetônicas e o quarto respondeu à pergunta de como coordenar as ações dos desenvolvedores de SO e Software neste modelo. Este artigo mostra um exemplo de divisão de um programa simples em módulos para ajustá-lo às realidades do novo sistema operacional.

Considere um exemplo clássico: um programa que permite abrir um arquivo que contém uma imagem de bitmap e visualizá-la na tela. A imagem pode ser dimensionada e, se o tamanho na escala atual exceder o tamanho da tela, role.

Nos sistemas operacionais modernos, esse problema geralmente é resolvido por um aplicativo com arquitetura fechada, ou seja, um que contenha todo o código necessário ou use componentes de terceiros apenas por sua própria iniciativa. O ponto principal é que você não pode usar parte do aplicativo - você pode iniciá-lo como está ou usar outra solução.

Para entender como esse problema é resolvido dentro da estrutura do sistema operacional Sivelkiriya, você primeiro terá que olhar "por baixo" deste programa e entender o que ele faz e com quais conceitos ele opera. A seguir estão as entidades que surgem durante a operação do programa.

  1. A localização da imagem.No caso clássico, é descrito pelo caminho para o arquivo no disco. Com uma consideração um pouco mais ampla, os endereços na rede local ou na Internet também se enquadram nessa categoria. Isso, no entanto, não esgota todas as possibilidades: a imagem pode ser localizada na RAM, na saída de algum programa (por exemplo, um processador de fotos ou um renderizador gráfico), em uma página da Web, em uma mensagem de bate-papo ou e-mail, dentro de um arquivo ou documento do escritório. Apesar de tecnicamente todas essas opções serem diferentes umas das outras e exigir um processamento diferente, do ponto de vista do usuário, todas elas servem a um propósito: indicam onde está localizada a imagem que ele deseja visualizar. Criar uma interface que permita escolher entre tantas opções é uma tarefa não trivial, mas conceitualmente não há obstáculos para essa abordagem.Além disso: não há razão para que o usuário não tenha a oportunidade de visualizar a imagem localizada em qualquer um dos locais acima.
  2. , . , , , .
  3. . , , jpeg gif. : jpeg .gif, gif . , , , , web-.
  4. , ( ) .
  5. . , tiff, . — , gif — .
  6. .
  7. : , , , .
  8. .
  9. ( ) , .
  10. ( ), .

No sistema operacional Sivelkiriya, cada uma das entidades listadas acima é descrita por uma determinada interface de dados. Essa representação permite seu uso em muitos contextos fora do modelo original (que será discutido mais adiante).

Cada interface é implementada por algum objeto, criado por algum módulo. O código dos métodos do objeto é executado dentro da estrutura do módulo que o gerou. Ao mesmo tempo, é incorreto falar sobre o lançamento de módulos como aplicativos separados, pois eles não têm seus próprios threads nem memória fora dos objetos criados por eles. Se você precisar armazenar um estado que vá além do trabalho com uma única imagem, ele será armazenado em um objeto separado, cujo acesso será realizado de acordo com as regras gerais - por meio da interface do objeto OS.

A estrutura dos módulos envolvidos no trabalho deste programa pode ser assim:

  1. O primeiro módulo define o comportamento de um objeto que implementa a interface "Localização do objeto" (uma imagem é um caso especial de um objeto). Em particular, determina como acessar bytes de um determinado local. No entanto, ele pode usar módulos que fornecem acesso direto ao suporte de disco ou rede, dependendo da localização física do objeto.
  2. O segundo módulo fornece acesso direto aos bytes da imagem. Além disso, fornece dicas sobre o possível tipo de conteúdo com base no método de armazenamento (extensão de arquivo, cabeçalhos de servidor da web etc.).
  3. O terceiro módulo, usando dicas sobre o tipo de conteúdo e acesso à sua representação de bytes, determina o tipo real de conteúdo (formato de arquivo de imagem).
  4. , ( , , ) ( ) . , : , . — : jpeg .
  5. , , , , . — — , , .
  6. , . , . — , , , , , , , .

Obviamente, além dos módulos descritos, o programa pode participar de módulos que fornecem recursos adicionais: registro em log, renderização de componentes de janelas, feedback sonoro e assim por diante.

É fácil ver que essa estrutura torna a reutilização da funcionalidade implementada o mais simples possível. Portanto, a instalação de um novo codec no sistema significa que esse tipo de imagem será automaticamente suportado em todos os contextos e programas. Diferentes módulos podem ser escritos por diferentes programadores e em diferentes idiomas; no entanto, na estrutura desse modelo de interação, essas diferenças não são significativas. Um e o mesmo codec pode ser usado para carregar imagens em uma tela nessa interface e para renderizá-las em um programa de mensagens, navegador, visualizador de diretórios e assim por diante.

O suporte para novos casos de uso é realizado elementarmente. Por exemplo, adicionar várias interfaces adicionais permite oferecer suporte a ações como mover para as imagens seguintes e anteriores (independentemente de sua localização e como acessá-las) ou aplicar filtros. A introdução de um thin client também não é um problema: como a passagem de dados e chamadas pelas bordas do módulo é controlada pelo sistema operacional, é possível transferir operações caras (por exemplo, decodificar o conteúdo de um arquivo e dimensionar uma imagem) para outra máquina.

Como os protótipos de todos os módulos descritos acima são conhecidos pelo sistema operacional, ele conhece suas necessidades do ponto de vista do sistema e pode agir em conformidade. Por exemplo, a operação de dimensionamento de imagens pode ser executada em um encadeamento separado, para que o trabalho com imagens grandes não bloqueie a interface em computadores low-end. Além disso, como os módulos não fazem suposições sobre os encadeamentos em que são executados, otimizações adicionais são possíveis: por exemplo, o encadeamento da interface com o usuário pode ser separado do encadeamento responsável pela computação (neste caso, dimensionamento), apenas se o último Não tive tempo para concluir o trabalho dentro de um período de tempo predeterminado e, com uma rápida redimensionagem, o desenho da imagem em uma nova escala pode ser iniciado em um fluxo adicional mesmo antescomo um segmento envolvido na renderização, que não precisa mais ser concluído, ele conseguirá processar o sinal até a conclusão. Como o sistema operacional possui informações sobre todos os threads em execução, sobre o carregamento e os recursos reais dos processadores do computador, os dados de otimização podem ser mais eficazes do que aqueles que o autor de um aplicativo separado pode fazer com base em suposições sobre seu ambiente de execução.

A questão de como os módulos que fornecem conjuntamente uma solução para um problema aplicado são interligados pode ser resolvida de várias maneiras. Por exemplo, é óbvio que a escolha de um módulo que lê bytes de um arquivo do disco é determinada pelo sistema de arquivos desta seção e, em todos os casos de acesso à mesma seção, o mesmo módulo será usado. O módulo responsável por determinar o formato da imagem provavelmente será instalado no nível do sistema e usado em todos os contextos. Uma exceção pode ser o caso de um módulo falhar: nesse caso, o sistema operacional pode procurar outro módulo instalado que corresponda a esse protótipo e, se existir, tentar usá-lo com os mesmos dados de entrada. Nesse caminho,o erro pode ser processado sem a intervenção do usuário e os dados sobre ele são coletados e, se permitido pelas políticas de segurança desta máquina, passados ​​aos desenvolvedores do módulo do problema, juntamente com as informações relacionadas necessárias. Se um módulo costuma ter problemas, o sistema operacional pode decidir excluí-lo da cadeia de pesquisa ou diminuir sua prioridade.

Em outros casos, a escolha do módulo pode ser definida pelo usuário e armazenada na configuração. Portanto, diferentes módulos de escala de imagem podem fornecer estilos de renderização diferentes (parâmetros de suavização de serrilhado ao diminuir o zoom ou desfocar as bordas dos pixels quando aumentam). Dependendo do contexto, o usuário pode precisar de uma abordagem diferente (bordas nítidas em pixels para posicionamento preciso ou embaçado para conforto visual).

Os métodos para iniciar os módulos também podem variar. Por exemplo, o módulo responsável pela renderização da janela do visualizador de imagens pode ser chamado pelo módulo responsável pela renderização da área de trabalho (clicando no arquivo gráfico na área de trabalho) ou pelo módulo que exibe o menu de inicialização do programa. Após a inicialização, o módulo da janela carrega os módulos necessários para concluir a tarefa atual.

Esta descrição é apenas uma demonstração da possibilidade fundamental de implementar um esquema de interação e não pode ser considerada como uma instrução completa para escrever um visualizador de imagens, sistema operacional e / ou módulos para ele.

Os artigos anteriores da série estão disponíveis aqui: um , dois , três , quatro. O texto completo, como antes, está disponível no site do projeto .

All Articles