Manejo de Excepciones

Anuncio
Manejo de Excepciones
• Manejo de Excepciones en Lenguajes
Tradicionales
• Manejo de Excepciones en Lenguajes Modernos.
• Manejo de Excepciones en ADA
• Manejo de Excepciones en C++
• Interacción con el HW
Manejo de Excepciones
• Una excepción es una situación anómala en la ejecución del programa,
es decir no contemplada en el flujo normal de ejecución de éste.
• Existen varios modelos distintos para manejar estas excepciones dentro
de los lenguajes de programación.
• Estos modelos son la base para construir sistemas tolerantes a fallos.
• Aquí sólo vamos a ver como se representan y manejan las excepciones.
• Vamos a tratar los siguientes aspectos:
• Manejo de excepciones en lenguajes tradicionales.
• Manejo de excepciones en lenguajes modernos.
• Manejo de excepciones en Ada, C y C++
Manejo de Excepciones
• Existe un conjunto de requisitos que cualquier modelo de manejo de
excepciones debe cumplir:
• R1: Debe ser simple y fácil de entender y usar.
• R2: El código para manejo de excepciones no debe dificultar el
entendimiento de la ejecución normal del programa.
• R3: El mecanismo debe ser diseñado de forma que no se produzcan
sobrecargas en tiempo de ejecución, salvo en el caso de excepciones.
• R4: El tratamiento de las excepciones detectadas en el entorno y por el
programa (externas e internas) debe ser homogéneo.
• R5: Se deben proporcionar mecanismos para programar acciones de
recuperación.
Lenguajes Tradicionales
• El mecanismo normal es devolver un valor que indique se
ha producido un error desde el procedimiento o función en
el que se ha producido.
if (llamada_función(parametros) == UN_ERROR)
{--código de error}
else { -- código normal}
• Es un mecanismo muy simple (R1) y permite programar
acciones de recuperación (R5)
• No cumple ningún otro requisito.
• Causa sobrecargas, dificulta la comprensión del código y
no está claro como podría manejar errores del entorno.
Lenguajes Tradicionales
• Otro mecanismo es el del salto incondicional, que se utiliza
principalmente en lenguajes ensambladores.
• La instrucción que sigue a la llamada a la función se salta, para indicar
la presencia o ausencia de error.
• Se suele implementar modificando el contador de programa (la
dirección de retorno) en tantos bytes como ocupe una instrucción de
salto.
Lenguajes Tradicionales
• Cuando pueden ocurrir más de una condición de error, el contador de
programa se puede modificar convenientemente
.
jsr pc, PRINT_CHAR
jmp IO_ERROR
jmp DEVICE_NOT_ENABLED
# proceso normal
•
Es muy eficiente (R3) y permite recuperar errores (R5), pero no
cumple ninguna otra restricción.
Lenguajes Tradicionales
• GOTO no local. Es la versión en lenguaje de alto nivel de la técnica
anterior utilizando etiquetas.
• RTL/2 proporciona este mecanismo para manejo de errores.
Svc data rrerr
label erl %etiqueta de error %
end data;
proc DondeSeDetecta();
.....
goto erl;
.....
endproc;
proc PruebaError();
.....
DondeSeDetecta();
.....
endproc;
proc main();
.....
restart:
.....
erl:=restart;
.....
PruebaError();
.....
endproc;
Lenguajes Tradicionales
• Cuando se utiliza de esta forma el GOTO no es solo un salto sino que
implica un retorno anormal de un procedimiento.
• El stack debe ser descartado hasta el punto en que se encuentra el
entorno del procedimiento que contiene la declaración de la etiqueta.
•
Es un mecanismo eficiente (R3) y flexible (R4 y R5) pero puede
conducir a programas poco claros (no satisface R1 y R2).
Lenguajes Tradicionales
• Variables procedimiento. En RTL/2 el mecanismo anterior se utiliza
sólo en el caso de errores irrecuperables, ya que tiene otro mecanismo
adicional que el de las variables procedimiento.
•
Se utilizan cuando el control debe devolverse al punto en el que el
error se originó (no es posible en el caso anterior).
Svc data rrerr
label erl;
%etiqueta de error %
proc(int) erp; %proced. de error %
end data;
proc recuperar(int);
......
endproc;
Lenguajes Tradicionales
proc DondeSeDetecta();
.....
if recuperable then erp(n)
else goto erl;
.....
endproc;
proc PruebaError();
.....
DondeSeDetecta();
.....
endproc;
proc main();
.....
restart:
.....
erl:=fallo;
erp:= recuperar
.....
PruebaError();
.....
endproc;
Manejo de Excepciones
Moderno
•
El manejo de excepciones en los lenguajes tradicionales está integrado
con el flujo normal del programa.
•
Los lenguajes modernos intentan que ese manejo sea más estructurado.
•
Cada lenguaje tiene sus particularidades.
•
Sin embargo, hay algunas cuestiones comunes:
Manejo de Excepciones
Moderno
• Se utilizan para representar errores producidos por el entorno y errores
de la propia aplicación.
• Una excepción síncrona es aquella que se produce (se eleva) como
consecuencia inmediata de una operación incorrecta.
•
Una excepción asíncrona es aquella que se eleva algún tiempo después
de que se realizara la operación que produjo la excepción. Puede
ocurrir en el proceso que la produjo o en otro proceso distinto.
Manejo de Excepciones
Moderno
• Existen, por tanto, cuatro tipos de excepciones:
– Detectadas por el entorno y elevadas síncronamente (errores en los
índices de un array, división por cero...).
– Detectadas por la aplicación y elevadas síncronamente (por
ejemplo, el incumplimiento de un determinado aserto definido en
el programa).
– Detectadas por el entorno y elevadas asíncronamente (una
excepción provocada por un fallo en el algún sistema controlado).
– Detectadas por la aplicación y elevadas asíncronamente (un
proceso puede detectar una condición de error como resultado de
que otro proceso no ha cumplido un límite temporal o no ha
terminado correctamente.
Manejo de Excepciones
Moderno
• Existen dos modelos para su declaración:
• un nombre constante que necesita ser declarado explícitamente.
• un objeto de un tipo particular que puede o no ser declarado.
• En Ada las excepciones se declaran como constantes, por
ejemplo las que puede elevar el entorno de ejecución se
encuentran declaradas en el paquete Standard:
Manejo de Excepciones
Moderno
package Standard is
......
Constraint_Error: exception ;
Program_Error: exception ;
Storage_Error: exception ;
Tasking_Error: exception ;
......
end Standard;
• C++ toma una visión orientada a objeto de las
excepciones; pueden ser objetos de cualquier tipo que son
lanzados/elevados (throw) como excepciones sin una
declaración previa. Estos objetos son capturados (catch)
por un manejador que nombre al tipo del objeto.
Dominio del Manejador
• Dentro de un programa puede haber varios manejadores
para una misma excepción.
• Asociado con cada manejador hay un dominio que
especifica la región de computación en la que, si la
excepción se produce, el manejador se activará.
• La precisión con la que un dominio pueda ser especificado
determinará la precisión con la que la fuente de la
excepción puede ser localizada.
Dominio del Manejador
• Por ejemplo, en el siguiente programa, la temperatura de
un sensor debe estar en un rango de 0..100, si la
temperatura está fuera del rango el sistema elevará la
excepción Constraint_Error. El manejador indica la
acción de recuperación que hay que llevar a cabo.
declare
subtype temp is integer range 0..100 ;
begin
--leer temperatura
exception
--manejador para Constraint_Error
end;
Dominio del Manejador
• En otros lenguajes como C++ y Modula-3, no todos los
bloques pueden tener manejadores de excepciones, sino
que el dominio de un manejador se indica explícitamente.
Por ej. en C++:
try {
//sentencias que pueden elevar
//una excepción
}
catch (nombre_excepción) {
//manejador
}
Dominio del Manejador
• A veces, el que los manejadores estén asociados a bloques
puede no permitir detectar el error con facilidad.
declare
subtype temp is integer range 0..100 ;
subtype presión is integer range 0..50 ;
subtype flujo is integer range 0..200 ;
begin
--leer temperatura
--leer presion
--leer flujo
No podemos saber
........
exactamente
exception
dónde se produce
--manejador para Constraint_Error
end;
el error
Dominio del Manejador
• Una posible solución:
declare
begin
--leer flujo
subtype temp is integer range 0..100 ;
exception
subtype pres is integer range 0..50 ;
--manejador
--Constraint_Error flujo
subtype flujo is integer range 0..200 ;
end;
begin
........
begin
exception
--otras posibles excepciones
--leer temperatura
end;
exception
--manejador Constraint_Error temp
end;
begin
--leer presión
exception
--manejador Constraint_Error presión
end;
Dominio del Manejador
• Otra solución sería permitir manejar excepciones a nivel de
instrucciones (no válido en Ada):
declare
subtype temp is integer range 0..100 ;
subtype pres is integer range 0..50 ;
subtype flujo is integer range 0..200 ;
begin
leer_temperatura;
exception--manejador Constraint_Error temp
leer_presión ;
exception--manejador Constraint_Error presión
leer_flujo;
exception--manejador Constraint_Error flujo
end;
Dominio del Manejador
• El lenguaje CHILL (CCITT) tiene esta facilidad.
Problema: se entremezcla el código de manejo de
excepciones con el flujo normal del programa (requisito
R2).
• La mejor solución es permitir pasar parámetros con la
excepción. Con C++ esto es automático ya que la
excepción es un objeto y puede contener cualquier tipo de
información.
• Ada
proporciona
un
procedimiento
(Exception_Information) que devuelve información acerca
de la excepción (esta información es dependiente de la
implementación).
Dominio del Manejador
• ¿Qué ocurre si no hay manejador asociado con el bloque o
procedimiento en el que se produce la excepción ?. Existen
dos aproximaciones:
• Indicar esta situación al programador en tiempo de
compilación.
• Buscar manejadores hacia atrás en la cadena de
llamadas al procedimiento donde se detecta la
excepción en tiempo de ejecución. A este
mecanismo se le denomina propagación de la
excepción.
Propagación de Excepciones
• Con esta aproximación aparece un problema cuando una excepción se
propaga más allá de su ámbito de visibilidad. Puede ocurrir que una
excepción declarada internamente se propage a una unidad más
externa.
• Para evitar este problema la mayoría de los lenguajes proporcionan una
opción por defecto en los manejadores que permiten referenciar a
excepciones desconocidas (catch all-when other).
• Si en un programa secuencial una excepción no se trata, el programa es
abortado.
• Si un programa contiene varios procesos y la excepción se produce en
un proceso concreto, sólo ese proceso es abortado, aunque en
ocasiones la excepción se propaga también al proceso padre.
Manejo de la Excepción
• Cuando una excepción ha sido tratada, el control puede ser
devuelto al lugar donde se produjo la excepción o no.
• Si el modelo de excepciones permite continuar la ejecución
del bloque donde se produjo la excepción, el manejador
puede tratar de anular la causa que produjo la excepción y
la ejecución podría seguir con normalidad.
• Este modelo se denomina modelo de continuación.
Manejo de la Excepción
• El modelo en el que el control no se devuelve al lugar
donde se produjo la excepción, se denomina modelo de
terminación.
• Existen modelos híbridos en los que el manejador puede
decidir continuar la ejecución por donde iba o terminar la
ejecución del bloque.
Modelo de Continuación.
Ejemplo
•
Consideremos tres procedimientos P, Q y R.
•
P llama a Q y Q llama a R.
•
R eleva una excepción r que es tratada por Q, suponiendo que no
existe un manejador en R.
•
El manejador de r es Hr.
•
Mientras se trata r, Hr eleva una excepción q que es manejada por Hq
en el procedimiento P.
Una vez está ha sido tratada la ejecución de R continúa.
•
Modelo de Continuación
Hq
P
1
5
4
Hr
Q
2
3
6
R
Modelo de Continuación
• Se puede ver el manejador como un procedimiento implícito al que se
llama cuando se produce una excepción.
• El principal problema de este modelo es que normalmente es bastante
difícil “reparar” los errores que han sido elevados por el entorno de
ejecución.
• Por ejemplo un error aritmético de overflow que ocurra en la mitad de
la evaluación de una expresión compleja puede conllevar que varios
registros contengan evaluaciones parciales. Como consecuencia de la
llamada al manejador, estos registros se pueden “machacar”.
Modelo de Continuación
• Aunque implementar un modelo de continuación estrictamente puede
ser difícil, un compromiso es reejecutar el bloque asociado con el
manejador.
• Eiffel proporciona esta facilidad (retry) como parte de su modelo de
manejo de excepciones.
•
Problema: si se han llevado a cabo acciones sobre el entorno no
pueden ser deshechas ! ! !.
Modelo de Terminación
• El control no se devuelve al punto donde se produjo el error, sino que
se considera que el bloque en el que la excepción se ha producido
termina. El control se pasa al bloque o procedimiento llamante.
• Un procedimiento por tanto puede terminar normalmente o como causa
de una excepción.
•
Cuando el manejador está dentro de un bloque, el control se pasa a la
primera instrucción que sigue al bloque, una vez que la excepción ha
sido tratada.
Modelo de Terminación
declare
subtype temp is integer range 0..100 ;
begin
....
begin
--leer temperatura
exception
--manejador Constraint_Error temp
end;
-- este código se ejecuta normalmente,
-- cuando el bloque acaba o cuando una
-- excepción ocurre y ha sido tratada.
........
exception
--otras posibles excepciones
end;
Modelo de Terminación
Proc. P
1
2
Proc. Q
3
P llama Q
Proc. P
4
5
8
Q llama R
6
Manejador
7
de r
Excepción
r
Manejo de Excepciones en ADA
• ADA incorpora:
− Declaración explícita de excepciones.
− Modelo de terminación.
− Propagación de excepciones no declaradas.
– Parámetros en las excepciones (muy limitado).
Manejo de Excepciones en ADA
• Las excepciones son declaradas mediante el tipo
predefinido exception o en el paquete predefinido
Ada.Exceptions que define un tipo privado llamado
Exception_Id.
– Error_dispositivo: exception;
• Cada excepción declarada tiene asociado un identificador
de excepción interno (Exception_Id) que puede ser
obtenido mediante el atributo Identity.
procedure Raise_Exception(E :in Exception_Id ;
Message : in String :=””) ;
function Exception_Message(X :
in Exception_Ocurrence) return String;
function Reraise_Ocurrence(X :
in Exception_Ocurrence) ;
function Exception_Identity(X :
in Exception_Ocurrence)return Exception_Id ;
function Exception_Name(X :
in Exception_Ocurrence) return String;
function Exception_Information(X :
in Exception_Ocurrence) return String;
........
private
--no especificado por el lenguaje
end Ada.Exceptions;
type Exception_Ocurrence is limited private ;
Null_Ocurrence: constant Exception_Ocurrence;
function Exception_Name(Id:Exception_Id) ;
return String;
type Exception_Id is private;
Null_Id: constant Exception_Id ;
package Ada.Exceptions is
Manejo de excepciones en ADA
Estas excepciones tienen ámbito en el programa completo:
• Constraint_Error : se eleva por ejemplo cuando se intenta asignar un
valor fuera de rango a una variable, cuando se accede más allá de los
límites de un array o cuando se intenta acceder a datos por medio de un
puntero a null;
•
Storage_Error: se produce cuando el sistema no puede proporcionar la
memoria necesaria para llevar a cabo la operación realizada debido a
limitaciones físicas.
Manejo de excepciones en ADA
• Una excepción puede ser elevada explícitamente mediante la sentencia
raise.
begin
.....
if error_dispositivo then raise Error_Dispositivo;
end if;
.....
end;
• Si Error_Dispositivo fuese del tipo Exception_Id en lugar de
exception,
se
utilizaría
el
procedimiento
Ada.Exceptions.Raise_Exception.
• Esto permitiría pasar una cadena de caracteres cómo parametro de la
excepción.
• El valor de Exception_Ocurrence se puede utilizar también para
determinar más precisamente la causa del error y su localización.
Manejo de excepciones en ADA
• Cada bloque (y por tanto cada subprograma, sentencia accept o tarea)
puede contenr un manejador de excepciones.
• Se declaran al final del bloque y tienen el siguiente formato:
declare
valor_alto,valor_bajo, no_responde: exception ;
--otras declaraciones
begin
--sentencias que pueden causar las excepciones
exception
when E :valor_alto|valor_bajo=>
-- accciones para corregir la excepción
--E contiene la ocurrencia de la excepción
when others=>
--otras excepciones
end ;
Manejo de excepciones en ADA
• Las excepciones que se producen dentro de un manejador no pueden
ser tratadas dentro del mismo manejador, ni en otro manejador del
mismo bloque.
• En este caso el bloque de manejo de excepciones acaba y la excepción
se propaga.
Propagación de excepciones en
ADA
•
Si no hay manejador de excepciones en un bloque/subprograma/accept, la
excepción se eleva de nuevo, es decir, se propaga.
•
En un bloque, la excepción se propaga al bloque o subprograma que lo
contiene.
•
En un subprograma, se eleva la excepción en el lugar de la llamada al
subprograma.
•
En una sentencia accept, se eleva tanto en la tarea llamante como en la
llamada.
•
Los manejadores de excepciones de los paquetes pertenecen al bloque de
inicialización, no a los subprogramas que engloba.
Una excepción elevada en un subprograma y no capturada en el manejador se
propaga al punto donde se llama, nunca al manejador de excepciones del
paquete donde se declara.
•
Propagación de Excepciones
procedure Allocate is
begin
--solicitar dptvo 1
--solicitar dptvo 2
--solicitar dptvo 3
exception
when others =>
--liberar los dispositivos ya concedidos
raise ;
Antes
end Allocate ;
de que se propague
la excepción se
pueden realizar un
conjunto de acciones
Dificultades del modelo de ADA
• Excepciones y paquetes
• Las excepciones que se elevan por el uso de un paquete se
declaran en la especificación de éste.
• No es obvio qué subprogramas elevan que excepciones.
• En ese caso, el programador debe enumerar todas las
excepciones del paquete cada vez que llama a un subprograma
o utilizar when others.
• La única forma de evitar esto es mediante comentarios.
• Paso de parámetros : sólo permite strings y a veces es
necesario pasar objetos de otro tipo.
Dificultades del modelo de ADA
• Ámbito y propagación:
• Se pueden propagar excepciones fuera de su ámbito.
• Estas excepciones sólo se pueden capturar con when
others.
• Sin embargo pueden volver a estar dentro del ámbito cuando se
sigan propagando.
Excepciones en C++
• El modelo es similar al de Ada, ya que se trata de un
modelo de terminación.
• Sin embargo, el modelo es más Orientado a Objeto y
permite representar excepciones mediante objetos
arbitrarios.
• C++ no requiere declarar las excepciones de forma
explícita, cualquier instancia de una clase puede ser
lanzada como una excepción (throw).
• No existen excepciones predefinidas.
Excepciones en C++
Una excepción es cualquier objeto, por ej. para representar la excepción
constraint_error de Ada:
class integer_constraint_error {
public :
int lower_range ;
int upper_range ;
int value ;
integer_constraint_error(int L, int U, int V) {
lower_range=L ;
upper_range=U ;
value=V
}
}
Excepciones en C++
class temperatura {
int T;
public:
temperatura(int inicial)
throw(integer_constraint_error)
{
check(inicial) ;
}
int modificar(int N)
throw(integer_constraint_error)
{
check(N) ; return(N) ;
}
private:
void check(int valor) {
if (valor>100) || valor<0)
throw
integer_constraint_error(0,
100,valor) ;
} else T=valor
}
}
Excepciones en C++
try {
.....
//bloque donde se produce la excepción
T.modificar(120);
...
}
catch (integer_constraint_error error) {
//manejador de la excepción
//error es el objeto que representa
//la excepción
cout <<”Error en temperatura “
<<”Límite
inf.”<<error.lower_range<<
<<”Límite sup.”<<error.upper_range<<
<<”Valor “<<error.value ;
}
catch(....){
}
Interacción con el HW
• Uno de los requisitos de los lenguajes para sistemas de tiempo real es
que deben proporcionar mecanismos para interactuar con el hardware.
• En los lenguajes tradicionales la programación de los dispositivos se
efectúa accediendo mediante la utilización de punteros a las posiciones
de memoria donde se encuentran mapeados los registros de los
dispositivos.
• Este mecanismo es excesivamente dependiente del sistema y lo ideal
es que los lenguajes proporcionen un modelo abstracto para el manejo
de los dispositivos.
• Estos modelos deben separar la parte portable del código de la parte no
portable.
Interacción con el HW
•
Además, estos modelos deben proporcionar un modelo abstracto de
manejo de interrupciones (en los lenguajes tradicionales el manejo de
interrupciones sólo es controlable a través de llamadas y estructuras
internas del sistema operativo).
• Los registros de los dispositivos se suelen representar mediante
variables, objetos o canales de comunicaciones (Occam).
• Las interrupciones en los lenguajes se suelen representar mediante :
• llamadas a procedimiento
• invocación de procesos esporádicos.
• eventos asíncronos (señales).
• mensajes sobre canales especiales
Todos estos mecanismos excepto
el del procedimiento se
ejecutan en el
espacio de direcciones del
proceso que controla la
interrupción y por tanto
requieren un cambio de contexto.
• condiciones de sincronización en memoria compartida.
Interacción con el HW
• En Ada se utilizan las cláusulas de representación para
manipular los registros de dispositivos.
• Una cláusula de representación puede ser :
• Definición de atributos: tamaño, alineamiento, espacio de
almacenamiento para las tareas, direcciones,...
• Representación de los tipos enumerados (valores internos para
los literales).
• Cláusulas de representación de registros (offsets y longitudes
de los componentes de un registro).
Interaccion con el HW. Ejemplo
•
Control/Status:
15-12 : Error.
11 : Busy
10-8 : Unit select
7 : Done/ready
6 : Interrupt_enable
5-3 : Reservados
2-1 : Función
0 : Device enable
•
Registro de datos :
15-8 : sin utilización
7-0 : datos
Ejemplo
type Error_T is (Read_Error, Write_Error,
Power_Fail, Other)
type Function_T is (Read, Write, Seek) ;
type Unit_T is new integer range 0..7 ;
type Csr_T is record
Errors :Error_T ;
Busy :Boolean ;
Unit :Unit_T ;
Done :Boolean ;
Ienable :Boolean ;
Dfun :Function_T ;
Denable :Boolean ;
end record ;
Ejemplo
• Cláusulas de enumeración : especifican los códigos internos para la
representación de los literales de los tipos enumerados.
00 - Read, 10 - Write, 11 - Seek
type Function_T is (Read, Write, Seek) ;
for Function_T use
(Read=>1,Write=>2,Seek=>3) ;
Ejemplo
• Cláusulas de representación de registros:
• Especifican el almacenamiento en memoria de los registros.
• Los bits en un registro se numeran desde 0 ; el rango en el
componente del registro indica el número de bits reservados para un
componente.
• Existen también atributos de tamaño, alineamiento u ordenación de
bits.
Ejemplo
Word : constant := 2 ; -- número de bytes en una
Bits_in_Word :constant :=16 ;
for Csr_T use record
Denable : at 0 range 0..0 ;
Dfun : at 0 range 1..2 ;
Ienable : at 0 range 6..6;
Done : at 0 range 7..7;
Unit : at 0 range 8..10;
Busy :at 0 range 11..11;
Errors : at 0 range 12..15 ;
end record ;
for Csr_T´Size use Bits_in_Word ;
for Csr_T´Alignment use Word ;
for Csr_T´Bit_Order use Low_Order_First ;
palabra
Ejemplo
• Definición de registros y su utilización
Tcsr: Csr_T;
for Tcsr´Address use 8#177566# ;
Tmp: Csr_T;
Tmp :=(
Denable=>True,
Dfun=>Read,
Ienable=>True,
Done=>False,
Unit=>4,
Errors=>None) ;
Tcsr :=Tmp ;
Definición
Uso
Para asegurar que todos los bits se
escriben al mismo tiempo se utiliza
una varible temporal
del mismo tipo.
Manejo de interrupciones en ADA
•
Una interrupción es un evento detectado bien por el hardware o por el sistema.
•
Cada ocurrencia de una interrupción consiste en dos fases : su generación y su entrega.
•
La generación es el evento en el sistema (hardware o software) que hace que la
interrupción esté disponible en el programa.
•
La entrega de una interrupción es la acción que lleva a cabo una parte del programa (el
manejador de interrupciones) en respuesta a una interrupción.
•
Entre la generación y su entrega la interrupción se dice que está bloqueada.
•
El manejador se invoca una vez por cada entrega de la interrupción.
•
Cuando una interrupción está bloqueda o está siendo atendida por el manejador, las
posibles futuras interrupciones de dicha interrupción se enmascaran.
Manejo de Interrupciones con
Procedimientos Protegidos
•
Un manejador de interrupciones en Ada es un procedimiento protegido (es decir,
encapsulado dentro de un tipo protegido).
•
Cada interrupción tiene un único identificador discreto que está predefinido en el
sistema.
•
Como se representa dicho identificador es dependiente de la implementación. Por
ejemplo, podría ser la dirección del vector de interrupción hardware asociado.
•
Para identificar el procedimiento protegido que se va a encargar de manejar una
determinada interrupción se utiliza uno de los siguientes pragmas:
pragma Attach_Handler(Manejador,Expresión) ;
--Puede aparecer en la especificación o cuerpo de
--cualquier objeto protegido y permite la asociación
--estática de un manejador a un identificador de
--interrupción dado por Expresión. El manejador se
--asocia cuando el objeto es creado.
pragma Interrupt_Handler(Handler_name) ;
-- Igual pero permite la asociación dinámica
Driver Analógico-Digital
• El conversor toma muestras de señales analógicas de sensores (presión,
temperatura,...).
• Convierte las medidas que usualmente vienen dadas en milivoltios y
proporciona un entero escalado en un registro hardware.
• El convertidor tiene dos registros de 16 bits:
• Datos (dirección 8#150000#)
• Control (dirección 8#150002#)
• El convertidor comienza una conversión poniendo a 1 el bit 0 del
registro de control (A/D start).
• Una vez finalizada envía una interrupción que debe ser manejada por
el driver.
Driver Analógico-Digital
• La estructura del registro del control es la siguiente:
Bit 0
A/D Start
1 Comienza conversión
Bit 6
Int. Dis/En.
1 Habilita las interrupciones
Bit 7
Done
1 Conversión completa
Bit8-13
Canal
64 canales de conversión
Bit 15
Error
1 indica error en la conversión.
• Utilizaremos un tipo protegido en un paquete que se podrá utilizar para
distintos conversores.
• Para cada petición de lectura, si ocurre un error, el driver reintentará la
lectura hasta 3 veces.
• Si después de tres intentos el error persiste elevará la excepción
Conversion_Error.
Driver Analógico-Digital
package ADC_Device_Driver is
Max _Measure : constant :=(2**16)-1 ;
type Channel is range 0..63 ;
subtype Measurement is integer range
0..Max_measure
procedure Read(Ch :Channel ;
M : out Measurement) ;
--bloquea hasta que finaliza la lectura
Conversion _Error:exception ;
private
for Channel’Size use 6 ;
--solo se usan 6 bits para indicar el canal
end ADC_Device_Driver ;
Driver Analógico-Digital
•
En el punto de entrada Read, el registro de control Cr se prepara con los
parámetros apropiados.
•
Una vez que se escribe el registro de control la tarea que ha llamado al punto
de entrada se encola en un punto de entrada privado (Done) para esperar la
interrrupción.
•
El flag Next_request se utiliza para asegurar que sólo una llamada a Read se
atiende al mismo tiempo.
•
Una vez que la interrupción ha ocurrido el sistema llamará al procedimiento
protegido asociado mediante el pragma y la barrera del punto de entrada Done
se pone a true, para que la tarea suspendida pueda tratar la interrupción.
•
En el punto de entrada Done, comprobamos que la conversión se ha realizado
correctamente y se devuelve el valor del registro de datos.
Si ha ocurrido un error se eleva una excepción, que será tratada en el
procedimiento Read ;
•
Driver Analógico-Digital
procedure Read(Ch :Channel ; M :out Measurement) is
begin
for I in 1..3 loop –3 reintentos
begin
Adc_Interface.Read(Ch,M) ;
El proceso cliente sólo llama a
Read con el número de canal a
leer y la variable donde devolver
el valor que ha leido.
return ;
exception
When Conversion_Error=>null ;
end ;
end loop ;
raise Conversion_Error ;
end Read ;
Si la conversión no ha tenido éxito
se eleva la excepción
Conversion_Error,
Driver Analógico-Digital
Protected type Interrupt_Interface(Int_Id :Interrup_id;Cr:
access control_Register;Dr: access Data_Register) is
entry read (chan:channel; M: out Measurement),
private
entry Done(chan :channel; M: out Measurement);
procedure Handler;
pragma Attach_Handler(Handler,int_Id);
pragma Interrupt_Priority(Adc_Priority);
Interrupt_Ocurred: Boolean:=False;
Asume que ‘Adc’ tiene un Interrupt_Id
Next_Request :Boolena:=True;
en ADA.Interrupt.Names
end Interrupt_interface;
Adc_Interface: Interrupt_Interface(Names.Adc, Control_Reg’access,
Data_Reg’access);
Driver Analógico-Digital
Protected body Interrupt_Interface is
entry Read(chan:channel;M: out Measurement) when Next_Request is
shadow_register : Control_Register;
begin
shadow_register:=(Ad_Start => Set, IE=>Set, Done=>Down,
ch=>chan,error=>Down);
Cr.all:=shadow_register;
Interrupt_ocurred:=False;
Next_request:=False;
requeue Done;
end Read;
Driver Analógico-Digital
procedure handler is
begin
Interrupt_ocurred:=true;
end handler;
entry Done (chan:channel; M: out Measurement) when interrupt_ocurred
is
begin
Next_Request:=True;
if Cr.Done =Set and Cr.Error=Down then
M:=Measurement(Dr.all);
else
raise Conversion_Error;
end if;
end Done;
end Interrupt_Interface;
Descargar