PORTOS
Sistema operativo de tiempo real orientado a componente


INTRODUCCIÓN
Portos es un sistema operativo de tiempo real (RTOS), orientado a componente, que puede cumplir requisitos críticos de tiempo real , y que permite añadir nuevos componentes software en tiempo de ejecución. 

Presenta dos novedades con respecto a los RTOS aplicados a los sistemas empotrados empleados en la industria en la actualidad, como son:

En primer lugar la planificación por plazos en lugar de la planificación por prioridades, lo que facilita enormemente a los ingenieros el diseño de aplicaciones por ser la manera mas natural para la planificación temporal de tareas ,y en segundo lugar el empleo de software de componentes, con las ventajas en cuanto a modularidad, escalabilidad, reusabilidad, sencillez y componibilidad que supone. 

La Componibilidad, clave del software de componentes, se entiende como la posibilidad de añadir nuevos componentes en tiempo de ejecución. Para los sistemas de tiempo real, significa que la adición de nuevas tareas no perjudica el cumplimiento de plazos de las que ya se están ejecutando.

Portos está diseñado de manera que soporta los estándares de componentes de mayor futuro dentro de los sistemas empotrados, como son COM de Microsoft (actualmente mejorado con COM+) y Java de Sun. COM es atractivo por su mínima sobrecarga y por su estándar OLE para el control de procesos estándar (OPC) mientras Java es atractivo por su portabilidad y seguridad.

REQUERIMIENTOS
En primer lugar cabe hacer una distinción entre los sistemas de tiempo real en cuanto a las restricciones temporales de las tareas:

Los sistemas rígidos de tiempo real en los cuales el incumplimiento de requisitos temporales supone un fallo grave del sistema y los sistemas flexibles de tiempo real en los cuales un incumplimiento esporádico de los requisitos temporales no condiciona al sistema

En los sistemas en que nos vamos a centrar, habrá una convivencia entre tareas críticas ( guiado, control de procesos, etc.) y un numero arbitrario de tareas no criticas (comunicaciones, interacción con el usuario, etc.).

Además, si se quieren añadir nuevas tareas habrá que tener en cuenta si son críticas o no. Una nueva tarea crítica se podrá añadir sólo si el sistema no está saturado y por tanto no se afectará a las tareas críticas existentes, mientras que una no crítica siempre podrá ser añadida pues basta con ralentizar su ejecución para no afectar a las críticas.

La cuestión fundamental en un sistema orientado a componentes de tiempo real, es la composición dinámica de tareas de tiempo crítico. Esto no lo soportan los modelos tradicionales (ej. VxWorks), ni tampoco algunos lenguajes (Java). Dichos modelos se basan en la planificación por prioridades de las tareas, esto es adecuado para sistemas cerrados y pequeños en donde no hay variación dinámica en las tareas, que son conocidas desde un principio y no cambian. Se establece entonces un orden relativo en relación con la respuesta a las interrupciones; este orden no es consistente con la adición de nuevas tareas desconocidas mientras el sistema está operando.

En las aplicaciones de tiempo real, lo importante es completar o iniciar las tares en el momento más apropiado, ni antes ni después , es decir en instantes fijos y predeterminados o en intervalos de tiempo predeterminados (determinismo), a pesar de las peticiones dinámicas de recursos y los conflictos, la sobrecarga de procesos y los fallos de hardware o software. El no determinismo de los sistemas basados en prioridades proviene de una falta de relación directa entre el concepto de prioridad y el de finalización o inicio en el momento más apropiado, lo que además es un problema desde el punto de vista de la ingeniería de software, debido a un aumento de complejidad considerable.

Situación de PORTOS respecto a otros sistemas operativos

Otra característica importante de los sistemas de tiempo real es que su aplicación a los sistemas empotrados debe ser compacta, es decir, que el software requiera poca memoria para almacenar el código y para su ejecución (eficiencia). Las memorias son componentes electrónicos que cuestan dinero, ocupan espacio y consumen energía. Se puede considerar , a modo de ejemplo que en aplicaciones exigentes se utilizan memorias del orden de: 128 Kb de EPROM y 1 Mb de RAM.

La eficiencia es fundamental, pero conlleva una pérdida de seguridad, esto es así, debido a que para evitar fallos como el acceso de un proceso a la memoria perteneciente a otro, el diseño del sistema operativo ha de ser más complejo, esto se puede compensar empleando lenguajes fuertemente tipados y modulares lo que aumenta la seguridad con un bajo coste de eficiencia.

Un aspecto importante a considerar de la seguridad de tipos, es la liberación de memoria dinámica, que no puede ser manual para sistemas abiertos debido a que puede conllevar una destrucción de estructuras de memoria compartidas entre objetos que se desconocen entre sí, lo que conlleva a la utilización de liberadores de memoria dinámica automáticos (automatic garbage collector ). Sin embargo esto introduce un problema adicional ya que los liberadores habituales asíncronos tienen la máxima prioridad, lo que ralentiza a otros procesos durante un período largo de tiempo, incluso a las tareas críticas que no utilizan memoria dinámica. 

