Instituto Politécnico de Viseu Escola Superior de Tecnologia de Viseu Engenharia de Sistemas e Informática Sistemas Operativos - 2005/2006 Trabalho Prático v1.0 Introdução O presente trabalho prático visa uma maior familiarização com a programação de mecanismos de sincronização e comunicação entre processos no ambiente UNIX/Linux. Poderá ser realizado em grupo, constituído por um número máximo de 3 alunos. O trabalho está sujeito a apresentação e defesa, realizada individualmente por cada aluno. É, obviamente, interdita a cópia parcial ou integral de trabalhos e, a ser detectada, conduzirá à adequada penalização dos envolvidos. O trabalho deverá apresentar-se na forma de código fonte e de um relatório claro e conciso, que também será objecto de avaliação. Chama-se à atenção para o facto de este enunciado poder ainda sofrer pequenas alterações. Os alunos poderão aperceber-se de eventuais actualizações, vigiando a respectiva versão. Para os alunos mais desatentos, refira-se que a execução deste trabalho prático, para além de constituir elemento de avaliação, representa também uma forma efectiva de preparação para as provas de avaliação. Contextualização As especificações apresentadas neste enunciado não correspondem à solução mais simples ou eficiente, devendo ser encaradas como um pretexto para conjugar, num único trabalho prático, um conjunto alargado de mecanismos de comunicação estudados, nomeadamente, ficheiros, sinais, pipes unidireccionais standard, pipes nomeados (FIFO), filas de mensagens, memória partilhada e semáforos. De modo a simplificar a avaliação deste trabalho, as indicações devem ser integralmente respeitadas. É, contudo, admissível que sejam tomadas opções diferentes, desde que, claramente, não representem uma forma de “contornar” algum dos aspectos em estudo. Estas opções devem encontrar-se devidamente fundamentadas no respectivo relatório. As opções tomadas no sentido de resolver circunstâncias que aqui não sejam explicitadas deverão, também, ser devidamente documentadas. Descrição do problema O contexto de utilização desta aplicação poderia, por exemplo, corresponder a uma redacção de um jornal. Várias agências noticiosas enviam notícias à redacção. As agências noticiosas classificam previamente as notícias por tópicos, como, por exemplo, política, sociedade, desporto, educação, etc. Os jornalistas da redacção, especializados em determinados tópicos, devem ser notificados aquando da recepção de novas notícias nesse tópico. Esta aplicação é constituída por vários programas que interagem entre si, conforme esquematizado na Figura 1. Todos os processos são executados num mesmo equipamento Linux e utilizam os mecanismos IPC estudados nas aulas práticas da disciplina. O programa Servidor serve de plataforma de difusão das notícias no seio da redacção. Cada programa leitor de notícias (Leitor) subscreve um ou mais tópicos. Sempre que uma notícia é publicada num tópico, todos os subscritores recebem a correspondente notificação. Se o programa leitor pretender ter acesso ao conteúdo da notícia, este comunica directamente com o programa associado a uma agência noticiosa (Agência). O programa Monitor visualiza um conjunto de estatísticas e informações adicionais sobre a utilização desta aplicação. 1/5 Figura 1 Implementação Na interacção entre estes processos são definidos vários mecanismos de comunicação de acordo com a Figura 2. Figura 2 Programa Servidor Processo Pai: Na fase de inicialização, este processo deve preparar convenientemente a estrutura de dados e criar todos os recursos necessários à comunicação entre processos. A lista de tópicos a serem considerados deve constar num ficheiro de texto. Todos os dados de configuração da aplicação (chaves de recursos IPC, subdirectoria de FIFO, etc) devem ser armazenados num ficheiro de texto para que possa ser consultado pelos restantes programas. Em seguida, este processo entra em ciclo ficando bloqueado à espera de mensagens (P1, P2) na fila de mensagens 1. Após a recepção de uma mensagem, lança um processo filho que tratará de responder ao processo que efectuou o pedido. Ao receber o sinal SIGINT, deve terminar, libertando todos os recursos que tiverem sido alocados. Processo Filho: 2/5 Este processo analisa a mensagem e responde de acordo com os seguintes tipos de mensagens: Lista tópicos: Este pedido tem origem em processos Agência (P1) ou Leitor (P2). O processo envia uma resposta (R1 ou R2) com a lista de tópicos definidos no Servidor. Subscreve tópico: Este pedido tem origem em processos Leitor (P2) que desejam subscrever um tópico. Não é necessário uma resposta de confirmação da subscrição. Cancela tópico: Este pedido tem origem em processos Leitor (P2) que desejam cancelar a subscrição de um tópico. Não é necessário uma resposta de confirmação do cancelamento da subscrição. Lista subscrições activas: Este pedido tem origem em processos Leitor (P2) com a indicação do PID do processo filho que recebe as notificações de novas mensagens. É enviada uma resposta (R2) com a lista de tópicos subscritos. Lista de notícias por tópico: Este pedido tem origem em processos Leitor (P2) com indicação do tópico pretendido. É enviada uma resposta (R2) com a lista de notícias desse tópico. A lista inclui o número da notícia e o respectivo título. Processo servidor de notícia: Este pedido tem origem em processos Leitor (P2) com indicação do número da notícia pretendida. É enviada uma resposta (R2) com o PID do processo filho Agência que serve o pedido de conteúdo da notícia. Publica: Pedido de publicação de uma notícia num determinado tópico com origem em processos Agência (P1). A mensagem correspondente a este pedido deve incluir o tópico, o título da notícia e o PID do processo que responderá a uma solicitação do conteúdo da notícia (PID do processo filho Agência). O processo envia uma resposta (R1) com a indicação do número da notícia (único no sistema). Envia, em seguida, para todos os processos Leitor que tenham subscrito o tópico, uma mensagem (N1) com informação do número da notícia e do respectivo título (difusão). Programa Agência Este programa permitirá às agências noticiosas, por um lado, solicitar a publicação de uma notícia num determinado tópico e, por outro, servir os vários processos Leitor que pretendam aceder ao conteúdo de uma notícia. As notícias estão previamente armazenadas em ficheiros de texto. Quando lançada a execução deste programa, deve, através da função fork(), lançar um processo filho. O processo pai será responsável pela interacção com o utilizador. O processo filho será responsável pela disponibilização do conteúdo de uma notícia solicitado por um processo Leitor. Processo pai: O processo pai disponibiliza uma linha de comandos (prompt) que permitirá ao utilizador introduzir os seguintes comandos: lt: Pedido ao Servidor da lista de tópicos. pb <topico> <ficheiro>: O pedido de publicação de uma notícia, num determinado tópico, é enviado ao Servidor (P1), obtendo deste um número de notícia que é único no sistema. A informação a enviar ao Servidor inclui o tópico, o título da notícia (1ª linha do ficheiro de texto) e o PID do processo filho que disponibiliza o conteúdo da notícia. Tal pedido é solicitado ao servidor através da fila de mensagens 1. O servidor responde (R1) com um número da notícia e fará a difusão da mesma pelos processos Leitor subscritores (N1). Recebida a resposta do servidor, o processo pai, através de um pipe unidireccional, envia ao filho a informação sobre o nome do ficheiro e o respectivo número da notícia e sinaliza tal facto com o envio de um sinal. O processo filho manterá esta informação numa tabela, permitindo-lhe responder a solicitações de conteúdos de notícias. s: Este comando termina o processo, devendo enviar um sinal ao processo filho para que termine a sua execução. Processo filho: Atende a pedidos (F1) de conteúdo de notícias colocadas na fila de mensagens 2. Quando recebe uma mensagem, esta contém o número da notícia e o remetente (PID do processo Leitor). Depois de identificado o ficheiro de texto com o conteúdo da notícia, cria um pipe nomeado (FIFO) para a transferência do conteúdo. Envia uma mensagem de resposta (F2) para o processo Leitor a confirmar a disponibilidade da notícia. Coloca no FIFO, o conteúdo do ficheiro de texto correspondente à notícia. A identificação do pipe nomeado coincide com 3/5 o PID do processo Leitor e é criado numa subdirectoria definida pelo programa Servidor (do conhecimento de ambos os processos comunicantes por consulta do ficheiro de configuração). Deve ser considerado um número máximo, configurado pelo servidor, de pipes nomeados em utilização simultânea. O controlo deste número máximo deve ser assegurado por semáforos. Programa Leitor Este programa permitirá aos jornalistas, por um lado, utilizar os serviços da aplicação (listar, subscrever e cancelar tópicos) e, por outro, solicitar à agência noticiosa o conteúdo de uma determinada notícia. Processo pai: O processo pai disponibiliza uma linha de comandos (prompt) que permitirá ao utilizador introduzir os seguintes comandos: lt: Pedido ao Servidor da lista de tópicos. nt <tópico>: Pedido ao Servidor da lista de notícias publicadas neste tópico. sb <tópico>: Pedido ao Servidor da subscrição de um tópico. Para além do tópico, a mensagem enviada deve incluir o PID do processo filho que irá receber as notificações de novas notícias (subscrição). Não é necessário uma resposta de confirmação da subscrição. csb <tópico>: Pedido ao Servidor do cancelamento da subscrição de um tópico. Não é necessário uma resposta de confirmação do cancelamento da subscrição. lts: Pedido ao Servidor da lista de tópicos subscritos. Para além do tópico, a mensagem enviada deve incluir o PID do processo filho que irá permitir ao Servidor identificar quais os tópicos que foram subscritos. vnt <número notícia>: Pedido do conteúdo de uma notícia. Em primeiro lugar, é solicitado ao Servidor o PID do processo filho Agência que serve o pedido de conteúdo da notícia. Recorrendo a este PID, envia uma mensagem, através da fila de mensagens 2. Recebida a confirmação da disponibilidade da notícia, abre o pipe nomeado criado numa subdirectoria definida pelo programa Servidor (ambas do conhecimento dos processos comunicantes). O nome do FIFO coincide com o PID deste processo. O conteúdo da notícia é lido do FIFO e visualizado no monitor. Terminado o processo de transferência, o FIFO é eliminado. s: Este comando termina o programa, devendo enviar um sinal ao processo filho para que termine a sua execução. Processo filho: O processo filho aguarda por mensagens colocadas na fila 2 que dizem respeito a notificações fornecidas pelo Servidor quando uma nova notícia é publicada num tópico que tenha sido subscrito por este programa. A notificação de uma notícia é visualizada no monitor (tópico, número e título). Programa Monitor: Para que o processo Servidor possa responder às solicitações, uma estrutura de dados deverá ser mantida em memória. Esta memória deve ser partilhada, permitindo ao programa monitor exibir, periodicamente (de 3 em 3 segundos), um conjunto de dados estatísticos sobre a utilização da aplicação. Devem constar, de entre outras informações que se julguem por convenientes, o número de notícias por tópico e o número de subscritores por tópico. Especificações Adicionais Em condições normais de execução, o programa Servidor deve ser colocado em execução antes do lançamento dos programas Agência, Leitor e Monitor. Uma das suas tarefas consiste na criação e inicialização dos mecanismos de comunicação, nomeadamente: • memória partilhada: com o tamanho necessário para a manutenção da estrutura de dados necessária para a aplicação; • filas de mensagens; • semáforos: para controlo de diversos aspectos, dos quais se destacam: a exclusão mútua no acesso à memória partilhada; a garantia de que nunca existirão mais do que k pipes nomeados (FIFO) em simultâneo, sendo k um valor configurável à partida. 4/5 Uma vez criados estes recursos, as respectivas identificações devem ficar disponíveis num ficheiro de configuração (ficheiro de texto) acessível aos restantes programas que constituem esta aplicação. A estrutura de dados deve atender aos seguintes limites: • Número máximo de tópicos: 10. • Número máximo de caracteres para um tópico: 20. • Número máximo de caracteres para um título: 50. • Número máximo de notícias por tópico: 10. • Número máximo de subscritores por tópico: 10. • Número máximo de notícias que são mantidas no processo filho Agência:10. Dada a existência destes limites, sugere-se que sejam sempre guardados os dados mais recentes. Assim, quando, por exemplo, o número de subscritores por tópico ultrapassa o valor limite (10), é eliminada a subscrição mais antiga. Se, por exemplo, o número de notícias por tópico for ultrapassado, é eliminada a notícia mais antiga. Estas eliminações não devem ser comunicadas aos restantes programas. É assumida a possibilidade de ocorrerem algumas inconsistências. Por exemplo, o conteúdo de uma notícia já não pode ser obtido, embora permaneça na estrutura de dados da aplicação. Tratamento de erros Em acréscimo ao normal controlo de erros nas aplicações, a implementação deste trabalho deverá também contemplar o tratamento de determinadas situações de anomalia. A título indicativo, apresentam-se alguns exemplos: • execução dos programas Agência, Leitor e Monitor, antes de lançar o programa Servidor; • tentativa de utilizar um recurso de IPC entretanto removido; • permanência de chaves de IPC resultantes de execuções passadas mal sucedidas; • erros nos pedidos feitos ao servidor (listar notícias de um tópico que não existe, subscrever um tópico que não existe, etc); • erros nos pedidos de conteúdos de notícias que já não podem ser servidas. Terminação dos processos e libertação de recursos Dada a importância associada à remoção dos recursos de comunicação, que por algum motivo permaneçam indevidamente alocados, aconselha-se a criação de um pequeno programa auxiliar que, quando invocado, desempenhe essa função. Durante a fase de desenvolvimento do trabalho e tendo em atenção as considerações feitas nas aulas relativamente a este assunto, os alunos devem vigiar sistematicamente a eliminação das chaves desnecessárias. Qualidade do código O código deve ser construído de forma a tornar simples não só o seu desenvolvimento como a própria leitura/avaliação. Devem ser usados comentários (de forma coerente e consistente) de modo a que, por um lado, se torne fácil a interpretação de passagens mais complexas e que, por outro, se demonstre que quem escreveu as respectivas instruções está consciente da sua semântica e implicações. Este aspecto será relevante na avaliação do trabalho. Relatório O relatório, que se pretende breve, deverá justificar as opções tomadas, bem como eventuais desvios relativamente às especificações constantes deste enunciado. Devem ser identificadas as principais dificuldades encontradas e respectivas soluções (quando não mencionadas neste enunciado). No caso do trabalho entregue não implementar todos as especificações referidas, as respectivas lacunas deverão necessariamente fazer parte desse relatório. Bom trabalho!! 5/5