Um depurador para a plataforma Holo

Propaganda
UNIVERSIDADE FEDERAL DO RIO GRANDE DO SUL
INSTITUTO DE INFORMÁTICA
CURSO DE GRADUAÇÃO EM CIÊNCIA DA COMPUTAÇÃO
Um depurador para a plataforma Holo
Por
Fábio Reis Cecin
Projeto de Diplomação
Prof. Dr. Cláudio Fernando Resin Geyer
Orientador
Prof. Dr. Jorge Luís Victória Barbosa
Co-Orientador
Porto Alegre, 29 de abril de 2002
Agradeço a todas as pessoas que contribuíram e
contribuem à minha formação como cientista da computação.
De forma geral, agradeço a todas as pessoas que contribuíram e
contribuem à minha evolução como consciência humana. De
coração, espero estar fazendo o mesmo por todos vocês.
Agradeço especialmente a todos os professores e colegas
com os quais convivi e convivo no Instituto de Informática da
UFRGS - um lugar de pessoas generosas, prontas para ajudar e
compartilhar.
Agradeço aos meus pais, à minha família, e à minha
Anelise, com todo o amor. Reservo agradecimento especial ao
meu orientador, Prof. Dr. Cláudio Resin Geyer, e ao meu coorientador, Prof. Dr. Jorge Luís Victória Barbosa. Obrigado
pelo apoio.
"Aqui e agora, rapazes! Aqui e agora!"
- Aldous Huxley (A Ilha)
Porto Alegre, abril de 2002
2
Sumário
LISTA DE FIGURAS .............................................................................................................................5
LISTA DE TABELAS .............................................................................................................................6
RESUMO ................................................................................................................................................7
ABSTRACT ............................................................................................................................................8
1. INTRODUÇÃO...................................................................................................................................9
1.1 TEMA..............................................................................................................................................9
1.2 CONTEXTO ......................................................................................................................................9
1.3 MOTIVAÇÃO ................................................................................................................................. 10
1.4 OBJETIVOS .................................................................................................................................... 10
1.5 ORGANIZAÇÃO DO TEXTO.............................................................................................................. 10
2. HOLO................................................................................................................................................ 12
2.1 HOLOPARADIGMA ......................................................................................................................... 12
2.2 HOLOLINGUAGEM ......................................................................................................................... 13
2.3 HOLOPLATAFORMA 1.0..................................................................................................................15
2.4 HOLO 1.0 ......................................................................................................................................17
2.4.1 Características...................................................................................................................... 17
2.4.2 Exemplo: Jantar dos Filósofos............................................................................................... 19
2.5 DEPURAÇÃO HOLO ........................................................................................................................ 20
2.5.1 Conceito de Depuração .........................................................................................................20
2.5.2 Depuração concorrente.........................................................................................................21
2.5.3 Depuração multiparadigma...................................................................................................22
2.5.4 Depuração distribuída........................................................................................................... 25
2.5.5 Serviços básicos de depuração para Holo 1.0 ........................................................................ 25
2.6 CONSIDERAÇÕES FINAIS ................................................................................................................ 28
3. HOLO EXTENSÃO PARA DEPURAÇÃO (HED).......................................................................... 29
3.1 VISÃO GERAL ................................................................................................................................29
3.2 EXTENSÃO DA HOLOPLATAFORMA 1.0 ........................................................................................... 31
3.3 HOLOJAVA ESTENDIDA ..................................................................................................................33
3.3.1 Visão Geral........................................................................................................................... 33
3.3.2 Formato da informação de depuração ................................................................................... 34
3.3.3 Alterações na gramática e limitações..................................................................................... 36
3.4 HOLO DEBUG INTERFACE - VISÃO GERAL ...................................................................................... 37
3.5 INTERFACES E ALGORITMOS DA HDI.............................................................................................. 37
3.5.1 Gerenciamento de sessões de depuração................................................................................ 39
3.5.2 Breakpoints........................................................................................................................... 40
3
3.5.3 Carga de entes estáticos ........................................................................................................ 40
3.5.4 Execução passo-a-passo........................................................................................................ 41
3.5.5 Inspeção da história de um ente.............................................................................................43
3.5.6 Detecção de mobilidade lógica .............................................................................................. 44
3.5.7 Configuração de requisições ................................................................................................. 44
3.6 HOLO DEBUGGER ..........................................................................................................................45
4. IMPLEMENTAÇÃO ........................................................................................................................ 48
4.1 HOLOJAVA ESTENDIDA ..................................................................................................................48
4.1.1 Visão geral............................................................................................................................ 48
4.1.2 Limitações e possibilidades de expansão................................................................................ 48
4.2 HOLO DEBUG INTERFACE .............................................................................................................. 49
4.2.1 Visão Geral........................................................................................................................... 49
4.2.2 Limitações e possibilidades de expansão................................................................................ 49
4.3 HOLO DEBUGGER ..........................................................................................................................50
4.3.1 Visão Geral........................................................................................................................... 50
4.3.2 Limitações e possibilidades de expansão................................................................................ 50
4.4 DESEMPENHO ................................................................................................................................51
5. CONCLUSÃO ...................................................................................................................................52
BIBLIOGRAFIA...................................................................................................................................54
ANEXOS ...............................................................................................................................................57
ANEXO 1 - C ÓDIGO JAVA GERADO PARA O "JANTAR DOS FILÓSOFOS" ................................................... 57
ANEXO 2 - DOCUMENTAÇÃO (JAVADOC) DA HDI ................................................................................. 61
4
Lista de figuras
Figura 1 – Gênese do Holoparadigma.................................................................................. 12
Figura 2 – Composição de entes .......................................................................................... 14
Figura 3 – Forma geral de representação de um ente estático na Hololinguagem ................. 15
Figura 4 – Holoplataforma 1.0............................................................................................. 16
Figura 5 – Problema do "Jantar dos Filósofos", modelado em Holo 1.0 ............................... 18
Figura 6 – Grafo de Invocação de Ações (AIG) de Holo...................................................... 23
Figura 7 – Exemplo de controle gráfico (à direita) para a exibição da HoloTree, a estrutura de
árvore em que os entes em Holo são organizados (à esquerda). .................................... 25
Figura 8 – Modelo da Holoplataforma estendida para depuração ......................................... 29
Figura 9 – Holoplataforma 1.0 estendida para depuração através da HED. Em destaque:
módulos que receberam extensões ou foram implementados no contexto deste trabalho.
.................................................................................................................................... 31
Figura 10 – Geração e utilização da informação que realiza o mapeamento bidirecional entre
código Java e programa Holo, necessário para a implementação dos algoritmos de
depuração. ................................................................................................................... 34
Figura 11 – Arquivo de informação de depuração para o "Jantar dos Filósofos" .................. 35
Figura 12 – Algoritmo de passo-a-passo do tipo step into ou step over adaptado para
implementação da HDI. ............................................................................................... 42
Figura 13 – Interface do Holo Debugger.............................................................................. 45
Figura 14 – Programa Java, classe “holo”, que implementa o ente “holo” do programa Holo
que simula o “Jantar dos Filósofos”. ............................................................................ 59
Figura 15 – Programa Java, classe "filosofo", que implementa o ente "filosofo" do programa
Holo que simula o "Jantar dos Filósofos”..................................................................... 60
5
Lista de tabelas
Tabela 1 – Ações que compõe a janta do filósofo ................................................................ 20
Tabela 2 – Serviços de depuração para Holo 1.0.................................................................. 26
Tabela 3 – Mapeamento da HED para a Holoplataforma 1.0 ............................................... 32
Tabela 4 – Informação de depuração gerada para arquivo pela HoloJava estendida ............. 35
Tabela 5 – Código do arquivo de informação de depuração e os atributos possíveis para uma
linha de código Java gerada pela ferramenta HoloJava 1.0 estendida. .......................... 36
Tabela 6 – Interfaces da HDI............................................................................................... 39
Tabela 7 – Comandos do Holo Debugger ............................................................................ 47
6
Resumo
A Hololinguagem (de forma abreviada, Holo) é uma linguagem de programação
oriunda de uma nova proposta para o desenvolvimento de software, o Holoparadigma. Este
trabalho fornece um tratamento inicial para o problema do suporte à depuração de
Holoprogramas. Este tratamento é realizado através da construção de uma visão geral sobre o
problema, que inclui, por exemplo, o aspecto multiparadigma da linguagem. Desta visão, foi
derivada uma proposta de extensão para a Holoplataforma, a Holo Extensão para Depuração
(HED). Esta extensão é então materializada sobre a Holo 1.0, a primeira versão da linguagem
e da plataforma Holo, que é fortemente embasada na plataforma Java. São desenvolvidos três
componentes para implementar a extensão: a HoloJava 1.0 estendida para depuração, a HDI
(Holo Debug Interface), uma implementação dos serviços básicos de depuração, e o Holo
Debugger, uma ferramenta de depuração para Holo.
Palavras-chave: Java, Holo, depurador, multiparadigma, arquitetura de depuradores.
7
Abstract
The Hololanguage (briefly, Holo) is a programming language originated from a new
standpoint for software development, the Holoparadigm. This work provides an initial
treatment for the problem of supporting the debug process of Holo programs. This treatment
is achieved through the construction of a general overview of the problem, that includes, for
example, the multiparadigm aspect of the language. From this vision, an extension to the
Holoplatform is proposed, the Holo Extension for Debugging (HED). This extension is
materialized over Holo 1.0, the first version of the Holo language and platform, which are
strongly tied to the Java platform. Three software components are developed to implement
the extension: the HoloJava 1.0 extended for debugging, the HDI (Holo Debug Interface), an
implementation of the basic debugging services, and the Holo Debugger, a debugger tool for
Holo.
Keywords: Java, Holo, debugger, multiparadigm, debugger architecture.
8
1. Introdução
1.1 Tema
Este trabalho trata do problema da depuração de programas escritos para a
Hololinguagem (abreviadamente, Holo) [BAR 01], uma linguagem concorrente e
multiparadigma. Neste contexto, o trabalho identifica algumas características de Holo que
introduzem problemas sobre a depuração de programas, e propõe uma especificação para a
arquitetura do depurador da Holoplataforma, a plataforma de desenvolvimento e execução de
Holoprogramas. Esta especificação é implementada sobre Holo 1.0, uma versão da linguagem
e da plataforma Holo que tem a linguagem e plataforma Java como base para a
implementação.
1.2 Contexto
Depuradores de programas são ferramentas críticas para o desenvolvimento de
software, e são muito pouco estudados, se comparados, por exemplo, aos compiladores [ROS
96, p.1]. Recentemente popularizou-se o emprego de múltiplas threads em programas para a
exploração da concorrência. Porém, o desenvolvimento de depuradores para programas
multithreaded enfrenta desafios [ROS 96, p. 173], como a eficácia do auxílio oferecido ao
programador para o diagnóstico de problemas oriundos de multithreading.
Linguagens de programação multiparadigma têm sido continuamente pesquisadas nos
últimos anos. O objetivo da criação de modelos integradores de paradigmas é a superação das
limitações de cada paradigma e a exploração conjunta de suas características consideradas
benéficas [BAR 01]. Torna-se necessário a adaptação das ferramentas de linguagens de
programação, como os depuradores, para as características destas linguagens.
O Holoparadigma [BAR 01a] é um novo paradigma de software , que busca, através
de um esforço integrador abrangente, unificar os benefícios de vários campos de pesquisa em
Ciência da Computação. Estes campos são: a exploração, implícita e explícita, da
concorrência, distribuição e paralelismo, a programação multiparadigma (paradigmas de
orientação a objetos, imperativo e lógico), as técnicas de Engenharia e Arquitetura de
Software, entre outros. O Holoparadigma surgiu de pesquisas realizadas no âmbito dos
projetos Opera [OPE 02] e Apello [APE 02].
Holo é uma linguagem de programação criada de acordo com os princípios
estabelecidos pelo Holoparadigma. Em Holo, realidade é modelada apenas por entes e
símbolos. Holo possui uma semântica distribuída, pois, ao expressar a realidade em entes
independentes que se comunicam através de troca de símbolos, a exploração do paralelismo
expresso naturalmente pelas construções da linguagem pode ser feita de forma automática
pela máquina [BAR 02].
A Holoplataforma (a plataforma de execução de programas Holo) atualmente possui
um protótipo implementado sobre a linguagem Java [JAV 02]. Este protótipo denomina-se
Holoplataforma 1.0, e é baseado na ferramenta HoloJava [BAR 01b], um tradutor de Holo
9
para Java, e em um ambiente integrado de desenvolvimento, o HoloEnv [BAR 99, SOA 00].
Esta versão da plataforma permite o desenvolvimento e execução de programas
desenvolvidos para Holo 1.0, o subconjunto da linguagem Holo que se encontra atualmente
implementado.
1.3 Motivação
A Holoplataforma não possuía suporte para a depuração de programas Holo. Este
trabalho pretende preencher esta lacuna de forma satisfatória, através de um modelo que
prioriza a flexibilidade, de forma que mudanças na implementação da plataforma ou na
linguagem causem um impacto mínimo na solução. A minimização destes impactos reduz a
quantidade de módulos que precisam de adaptações ou re-implementações, reduzindo custos.
Os módulos da solução fornecem a fundação para a construção de interfaces homemmáquina em ferramentas de depuração Holo. Também fornecem um modelo de depuração
que pode ser aproveitado, ou que ao menos serve como parâmetro para novos estudos sobre
depuração, caso a Holoplataforma seja implementada na íntegra, sem a utilização da
plataforma Java como fundação.
A concepção de um suporte para a depuração de programas Holo envolve várias
questões de interesse, como a depuração de uma linguagem concorrente, distribuída e
multiparadigma. Os aspectos multiparadigma e distribuído não são o foco deste trabalho, mas
foi realizado um estudo inicial sobre estes temas, que pode servir como um ponto de partida
para discussão futura.
1.4 Objetivos
Os objetivos deste trabalho são:
•
Identificar as necessidades de Holo em relação à depuração de programas;
•
Fornecer um modelo geral para a arquitetura do depurador da Holoplataforma;
•
Implementar serviços de depuração para Holo 1.0, o subconjunto de Holo
atualmente implementado, através do desenvolvimento de um módulo depurador;
•
Implementar uma ferramenta de depuração (interface) simples para demonstrar o
funcionamento do módulo;
•
Orientar o projeto do módulo depurador de forma a permitir a posterior integração
de uma interface gráfica de depuração ao ambiente HoloEnv;
•
Documentar a API do módulo depurador para servir de referência para a
implementação desta interface gráfica.
1.5 Organização do Texto
O capítulo 2 introduz o Holoparadigma e a Hololinguagem, seguindo com uma
discussão sobre a Holoplataforma, a plataforma de desenvolvimento e execução de Holo. A
seguir, é apresentada a Holoplataforma 1.0, a versão atual da plataforma e desenvolvimento
10
de programas Holo. Após, é descrita a linguagem Holo 1.0, o subconjunto de Holo que é
reconhecido atualmente pela Holoplataforma 1.0. Juntamente com esta descrição, é
apresentado um exemplo de programa Holo 1.0. Por fim, realiza-se uma revisão sobre o
conceito de depuração e uma discussão sobre as necessidades de Holo em relação à
depuração de programas, que resulta na especificação dos serviços básicos a serem oferecidos
pelo depurador.
O capítulo 3 apresenta inicialmente o modelo geral proposto para a arquitetura do
depurador da Holoplataforma, o HED (Holo Extensão para Depuração). A seguir, o modelo
da HED é adaptado para Holo 1.0, e mostram-se os componentes do modelo que foram
supridos pela plataforma Java, e quais foram implementação própria deste trabalho. A seguir,
descreve-se o modelo e os algoritmos utilizados no projeto e implementação dos três módulos
desenvolvidos neste trabalho: a ferramenta HoloJava estendida, a Holo Debug Interface, e o
Holo Debugger.
O capítulo 4 trata de questões relativas à implementação dos módulos. É fornecida
uma visão geral do ambiente de desenvolvimento, bibliotecas utilizadas e indicadores de
quantidade de código produzido para cada um dos módulos. Também é fornecida uma análise
das limitações e possibilidades de expansão de cada um deles. Por fim, o capítulo apresenta
considerações sobre o desempenho dos programas desenvolvidos.
O capítulo 5 faz um resumo do trabalho, destaca resultados e conclusões, e aponta
várias perspectivas de trabalhos futuros.
11
2. Holo
Este capítulo primeiramente apresenta o Holoparadigma, suas motivações e conceitos
básicos. A seguir, é detalhada a Hololinguagem, enumerando as suas construções, destacando
suas características básicas e dissecando a definição de Holoprograma. Após, é definido um
modelo da Holoplataforma, a plataforma de desenvolvimento e execução de Holo. Por fim,
realiza-se uma discussão sobre questões relacionadas à depuração de programas Holo.
2.1 Holoparadigma
O ser humano contemporâneo possui uma visão de mundo excessivamente
fragmentária, originada do pensamento de Descartes [CAP 96]. Uma conseqüência
desagradável desta maneira de enxergar ao mundo é a idéia, formada pelas pessoas, de que
elas são seres sem relação direta com os outros seres e do universo em que se situam. Isto as
leva a uma incompreensão sobre a própria existência e a um comportamento individualista,
que afeta a sociedade como um todo.
O pensamento cartesiano não é algo inerentemente negativo. Grande parte do sucesso
atual da ciência provém do paradigma de fragmentação e especialização. Porém, ao
fragmentarmos a realidade, perdemos a visão do todo e das relações que envolvem a parte
estudada de outras partes da realidade [BAR 02, p.37]. Ortega y Gasset [ORT 92, p.72]
defende que o movimento que leva a investigação científica a fragmentar-se indefinidamente
em problemas particulares exige uma regulagem compensatória. Essa regulagem deve ser
realizada através de um movimento no sentido contrário, de síntese do conhecimento
existente.
O Holoparadigma é uma nova proposta para o desenvolvimento de software, que
busca integrar os esforços de vários outros campos de pesquisa em Ciência da Computação.
A figura 1 ilustra a gênese do Holoparadigma.
Temas
Básicos
Temas
Intermediários
Tema
Final
Paralelismo
Implícito
Sistemas
Distribuídos
Multiparadigma
Distribuição
Implícita
Arquitetura de
Software
Novos
Paradigmas
Holoparadigma
Figura 1 – Gênese do Holoparadigma
12
Resumidamente, os temas que são englobados pelo estudo do Holoparadigma são:
•
Paralelismo implícito: proposta de que as fontes de paralelismo estejam presentes
nas construções da linguagem de programação, e sejam exploradas
automaticamente pela plataforma de execução;
•
Sistemas distribuídos: estudo relacionado a software que executa em vários nodos
processadores conectados por redes;
•
Multiparadigma: criação de linguagens de programação cujo paradigma é uma
integração de outros paradigmas ditos “básicos”, como o imperativo, o lógico, o
funcional e o orientado a objetos;
•
Arquitetura de Software [IEE 95, SHA 96]: tema que sintetiza as várias
abordagens da Engenharia de Software, se dedicando à descrição de componentes,
as interações entre eles e os padrões que guiam sua composição;
•
Distribuição implícita: exploração automática, pelo ambiente de execução, da
capacidade de espalhar componentes dinâmicos de um programa em vários nodos
processadores de uma rede;
•
Novos paradigmas: a criação de um novo paradigma de modelagem e
programação de software.
Um dos objetivos do Holoparadigma é a busca por um melhor desempenho e
aproveitamento dos recursos computacionais através da exploração automática do
paralelismo e da distribuição presentes nos programas. A exploração automática também
desobriga o programador a planejar o algoritmo exato de utilização dos recursos
computacionais, permitindo que este se concentre em outras tarefas, como a especificação e
depuração do software.
2.2 Hololinguagem
A Hololinguagem (abreviadamente, Holo) é uma linguagem de programação derivada
do Holoparadigma. Holo é uma linguagem multiparadigma, que integra os paradigmas
básicos de programação imperativo, lógico e orientado a objetos. Estudos recentes buscam a
integração do paradigma funcional [DUB 01] à linguagem. De acordo com [BAR 01], o
paradigma imperativo, bastante flexível, é fraco na expressão automática de fontes de
paralelismo presentes no sistema, que são modeladas por naturalidade pelos paradigmas
lógico e orientado a objetos. A integração de paradigmas permite a integração das suas fontes
de paralelismo e aumenta a versatilidade da linguagem. A Hololinguagem, de acordo com as
premissas do Holoparadigma, visa explorar estas fontes de paralelismo e distribuição de
forma implícita. Isto é conseguido à medida que as construções básicas da linguagem,
utilizadas pelos programadores para construir os programas, exprimem as fontes de
paralelismo de forma bastante sublime.
Algumas das construções básicas de Holo são:
13
Ente. O ente é a principal abstração de Holo. Toda existência é um ente, desde a mais
simples até a mais complexa. Na linguagem Holo, um ente pode ser estático ou dinâmico.
Entes estáticos funcionam como "moldes" para a instanciação (em Holo, clonagem) de entes
dinâmicos. Em C++ e Java, ente estático é análogo a classe, e ente dinâmico é análogo a
objeto, ou seja, a instância de uma classe.
Símbolo. De acordo com [BAR 02, p.41], o símbolo é o átomo de informação no
Holoparadigma. Holo propõe a utilização do processamento simbólico como principal
instrumento para o tratamento de informações, característica herdada do paradigma em
lógica. Neste sentido, a variável lógica e a unificação são consideradas a base do tratamento
de símbolos. Assim como variáveis lógicas, variáveis em Holo armazenam símbolos, e não
possuem tipo.
História. Um ente é uma existência temporal, possuindo passado, presente e futuro,
sendo que a história de um ente representa parte do seu passado. Na história, são registradas
constatações do presente que são de interesse do ente, na forma de símbolos. A história
funciona de maneira bastante semelhante a um blackboard lógico [GAR 95, VRA 95, PFL
97].
Comportamento, ação e interface. Um ente possui um comportamento, isto é, uma
descrição do processamento que ele realiza. O comportamento é composto de ações. Ações
são análogas a métodos de objetos de linguagens como C++ e Java. Holo estabelece dois
tipos básicos de ações: a ação imperativa (IA), oriunda do paradigma imperativo [GHE 98,
p.259; SEB 99, p.21], e a ação lógica (LA), oriunda do paradigma em lógica [KOW 79, ROB
92]. Ações multiparadigma (MA) são ações que integram os comportamentos em lógica e
imperativo. Por fim, um ente possui uma interface, que descreve suas possíveis relações de
comportamento com os demais entes.
Nível 0
Ente
I
n
t
e
r
f
a
c
e
Comportamento
História
I
n
t
e
r
f
a
c
e
Comportamento
Ente
Nível 2
Nível 2
História
Ente 1
Ente 2
...
História
Ente n
Ente
História
Nível 1
Ente
Ente
Ente
História
Ente
(a) Ente elementar
(b) Ente Composto
(c) Exemplo de composição (3 níveis)
Figura 2 – Composição de entes
Composição de entes e HoloTree. O ente até aqui descrito é classificado como ente
elementar. Ele possui uma interface, uma história e um comportamento. É possível a
14
composição de entes em Holo. Um ente composto é um ente elementar que possui outros
entes na sua composição. A composição de entes dinâmicos, em tempo de execução do
Holoprograma, forma uma estrutura de árvore denominada HoloTree. Os nodos terminais da
árvore representam entes elementares, e os outros são entes compostos. Um ente composto
assemelha-se a um grupo [LEA 01], podendo ser enxergado como um ambiente
compartilhado pelos seus entes componentes. Os entes componentes possuem acesso a
história do ente pai, ou seja, a história do seu contexto, como pode ser observado na figura
2c. Esta história atua como um meio de sincronização entre os entes componentes. A
HoloTree é uma estrutura dinâmica. Entes podem trocar de contexto, ultrapassando fronteiras
entre entes. Esta troca é denominada mobilidade lógica.
Um programa Holo é, basicamente, um texto composto por uma seqüência de
descrições de entes estáticos (figura 3). O corpo de um ente estático é formado por duas
partes: comportamento e história. O comportamento é constituído por um conjunto de ações
que implementam a funcionalidade do programa. Estas ações estão disponíveis no interior de
um ente e, através da interface, podem ser exportadas para acesso do exterior de um ente. A
história é descrita por uma seqüência de Cláusulas Lógicas com Extensões não Imperativas
(CLEIs). A história de um ente estático é o valor inicial da história dos entes dinâmicos que
serão clonados a partir dele.
<nome> (<argumentos>) cloning (<descrição>)
interface <ações exportadas>.
{
I
n
t
e
r
f
a
c
e
Cabeça
Comportamento
Ações
history
{
Corpo
CLEIs
História
}
}
Figura 3 – Forma geral de representação de um ente estático na Hololinguagem
Se um programa Holo é basicamente composto de uma lista de entes, um ente é
basicamente composto de uma lista de ações. No contexto deste trabalho, bastará a
informação de que uma ação imperativa é formada por uma seqüência de comandos, e uma
ação lógica é uma declaração (seqüência de cláusulas) Prolog. As construções sintáticas de
Holo são apresentadas em maior detalhe por [BAR 02].
2.3 Holoplataforma 1.0
Toda linguagem de programação precisa de uma plataforma, ou seja, um ferramental,
de desenvolvimento e execução de programas. A plataforma de Holo é a "Holoplataforma"
[BAR 02], e o termo refere-se à plataforma completa de desenvolvimento e execução de
programas Holo. Nesta seção, será definido um modelo que contempla apenas o subconjunto
da Holoplataforma que é relevante para a discussão deste trabalho. Especificamente, este
15
subconjunto compreende os módulos que já estão em funcionamento no protótipo Java da
plataforma, e que são vitais para o ciclo de depuração de programas. Para abreviar o texto,
este subconjunto será rotulado simplesmente de Holoplataforma.
Atualmente, apenas um subconjunto da linguagem Holo encontra-se implementado.
Este subconjunto denomina-se "Holo 1.0". Para demonstrar Holo 1.0, foi implementada a
"Holoplataforma 1.0", a primeira versão da plataforma. Esta versão é baseada na plataforma
Java [JAV 02]. Nesta versão, para se executar um programa Holo, este é primeiro traduzido
para Java, através da ferramenta HoloJava [BAR 01b]. A seguir, o programa traduzido é
compilado pelo compilador Java (JavaC), e depois executado por uma Máquina Virtual Java
(JVM). Caso o programa Holo possua trechos em lógica, o código Prolog correspondente
será gerado pela ferramenta HoloJava, que será depois traduzido para Java através da
ferramenta PrologCafe [PRO 02].
A versão atual suporta a execução concorrente de vários entes em um mesmo nodo
processador. A concorrência entre entes foi implementada por Java Threads [OAK 99]. Para
a comunicação entre os entes (ou seja, sincronização entre as threads que executam o
comportamento dos entes) utiliza-se a biblioteca Jada [CIA 02], que provê um mecanismo de
blackboards para a implementação da história dos entes.
A figura 4 ilustra a implementação da Holoplataforma, inserida na sua realidade de
uso.
Holocompilador
HoloEnv
Holoprograma
HoloJava
Fonte Prolog
(Lógica)
Programador
Fonte Java
(Imperativo/OO)
Interage
PrologCafe
JavaC
Fonte Java
(compilador Java)
(Lógica)
Holocódigo
Interage
Bytecode Java do
Programa Holo
Usuário Final
Projeta
Execução
(Interface com o usuário)
Bibliotecas
(Java2, Jada,
PrologCafe)
Máquina Virtual
Java (JVM)
Holomáquina
Figura 4 – Holoplataforma 1.0
A distinção entre a execução projetada do programa e a máquina executando o código
do programa foi traçada porque o programador pode interagir mais diretamente com a
máquina, além de interagir com a interface do programa. Esta interação direta com a máquina
é feita através do módulo depurador, que será apresentado no capítulo 3.
16
Na figura está inserido o HoloEnv, que é um ambiente integrado de desenvolvimento
(IDE). Ele esconde os passos intermediários de tradução, compilação e execução de
programas, além de prover ferramentas de edição e outras facilidades ao programador Holo.
Futuramente, o HoloEnv integrará também uma interface visual para a depuração de
programas, baseada no módulo depurador desenvolvido neste trabalho.
No âmbito das pesquisas do Holoparadigma, a Holoplataforma será futuramente
desligada da plataforma Java, com a implementação de um compilador e de uma máquina
virtual, ambos próprios para Holo. A Máquina Virtual Holo executará um código virtual
multiparadigma, e terá uma versão capaz de executar um programa Holo de forma
distribuída. Como as possibilidades de distribuição de um programa Holo estão implícitas no
mesmo, estas serão exploradas automaticamente pelo ambiente.
Destaca-se aqui esta re-implementação futura para salientar que o suporte para
depuração de programas também precisará ser re-implementado, porém o modelo de
depuração abstrato e a ferramenta de depuração devem, idealmente, permanecerem
inalterados. Um dos objetivos deste trabalho é o de separar o estudo da interface homemmáquina do depurador Holo, do projeto das APIs depurador-máquina e das implementações
destas APIs.
2.4 Holo 1.0
2.4.1 Características
Como mencionado na seção anterior, apenas um subconjunto da linguagem Holo,
denominado "Holo 1.0", encontra-se implementado atualmente. O depurador implementado
neste trabalho atua sobre esta versão da linguagem. As principais características presentes em
Holo 1.0 são:
•
Entes estáticos possuem o nome como especificação de interface;
•
Entes estáticos podem declarar Ações Modulares Lógicas (MLAs) e Ações
Imperativas (IAs);
•
Entes estáticos podem declarar o estado inicial da sua história;
•
Ações possuem nome e aridade na especificação da interface;
•
Comando "clone", para clonagem de transição (instanciação de entes);
•
Comando "move", para mobilidade lógica de entes;
•
Perguntas e afirmações, construtivas e destrutivas, para a história do ente;
•
Acesso à história do contexto do ente (história do pai) através do comando
out(history)
•
Invocação de uma ação sobre o próprio ente (self), ou sobre uma referência a outro
ente.
Este subconjunto da linguagem já permite o desenvolvimento de aplicações de teste.
Um dos problemas clássicos que já é programável em Holo é o do "Jantar dos Filósofos", que
17
exercita a concorrência da linguagem. A seção seguinte mostra uma implementação, em Holo
1.0, destes problema, seguida de uma explicação do seu funcionamento.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
holo()
{
holo()
{
writeln('CINCO FILOSOFOS VAO JANTAR.'),
writeln('CADA FILOSOFO COME CINCO VEZES.'),
writeln('O JANTAR ESTA INICIANDO.....'),
for X := 1 to 5 do
{
clone(filosofo(X),null)
}
for X := 1 to 5 do
{
history#end
}
writeln('O JANTAR ACABOU.')
}
history
{
chopstick(1).
chopstick(2).
chopstick(3).
chopstick(4).
chopstick(5).
ticket. ticket. ticket. ticket. ticket.
seat(1,2). seat(2,3). seat(3,4). seat(4,5). seat(5,1).
}
}
filosofo()
{
filosofo(Ident)
{
writeln('Fisolofo esta jantando: ',Ident),
for Cont := 1 to 5 do
{
out(history)#ticket,
out(history)#seat(#F1,#F2),
out(history)#chopstick(#F1),
out(history)#chopstick(#F2),
for Atraso := 1 to 1000 do
{}
out(history)!chopstick(F2),
out(history)!chopstick(F1),
out(history)!seat(F1,F2),
out(history)!ticket,
writeln('Comendo ',Ident,' - ',Cont)
}
out(history)!end
}
}
Figura 5 – Problema do "Jantar dos Filósofos", modelado em Holo 1.0
18
2.4.2 Exemplo: Jantar dos Filósofos
Este problema é utilizado com freqüência como exemplo canônico de concorrência. O
problema especifica um jantar onde há cinco filósofos e apenas cinco talheres. Cada filósofo
precisa apoderar-se de dois talheres adjacentes ao seu assento para comer. Após utilizá-los,
ele retorna os talheres para que outros filósofos possam comer. O detalhe é o de que os
filósofos param freqüentemente de comer para pensar, liberando os talheres, ou seja, o jantar
de um filósofo consiste de várias seqüências de obtenção e liberação dos talheres. Problemas
como deadlocks e starvation podem ocorrer. A figura 5 lista um programa em Holo 1.0 que
implementa o problema do "Jantar dos Filósofos".
Este programa possui dois entes estáticos declarados: holo e filósofo. Em tempo de
execução, o ente holo (estático) é automaticamente clonado (instanciado) como o ente d_holo
(dinâmico), que é a raiz da HoloTree. A ação d_holo.holo/0 (ação holo de aridade zero) é
invocada pela thread principal, sendo este o ponto de entrada do programa.
O laço das linhas 8 a 11 realiza a clonagem de cinco entes dinâmicos do tipo filósofo,
e especifica que a ação construtiva destes entes é a de aridade um, pois passa um argumento
para o nome do ente. A ação construtiva deve, obrigatoriamente, possuir o mesmo nome do
ente. O parâmetro passado para cada filósofo criado é um número (de 1 a 5) que o identifica
na mesa de jantar. Os entes dinâmicos do tipo "filósofo" serão criados no contexto do ente
d_holo, sendo portanto instanciados como seus descendentes diretos na HoloTree.
O laço das linhas 12 a 15 realiza a retirada de cinco tokens (tuplas de apenas um
elemento) de nome "end" da história do ente d_holo. Estes tokens são inseridos na história do
ente d_holo pelos entes filósofos à medida em que estes terminam o seu jantar. O operador
"#" caracteriza uma pergunta destrutiva, isto é, o token é consumido após sua leitura, e
bloqueante, isto é, a thread que executa a pergunta permanecerá bloqueada até que a história
do ente d_holo possua um ou mais tokens de nome "end".
As linhas 19 a 28 especificam o conteúdo inicial da história do ente d_holo. É
interessante ressaltar a forma de especificação de tuplas: o primeiro elemento é seguido dos
demais elementos especificados dentro de parênteses e separados por vírgulas.
O laço das linhas 36 a 49 constitui a atividade de comer, realizada por um filósofo.
Observe-se que as ações que implementam o comportamento do filósofo, através da
construção out(history), atuam sobre a história externa do ente filósofo, ou seja, a história do
ente d_holo. A janta do filósofo, no exemplo é composta de cinco repetições sobre um
conjunto de ações. A tabela 1 detalha esta s ações.
Na implementação do filósofo, é introduzida mais uma construção presente em Holo,
a afirmação sobre a história, através do operador "!". Por fim, na linha 50, o filósofo avisa
que já encerrou sua atividade, com a inclusão do token "end" na história de d_holo. O
programa termina quanto todos os filósofos incluem este token na história, e o ente d_holo, a
seguir, retira-os da história.
19
Linha(s)
Atividade
38
Retira um ticket (avisa que está com fome)
39
Retira um assento (seat) qualquer, recebendo a
informação dos talheres adjacentes à esta
cadeira específica (F1 e F2)
40 - 41
Aguarda e retira os dois talheres (chopsticks)
adjacentes ao seu assento.
42 – 43
Realiza um delay (filósofo comendo)
44 – 45
Devolve os talheres à história
46
Devolve o assento à história
47
Devolve o ticket (não está mais com fome)
Tabela 1 – Ações que compõe a janta do filósofo
2.5 Depuração Holo
Esta seção introduz a questão da depuração de programas Holo. Primeiramente
discute-se o conceito de "depuração", seguido de uma análise de certos aspectos da
Hololinguagem e seu impacto no problema da depuração de programas. Por fim, enumeramse os serviços básicos de depuração Holo 1.0, que foram identificados e são oferecidos pelo
módulo depurador projetado e implementado por este trabalho.
2.5.1 Conceito de Depuração
Os termos "depuração", "depurador" e similares são adaptações de uma outra família
de termos originais em inglês ("debugging", "debugger"...), cuja raiz é o termo "bug", que
significa o mesmo que "defeito" em um programa. Uma tradução mais literal do termo
"debugger" resultaria em algo similar a "eliminador de defeitos", o que é um termo muito
menos abrangente do que "depurador". Em [ROS 96, p. 1], o autor reconhece que o termo
"debugger", no sentido de eliminador de defeitos, não é o termo mais apropriado, e prossegue
para classificar os depuradores de programas como ferramentas que servem para iluminar a
natureza dinâmica dos programas, servindo para permitir um melhor entendimento dos
mesmos, além de servirem para localizarem e consertarem erros de programação.
O termo em português é mais genérico, e pode ser considerado mais apropriado.
"Depurar" significa essencialmente "aprimorar". Um depurador de programas é utilizado, em
grande parte, em um processo iterativo de aprimoramento do programa. O programador
coloca o seu programa sob a "lente" do depurador, retira conclusões e realiza modificações
sobre o mesmo, e repete o processo. O objetivo é, neste caso, melhorar o programa em
direção a um estado ideal que, entre suas características, encontra-se a ausência de defeitos.
Defeitos são causa de falhas, que por sua vez compreendem comportamento errático exibido
pelo programa, quando este é executado [FRA 97].
20
Porém, um depurador não serve apenas para depurar um programa. O depurador de
programas é, essencialmente, uma ferramenta de análise do comportamento de um programa,
podendo servir até como uma ferramenta didática. E, como fator adicional, se por um lado os
termos "depurador" e "debugger" (eliminador de defeitos) não abrangem todo o significado
necessário, por outro eles possuem talvez significação excessiva, se considerarmos as
ferramentas que hoje são denominadas de "depuradores". Por exemplo, uma ferramenta de
análise de performance (profiler) também pode ser considerada um depurador, pois auxilia o
programador a aprimorar o seu programa. Pode até ser considerado um "eliminador de
defeitos", pois uma baixa performance apresentada por um programa também pode ser
considerada uma falha do mesmo. Porém, serviços de profiling não são diretamente
associados a depuradores de programas, atualmente.
Neste trabalho, o termo "depuração" terá um significado bastante ligado com as
atuais ferramentas comerciais que são denominadas de "depuradores de programas"
(debuggers). Como exemplo destas ferramentas, podemos citar o depurador integrado aos
ambientes JBuilder [BOR 02] e Visual C++ [MIC 02], e o depurador gdb [GDB 02].
Atualmente, observa-se uma tendência à integração de cada vez mais serviços aos
depuradores, como profilers, heap checkers (verificadores de consistência da memória), e
outros. De qualquer maneira, um certo conjunto de serviços básicos permanece inalterado. O
foco deste trabalho é a criação de um depurador Holo que oferece estes serviços básicos para
a plataforma Holo 1.0. Estes serviços, como execução passo-a-passo, inserção de
breakpoints, e serviços gerais de consulta ao estado do programa, traduzem-se, sem grandes
alterações, do contexto de linguagens como Java e C++ para o contexto de Holo. Estes
serviços estão relacionados na seção 2.5.5.
2.5.2 Depuração concorrente
Um programa concorrente é um programa composto por fluxos de execução
independentes que competem continuamente por acesso a recursos compartilhados, como
estruturas de dados e fatias de tempo de processamento. Atualmente, o mecanismo de
concorrência mais difundido na comunidade de desenvolvimento de software é, certamente, o
mecanismo de "threads", tanto que os conceitos são freqüentemente utilizados como se
fossem sinônimos. Uma thread geralmente é implementada, pelos sistemas operacionais,
como um "processo leve", cujo chaveamento de contexto é bem menos custoso do que o
chaveamento de um processo convencional.
A concepção de ferramentas de depuração de programas concorrentes, ou
"multithreaded", é muito mais complexa do que a implementação de depuradores de
programas com apenas um fluxo de execução. Um programa multithreaded é muito mais
difícil de ser analisado por um programador, e é responsabilidade da ferramenta de depuração
amenizar este impacto, com a criação de mecanismos especiais para controle de programas
multithreaded. A implementação destas ferramentas também é problemática, pois o suporte
dado pelos sistemas operacionais para a depuração multithreaded é geralmente inadequado
[ROS 96, p.179]. A plataforma Java pode ser considerada uma exceção à regra, possuindo
21
uma arquitetura de depuração bastante robusta, concebida para a depuração de uma
linguagem fundamentada em multithreading [ROS 96, p.77].
Holo é uma linguagem que gera programas concorrentes. Porém, diferentemente de
Java, algumas das fontes de concorrência da linguagem são declaradas implicitamente nas
suas construções. Por exemplo, a descrição de um programa através da separação em "entes"
permite a exploração automática, pela máquina, da concorrência inter-entes [BAR 02]. Em
Holo, o programador não manipula diretamente "threads", sendo que estas compreendem
apenas um mecanismo para a implementação da linguagem.
Mas se o mecanismo de threads é abstraído do programador pelas construções
gramaticais da linguagem, um depurador Holo não pode se dispor tão facilmente desta
realidade. O depurador precisa conciliar duas tarefas bastante divergentes: a tarefa de
oferecer todo o controle e visão da máquina, necessários para que o programa seja depurado,
e a de esconder a implementação da máquina atrás da abstração da linguagem. Como é
apontado em [ROS 96], muitos depuradores de linguagens de alto nível, quando estas são
compiladas para código nativo de um processador, precisam exibir uma janela de inspeção do
programa em nível de instruções, e precisam exibir o conteúdo dos registradores do
processador. Ou seja, às vezes é necessário que a ilusão seja conscientemente quebrada e
exposta para um usuário, a fim de não comprometer a cobertura da ferramenta.
Neste trabalho, optou-se por exibir, nas interfaces do depurador, a realidade da
implementação da concorrência de Holo em threads. O programador Holo terá controle sobre
a execução das threads do seu programa. Para manter um elo com a abstração Holo, todas as
threads são associadas aos seus respectivos entes, sendo que no protótipo atual da
Hololinguagem, a concorrência intra-entes ainda não foi implementada, e a concorrência
inter-entes é implementada com a criação de uma thread para executar o comportamento de
cada ente criado, sendo o ponto de entrada de execução a ação construtiva do ente.
Esta abordagem da depuração concorrente em Holo visa aproveitar todo o suporte e
toda a tradição da literatura, atualmente presentes para a depuração de programas
multithreaded. Para eliminar a exibição das threads pelo depurador, torna-se necessária a
criação de uma abstração em Holo para as mesmas, pois o controle das threads pelo
programador é essencial para a depuração de programas multithreaded. Esta questão está em
aberto.
2.5.3 Depuração multiparadigma
Em Holo é possível se identificar estruturas lógicas e estruturas imperativas. A
principio, a depuração em Holo poderia ser tratada como uma concatenação de dois
problemas totalmente distintos: a depuração de uma linguagem imperativa e a depuração de
módulos de linguagem lógica declarativa. Esta abordagem de concatenação seria
provavelmente aceitável comercialmente, porém, uma solução mais interessante, que segue a
filosofia da linguagem, consistiria na criação de um modelo de depuração com uma
22
semântica que integre os paradigmas básicos de Holo. Algumas possibilidades são
apresentadas a seguir.
Em Holo, módulos ou trechos declarativos de programa podem ser considerados como
uma extensão controlada pela parte imperativa do programa. Isto é determinado pelo Grafo
de Invocação de Ações (AIG) de Holo, como mostra a figura 6. Na figura, ações imperativas
e multiparadigma (MA, IA, MIA) podem invocar qualquer tipo de ação, mas ações lógicas
(LA, MLA) só podem invocar outras ações lógicas. É interessante notar que a maioria das
implementações comerciais de linguagens declarativas como Prolog vem com extensões
imperativas com o objetivo de implementar interfaces com o “mundo exterior”. Isto pode ser
observado nos depuradores dos ambientes Trinc-Prolog [TRI 02], SICStus Prolog [SIC 02] e
Amzi Prolog [AMZ 02].
MA
IA
MIA
LA
MLA
Região
Imperativa
Região
Lógi
ógica
Figura 6 – Grafo de Invocação de Ações (AIG) de Holo
A depuração de programas Prolog é feita principalmente através da utilização de
traços de execução [TOB 93] e predicados especiais, que atuam sobre um interpretador
Prolog. O controle do fluxo de execução por um depurador Prolog tipicamente atua sobre o
modelo da "caixa de procedimento", introduzido por Byrd [BYR 80]. É aparente que o
suporte para depuração de programas declarativos tem avançado muito pouco, quando
contrastado com a sofisticação atual dos depuradores de linguagens imperativas, como o
depurador Java integrado ao ambiente de desenvolvimento "JBuilder Personal" [BOR 02],
que é disponibilizado gratuitamente para uso não-comercial.
Até aqui, duas constatações foram feitas: a de que o suporte para depuração
declarativa é bastante rudimentar se comparado às facilidades presentes nos depuradores
comerciais de linguagens imperativas, e a de que, na prática, o paradigma declarativo se
beneficia de uma shell de controle imperativo. Destas constatações, surge a idéia de se
transportar alguns conceitos da depuração imperativa para a depuração declarativa, visando
uma maior integração dos paradigmas de depuração.
23
Por exemplo: o recurso de passo-a-passo, requerimento básico e obrigatório de um
depurador comercial de uma linguagem imperativa, poderia ser estendido para que, quando o
usuário da ferramenta de depuração realizar um “passo” que o leva de uma região imperativa
para uma região declarativa, ele assuma uma semântica diferente. Uma semântica possível,
seria a de acompanhar o “raciocínio” realizado pela máquina sobre a declaração do programa
lógico. Desta forma, após um “passo”, seria destacado, no texto do programa, a cláusula que
está sendo atualmente testada. O “passo -a-passo” em lógica, ao contrário do “passo -a-passo”
imperativo, poderia andar “tanto para frente como para trás”, mostrando para o usuário do
depurador o mecanismo de backtracking em funcionamento. Este recurso consta em
depuradores Prolog como o depurador integrado ao ambiente Trinc-Prolog [TRI 02].
Esta idéia sobre o passo-a-passo é apenas uma das muitas formas possíveis de integrar
os paradigmas para um módulo depurador de Holo. A concepção de uma solução otimizada
para a integração dos paradigmas de depuração de linguagens lógicas e imperativas
transcende os objetivos deste trabalho. Em nível de implementação, o tratamento de Prolog
no contexto deste trabalho está restrito à capacidade do depurador em decodificar uma pilha
de ativação de uma thread que envolva tanto registros de ativação de MLAs quanto de IAs.
Ou seja, o usuário do depurador pode visualizar uma pilha de ativação multiparadigma.
Para completar o quadro da depuração multiparadigma em Holo, o paradigma básico
da orientação a objetos, integrado por Holo, é tratado na depuração principalmente em nível
de exibição das estruturas de dados para o programador. Um programa imperativo puro não
possui, nos seus dados, hierarquia que possa ser extraída pelo depurador sem “dicas”
fornecidas pelo programador. Um programa muito extenso, com centenas ou milhares de
instâncias e símbolos presentes durante a sua execução, é mais facilmente analisado se
hierarquias e redes destes símbolos podem ser automaticamente reconstruídas e exibidas pelo
depurador. No caso de Holo, por exemplo, a árvore de entes (HoloTree) poderia ser exibida
em um controle gráfico do tipo “árvore com nodos expansíveis”, como mostra a figura 7. Isto
é muito vantajoso, pois o colapso e a expansão da estrutura de nodos, extraída diretamente
das construções da linguagem, permite ao usuário lidar com a enorme quantidade de
informação apresentada na interface com mais facilidade.
24
holo
ente1
ente2
ente4
ente3
ente5
Figura 7 – Exemplo de controle gráfico (à direita) para a exibição da HoloTree, a estrutura de
árvore em que os entes em Holo são organizados (à esquerda).
2.5.4 Depuração distribuída
Como discutido anteriormente, um programa Holo possui fontes implícitas e
explícitas de paralelismo em seu programa. O objetivo de Holo é que a maneira com que este
paralelismo é explorado fique a critério do ambiente distribuído de execução. Este
mecanismo, baseado em algum critério de escalonamento, move entes de um nodo para outro,
de forma a maximizar o desempenho do sistema. Desta forma, parte do trabalho de se
escrever uma aplicação composta de fluxos de execução independentes é absorvida pelas
próprias construções da linguagem, que são utilizadas normalmente pelo programador no
esforço de descrever o funcionamento correto do programa.
A execução de um programa Holo em uma arquitetura distribuída resultaria em
conjuntos de entes executando em nodos processadores conectados por uma rede. Entes
locais a um nodo processador concorreriam, por exemplo, por tempo de processamento. O
protótipo atual de Holo roda apenas sobre um único nodo processador, implementando a
concorrência entre entes que compartilham o único nodo.
Estudos sobre depuração de programas distribuídos foram feitos por [WAH 92, MEI
96, NER 97]. A depuração distribuída será um problema a ser tratado em Holo, porém,
transcende o escopo deste trabalho.
2.5.5 Serviços básicos de depuração para Holo 1.0
A tabela 2 relaciona os serviços básicos identificados como necessários para a
implementação de um depurador para Holo 1.0, juntamente com uma descrição dos mesmos.
25
Serviço
Descrição
Execução passo-a-passo Permite a uma thread executar uma única linha de comando
do tipo step into
da linguagem Holo, inclusive decompondo chamadas de
ações em seus respectivos passos.
Execução passo-a-passo Idem a "step into", porém trata chamadas de ações como
do tipo step over
um passo único.
Execução passo-a-passo Faz com que a thread continue a execução da sua ação atual
do tipo step out
até que esta retorne à ação que a invocou.
Criação e remoção de Inserção e remoção de pontos de parada em linhas do
breakpoints
programa. Estes pontos causam a suspensão do programa
no momento em que um fluxo de execução (thread) vai
executar a linha em questão. Deve existir a possibilidade do
breakpoint suspender apenas a thread que o ativou, e não
apenas a suspensão de todo o programa.
Inspeção da história de Realiza a consulta ao conteúdo da história de um ente
um ente
dinâmico, ou seja, obtém a lista de tuplas atualmente
presentes na história do mesmo.
Inspeção da HoloTree
Obtenção do estado atual da HoloTree.
Opção para detecção de Causa a interrupção do programa quando uma mobilidade
mobilidade lógica
lógica (através do comando "move") estiver para ocorrer.
Obtenção da lista de Retorna a lista de threads ativas no momento.
threads em execução
Obtenção da pilha de Retorna a pilha de ativação de uma thread, que mostra a
ativação (call stack) de seqüência de chamadas a ações que estão ativas (pendentes)
uma thread
no momento. A thread deve estar suspensa.
Localização de threads
Dado um registro de ativação de uma thread (elemento da
pilha de ativação), permite a identificação da linha atual em
execução no programa.
Inspeção de variáveis Dado um registro de ativação de uma thread, retorna uma
locais
lista de variáveis locais e seus valores, e permite a pesquisa
de uma variável local pelo seu nome.
Suspensão
continuação
execução
e Permite suspensão e continuação do programa como um
da todo (todas as threads) ou apenas de uma thread
individualmente.
Tabela 2 – Serviços de depuração para Holo 1.0
26
Pela tabela 2, observa-se que a maioria dos serviços do depurador operam no contexto
de uma ou mais threads. A linguagem Holo não especifica como deve ser implementada a
concorrência entre entes, mas em Holo 1.0 esta concorrência é implementada através da
criação de uma thread para executar a ação construtiva de cada ente criado. Portanto, a
tendência é a de que a depuração da Hololinguagem envolva um grande número de threads. É
importante um bom suporte para o gerenciamento das mesmas.
Os serviços de depuração para ações lógicas (MLAs), nesta versão do depurador,
limitam-se à identificação de registros de chamadas a MLAs na pilha de ativação de uma
thread. Não será possível inspecionar estes registros para a identificação do ponto exato do
backtracking no código da MLA, ou inspecionar o valor e nomes das variáveis locais. Porém,
os serviços de depuração para a parte imperativa da linguagem, relacionados na tabela, foram
totalmente implementados.
Com os serviços básicos apresentados na tabela 2, é possível também a
implementação de serviços sofisticados através de composição. Alguns exemplos seriam:
•
Agrupamento de threads ou entes: oferecer comandos que permitam, ao usuário
do depurador, atuar sobre grupos de threads ou entes. Bastaria manter a
informação de grupo em uma estrutura de dados, e enviar o comando,
individualmente, para cada thread ou ente do grupo. Por exemplo, seria possível a
suspensão ou continuação de um grupo específico de threads. Também seria
possível a requisição de notificação quando qualquer ente de um grupo fosse
movido de seu contexto atual na HoloTree.
•
Seleção ou agrupamento de threads ou entes baseado em atributos: seria possível
que, por exemplo, o depurador agrupasse automaticamente threads ou entes
automaticamente, no momento em que são criados, ou durante algum momento de
sua execução (como após a ocorrência de mobilidade), baseado em atributos dos
mesmos. Por exemplo, entes que possuam um nome que inicie com "filosofo", ou
que possuam uma certa informação em suas histórias, podem ser identificados
pelo depurador, e um comando pré-definido pode ser executado sobre eles como,
por exemplo, inserção automática em um grupo.
•
Breakpoints condicionais: uma característica freqüentemente presente em
ferramentas comerciais é a possibilidade de inserção de breakpoints que, após
serem atingidos por uma thread, notificam o usuário apenas se certas condições
forem satisfeitas. Por exemplo, é possível a criação de breakpoints que apenas são
disparados, ou cessam de serem ativados, após um certo número de ativações. Um
breakpoint condicional também pode ser sensível apenas a certas threads, ou a
certos entes dinâmicos.
•
Salvamento de informações para análise posterior: a ferramenta de depuração
pode, por exemplo, coletar todas as configurações da HoloTree durante um certo
período, e gravá-las em um arquivo. Este arquivo pode ser usado, por exemplo,
para realizar uma animação gráfica ou uma análise da evolução da HoloTree.
27
Esta composição é responsabilidade da "ferramenta de depuração" propriamente dita,
ao passo que os serviços básicos são oferecidos pelo "módulo depurador". Estes serviços
básicos são fornecidos, pelo módulo depurador, para a ferramenta através da HDI (Holo
Debug Interface), uma API desenvolvida neste trabalho. A ferramenta de depuração
desenvolvida neste trabalho (Holo Debugger), que será vista mais adiante, serve como
demonstração dos serviços básicos da API.
2.6 Considerações finais
É evidente que o problema da depuração de programas Holo oferece muitas frentes
para pesquisa e implementação. Por um lado, a depuração de programas multiparadigma é
um tema que envolve a integração dos paradigmas básicos em nível de interface do
depurador. Apesar de ser possível a implementação simultânea de interfaces distintas no
mesmo depurador, é desejável uma solução que integre, parcialmente ou totalmente, os
depuradores de linguagens de programação em lógica (Prolog) e depuradores imperativos.
Por outro lado, à medida em que avançarem os estudos sobre a plataforma Holo distribuída
(DHolo), é interessante avançar estudos sobre o suporte à depuração distribuída que deve ser
fornecido por esta plataforma.
Neste contexto, este trabalho possui uma implementação focada nos serviços de
depuração que atendem às necessidades de Holo 1.0, o que inclui um suporte adequado para a
depuração de programas multithreaded. Para este fim, oferece um modelo para a arquitetura
do depurador Holo, que pode ser usado também em futuras implementações da plataforma e
que deve evoluir juntamente com a pesquisa no âmbito do Holoparadigma. Este modelo é
apresentado no capítulo 3.
28
3. Holo Extensão para Depuração (HED)
Este capítulo apresenta a Holo Extensão para Depuração (HED), uma extensão ao
modelo da Holoplataforma que adiciona suporte à depuração de programas. Primeiramente, é
apresentada a Holoplataforma estendida com a inclusão dos módulos necessários para a
depuração. A seguir, apresentam-se as modificações realizadas sobre o protótipo Java de
Holo para a implementação do depurador. Por fim, são descritos os três componentes do
depurador que foram implementados neste trabalho: a extensão da ferramenta HoloJava 1.0
para geração de informação de depuração, a HDI (Holo Debug Interface), a especificação e
implementação de uma API para ferramentas de depuração Holo, e o Holo Debugger, uma
ferramenta simples de depuração baseada na HDI.
3.1 Visão geral
A figura 8 apresenta o modelo da Holoplataforma estendida para depuração. Apesar
de implementada sobre a Holoplataforma 1.0, a HED prevê mudanças na implementação da
plataforma. O principal componente adicionado foi o Holodepurador, que controla o
programa em execução na máquina. Os ambientes de execução do Holodepurador e da
Holomáquina podem ser o mesmo, ou podem ser distintos. No último caso, configura-se uma
sessão de depuração remota. Os sub-componentes do modelo são:
Holocompilador
HoloEnv
Programador
Interage
Holoprograma
Interage
Informação de
Depuração
Execução
(Interface com o usuário)
IHM - Interface
Homem-Máquina
Gerador de Informação
de Depuração
Holocódigo
Projeta
Máquina
IPD - Interface
de Programação
do Depurador
IDM - Interface
de Depuração
da Máquina
PFD – Processo
Front-end
do Depurador
PBD - Processo
Back-end
do Depurador
PDM - Protocolo
Depurador-Máquina
Holodepurador
Holomáquina
Figura 8 – Modelo da Holoplataforma estendida para depuração
Gerador de Informação de Depuração. É a parte do compilador responsável por
inserir informação no código que é necessária para a implementação dos algoritmos do
depurador. Por exemplo, o algoritmo que determina o ponto do programa em que uma thread
se encontra. Estando a thread parada, com o seu apontador de instrução indicando uma certa
29
instrução no código do programa, é necessário que esta posição seja traduzida para uma
informação acessível ao programador, no caso, o número da linha no texto original do
programa. Este mapeamento é resolvido pelo depurador através da inclusão da informação
necessária no código. A inclusão da informação no código introduz um overhead sobre a
execução. Tipicamente, os compiladores que geram informação de depuração fazem isto de
forma opcional, podendo gerar duas versões do código: uma destinada para o usuário final,
sem a informação, e uma destinada para ser executada sob o depurador, com a informação.
Interface de Depuração da Máquina (IDM). É a API que publica as funções de
depuração suportadas pela máquina, tipicamente, funções de baixa granularidade.
Processo Back-end do Depurador (PBD). É a parte do depurador que precisa
executar próximo à máquina sendo depurada. Interage com a máquina através da IDM. Se a
"máquina" é, de fato, uma máquina virtual (como é o caso de Holo) o back-end pode ser
outro processo, sob o controle do mesmo sistema operacional, que interage com a máquina
através da IDM. O PBD também pode fazer parte da implementação da máquina virtual. A
plataforma Java, por exemplo, permite as duas possibilidades.
Protocolo Depurador-Máquina (PDM). É um protocolo de comunicação que
conecta os ambientes da máquina e do depurador. Conecta o PBD com o resto dosoftware do
depurador, executando juntamente ao usuário programador.
Processo Front-end do Depurador (PFD). Implementa os serviços de depuração,
comunicando-se através do protocolo (PDM) com o back-end (PBD).
Interface de Programação do Depurador (IPD). É a API que publica as funções de
depuração implementadas pelo PFD, tipicamente funções de alta granularidade, que serão
utilizadas para a implementação dos serviços fornecidos para o usuário do depurador.
Interface Homem-Máquina (IHM) do Depurador. É a interface com o usuário do
depurador. Expõe os controles e os meios de visualização da sessão de depuração ao
programador. A funcionalidade dos elementos da interface é acessada pela IPD, e
implementada pelo PFD. Este componente também pode implementar serviços mais
especializados, baseados nos serviços básicos de depuração publicados pela IPD.
O projeto da HED é baseado na arquitetura do depurador da Plataforma Java, a JPDA
(Java Platform Debugger Architecture) [JPD 02]. A figura 8 pode ser adaptada para
representar a atual versão da plataforma Java (1.4) com pouca modificação. Este projeto foi
adotado por permitir a depuração remota de programas, com a conseqüente minimização da
intrusão causada pela presença do depurador no ambiente de execução do programa depurado
[ROS 96], e também por possuir uma organização bastante modular, que permite que os
módulos sejam implementados separadamente (máquina, front-end, back-end e interface do
depurador) enquanto aderirem às interfaces e protocolos que os conectam. A JPDA
representa a segunda geração de suporte à depuração em Java. Este modelo se revela ideal
para depuração de plataformas com máquinas virtuais, como é o caso de Holo e Java.
Esta adição à Holoplataforma permite que o programador interaja diretamente com a
máquina através da IHM do modelo, ou seja, da ferramenta de depuração, que é a interface
30
com o restante do módulo depurador. Esta interação direta com a máquina tem como objetivo
inspecionar o estado e controlar a execução de instruções pelo programa carregado na
máquina, sem que o programa do usuário precise explicitamente adicionar suporte para a sua
depuração.
3.2 Extensão da Holoplataforma 1.0
Neste trabalho, o modelo de extensão para depuração, apresentado na seção anterior,
foi implementado sobre a Holoplataforma 1.0, adicionando o suporte à depuração para o
protótipo de Holo. A figura 9 ilustra a configuração atual da implementação da plataforma. A
tabela 3 relaciona os componentes do modelo abstrato (HED) com os componentes do
modelo implementado (Holoplataforma 1.0 estendida para depuração).
Holocompilador
HoloEnv
Holoprograma
Programador
Interage
HoloJava 1.0
Estendida
Código-fonte
Prolog (Lógico)
Código-fonte
Java
PrologCafe
(Imperativo/OO)
JavaC
Código-fonte
Java (Lógico)
Bytecode Java do
programa Holo
Arquivo de
Informação de
Depuração
Execução
Interage
(Interface com o usuário)
Projeta
Bibliotecas
(Java2, Java, PrologCafe)
Holocódigo
IHM
Holo Debugger
IPD
HDI
Holo Debug Interface
Java Virtual Machine
executando bytecode Java
que implementa o programa Holo
Implementação da HDI
(Classes Java)
PFD
JDI
Java Debug Interface
Processo Front-end
de depuração da JPDA
Implementação Java2/JDK
Holodepurador
JDWP
Java Debug
Wire Protocol
(PDM)
Processo Back-end
de depuração da JPDA
Implementação Java2/JDK
(PBD)
Holomáquina
Figura 9 – Holoplataforma 1.0 estendida para depuração através da HED. Em destaque:
módulos que receberam extensões ou foram implementados no contexto deste trabalho.
31
Componente da HED
Mapeamento para a extensão de Holo 1.0
IHM
Holo Debugger
IPD
Holo Debug Interface (HDI)
PFD
Implementação da HDI, baseada na JDI (Java Debug
Interface), que é a IPD da plataforma Java.
PDM
Java Debug Wire Protocol (JDWP)
PBD e IPD
Java Virtual Machine (JVM)
Tabela 3 – Mapeamento da HED para a Holoplataforma 1.0
A implementação da HED sobre a Holoplataforma 1.0 é fortemente embasada na
implementação atual da arquitetura do depurador da plataforma Java, a JPDA (Java Platform
Debugger Architecture). Os componentes da JPDA implementam todos os serviços de
depuração sobre o bytecode Java que implementa o programa Holo. A API de mais alto nível
da JPDA, a JDI (Java Debug Interface), é, seguindo a nomenclatura da HED, uma interface
de programação para depuradores (IPD) Java. Neste contexto, a JDI foi utilizada para a
implementação da HDI. Desta forma, no contexto dos serviços de depuração de programas, a
HDI traduz a linguagem Java para Holo, e a JDI, manipulada pelas classes de implementação
HDI, traduz o bytecode Java para linguagem Java. Porém, para que os algoritmos da HDI
realizem a depuração de Holo sobre Java, é preciso que o programa Holo possua um
mapeamento para as instruções da Holomáquina, ou seja, em última análise, para o bytecode
Java. Como será detalhado na seção 3.3, a plataforma Java provê o mapeamento do bytecode
Java para a linguagem Java, e, para o mapeamento da linguagem Java para Holo, a
ferramenta HoloJava foi estendida para gerar esta informação.
De acordo com esta configuração, no ambiente depurado, a Holomáquina, residem
dois processos: a Máquina Virtual Java (JVM) e o processo back-end do depurador (PBD),
que se comunica com a JVM através da JVMDI (Java Virtual Machine Debug Interface, a
IDM do modelo). Na prática, o PBD default da plataforma Java é implementado no mesmo
processo da JVM (situação exibida pela figura 9), sendo a JVMDI publicada para a
construção de depuradores por outros fornecedores de software. O ambiente depurado e o
ambiente depurador se comunicam através da JDWP (Java Debug Wire Protocol, o PDM do
modelo). O módulo front-end do Holodepurador (PFD) é composto de duas implementações:
•
Front-end de depuração Java: processo fornecido pela plataforma Java que
implementa a JDI (Java Debug Interface), a API de depuração de alto-nível de
Java.
•
Implementação da HDI (Holo Debug Interface): classes Java que controlam o
PFD Java através da JDI.
A Holo Debug Interface (HDI) é a interface de programação de depuradores Holo, ou
seja, a IPD do modelo da HED. A sua implementação esconde a abstração “Máquina Virtual
32
Java”, fornecida pela JDI, substituindo -a por uma interface de programação com uma
“Máquina Virtual Holo”. A HDI é a principal contribui ção deste trabalho em nível de
implementação. Com base na HDI, foi implementado o depurador Holo Debugger, que é a
ferramenta de depuração propriamente dita (a IHM do modelo). É uma ferramenta composta
basicamente de uma interface homem-máquina, que é alimentada através de chamadas para a
HDI. É importante observar que o Holo Debugger poderia ter sido implementado diretamente
sobre a JDI, porém, além de se tornar uma ferramenta bem mais complexa, o depurador
estaria amarrado à uma implementação particular da Holoplataforma. Ao seguir o modelo
proposto pela HED, é possível que a Holoplataforma seja re-implementada, de forma
independente de Java, sem que seja necessário alterar o código-fonte do Holo Debugger.
Obviamente, neste cenário, a HDI teria que ser re-implementada, pois a JDI não estaria mais
disponível para oferecer a implementação dos serviços de depuração. Porém, a especificação
da API HDI poderia permanecer inalterada.
3.3 HoloJava estendida
3.3.1 Visão Geral
A ferramenta HoloJava foi modificada para gerar informação de depuração.
"Informação de depuração" significa uma informação que permite à máquina e ao depurador
relacionarem elementos do código (instruções, endereços) com elementos do programa que o
gerou (linhas de texto, identificadores). Este mapeamento entre código e programa é gerado e
gravado em “tabelas de símbolos” [ROS 96, p. 157 -161], que não devem ser confundidas
com as tabelas de símbolos internas utilizadas pelos compiladores. As tabelas em questão são
inseridas no código do programa, e são utilizadas, pela máquina e pelo depurador, para
viabilizar a execução dos algoritmos de depuração.
Por exemplo, quando o usuário de um depurador quer saber o valor de um
identificador cujo nome é “X”, o depurador consulta a tabela para saber em que endereço de
memória da máquina se encontra o valor de "X". Da mesma maneira, se o usuário quer que a
execução do programa seja interrompida quando a linha do programa de número "47" for
atingida por um fluxo de execução (thread), o depurador consulta a tabela para saber em que
ponto do código deve ser inserido um breakpoint.
No atual protótipo de Holo, a grande parte do trabalho de geração de tabelas de
símbolos, e utilização das mesmas em algoritmos de depuração, é suprida pela plataforma
Java. A Máquina Virtual Java (JVM) e a JPDA (arquitetura do depurador Java) se
encarregam da implementação dos algoritmos de depuração Java a partir da informação
gerada e inserida no bytecode Java pelo compilador JavaC. Assim, o mapeamento entre
"Código Java" e "Programa Java", no contexto da depuração de programas, é completamente
suportado pela plataforma Java.
Para implementar a depuração de programas Holo, foi preciso adicionar um
mapeamento adicional, entre "Programa Java" e "Programa Holo". Quem cobre este
mapeamento é a informação de depuração Holo, que é gerada juntamente com o "Código
33
Holo" pela HoloJava estendida. Assim, fecha-se a ponte entre "Código Java" e "Programa
Holo", necessária para a implementação dos serviços e algoritmos de depuração de
Holoprogramas.
A informação de depuração que é gerada pela HoloJava é separada em dois tipos:
•
Mapeamento de símbolos: mapeamento entre símbolos Holo e símbolos Java,
como nomes de variáveis Holo e Java, entes Holo e classes Java, etc.
•
Mapeamento de linhas: mapeamento entre números de linha Java e números de
linha Holo (linhas do texto-fonte do programa).
A figura 10 ilustra o envolvimento dos módulos com a geração e a utilização da
informação de depuração. A figura deve ser lida da seguinte maneira: o mapeamento de
código realiza a tradução entre o bytecode Java executando na Máquina Virtual Java e as
construções do programa Holo que originou este bytecode. Este mapeamento é realizado pela
informação de depuração, que é gerada pelo Holocompilador (HoloJava estendida + JavaC) e
consumida pelo aparato de depuração de programas Holo (Java VM + JPDA + HDI + Holo
Debugger).
Código
Java
Informação de
Depuração Java
Tempo de
Compilação
HoloJava
Estendida
JavaC
Programa
Java
Informação de
Depuração Holo
Máquina +
Depurador
Holo
Java VM
JPDA
Programa
Holo
Mapeamento
de Código
Tempo de
Execução
(Depuração)
Figura 10 – Geração e utilização da informação que realiza o mapeamento bidirecional entre
código Java e programa Holo, necessário para a implementação dos algoritmos de depuração.
3.3.2 Formato da informação de depuração
Atualmente, a ferramenta HoloJava estendida para depuração gera um arquivo
que contém todas as informações necessárias para a realização do mapeamento entre o código
Java gerado e o programa Holo original. A figura 11 lista o arquivo de informação de
depuração gerado para o programa Holo que implementa o "Jantar dos Filósofos",
apresentado na seção 2.4.2. A tabela 4 lista as construções utilizadas atualmente, pela
HoloJava 1.0 estendida, para a geração do arquivo, e o tipo de informação que é expressa por
cada uma.
34
#SB:1:holo
#IA:3:holo/0/0
5 47 .
6 48 .
7 49 .
8 50 .b.
10 53 ........e
12 62 b.
14 64 .....e
16 70 .
17 71 r
#SB:31:filosofo
#IA:33:filosofo/0/0
35 21 .
36 22
38 25
39 28
40 34
41 39
42 44
44 49
45 53
46 57
47 61
48 64
50 67
51 70
#END
.b.
...
......
.....
.....
.b..e
....
....
....
...
..e
...
r
Figura 11 – Arquivo de informação de depuração para o "Jantar dos Filósofos"
Construção
#SB:<linha>:<nome>
e
#END
Informação
Indica o início da declaração, na linha Holo
especificada, de um ente estático com o
nome especificado. A declaração termina
com o início da declaração de outro ente, ou
com a declaração especial #END, que
sinaliza o fim da lista de entes estáticos do
programa.
#IA:<linha>:<nome>:<aridade>:<retorno>
Indica o início da declaração, na linha Holo
especificada, de uma ação imperativa (IA)
de nome e aridade especificados. Caso a
ação possua valor de retorno, o parâmetro
<retorno> é 1, caso contrário, será 0.
#MLA:<linha>:<nome>:<aridade>:<retorno>
Idem à anterior, porém, indica a declaração
de uma ação lógica modular.
<linha Holo> <linha Java> <lista de atributos> Indica uma entrada para a tabela de
mapeamento entre código Holo e Java.
Mapeia o número de linha Holo para o
conjunto de linhas Java que inicia com o
número de linha Java especificado, com a
extensão de uma linha para cada símbolo
presente na lista de atributos.
Tabela 4 – Informação de depuração gerada para arquivo pela HoloJava estendida
35
As linhas do arquivo de informação de depuração que indicam entradas para a tabela
de mapeamento de código carregam duas informações: a localização das linhas de código
Java que implementam uma linha de código Holo, e a “natureza” de cada uma das instruções
Java individuais que implementam esta linha de Holo. A distinção desta natureza das
instruções Java foi necessária para a implementação do algoritmo de execução "passo-apasso" do depurador, que será visto em detalhe na seção 3.5.4. Esta informação é indicada
pela "lista de atributos" da entrada de mapeamento de código, que atribui um código (no
arquivo, representado por um caractere) para cada linha de código Java gerada pela
ferramenta HoloJava. Os códigos e os atributos correspondentes da linha Java gerada são
relacionados na tabela 5.
Código
Natureza da Instrução
.
Indica uma linha Java que não possui nenhuma
semântica de desvio.
b
Indica uma linha Java que possui semântica de
desvio local (dentro da ação).
c
Indica uma linha Java que causa desvio por
chamada a uma ação Holo, ou seja, que causa
empilhamento de mais um registro de ativação
na pilha da thread.
e, r
Indicam uma linha Java que causa um retorno
de ação Holo. (“r” indica retorno por atingir a
declaração de fim de ação Holo, que é
representada pelo caractere “}”)
Tabela 5 – Código do arquivo de informação de depuração e os atributos possíveis para uma
linha de código Java gerada pela ferramenta HoloJava 1.0 estendida.
3.3.3 Alterações na gramática e limitações
A ferramenta HoloJava, atualmente, é gerada automaticamente pelo gerador de
parsers JavaCC [JAV 02a], sendo suprido para este a gramática "decorada" da linguagem, ou
seja, a descrição da gramática acrescida de ações (código Java qualquer) associadas à
seqüência de tokens que forem reconhecidos pela aplicação do parser. A geração de um
arquivo de depuração para HoloJava consistiu da alteração destas ações para incluir a geração
do arquivo de informação de depuração.
Uma limitação da informação gerada e, conseqüentemente, do depurador
implementado, é a ausência de informação de mapeamento entre o código Holo e o código
Java que implementa o código Prolog gerado pela ferramenta HoloJava. Esta limitação devese à complexidade excessiva do código Java gerado pela ferramenta PrologCafe. Para
36
viabilizar a realização do mapeamento para o código em lógica de Holo, seria necessário um
estudo da estrutura deste código gerado pela ferramenta PrologCafe, ou então, a utilização de
outra ferramenta ou estratégia para o tratamento do código Prolog em Holo.
3.4 Holo Debug Interface - Visão Geral
Como destacado anteriormente, grande parte da arquitetura do depurador do protótipo
é implementada pela JPDA, a arquitetura do depurador de Java. Como um programa Holo é,
atualmente, um programa Java quando está executando na máquina Holo (que é
essencialmente implementada por uma maquina virtual Java), para o protótipo foi necessário
o acréscimo de uma camada adicional de software, a HDI (Holo Debug Interface), que traduz
a interface de programação para depuração Java em uma para depuração Holo.
A HDI é uma interface de programação que facilita a criação da ferramenta de
depuração Holo. Através dela, o programador da ferramenta de depuração pode se concentrar
no desenvolvimento da interface homem-máquina de depuração e dos serviços agregados de
depuração, abstraindo-se dos detalhes de implementação dos serviços básicos, que são
fornecidos pelas classes que implementam a HDI. A ferramenta não precisa saber como, por
exemplo, interagir com o protocolo de depuração ou como implementar os algoritmos básicos
de depuração. É necessário apenas invocar os métodos sobre as interfaces da HDI e tratar as
possíveis exceções. A HDI, atualmente implementada em Java, fornece uma coleção de
interfaces Java para acesso às suas classes.
A JDI (Java Debug Interface), a camada mais abstrata da JPDA, foi a API utilizada
para a implementação da HDI. Uma das características de projeto da JDI, que também foi
adotada pela HDI, é a visão da ferramenta de depuração como uma ferramenta que manipula
uma "imagem" da máquina. Esta imagem é composta por um conjunto de "espelhos"
(mirrors), que são objetos intermediários, que representam os objetos do programa que estão
presentes na máquina. Os espelhos manipulados pelo depurador possuem duas funções
básicas: refletir o valor mais recente conhecido do objeto real, e atuar como um intermediário
(proxy) para a manipulação deste objeto. Para cada tipo diferente de objeto ou entidade
identificável da Máquina Virtual Holo (inclusive a própria), foi criada uma interface na HDI.
Esta interface esconde a implementação atual do objeto-espelho em questão. Desta forma, a
ferramenta de depuração é isolada da implementação dos serviços de depuração oferecidos,
caso a interface permaneça constante.
3.5 Interfaces e Algoritmos da HDI
A tabela 6 relaciona as principais interfaces da HDI, indicando que tipo de objeto
representam e quais operações permitem que sejam realizadas sobre o mesmo. Algumas das
interfaces não representam diretamente elementos de modelagem de Holo, mas provedores de
serviços de depuração, como gerenciadores de Holomáquinas e de eventos. Todas as
interfaces são atuam apenas para uma única sessão de depuração, ou seja, operam no contexto
de apenas uma Holomáquina. A única exceção é a interface HoloVirtualMachineManager,
que é responsável por disparar as Holomáquinas que estarão sob o comando do depurador.
37
Interface
Representa
Função principal
HoloVirtualMachineManager Um
gerenciador
Holomáquinas
de Iniciar uma sessão de depuração
sobre um programa Holo,
iniciando a máquina Holo.
HoloVirtualMachine
Uma Holomáquina
Controlar a máquina como um
todo (suspensão e cancelamento
da execução), obter uma
referência para o ente raiz da
HoloTree, obter a lista de
threads e de entes estáticos do
programa.
HoloEventRequestManager
Interface para requisição de Permitir que o depurador
notificação de eventos
registre a intenção, junto à
Holomáquina, de que deseja ser
notificado quando certo tipo de
evento ocorrer na execução do
programa.
HoloEventQueue
Interface para acesso à fila Permite a retirada de eventos
de eventos
gerados pela Holomáquina.
HoloThread
Uma thread
HoloStackFrame
Um registro de ativação da Permitir acesso à informação do
pilha de ativação de uma contexto de uma chamada de
thread
ação,
como: posição
do
apontador de instrução da thread
no programa Holo e a lista de
variáveis locais à chamada de
ação em questão.
HoloBeingType
Um ente estático
Fornecer informação estática do
ente (nome, lista de ações, linha
do programa)
HoloAction
Uma ação
Fornecer informação estática da
ação (nome, tipo, aridade,
retorno, linha do programa)
Permitir a manipulação da
thread. Por exemplo, suspensão
ou continuação de execução,
obtenção da pilha de ativação e
obtenção do status da thread
(executando, esperando em
monitor, morta...)
38
HoloBeingReference
Um ente dinâmico
Fornecer informação sobre o
ente, como o ente estático que o
originou, e os seus entes
predecessor e sucessores na
HoloTree
HoloVariable
Uma variável
Fornecer uma referência a uma
variável local a um registro de
ativação
HoloVariableValue
Valor de uma variável
String que representa o conteúdo
de uma HoloVariable
HoloEventRequest
Uma
requisição
de
notificação de evento de
interesse do depurador,
criada
através
do
HoloEventRequestManager.
Permite a configuração da
requisição.
Deriva
outras
interfaces especializadas para
requisição
de
eventos
específicos, como criação de
breakpoints e inspeção de
história.
HoloEvent
Um evento que ocorreu na
Holomáquina, de interesse
do depurador. Acessado por
consulta a HoloEventQueue
Contém informação sobre o
evento gerado. Deriva outras
interfaces especializadas que
indicam o tipo de evento
específico, como notificação de
breakpoint
atingido
ou
conclusão de leitura de uma
história.
HoloLocation
Localização de uma linha
de código Java que
implementa um comando de
Holo.
Fornecer informação sobre a
localização, como a que ação
(HoloAction) e a que ente
estático
(HoloBeingType)
pertence.
Tabela 6 – Interfaces da HDI
As seções seguintes detalham algumas das interfaces da HDI que encapsulam os
principais algoritmos do depurador, seguido de uma descrição dos algoritmos empregados,
onde for o caso.
3.5.1 Gerenciamento de sessões de depuração
A interface HoloVirtualMachineManager atualmente oferece, para a ferramenta de
depuração, a opção de se iniciar uma máquina Holo localmente, executando um programa
39
Holo. Caso a máquina inicie com sucesso, uma interface HoloVirtualMachine é retornada.
Esta interface representa a máquina Holo, e será utilizada pelo depurador para interagir com a
máquina, durante toda a sessão de depuração. O modelo prevê que a interface
HoloVirtualMachineManager também forneça serviços de disparo de Holomáquinas remotas,
para permitir que o depurador execute em um ambiente isolado da máquina Holo. Também
prevê a possibilidade de anexação (attach) do depurador a uma Holomáquina que esteja
suspensa devido a um erro. Contudo, estas opções não se encontram implementadas
atualmente.
3.5.2 Breakpoints
A interface HoloBreakpointRequest representa uma requisição de notificação quando
uma thread atingir uma certa linha do programa, fornecida como parâmetro para a requisição.
Quando o breakpoint é atingido, um objeto do tipo HoloBreakpointEvent é inserido na fila de
eventos do depurador.
A implementação dos algoritmos de inserção e remoção de breakpoints é baseada na
implementação de breakpoints em Java, através da JDI (Java Debug Interface). Para isto, ao
criar um breakpoint em uma linha do programa Holo, através da tabela de símbolos,
construída a partir do arquivo de informação de depuração gerado pela HoloJava estendida, é
possível identificar a localização, no código Java, da primeira linha de código Java que
implementa aquela linha Holo. Assim, é requisitado um breakpoint Java nesta linha, para a
JDI. Quando a JDI notifica a implementação da HDI de um evento de breakpoint Java, este
evento é traduzido, através de uma tabela que converte breakpoints Holo em Java, para um
evento de breakpoint Holo.
3.5.3 Carga de entes estáticos
A interface HoloBeingLoadedRequest representa uma requisição de notificação
quando um ente estático for carregado pela máquina. Atualmente, o evento de carga de entes
estáticos baseia-se na carga e preparação das classes Java que implementam os entes. Quando
um ente estático é carregado pela Holomáquina, um objeto do tipo HoloBeingLoadedEvent é
inserido na fila de eventos do depurador.
A aplicação principal deste evento é na validação de breakpoints [ROS 96, p.111],
responsabilidade que é, atualmente, da ferramenta de depuração, e não da implementação da
HDI. Quando um usuário do depurador criar um breakpoint em uma certa linha de programa
Holo, e o programa não estiver sido ainda iniciado, não é possível saber se este breakpoint
aponta para uma linha válida do programa, ou seja, uma linha a que corresponda código
gerado (no caso, uma linha que gere código Java). Um breakpoint pode ser validado quando
um ente estático é carregado. Quando isto ocorre, um novo objeto, representando aquele ente
estático, é adicionado ao depurador. Este objeto pode ser acessado através da interface
HoloBeingType, que especifica quais linhas do programa Holo pertencem a código gerado,
ou seja, linhas que pertencem à ações deste ente estático. O breakpoint é validado assim que
40
um ente estático carregado contém, nas suas ações, a linha de parada, especificada como
parâmetro do breakpoint.
3.5.4 Execução passo-a-passo
A interface HoloStepRequest representa uma requisição de execução de um "passo"
(geralmente, execução de uma linha) do programa. Como parâmetros para a requisição
devem ser fornecidos uma thread, que deve estar suspensa, e o tipo de passo (step into, step
over ou step out). Quando a execução do passo é completada, um objeto do tipo
HoloStepEvent é colocado na fila de eventos do depurador.
O algoritmo de execução passo-a-passo implementado pela HDI é eficiente. Seria
possível a implementação de um algoritmo que simplesmente utilizasse a implementação do
serviço de passo-a-passo em Java, oferecido pela JDI. Desta forma, algoritmo poderia, por
exemplo, realizar um "passo" em Java para cada linha Java que implementa a linha Holo.
Porém, como é indicado em [ROS 96, p.124], um algoritmo de passo-a-passo implementado
desta forma ("repeated instruction single-step") não é eficiente. Como a relação entre linhas
Holo e Java é, tipicamente de 1 para 3, ao contrário da relação entre linguagens de alto nível e
código nativo correspondente (instruções de máquina), que podem chegar a 1 para 1000,
talvez a implementação por repetição de passos sobre as instruções não causasse um
overhead muito grande sobre o algoritmo. Apesar disto, optou-se neste trabalho a
implementação do algoritmo "inteligente", seguindo a forma geral apresentada por
Rosemberg em [ROS 96, p.119].
O algoritmo implementado requer que cada instrução de máquina (no caso, linha de
código Java) que implementa uma linha do programa de alto-nível (no caso, linha de
programa Holo), seja decodificada para a obtenção do seu tipo. No caso, é necessário que o
algoritmo possa identificar se a instrução nunca causa nenhum tipo de desvio, ou seja, após a
sua execução, o apontador de programa sempre aponta para a próxima instrução na seqüência
natural do código. Caso a instrução não seja deste tipo, ela deve ser identificada como uma
instrução de chamada de função (call instruction) ou uma instrução de desvio (branching
instruction). O algoritmo de passo-a-passo da HDI também diferencia instruções de retorno
de chamadas para facilitar a implementação dos mesmos. Optou-se por omitir estes detalhes
da descrição do algoritmo.
A figura 12 apresenta, de forma conjunta, os algoritmos de execução passo-a-passo,
dos tipos step into e step over, descrito em [ROS 96, p.121-124] e adaptado para o contexto
de Holo sobre Java, implementado na HDI. Neste contexto, por uma "instrução" entenda-se
"linhas de código Java" geradas pela ferramenta HoloJava, e por "apontador de instrução",
entenda-se um "número de linha e nome de classe Java".
41
Entrada
Tipo do passo (step into ou step over), a Thread em estado "suspenso" (ou seja,
não apta a receber fatias de tempo do escalonador) que vai realizar o passo, e o
apontador para a instrução atual da thread.
Saída
Thread ainda em estado suspenso, com novo valor para o seu apontador de
instrução e, possivelmente, nova configuração da sua pilha de ativação (pilha de
chamadas de ações). A instrução apontada é a implementação do próximo
comando Holo, na ordem lógica do programa, a ser executado.
Método
1. moved := false e batch := false
2. simulated_pc := current_pc
3. se (moved_flag == true) e (simulated_pc aponta para uma instrução que
implementa o início de um comando) então:
se (batch == false)
step into completado, enviar notificação à interface do depurador e interromper
algoritmo.
senão:
fazer batch = false e criar um breakpoint interno nesta instrução que, quando
atingido, retornará a execução do algoritmo no passo 2. continuar a execução da
thread e interromper o algoritmo.
4. decodifica o tipo de linha Java apontada por simulated_pc (normal, ou algum
tipo de instrução de desvio).
5. se (instrução é do tipo normal) então faz moved = true e batch = true, e avança
simulated_pc para a próxima instrução na seqüência natural do programa, e
retorna para o passo 3.
6. se (batch == true) então fazer batch = false e criar um breakpoint interno nesta
linha Java que, quando atingido, retornará a execução do algoritmo no passo 2.
continuar a execução da thread e interromper o algoritmo.
7. fazer moved = true
8. se (passo é do tipo step over) e (instrução é do tipo call), então requisitar um
passo interno Java do tipo step over que, quando completado, retornará a
execução do algoritmo no passo 2. senão, requisitar um passo interno Java do tipo
step into que, quando completado, retornará a execução do algoritmo no passo 2.
em ambos os casos, continuar a execução da thread e interromper o algoritmo.
Figura 12 – Algoritmo de passo-a-passo do tipo step into ou step over adaptado para
implementação da HDI.
A idéia geral do algoritmo é a de utilização de execução contínua sobre seqüências de
instruções que não causam desvio (no caso, intituladas de "normais"). O algoritmo segue
avançando um apontador de programa simulado (simulated_pc) até que este aponte para o
42
início da implementação de uma linha Holo, ou que seja encontrada uma instrução de desvio.
Quando isto ocorre, o depurador insere um breakpoint interno nesta instrução, e continua a
execução da thread, que executará um bloco de instruções sem precisar notificar o depurador.
Quando é necessário executar uma instrução de desvio, requisita-se a execução apenas
daquela instrução para a máquina. No caso da HDI, é feito um pedido de execução passo-apasso, em nível de Java, para a JDI.
O algoritmo de passo do tipo step out é mais simples. Dada uma thread suspensa,
basta localizar a instrução, no registro de ativação anterior da pilha de ativação da thread, que
sucede a instrução do tipo call que empilhou a chamada atual. Nesta instrução, é inserido um
breakpoint interno a HDI que, quando atingido, retorna a execução do algoritmo de step out,
que apenas notifica a ferramenta de depuração que o passo foi completado com sucesso.
3.5.5 Inspeção da história de um ente
A interface HoloHistoryRequest representa uma requisição de consulta ao conteúdo
atual da história de um ente. A ferramenta de depuração faz a requisição para a HDI e,
quando a história do ente termina de ser coletada, é retornada através de um evento
HoloHistoryEvent, inserido na fila de eventos do depurador.
Esta operação foi modelada desta maneira (requisição assíncrona) porque a biblioteca
Jada, que implementa a história, não permite a leitura de todas as tuplas da história de forma
atômica, e é possível que implementações futuras da história também possuam esta limitação.
Como só é possível a leitura de toda a história através da retirada, e posterior re-inserção, de
todas as tuplas da história, é possível que uma thread do programa usuário enxergue a
história em um estado inconsistente. É possível evitar isso através da suspensão de todo o
programa enquanto a leitura é feita. Porém, isto pode não ser desejado pelo usuário da
ferramenta de depuração se, por exemplo, uma história pouco acessada possuir uma
quantidade grande de elementos. Isto causaria um atraso desnecessário na execução do
programa sob o depurador.
Sendo este serviço modelado como uma requisição assíncrona, bastou se criar uma
thread, a serviço do depurador, para extrair as tuplas da história de forma concorrente ao
programa do usuário, enquanto aquela história é protegida de acesso por uma seção crítica.
Quando o depurador termina de examinar a história, seu acesso é novamente liberado para as
threads da aplicação. Desta maneira, a aplicação pode continuar a executar, sendo que as
únicas threads que ficarão temporariamente bloqueadas serão aquelas que aguardam acesso a
uma história sob inspeção do depurador.
Pode ser desejável que toda a aplicação seja suspensa durante a leitura de uma
história. Por exemplo, se o programador quiser se certificar que a inspeção da história não irá
afetar a ordem de execução das threads. Para isto, basta usar a HDI para suspender a máquina
Holo antes da requisição, e continuar a execução após notificação da conclusão da leitura.
Apesar da thread que inspeciona a história estar localizada na Holomáquina, ela é
identificada como uma thread auxiliar do depurador, e não é suspensa.
43
3.5.6 Detecção de mobilidade lógica
A interface HoloTreeModificationEvent representa uma requisição de notificação,
sempre que a HoloTree do programa sofrer alterações, ou seja, sempre que uma mobilidade
lógica de entes ocorrer. Quando ocorre mobilidade, um evento do tipo
HoloTreeModificationEvent é inserido na fila de eventos do depurador. Após receber o
evento, o depurador pode, por exemplo, realizar uma leitura do estado atual da HoloTree para
exibição ao usuário.
A detecção de mobilidade foi feita através da inserção de código Java especial no
código gerado pela HoloJava. Este código insere uma chamada a uma rotina especial,
inserida pelo depurador no código do programa, antes da execução do código Java que
implementa o comando move de Holo. Esta rotina não realiza nenhuma operação, porém,
serve como um ponto para que o depurador insira um breakpoint interno nesta rotina, caso
haja uma requisição para monitoração de mobilidade. Quando o breakpoint é atingido, o
evento HoloTreeModificationEvent é gerado e enviado para o depurador Holo (cliente da
HDI), que tem a opção de ler o estado atual da HoloTree antes que ela seja modificada. Isto é
possível através do controle de políticas de suspensão, apresentado na próxima seção.
3.5.7 Configuração de requisições
Após o depurador Holo criar uma requisição de notificação de evento, através da HDI,
ele pode configurá-la através da interface que representa a requisição, antes que esta seja
habilitada e gere eventos. Duas opções de configuração para requisições são importantes: a
definição da política de suspensão da requisição, e a criação de uma seqüência de filtros para
a requisição.
A política de suspensão da requisição determina, quando o evento requisitado ocorrer
na máquina Holo, quais threads serão automaticamente suspensas, antes mesmo que o
depurador seja notificado do evento. A HDI disponibiliza três opções para políticas de
suspensão:
•
SUSPEND_NONE: Não suspende nenhuma thread quando o evento requisitado
ocorrer. O programa continua executando normalmente. Por exemplo, no caso em
que um breakpoint é atingido, a aplicação será notificada de que aquele ponto do
programa foi atingido, porém, a aplicação não será interrompida naquele ponto.
•
SUSPEND_EVENT_THREAD: Suspende apenas a thread que causou a geração
do evento. Por exemplo, no caso de um breakpoint ser atingido, apenas a thread
que atingiu o breakpoint é suspensa. Todas as outras threads da aplicação
continuam executando normalmente.
•
SUSPEND_ALL: Suspende todas as threads da aplicação quando o evento
ocorrer. É a política default.
Este mecanismo de políticas de suspensão é utilizado pela JDI. Como mencionado na
seção 3.5.6, se a política de suspensão do evento de modificação da árvore não for
SUSPEND_ALL, é possível que dois ou mais eventos do tipo HoloTreeModificationEvent
44
estejam presentes na fila de eventos da ferramenta de depuração ao mesmo tempo, o que
significa a perda da informação sobre um estado intermediário da HoloTree, pela ferramenta.
Porém, pode ser de interesse do usuário do depurador apenas a contagem de operações de
mobilidade executadas. Neste caso, uma política do tipo "suspend none", que causa um
menor atraso à execução da aplicação, é suficiente. Isto também poderia ser aplicado, por
exemplo, à criação de contadores de passagens (breakpoints com política "suspend none").
A criação de seqüências de filtros ainda não está completamente implementada na
HDI, e trata-se de outro serviço oferecido pela JDI. Por exemplo, seria possível a
especificação de breakpoints que só são ativados por certas threads, através de filtros de
inclusão ou de exclusão de threads. Um filtro simples, de contagem de ativação, está
implementado na HDI. Ele permite a geração de um evento, a partir de uma requisição,
somente após um número mínimo de ocorrências daquele evento. Inclusive, após este número
de ocorrências, o evento não é mais gerado. Isto pode ser útil para a implementação, pela
interface do depurador, de serviços como "run-to-here" (execução até um ponto do programa
apontado pelo usuário). No caso, a implementação se dá com a criação de um breakpoint, no
ponto desejado do programa, que só pode ser ativado uma única vez. Quando for ativado, ele
é automaticamente removido.
3.6 Holo Debugger
O Holo Debugger é uma ferramenta de depuração do tipo "linha de comando", como
o depurador jdb [JDB 02], mas com uma conveniência adicional de separar as mensagens
emitidas pelo depurador e pelo programa. A figura 13 apresenta a interface da ferramenta.
Figura 13 – Interface do Holo Debugger
Os painéis indicados na figura são:
1. Janela de saída do programa: Exibe mensagens emitidas pelo programa em
execução.
2. Janela de saída do depurador: Exibe mensagens emitidas pelo depurador.
3. Caixa de entrada: Espaço para o usuário enviar comandos para o depurador.
45
Os comandos da versão atual do Holo Debugger são implementados a partir dos
serviços básicos disponibilizados pela HDI. A tabela 7 lista todos os comandos do depurador,
como uma descrição de suas ações. O Holo Debugger atualmente não agrega muito valor aos
serviços já oferecidos pela HDI, sendo a validação da API sua principal função. As funções
oferecidas pela versão atual do Holo Debugger já permitem que o programador extraia
qualquer informação, em tempo de execução, que pode ser expressa em Holo 1.0. Também
permite o total controle da execução do programa, podendo este acompanhar a execução de
apenas uma thread, individualmente, executando uma linha do seu programa Holo de cada
vez.
Neste sentido, o Holo Debugger oferece funcionalidade comparável ao depurador
Java jdb. Assim como a Sun Microsystems, fornecedora do jdb, fornece o mesmo como um
depurador exemplo da sua arquitetura do depurador para Java (JPDA), a interface atual do
Holo Debugger é uma demonstração da HED, a arquitetura do depurador proposta por este
trabalho e, principalmente da HDI, a interface de programação para depuradores Holo,
implementada no contexto da HED.
Os resultados obtidos corroboram a implementação da segunda versão do Holo
Debugger, integrada ao HoloEnv, que possuirá uma interface gráfica. Um depurador gráfico
justifica a oferta de serviços adicionais, compostos dos serviços básicos oferecidos pela HDI.
Por exemplo, torna-se viável a criação de diálogos para a especificação de breakpoints com
filtros, por exemplo, que desativam o breakpoint para um certo conjunto de threads. É
possível, porém pouco prático, que o usuário gerencie este tipo de serviço através de uma
interface puramente textual. A especificação através de janelas, menus, e listas é mais prática.
Comando
Ação
load [caminho] <holoprograma > Carrega e executa o holoprograma especificado,
[argumentos...]
juntamente com uma lista de argumentos. O caminho deve
conter o programa na forma compilada, com informação
de depuração. Interrompe a execução antes que o primeiro
comando Holo execute, retornando o controle ao
depurador.
run [caminho] <holoprograma> Similar a load, porém não suspende a execução ao
[argumentos...]
encontrar o primeiro comando Holo.
Exit
Encerra a sessão de depuração atual.
Cls
Limpa a janela de mensagens do depurador.
Help
Exibe a ajuda do depurador.
Pause
Suspende a execução do programa, ou seja, suspende
todas as threads que ainda não estão suspensas.
Cont
Continua a execução do programa (continua a execução
de todas as threads que estão suspensas).
46
sel <nome-ente>
Seleciona um ente da HoloTree. Também é o comando
utilizado para se selecionar uma thread. A thread
selecionada é a thread associada ao ente, ou seja, a thread
que foi criada para a execução do comportamento deste
ente.
Sel
Imprime informações sobre o ente e a thread atualmente
selecionados, juntamente com a um traço da execução da
thread (pilha de ativação) e estado da thread (suspensa,
em execução, em espera...).
T
Lista todas as threads atualmente ativas.
S
Step into: faz com que a thread selecionada execute uma
linha de programa Holo. A thread deve estar suspensa.
N
Step over: idem a step into, porém trata as chamadas a
ações como operações atômicas.
R
Step out: faz com que a thread selecionada retorne da
ação atual. A thread deve estar suspensa.
tree
Exibe o estado atual da HoloTree.
trece [on | off]
Liga ou desliga a detecção e impressão, na janela de saída
do depurador, de modificações sofridas pela HoloTree, à
medida que o programa executa.
stop <número-da-linha>
Cria um breakpoint (incondicional) em uma linha do
programa.
clear
Lista todos os breakpoints atuais, bem como seu estado
(confirmado ou não-confirmado).
clear <número-da-linha>
Remove todos os breakpoints inseridos em uma linha do
programa.
locals
Exibe todas as variáveis locais ao contexto de execução da
thread atualmente selecionada. A lista associa cada nome
de variável ao seu valor atual e a que chamada (registro de
ativação) pertence.
his
Exibe o conteúdo da história do ente atualmente
selecionado.
his <nome-ente>
Exibe o conteúdo da história de um ente, dado o seu
nome.
Tabela 7 – Comandos do Holo Debugger
47
4. Implementação
Este capítulo descreve detalhes da implementação dos softwares desenvolvidos neste
trabalho: a extensão da ferramenta HoloJava 1.0, a implementação das classes da Holo Debug
Interface, e a implementação do Holo Debugger.
Todo o software foi desenvolvido em Java. A plataforma de desenvolvimento adotada
foi a J2SE (Java2 Standard Edition) versão 1.3.
A versão mais atual das ferramentas, incluindo código fonte e documentação, é
disponibilizada por WWW no endereço <http://www.inf.ufrgs.br/~fcecin/holo/>.
4.1 HoloJava estendida
4.1.1 Visão geral
As alterações na ferramenta HoloJava, versão 1.0, consistem de alterações à gramática
da linguagem (holojava.jj) e de alterações nas classes do pacote holoj.lang, que implementa
algumas classes base da linguagem Holo.
À gramática da linguagem, de forma aproximada, foram adicionadas 480 linhas de
código para implementar a geração de informação de depuração, e em torno de 150 linhas de
código foram alteradas. Estas modificações não alteram, de forma perceptível, o tempo de
execução da ferramenta. Não foram feitos testes para geração de informação de depuração
para grandes programas Holo, já que o protótipo da ferramenta não foi desenvolvido ou
otimizado para este propósito.
As alterações ao pacote holo.lang consistem da adição de uma nova classe
(DBVector) de 110 linhas, e de algumas alterações à classe Being, a classe base das classes
que implementam entes estáticos de Holo. A classe DBVector re-implementa o vetor de entes
da HoloJava (BVector) com sua estrutura interna alterada de forma a facilitar a sua inspeção
pela API de depuração de Java, o que viabiliza o serviço de depuração Holo de inspeção da
HoloTree.
4.1.2 Limitações e possibilidades de expansão
Atualmente não é gerada informação de depuração sobre o conteúdo de MLAs, as
ações lógicas modulares (sintaxe Prolog) de Holo 1.0. Isto se traduz basicamente na
impossibilidade de acompanhar, junto ao programa Holo, o fluxo de execução dentro de uma
MLA. A MLA é enxergada, pelo módulo depurador de Holo, como uma ação atômica. Uma
alternativa para resolver este problema, dada a implementação atual do Holocompilador 1.0,
que possui como componente a ferramenta PrologCafe, seria a realização do mapeamento do
código Java gerado pelo PrologCafe de volta para o Prolog original, e deste, de volta para o
programa Holo. Porém, o código gerado pela ferramenta PrologCafe é bastante complexo.
Seria necessário um certo entendimento do funcionamento interno da ferramenta.
48
Outra possibilidade seria a inclusão de um interpretador Prolog ao ambiente de
execução do programa Holo traduzido. Isto também eliminaria o atual gargalo do
Holocompilador 1.0, que é a utilização do conversor PrologCafe, que converte Prolog para
Java. Este conversor é responsável por, no mínimo, 90% do tempo necessário para a tradução
de Holo para Java, quando o programa Holo contém MLAs. Como desvantagem tem -se que a
interpretação de uma linguagem na sua forma original é, geralmente, mais lenta do que a
execução de uma forma pré-processada ou compilada. De qualquer forma, é necessário que o
interpretador exponha uma API de depuração, para que o usuário do depurador Holo pudesse
controlar a execução do programa Prolog de forma indireta, através da depuração do
programa Holo, da mesma maneira que é feito atualmente com o mapeamento da depuração
de Java para Holo.
4.2 Holo Debug Interface
4.2.1 Visão Geral
A implementação da HDI consistiu no desenvolvimento, em Java, de uma hierarquia
de interfaces, e sua posterior implementação em classes. A implementação da Holo Debug
Interface (HDI) consiste atualmente de 33 classes, e de 36 interfaces para estas classes. As
classes somam 4330 linhas de código, e as interfaces somam 1224 linhas, em um total de
5554 linhas. A implementação da HDI utiliza diretamente as interfaces e a implementação
default da JDI (Java Debug Interface), ou seja, como provida pela plataforma J2SE da Sun,
versão 1.3.1 e posteriores.
4.2.2 Limitações e possibilidades de expansão
A versão atual das classes da HDI implementa suporte apenas para o início de uma
sessão de depuração local, ou seja, a máquina disparada para executar o programa a ser
depurador executa sob o mesmo ambiente do depurador. Poderia ser adicionado suporte para
depuração remota, com o depurador iniciando a máquina depurada, ou o contrário. Também
poderia ser possível que o depurador abarcasse (attach) uma máquina Holo em execução. A
plataforma Java, através da JDI, atualmente provê esta funcionalidade. Seria necessária
apenas a implementação das classes e interfaces da HDI para redirecionar este serviço para o
Holodepurador.
A HDI não oferece uma variedade de filtros para a configuração das requisições de
eventos. O único filtro implementado foi o contador de ativação do evento, como exposto na
seção 3.5.7. Isto pode ser contornado com realização de filtragem na própria ferramenta de
interface de depuração, após esta receber o evento da HDI. Porém, seria interessante que a
HDI oferecesse estes filtros para que fosse poupado o trabalho dos desenvolvedores das
ferramentas de depuração Holo, além do ganho de performance pela eliminação prévia de
eventos não interessantes, que podem gerar, entre outras formas de overhead, suspensões e
continuações desnecessárias de várias threads do programa do usuário, devido às políticas de
suspensão das requisições de eventos.
49
Outra limitação do protótipo implementado é a ausência de um conjunto de exceções
adequado. Quando um erro ocorre internamente à implementação da HDI, geralmente os
métodos abortam a execução com uma ou várias mensagens de diagnóstico na saída padrão,
mas o programa não é interrompido, ou então um stack trace de Java, geralmente causado por
uma exceção da JDI, é exibido para o usuário. Isto pode ser resolvido com a revisão dos
pontos de falha e da substituição das mensagens de erro atuais por comandos (Java throw)
que levantem exceções próprias da HDI.
Em relação à linguagem Holo 1.0, a HDI não oferece todos os serviços de depuração
necessários para a inspeção da execução de ações modulares lógicas (MLAs). Atualmente, as
chamadas a MLAs apenas aparecem na pilha de ativação de uma thread com o nome da
MLA, não sendo possível a execução de um "passo", a inserção de breakpoints, a
identificação de valores de variáveis locais ou a localização do ponto de execução atual da
thread, dentro do código de uma MLA. Isto depende primeiramente da geração, pela
ferramenta HoloJava, de toda a informação de depuração necessária. Após, seria necessária a
especificação dos serviços a serem oferecidos. No caso do serviço de "passo-a-passo", por
exemplo, seria necessário definir uma semântica para o mesmo, quando executado em código
Prolog. E, por fim, deve ser feita a implementação das classes que implementam os serviços.
4.3 Holo Debugger
4.3.1 Visão Geral
O Holo Debugger consiste de 8 classes Java, e sua implementação mede 2013 linhas.
A ferramenta teve sua interface desenvolvida com controles gráficos básicos do pacote
Swing, de Java. As funcionalidades de depuração Holo foram todas desenvolvidas através da
utilização das interfaces publicadas pela HDI, ou seja, o Holo Debugger é livre da
implementação das interfaces da HDI. A tarefa principal da ferramenta é traduzir os
comandos textuais do usuário em requisições para as interfaces da HDI. O Holo Debugger
também agrega valor aos serviços oferecidos pela HDI, como a manutenção de uma lista de
breakpoints requisitados pelo usuário, e também implementa a validação de breakpoints.
4.3.2 Limitações e possibilidades de expansão
A maior limitação da ferramenta é, atualmente, a sua interface textual. Este tipo de
interface tanto diminui a interatividade da sessão, por tornar a entrada de comandos mais
lenta, quanto torna difícil a exposição, ao usuário, do contexto que ele necessita para analisar
o seu programa. Num momento em que as próprias ferramentas e linguagens de programação
mostram tendências a se tornarem cada vez mais "visuais", é significativo que as ferramentas
de depuração continuem amparando esta tendência. A interface gráfica da ferramenta Holo
Debugger já se encontra em desenvolvimento, no âmbito do projeto Holo [HOL 02].
50
4.4 Desempenho
A otimização do tempo de execução não foi uma preocupação principal durante a
implementação deste trabalho. Porém, os algoritmos do depurador devem possuir um tempo
de execução que evolui de forma satisfatória na medida em que cresce o tamanho do
programa de entrada, pelo menos no que diz respeito ao seu modelo, e não à implementação
atual dos algoritmos.
Dito isto, afirma-se aqui que o Holo Debugger é um depurador suficientemente
responsivo. Talvez seja possível que o usuário note uma pequena diferença entre executar um
"passo" de execução no Holo Debugger, que utiliza o algoritmo de passo-a-passo
implementado pela HDI, e executar o mesmo passo no jdb, o depurador da Sun que serve
como exemplo da JDI. Esta conclusão é possível, uma vez que a HDI utiliza a JDI para sua
implementação, ou seja, a HDI certamente introduz alguma forma de overhead sobre a JDI.
Porém, para o autor deste trabalho, este overhead não pôde ser percebido, ao comparar o
tempo gasto pelas atividades comuns entre o Holo Debugger e o jdb.
Adicionalmente, observa-se que um programador tipicamente gasta muito mais tempo
com outras atividades (entrar comandos no depurador e analisar os dados exibidos pelo
mesmo, por exemplo) do que esperando pela execução do programa sob o depurador, se
considerarmos apenas o tempo de overhead inserido pelo depurador. Neste contexto, o
overhead inserido pelo Holo Debugger é similar ao do depurador jdb, da Sun.
51
5. Conclusão
O depurador é uma ferramenta essencial no desenvolvimento de programas. Este
trabalho se propôs a buscar uma visão inicial e abrangente para o problema da depuração de
programas para a linguagem Holo, incluindo a identificação de questões como a da depuração
de linguagens multiparadigma.
Dento desta visão, este trabalho propôs uma extensão abstrata para a Holoplataforma,
denominada de HED (Holo Extensão para Depuração) que identifica uma série de
componentes que devem estar presentes na implementação concreta da plataforma para
permitir a depuração de programas. A configuração proposta pela HED não é a única
possível, porém, ela possui pelo menos duas vantagens: permite que o ambiente do depurador
e o ambiente depurador sejam isolados, mantendo um vínculo através de um protocolo de
comunicação, e divide a implementação em camadas, o que facilita o reuso do software do
depurador.
As mudanças na Holoplataforma, propostas pela HED, foram baseadas na arquitetura
do depurador da plataforma Java, a JPDA (Java Platform Debugger Architecture), que ainda
não faz parte da especificação padrão da plataforma Java, mas já apresenta resultados
positivos, como constatado na sua fácil utilização para a implementação das ferramentas
derivadas deste trabalho.
Por fim, implementou-se, em Holo 1.0, as alterações propostas pela HED, através da
reutilização de componentes da plataforma Java, e do desenvolvimento de três softwares
adicionais: a extensão para a ferramenta HoloJava 1.0, a API de depuração HDI (Holo Debug
Interface), e a ferramenta de depuração Holo Debugger. Estas ferramentas implementam a
grande parte dos serviços identificados como essenciais para o depurador Holo 1.0, sendo que
a principal limitação foi a ausência do suporte completo para a depuração das ações lógicas
(Prolog). Esta tarefa é indicada como uma proposta de trabalho futuro, juntamente com um
estudo mais aprofundado sobre depuração multiparadigma.
Deste trabalho, pode-se concluir:
•
A plataforma Java oferece um suporte sem precedentes para o desenvolvimento de
depuradores. Rosemberg, em [ROS 96], faz uma revisão do estado da arte das
ferramentas de depuração, e descreve em detalhes as dificuldades de
implementação de um depurador para uma linguagem como C/C++ e que precisa
acessar diretamente um Sistema Operacional. Muitas das dificuldades apontadas
pelo autor não são relevantes no desenvolvimento de depuradores Java. Este
trabalho dificilmente possuiria a quantidade de implementação apresentada se a
linguagem intermediária de Holo fosse, por exemplo, C++, ou se Holo compilasse
diretamente para código nativo.
•
Este sucesso da plataforma Java foi o motivador da adoção do seu projeto como
fonte de inspiração para o projeto da HED. A qualidade deste suporte oferecido
deve ser levada em conta, quando do desenvolvimento completo da
52
Holoplataforma, incluindo implementações próprias do compilador e da máquina
virtual Holo.
•
Um depurador é uma ferramenta de implementação crítica, que se beneficia, em
vários aspectos, da sua modularização. Isto também foi observado por [BID 99],
que realiza um estudo de caso de reutilização de software para a construção de
uma ferramenta de depuração.
•
A implementação de um depurador de alto-nível (HDI), baseado em outro módulo
depurador de alto-nível (JDI), não resulta, obrigatoriamente, em overhead
significativo, como poderia ser considerado. Não foi verificado se a performance
do depurador aumenta proporcionalmente ao tamanho e à complexidade do
programa.
Como possíveis trabalhos futuros, pode-se citar:
•
Manutenção do modelo e da implementação, acompanhando o desenvolvimento
da linguagem e da plataforma Holo em suas versões futuras (2.0 e posteriores);
•
Quando for realizado o desenvolvimento do ambiente de execução distribuída de
programas Holo (DHolo), será necessário o estudo de questões relativas à
construção de depuradores distribuídos;
•
Estudo de técnicas de replay de execução, que permitam que uma execução do
programa seja gravada, para que possa realizar várias sessões de depuração sobre
a mesma seqüência de computações da linguagem, através da reconstrução da
ordem de eventos que afetam o programa, como ordem de troca de mensagens, de
execução de caminhos concorrentes, ou de entrada e saída de dados;
•
Estudo aprofundado e implementação completa do suporte, no sistema depurador,
ao paradigma de programação em lógica;
•
Desenvolvimento de uma interface gráfica ao Holo Debugger, integrada ao
ambiente de desenvolvimento HoloEnv (já em andamento).
53
Bibliografia
[AMZ 02]
Amzi! Prolog. Disponível por WWW em <http://www.amzi.com>. Acesso em abril
de 2002.
[APE 02]
APPELO – Ambiente de Programação Paralela em Lógica. Disponível em:
<http://www.inf.ufrgs.br/procpar/opera/APPELO/>. Acesso em abril de 2002.
[BAR 99]
Barbosa, J. L. V., Geyer, C. F. R. (1999) "Software Multiparadigma Distribuído",
Revista de Informática Teórica e Aplicada (RITA), Porto Alegre, v.6 n.2 p.67-87.
[BAR 01]
Barbosa, Jorge Luis Victória; Geyer, Cláudio Fernando Resin. (2001) "Uma
Linguagem Multiparadigma Orientada ao Desenvolvimento de Software
Distribuído". V Simpósio Brasileiro de Linguagens de Programação (SBLP),
Curitiba, Brasil.
[BAR 01a]
Barbosa, Jorge L. V.; Geyer, Cláudio F. R. (2001a) "Integrating Logic Blackboards
and Multiple Paradigms for Distributed Software Development". In: International
Conference on Parallel and Distributed Processing Techniques and Applications
(PDPTA 2001), Las Vegas, United States. Proceedings… Las Vegas: CSREA Press,
June 2001. p.808-814.
[BAR 01b]
Barbosa, J. L. V., Du Bois, A., Pavan, A.; Geyer, C. F. R. (2001b) "HoloJava:
Translating a Distributed Multiparadigm Language into Java", In: Conferência Latino
Americana de Informática, v.27, Mérida, Venezuela. Proceedings… Mérida:
Universidad de Los Andes.
[BAR 02]
Barbosa, Jorge L. V., (2002) "Holoparadigma: Um Modelo Multiparadigma
Orientado ao Desenvolvimento de Software Distribuído". Tese de doutorado. 213p.
[BID 99]
Biddle, R., Marshall, S., Miller-Williams, J., Tempero, E. (1999) "Reuse of
Debuggers for Visualization of Reuse", In: Fifth Symposium on Software
Reusability, Los Angeles, United States, Proceedings of… p.92-100. ACM Press.
[BOR 02]
Borland JBuilder 6 Personal. Disponível por WWW no endereço:
<http://www.borland.com/products/jbuilder/personal>. Acesso em abril de 2002.
[BYR 80]
Byrd, L. (1980) "PROLOG Debugging Facilities", Technical Report, D.A.I. Research
Paper 19, Department of Artificial Intelligence, University of Edinburgh.
[CAP 96]
Capra, Fritjof, (1996) "The Web of Life: A New Scientific Understanding of Living
Systems", Anchor Books.
[CIA 02]
Ciancarini, P., Rossi, D. (2002) "JADA: A coordination toolkit for Java". Disponível
em: <http://www.cs.unibo.it/~rossi/jada>. Acesso em abril de 2002.
[DUB 01]
Du Bois, André Rauber; Barbosa, Jorge Luis Victória; Geyer, Cláudio Fernando
Resin. (2001) "Adding Functional Programming into the Holo Language". In:
Functional and (Constraint) Logic Programming (WFLP), 10., Kiel, Germany.
"Proceedings…" Kiel: Christian-Albrechts-Universität, September. p.45-58.
54
"Proceedings…" Kiel: Christian -Albrechts-Universität, September. p.45-58.
[FRA 97]
Frankl, Phyllis et al. (1997) "Choosing a testing method to deliver reliability",
International Conference on Software Engineering. Proceedings... Boston, United
States. ACM Press, p. 68-78.
[GAR 95]
Garlan, D. et al. (1995) "Research Directions in Software Engineering". ACM
Computing Surveys, New York, v.27, n.2, p.257-276, June.
[GDB 02]
GDB: The GNU Project Debugger. Disponível por WWW
<http://www.gnu.org/software/gdb/gdb.html>. Acesso em abril de 2002.
[GHE 98]
Ghezzi, C.; Jazayeri, M. (1998) "Programming Language Concepts", New York: John
Wiley & Sons. 427p.
[HOL 02]
Projeto Holo - Software Multiparadigma Distribuído. Disponível por WWW em:
<http://www.inf.ufrgs.br/~holo>. Acesso em abril de 2002.
[IEE 95]
IEEE Transactions on Software Engineering. New York, v.21, n.4, April 1995.
(Special Issue on Software Architecture)
[JAV 02]
Java. Disponível em: <http://java.sun.com>. Acesso em abril de 2002.
[JAV 02a]
JavaCC – The Java Parser Generator. Disponível por WWW
<http://www.webgain.com/products/java_cc/>. Acesso em abril de 2002.
[JAV 02b]
Javadoc Tool Home Page. Disponível em <http://java.sun.com/j2se/javadoc/>.
Acesso em abril de 2002.
[JDB 02]
jdb. Disponível em <http://java.sun.com/products/jpda/doc/soljdb.html>. Acesso em
abril de 2002.
[JPD 02]
Java Platform Debugger Architecture. Disponível por
<http://java.sun.com/products/jpda>. Acesso em abril de 2002.
[KOW 79]
Kowalski, Robert. (1979) "Logic for Problem Solving". New York: Elsevier.
[LEA 01]
Lea,
Doug.
"Objects
in
Groups".
Disponível
por
<http://gee.cs.oswego.edu/dl/groups/>. Acesso em: abril de 2002.
[MEI 96]
Meier, M. S., Miller, K. L., Pazel, D. P., Rao, J. R., Russell, J. R. (1996)
"Experiences with building distributed debuggers", In: Symposium on Parallel and
Distributed Tool. Proceedings… Philadelphia, United States. p.70 -79. ACM Press.
[MIC 02]
Microsoft
Visual
C++.
Disponível
por
<http://www.microsoft.com>. Acesso em abril de 2002.
[NER 97]
Neri, D., Pautet, L., Tardieu, S. (1997) "Debugging distributed applications with
replay capabilities", In: Annual International Conference on Ada. Proceedings… St.
Louis, United States.
[OAK 99]
Oaks, S., Wong, H. (1999) "Java Threads", 2nd Edition, O'Reilly, 332 pages.
[OPE 02]
OPERA – Prolog Paralelo. Disponível em: <http://www.inf.ufrgs.br/
procpar/opera/OPERA/index.html/>. Acesso em abril de 2002.
55
WWW
WWW
WWW
no
em:
em:
em:
em:
endereço:
[ORT 92]
Ortega y Gasset, José. (1992) "Mision de la Universidad". Madri: Alianza Editorial.
238p.
[PFL 97]
Pfleger, Karl; Hayes-Roth, Barbara. (1997) "An Introduction to Blackboard-Style
Systems Organization", Computer Science Department, Stanford University, July.
(Technical report)
[PRO 02]
PrologCafe.
Disponível
por
WWW
u.ac.jp/PrologCafe/>. Acesso em abril de 2002.
[ROB 92]
Robinson, J. A. (1992) "Logic and Logic Programming". Communications of the
ACM, New York, v.35, n.3, p.40-65, March.
[ROS 96]
Rosemberg, Jonathan B., (1996) "How Debuggers Work: Algorithms, Data Structures
and Architecture", John Wiley & Sons.
[SEB 99]
Sebesta, Robert W. (1999) "Concepts of
Wesley. 670p.
[SHA 96]
Shaw, M.; Garlan, D. "Software Architecture: Perspectives on an Emerging
Discipline". New Jersey: Prentice-Hall, 1996. 242p.
[SIC 02]
SICStus Prolog. Disponível por WWW em <http://www.sics.se/sicstus>. Acesso em
abril de 2002.
[SOA 00]
Soares, L. C. (2000) "Princípios de uma ferramenta CASE para o Holoparadigma",
Pelotas: ESIN-UCPel, 60p. (Projeto de Diplomação).
[TOB 93]
Tobermann, G., Beckstein, C. (1993) "What's in a trace: The box model revisited",
In: Proc. of the First Internat. Workshop on Automated and Algorithmic Debugging,
Linkoeping, Sweden, v.749 of LNCS, Springer-Verlag.
[TRI 02]
Trinc-Prolog: Object-Oriented Prolog. Disponível por WWW em <http://www.trincprolog.com>. Acesso em abril de 2002.
[VRA 95]
Vranes, Sanja; Stanojevic, Mladen. (1995) "Integrating Multiple Paradigms within
the Blackboard Framework". IEEE Transactions on Software Engineering, New
Debugging York, v.21, n.3, p.244-262, March.
[WAH 92]
Wahl, N. J., Schach, S. R. (1992) "A paradigm for distributed debugging", In: ACM
Annual Computer Science Conference, Kansas City, United States. Proceedings…,
p.235-242, ACM Press.
56
em:
<http://kaminari.scitec.kobe-
Programming Languages". Addison
Anexos
Anexo 1 - Código Java gerado para o "Jantar dos Filósofos"
As figuras 14 e 15 apresentam o código, gerado pela ferramenta HoloJava 1.0
estendida, para o programa Holo listado na figura 5. A listagem possui uma formatação um
pouco desagradável, pois o código gerado não foi totalmente organizado para a leitura
humana. Porém, dada a listagem do arquivo de informação de depuração gerado pela
HoloJava (figura 11) para este mesmo programa, e a descrição do formato do arquivo (seção
3.3.2), é possível que o leitor realize o mesmo mapeamento, entre os dois programas (Holo e
Java), realizado pelo módulo depurador de Holo.
Duas classes são adicionadas ao programa pela HoloJava 1.0 estendida quando a
ferramenta é iniciada com a opção de geração de informação de depuração. Estas classes são
"HoloHistoryCollector" e "HoloTreeTracer". É possível encontrar referências a elas nas
figuras 14 e 15. Estas classes auxiliam os algoritmos da HDI, de leitura da história de um
ente, e de detecção de ocorrência de mobilidade lógica, respectivamente. A listagem destas
classes não é incluída aqui, mas pode ser obtida a partir da utilização da ferramenta HoloJava
sobre qualquer programa Holo, pois o conteúdo das classes é independente do programa que
é traduzido.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import jada.*;
import holoj.lang.*;
public class
holo extends Being{
public static holo _holoroot;
public static HoloHistoryCollector _hdi_history_collector_thread;
holo(){
this.father=null;
this.son=new DBVector();
this.name="holo";
setName(this.name+"-thread");
history = new ObjectSpace();
}
static String[] args; // reference to command-line arguments
public static void main (String argumentos[]){
holo.args = argumentos; // save reference to command-line arguments
// thread do depurador - coletora de histórias de entes
_hdi_history_collector_thread = new HoloHistoryCollector();
_hdi_history_collector_thread.setDaemon(true);
57
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
_hdi_history_collector_thread.start();
HoloTreeTracer.tracer.changeStart();
_holoroot = new holo();
HoloTreeTracer.tracer.changeEnd();
_holoroot.start();
} // fim main
//inicio run
public void run() {
Being holo_temp = null;
Tuple tuple = null;
insert_history();
System.out.println("CINCO FILOSOFOS VAO JANTAR.");
System.out.println("CADA FILOSOFO COME CINCO VEZES.");
System.out.println("O JANTAR ESTA INICIANDO.....");
String X = "";
for (int X_integer = 1;X_integer<=5;X_integer++){
X =""+X_integer;
HoloTreeTracer.tracer.changeStart();
holo_temp = new filosofo(this,"varname_0",X);
this.son.addElement(holo_temp);
HoloTreeTracer.tracer.changeEnd();
holo_temp.start();
holo_temp=null;
}
for (int X_integer = 1;X_integer<=5;X_integer++){
X =""+X_integer;
/*HISTORY 1*/
synchronized (history){ tuple = (Tuple) history.in(new Tuple("end"));
}
}
System.out.println("O JANTAR ACABOU.");
}
public void
history.out
history.out
history.out
insert_history() {
(new Tuple ("chopstick","1"));
(new Tuple ("chopstick","2"));
(new Tuple ("chopstick","3"));
58
79
80
81
82
83
84
85
86
87
88
89
90
91
92 }
history.out
history.out
history.out
history.out
history.out
history.out
history.out
history.out
history.out
history.out
history.out
history.out
}
(new
(new
(new
(new
(new
(new
(new
(new
(new
(new
(new
(new
Tuple
Tuple
Tuple
Tuple
Tuple
Tuple
Tuple
Tuple
Tuple
Tuple
Tuple
Tuple
("chopstick","4"));
("chopstick ","5"));
("ticket"));
("ticket"));
("ticket"));
("ticket"));
("ticket"));
("seat","1","2"));
("seat","2","3"));
("seat","3","4"));
("seat","4","5"));
("seat","5","1"));
Figura 14 – Programa Java, classe “holo”, que implementa o en te “holo” do programa Holo
que simula o “Jantar dos Filósofos”.
1 import jada.*;
2 import holoj.lang.*;
3
4 public class filosofo extends Being {
5
6
7 public String Ident;
8
9 filosofo(Being father,String name, String Ident){
10
this.Ident=Ident;
11
this.father=father;
12
this.son=new DBVector();
13
this.name=name;
14
setName(this.name+"-thread");
15
history = new ObjectSpace();
16
}
17
18
public void run(){
19
insert_history();
20
Tuple tuple=null;
21 Being holo_temp = null; Syste m.out.println("Fisolofo jantando: "+Ident);
22 String Cont = "";
23 for (int Cont_integer = 1;Cont_integer<=5;Cont_integer++){
24
Cont =""+Cont_integer;
25 synchronized (father.history) {tuple = (Tuple)father.history.in(new
Tuple("ticket"));
26
27
}
28 synchronized (father.history) {tuple = (Tuple)father.history.in(new
Tuple("seat",new String().getClass(),new String().getClass()));/*RPAREN2*/
29
30
}
31 //Position: 3 -- counthist:2
59
32
String F1 = (String)tuple.getItem(1);
33
String F2 = (String)tuple.getItem(2);
34 synchronized (father.history) {tuple = (Tuple)father.history.in(new
Tuple("chopstick",new String().getClass()));/*RPAREN2*/
35
36
}
37 //Position: 2 -- counthist:1
38
F1 = (String)tuple.getItem(1);
39 synchronized (father.history) {tuple = (Tuple)father.history.in(new
Tuple("chopstick",new String().getClass()));/*RPAREN2*/
40
41
}
42 //Position: 2 -- counthist:1
43
F2 = (String)tuple.getItem(1);
44 String Atraso = "";
45 for (int Atraso_integer = 1;Atraso_integer<=1000;Atraso_integer++ ){
46
Atraso =""+Atraso_integer;
47
48
}
49
synchronized
(father.history)
{father.history.out
(new
Tuple
("chopstick",F2));/*RPAREN2*/
50
51
}
52 //Position: 2 -- counthist:0
53
synchronized
(father.history)
{father.history.out
(new
Tuple
("chopstick",F1));/*RPAREN2*/
54
55
}
56 //Position: 2 -- counthist:0
57
synchronized
(father.history)
{father.history.out
(new
Tuple
("seat",F1,F2));/*RPAREN2*/
58
59
}
60 //Position: 3 -- counthist:0
61
synchronized
(father.history)
{father.history.out
(new
Tuple
("ticket"));/*OFINAL2*/
62
63
}
64
System.out.println("Comendo "+Ident+" - "+Cont);
65
66
}
67
synchronized
(father.history)
{father.history.out
(new
Tuple
("end"));/*OFINAL2*/
68
69
}
70
}
71
public void insert_history() {
72
}
73 }
Figura 15 – Programa Java, classe "filosofo", que implementa o ente "filosofo" do programa
Holo que simula o "Jantar dos Filósofos”.
60
Anexo 2 - Documentação (Javadoc) da HDI
Este anexo relaciona a documentação das principais interfaces Java publicadas pela
Holo Debug Interface. Esta documentação foi gerada pela ferramenta Javadoc [JAV 02b]. A
versão completa desta documentação pode ser obtida por WWW através do endereço
<http://www.inf.ufrgs.br/~fcecin/holo/docs/index.html>.
61
Download