A modo de orientación se puede decir que con la liberación automática de memoria no se pueden asegurar tiempos de respuesta inferiores a 100 milisegundos . Cuando se necesita trabajar con memoria dinámica se prohíbe la solicitud y liberación de memoria en las fases de funcionamiento de tiempo real, será en las fases de tiempo no real cuando esto se produzca. Esta separación en fases de tiempo real y no real es un artificio que añade complejidad al sistema. Sin embargo el algoritmo empleado en Portos es compatible con las tareas rígidas de tiempo real con frecuencias de 10kHz.

Gracias a la tecnología de componentes el tamaño del sistema operativo puede estar en un rango casi ilimitado. Desde un mínimo, en caso de requerir poca funcionalidad, cabe la adición de componentes hasta lograr el sistema a la medida deseada.

También es interesante el funcionamiento con conexiones en red. El uso de protocolos estandarizados, como TCP/IP, browsers de Web o sistemas completos de ventanas, permitirá entre otras cosas, la monitorización del estado del sistema empotrado desde un nodo remoto. Una elección interesante es Java. Sin embargo el soporte de Java basado en la interpretación de código no es aceptable.

Una implementación de Java basada en un intérprete de código no es la más adecuada para un sistema rígido de tiempo real. Además, en Java el desarrollo de drivers es problemático, por las restricciones de seguridad de este lenguaje y su código especial. Una solución a este problema es COM de Microsoft mediante el OLE para control de procesos (OPC) con el que un driver de una tarjeta puede servir idealmente para distintas aplicaciones y distintos sistemas operativos. Las nuevas implementaciones de Java pueden llegar a aportar algo en este sentido.

La ingeniería de software adolece de una doble problemática: por un lado la dificultad de desarrollo, paliada en parte por las herramientas de ayuda a éste (RAD), y por otro la dificultad de modificación, que además es agravada precisamente por dichas herramientas que no facilitan la modificación de las aplicaciones. La complejidad creciente de los sistemas empotrados necesita herramientas parecidas a las RAD del desarrollo de intrerfaces de usuario.

La adición y sustitución de componentes simplifica la ampliación, mantenimiento y reelaboración de sistemas extensos de software (escalabilidad y reusabilidad). Esto puede lograrse usando el software de componentes, lo cual sólo es posible aplicando algún estándar.


ESTÁNDARES
En la actualidad existen tres estándares: CORBA de OMG, COM de Microsoft y Java de Sun. Aquí se va a dar una breve comparación de ellos en su aplicación a sistemas empotrados.

En cuanto a la eficiencia, podemos distinguir tres aspectos: velocidad, tamaño y determinismo temporal.

Una llamada a un método COM consiste en una doble desreferencia seguida de una indexación a una tabla de métodos, lo que lo hace a este estándar óptimo en términos de velocidad. Mientras que las llamadas en CORBA siempre pasan a través de un objeto central servidor de peticiones. Por otro lado, la opinión general es que Java es lento aún con el uso de compiladores nativos puesto que los programadores no tienen acceso a las estructuras de datos estáticas y tampoco existen parámetros pasados por referencia, lo que produce reserva de memoria, copia y liberación de memoria dinámica innecesarios.

En cuanto a tamaño de código, COM es simplemente un conjunto de convenciones mientras que Java es un lenguaje complicado que, por ejemplo incluye 34 clases con varios cientos de métodos, y CORBA necesita compiladores especiales y adaptadores de objetos.

Con respecto al determinismo del tiempo, COM y CORBA no definen abstracciones de thread; y Java a través de su clase Java.Lang.Threads, implementa los tradicionales threads con prioridades, los cuales pueden usar los objetos Java como monitores y señales para sincronización y comunicación respectivamente. Sin embargo sus 10 niveles de prioridad, resultan escasos para sistemas de tiempo real, ya que si varios threads tienen que compartir el mismo nivel de prioridad su comportamiento se vuelve no determinista, cualquier sistema de tiempo real actual dispone de más de 256 niveles.

Otro aspecto importante es la seguridad, tanto CORBA como COM separan el interface de la implementación, lo que proporciona una gran seguridad de tipos. Sin embargo en cuanto a la liberación automática de memoria, que en sistemas abiertos en los que no se tiene un conocimiento completo del entorno del componente, es vital, CORBA simplemente carece de este mecanismo y COM ha anunciado que en una versión futura dará soporte a una recolección automática de basura pero por el momento no se sabe nada más, Java sí dispone de ella.

