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;