La sencillez es otro aspecto importante en el aprendizaje y uso de una tecnología, CORBA Y COM no son complicados, pero la integración de componentes en los distintos lenguajes que se usen añade una complejidad adicional importante, Java es un lenguaje complicado pero mientras no nos salgamos de él, la integración de componentes es muy sencilla.

En cuanto a las herramientas de implementación en los distintos estándares, CORBA necesita de compiladores (Direct-To-Som) y adaptadores de objetos, especiales, ya que sus productos no son compatibles a nivel binario. Los productos COM, por otro lado solo funcionan con procesadores Intel pero dadas las características especiales del compilador Direct-To-Com, estas pueden ser adaptadas a otro compilador para una arquitectura distinta de procesador. Java es un lenguaje con una gran portabilidad, sin embargo en cuanto a herramientas para la implementación de componentes es todavía inmaduro; con respecto a los RTOS, hay que indicar que sus estrategias de planificación no están estandarizadas, lo que puede provocar, que implementaciones sobre distintos sistemas, tengan comportamientos distintos.

Hay que indicar asimismo, la gran ventaja que ofrece COM en cuanto a la conservación de los interfaces antiguos, al actualizar los objetos en nuevas versiones sin necesidad de tocarlos de manera que las aplicaciones que los usaban lo pueden seguir haciendo y no es necesaria ninguna modificación, esto también puede ser emulado por CORBA y Java empleando alguna convención

Resumiendo, tanto COM como Java parecen indicados para trabajar en tareas de tiempo real estricto utilizando las APIs específicas de Portos. Si COM se utiliza en los manejadores de dispositivos y Java para el software portable no crítico, ambos pueden verse como complementarios. Para aplicaciones muy exigentes la mejor solución es utilizar exclusivamente Component Pascal.

PORTOS
Portos dispone de un núcleo muy reducido de multitarea expropiativo apto para problemas de tiempo real estricto. El interface de tareas incluye una combinación de las típicas construcciones de monitores y señales como las de Java. Otras herramientas de sincronización como semáforos pueden emularse. Además incluye un algoritmo propio para recolección asíncrona de basura para aplicaciones con restricciones de tiempo real estricto y para sistemas con menos de 1Mbyte de memoria RAM.

El sistema operativo está implementado en el lenguaje Component Pascal. Éste comparte las propiedades de seguridad de Java pero es mucho menor y más simple. Estos mecanismos de seguridad pueden se r deshabilitados de manera que se puedan implementar manejadores de dispositivos. Para los threads (subprocesos o tareas que no son de tiempo real) se puede añadir la planificación de Java basada en prioridades. Los ficheros de clases de Java son convertidos a ficheros de Componenet Pascal antes de ser transferidos a Portos vía comunicación serie (ej. TCP/IP) o grabados en una EPROM. Esto significa que Portos no necesita ninguna máquina virtual ni intérprete de código ni compilador en tiempo de ejecución.

Portos es un sistema operativo Java. La abstracción del planificador de tareas críticas se da en forma de clases Java, por lo tanto cualquier componente Java puede implementar este tipo de tareas usando esta API. Un algoritmo propio de recolección de basura permite que aun estando ejecutándose pueda ser interrumpido por una tarea crítica, de todas maneras éste puede ser desconectado durante las fases de tiempo real.

La configuración mínima de Portos se compone de los módulos PortosKernel, que contiene facilidades de bajo nivel y el manejador del heap incluido el recolector de basura asíncrono, y el módulo PortosTasks (público) que es el interface principal para las aplicaciones de tiempo real. Son suficientes siempre y cuando la aplicación contenga todos los manejadores de dispositivos necesarios.

Opcionalmente, el módulo PortosThreads (público) implementa un planificador por prioridades para threads. Este puede conectarse a PortosTasks y por supuesto puede ser sustituido por otros mecanismos de threads.

CommStreams (módulo público) se utiliza para comunicación, en particular sobre V24 y sobre Ethernet vía TCP/IP y UDP/IP. PPP, FTP y otros servicios de Internet se suministran como opciones.

Estructura global de PORTOS

El módulo público Meta se utiliza para programación.

Tanto Meta como CommStreams son módulos del BlackBox Component Frameworks.

PortosLog (público) es un módulo que se utiliza para expedir comandos remotos en el sistema de desarrollo Denia (se verá posteriormente) que serán ejecutados en Portos.

PortosLoader es necesario para cargar nuevos módulos, en particular los nuevos ficheros de código en tiempo de ejecución desde el nodo remoto (host).

PortosCOM implementa los servicios básicos para objetos COM. Opera como un cargador de DLL tal y como lo hace PortosLoader con los ficheros

PortosJava implementa las clases asociadas a la definición del lenguaje Java.

DEFINITION PortosTasks;
TYPE
(* primitiva de sincronización monitor/señal *)
Synchronizer = POINTER TO EXTENSIBLE RECORD
(* entrada no bloqueante *)
(s: Synchronizer) TryEnter (OUT hecho:BOOLEAN), NEW;
(s: Synchronizer) Enter, NEW; (* bloqueo *)
(s: Synchronizer) Exit, NEW; (* desbloqueo *)
(* despertar una tarea en espera *)
(s: Synchronizer) Notify, NEW;
(* despertar todas las tareas en espera *)
(s: Synchronizer) NotifyAll, NEW;
(* alguna tarea esta esperando notificación *)
(s: Synchronizer) Awaited (): BOOLEAN, NEW;
(* espera de notificación con limite de tiempo *)
(s: Synchronizer) Wait (useg: INTEGER): NEW
END;

(* proceso cliente controlado por una tarea *)
Handler = POINTER TO ABSTRACT RECORD
(* este procedimiento implementa el comportamiento de la tarea *)
(h: Handler) Run-, NEW, ABSTRACT;
(* manejador opcional de excepciones *)
(h: Handler) HandleException-, NEW, EMPTY
END;

(* control de la ejecución concurrente de manejadores *)
Task = POINTER TO LIMITED RECORD
(t: Task) Start, NEW; (* tarea preparada para planificación *)
(t: Task) Stop, NEW; (* tarea inactiva *)
(t: Task) Suspend, NEW; (* espera a una reanudación *)
(t: Task) Resume, NEW (* reanudación tras una suspensión *)
END;

VAR current-: Task; (* tarea ejecutándose actualmente *)
(* funciones para crear tareas normales, periódicas y esporádicas (interrupciones) *)
PROCEDURE NewTask (handler: Handler; duracion, plazo: INTEGER) Task;

PROCEDURE NewPeriodicTask (handler: Handler; duracion, plazo: INTEGER; periodo: INTEGER): Task;

PROCEDURE NewSynchedTask (handler: Handler; duracion, plazo: INTEGER; factor: INTEGER; tareaPeriodica: Task): Task;

PROCEDURE NewSporadicTask (handler: Handler; duracion, plazo: INTEGER; minPeriodo: INTEGER; tipoEvento: INTEGER): Task;

PROCEDURE Time (): INTEGER;

PROCEDURE Sleep (useg: INTEGER);

END PortosTasks.

CODIGO: El interface de Portos simplificado

Al crearse una tarea deben especificarse la duración de la tarea y un plazo. La duración especifica el máximo tiempo de CPU que la tarea puede consumir hasta terminar. Se utiliza para determinar su admisión al sistema o cuándo es insuficiente el tiempo asignado de CPU.

El manejador de tareas PortosTasks.Handler se compromete a usar un tiempo máximo de CPU. Si el manejador consume demasiado tiempo de computación, entonces la tarea se aborta y se eleva una excepción. Por su parte el planificador garantiza a la tarea admitida que tiene suficiente tiempo para completarse antes de que se cumpla el plazo especificado.

El planificador trabaja a intervalos de tiempo de unos 100 microsegundos, al final de cada intervalo se planifican las tareas y se revisan las posibles violaciones de restricciones de tiempo.

DENIA
Denia es un entorno de desarrollo cruzado para crear aplicaciones Portos. Es una extensión del BlackBox Component Builder, que es una herramienta RAD optimizada para el desarrollo de aplicaciones orientadas al componente. Permite transferir ficheros de código y datos a y desde un sistema empotrado en el que se ejecuta Portos. Su compilador cruzado Component Pascal produce código máquina para PowerPC, depuración simbólica cruzada, intérprete para comandos remotos y controles remotos (visuales). Denia junto con BlackBox está disponible para Windows NT y Windows 95.

Las conexiones pueden abarcar desde líneas serie V24 para sistemas simples hasta conexiones TCP/IP por procesador para sistemas multiprocesadores. En este sentido lo normal es trabajar con una Intranet corporativa, pero es posible también utilizar Internet.

Sistema completo

CONCLUSIONES
En este artículo se ha dado una visión general de los aspectos que se han tenido en cuenta en el diseño de Portos y Denia como es su planificador de control de plazos que rompe con los sistemas de planificación habituales por su sencillez en el manejo del tiempo al emplearlo de una forma más intuitiva para los ingenieros.

En esta misma línea su software de alto nivel Denia permite manejar unidades corrientes para magnitudes como Newtons para fuerzas y radianes para ángulos, lo que facilita el desarrollo de aplicaciones de tiempo real.

Las propiedades de seguridad del sistema operativo y de los lenguajes de programación Component Pascal y Java dan un alto nivel de robustez.

El soporte COM resuelve el problema de la construcción de manejadores de dispositivos y Java permite la portabilidad de componentes no críticos.

BIBLIOGRAFÍA

AUTORES
Henrique Hernández y Tomás Cortés