Wind River Vxworks QNX

Anuncio
Wind River – Vxworks
QNX
Sistemas Operativos
En Tiempo Real
Elección de un sistema operativo
Requerimientos de una aplicación en tiempo real :
•
•
•
•
•
Acceder a dispositivos de E/S a bajo nivel
Trabajar con interrupciones
Medir y manipular el tiempo
Organitzar la aplicación en tareas de ejecución concurrente.
Permitir elegir y parametrizar el algoritmo de planificación,
preferentemente basado en prioridades.
• Disponer con eficientes mecanismos de comunicación y sincronismo.
• Los parámetros temporales del entorno de ejecución son pequeños y
conocidos ( cambios de contexto e interrupciones)..
– Ejemplos de SOTR pur0s:
QNX, VxWorks, LynxOS, RTEMS
– Exemplos de extensiones de
tiempo real::
Windows CE, RTX-Win NT,
RTLinux
Programación de periféricos
• Periférico
– Disposito que permite a un sistema basado en microprocessador
realitzar una serie de acciones no consideradas de cálculo o de
transferencia con memoria.
– Ejemplos:
•
•
•
•
•
Interfícies digitales de entrada y salida
Interfícies analógicas de entrada y salida
Interfícies de comunicaciones
Computadores/temporitzadores
Gestores de interrupciones
Organización interna: registros de
programación
Accions básicas con periféricos
• Configuración :
Ejemplos: velocitat de transmissió (RS-232),
número de canal (CAD), iniciar conversió (CAD)
• Estado
Ejemplos: fin de conversión (CAD), error en la
recepción(RS-232)
• Transferencia de datos
Ejemplos: datos adquiridos (CAD), mensaje
recepción (RS-232)
Interrupciones en QNX: ejemplo PCL
PCL-812PG
Lectura AD por interrupción:
Variables compartidas:
volatile unsigned char lowByte,
highByte;
unsigned int adrBase = 0x220;
Rutina de servicio a la interrupción:
const struct sigevent * isrPCL(void
* area, int id)
{
highByte = in8(adrBase+5);
lowByte = in8(adrBase+4);
out8(adrBase+8,0);
return NULL;
}
int main(void)
{
int id;
unsigned char canal = 0, mode = 0x06;
unsigned int dadaBin = 0;
ThreadCtl(_NTO_TCTL_IO, 0);
id = InterruptAttach(IRQ5,isrPCL,NULL,0,0);
/* ...manca configurar el temporitzador... */
out8(adrBase+10,canal);
out8(adrBase+11,mode);
/* ...un cop rebuda la interrupció... */
InterruptLock();
dadaBin = highByte;
dadaBin = ((dadaBin << 8) & 0x0F00) + lowByte;
InterruptUnlock();
/* ...per finalitzar... */
out8(adrBase+11,0);
InterruptDetach(id);
}
Tiempo
La aplicación de control necesita coordinar la ejecución en el tiempo
Necesidades:
• Acceso a un reloj.
• Medir el tiempo en intervalos.
• Expresar retardos.
• Programar accions periòdiques o aperiódicas.
• Exemple amb retard relatiu en QNX:
do
#include <time.h>
#include "sitr.h"
#define PERIODE 0.01
#define DURADA 4.0
{
codigo periodico
/*************************************
CODI
int main(void) {
struct timespec t0, t1, retardRelatiu;
double tf;
clock_gettime(CLOCK_REALTIME, &t0);
tf = timespec2double(t0)+DURADA;
retardRelatiu =
double2timespec(PERIODE);
**************************************
/
clock_gettime(CLOCK_REALTIME,
&t1);
if (tf < timespec2double(t1))
break;
conversión de timespec a
double
conversión de double a
timespec
clock_nanosleep(CLOCK_REALTIME, 0,
&retardRelatiu, NULL);
retardo
} while (1);
}
Sistemas multitarea
• Una tarea es un conjunto de instrucciones que se ejecutan secuencialmente.
Normalmente son bucles infinitos
• Las tareas son concurrentes entre ellas
• En sistemes monoprocesador, el gestor se encarrega de la ejecución virtualmente
paralela de las tareas. A nivel de instrucción máquina la ejecución es secuencial
(monoprocesador)
• En sistemas multiprocesadores o distribuidos la ejecución es realmente en paralelo, a
nivel instrucción máquina. (comunicación, sincronización, protección de recursos
mediante acceso exclusivo)
•El SOTR proporciona el código que ejecutará concurrentemente estas tareas y las
tareas del sistema. (gestor)
– El gestor decide qué tarea se llevará a cabo.
– El gestor va alternando en el CPU la ejecución de
tareas. ( cambio de contexto).
– Contexto: registros internos CPU + programa +
información relevante a la tarea.
asignación
de CPU
tarea A
tarea B
Cronograma
tempo
cambio de contexto:
• guardar registros
antes de desalojar la
tarea B
• restaurar registros
cuando la tarea A va
ser desalojada
Planificación de tareas
• Los algoritmos de planificación determinan la forma de repartir a lo
largo del tiempo los CPU’s entre todas las tareas que forman una
aplicación.
Programación de una aplicación de tempo real
• Acceder a dispositivos de E/S a bajo nivel
• Trabajar con interrupciones
• Medir y manipular el tiempo
• Organizar la aplicación en tareas de ejecución concurrente.
• Permitir elegir y parematrizar el algoritmo de planificación,
preferentemente basado en prioridades.
• Disponer de mecanismos de sincronización y comunicación.
• Garantizar que los parámetros temporales del entorno de ejecución
(e.j. cambios de contexto y servicio de interrupciones) son pequeños y
conocidos.
Requerimientos temporales
• Los requerimientos temporales de STR se especifican normalmente
en base a los seguientes parámetros:
• el período, T
• el termino, D
• el tiempo de cómputo, C
• el tiempo de respuesta, R
tarea
R
C
D
A
T
tiempo
(x 5 ms)
• Tareas esporádicas (aperiódicas), T representa el tiempo mínimo entre
dos activacions consecutivas
• Se debe conseguir que todas las tareas se ejecuten dentro del término
previsto (R ≤ D per todas las tareas)
•
Mecanismo de invocación:
– Cireterio asignación CPU
– Gestor cooperativo (cooperative scheduling): mientras la
CPU está en posesión de una tarea, el gestor no puede
intervenir hasta que la tareaa invoque explícitamente a
través de la API (e.j., retardo), o bien acabe su ejecución.
– Gestor apropiativo (preemptive scheduling): como el
gestor cooperativo, frente a un acontecimiento, el gestor
toma el control de la CPU, interrumpiendo la tarea en
curso.
g. aprop.
g. coop.
tasca A
tasca A
tasca B
tasca B
temps
temps
•
•
•
El gestor apropiativo es más adecuado que el
cooperativo per a un sistema de tempo real (STR) ya
que el gestor puede controlar de manera
centralitzada la respuesta las tareas.
El gestor apropiativo round-robin es adecuado para
sistemas multiusuario, se debe repartir de forma
equitativa el CPU.
El gestor apropiativo basado en prioridades es
adecuado para un STR ya que es posible garantizar de
forma determinista si los términos de respuesta van a
cumplirse o no.
Tareas en QNX. Ejemplo de multitarea
• QNX permite organizar las tareas de forma concurrente. El gestor está
implementado de forma transparente al usuario. La gestión es apropiativa
basada en prioridades.
• Toda aplicación (proceso) tiene como mínimo una tarea, que
corresponde con el código de la función main().
• Una tasca puede crear otras tareas mediante la función
pthread_create(). Por defecto, las nuevas tareas son creades con la misma
prioridad.
•Las tareas de igual prioridad se pueden gestionar de varias maneras, (por
defecto round-robin).
• Si una tarea crea otras tareas, antes de acabar, deberá esperar la
finalitzación de las tareas creadas, mediante la función pthread_join().
Estados de las tareas en QNX
–
19 estados de suspensión
o bloqueo
pthread_join()
MsgSend()
preparada
execució
clock_nanosleep()
• Ejemplo:
#include <pthread.h>
void * controlador(void * c) {
…
clock_nanosleep(CLOCK_REALTIME, 0,
&retardRelatiu, NULL);
…
}
void * supervisor(void * s) {…}
int main() {
pthread_t tidS, tidC;
…
pthread_create(&tidS, NULL, supervisor,
NULL);
pthread_create(&tidC, NULL, controlador,
NULL);
…
pthread_join(tidS, NULL);
pthread_join(tidC, NULL);
}
g. rr--r
nanoslee
p
controlador
supervisor
TS
main
join
join
temps
Comunicación: mensajes
• Introducció:
– La interacción se realitza mediante las instrucciones envío
(send()) y la recepción (receive())
– En sistemas con memoria compartida es un mecanismo
alternativo de interacción, mientras que en sistemas
distribuidos el paso de mensajes es la única alternativa.
– Hay sincronización y en el proceso de comunicación hay como
mínimo un emisor y un receptor.
Ejemplo de envío de mensajes
mensajes::
#include <stdio.h>
typedef struct {
double dada;
} misDades;
typedef struct {
enum {OK, NOK} confirm;
} misACK;
int main(void)
{
int coid;
int nd, pid, chid;
FILE * fp;
misDades mdad;
misACK mack;
fp=fopen("/net/odysseus/home/alumne/dat.cfg",“r");
fscanf(fp,"%d %d",&pid,&chid);
fclose(fp);
nd=netmgr_strtond("/net/odysseus",NULL);
coid=ConnectAttach(nd,pid,chid,0,0);
mdad.dada=123.456;
MsgSend(coid,&mdad,sizeof(misDades),&mack,sizeof(mis
ACK));
if (mack.confirm==NOK) printf("C: error de
recepcio!!\n");
}
Ejemplo de recepción de mensakes
#include <stdio.h>
typedef struct {
double dada;
} misDades;
typedef struct {
enum {OK, NOK} confirm;
} misACK;
int main(void)
{
int chidS;
int rcvid;
FILE * fp;
misDades mdad;
misACK mack;
chidS=ChannelCreate(0);
fp=fopen("/net/odysseus/home/alumne/dat.cfg",“w"
);
fprintf(fp,"%d %d",getpid(),chidS);
fclose(fp);
rcvid=MsgReceive(chidS,&mdad,sizeof(misDades),NU
LL);
printf("S: %lf\n",mdad.dada);
mack.confirm=NOK;
MsgReply(rcvid,0,&mack,sizeof(misACK));
}
Colas:
• La comunicación és del tipus envío asíncrono.
• Se debe activar el proceso de gestión de
dolas. (mqueue)
• La cola se crea con la funció mq_open(), y
sus características.
mq_send()
mq_receive()
Ejemplo de utilización de colas
colas::envío
#include <stdio.h>
#include <mqueue.h>
#define CAPACITAT_CUA 5
typedef struct {
double dada;
} misDades;
int main(void)
{
mqd_t bustia;
struct mq_attr qattr;
misDades mdad;
qattr.mq_maxmsg=CAPACITAT_CUA;
qattr.mq_msgsize=sizeof(misDades);
bustia=mq_open("/bustia", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR,
&qattr);
mdad.dada=123.456;
mq_send( bustia, (char *)&mdad, sizeof(misDades), 0);
printf(“Ll: %lf\n",mdad.dada);
mq_close(bustia);
}
Ejemplo de colas
colas:: Recepción
#include <stdio.h>
#include <mqueue.h>
#define CAPACITAT_CUA 5
typedef struct {
double dada;
} misDades;
int main(void)
{
mqd_t bustia;
struct mq_attr qattr;
misDades mdad;
qattr.mq_maxmsg=CAPACITAT_CUA;
qattr.mq_msgsize=sizeof(misDades);
bustia=mq_open("/bustia", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR,
&qattr);
mq_receive( bustia, (char *)&mdad, sizeof(misDades), NULL);
printf("R: %lf\n",mdad.dada);
mq_close(bustia);
mq_unlink("/bustia");
}
Ejemplo, el seguente codigo crea una tarea controlador con prioridad 15 y mecanismo
de planificación FIFO, cambia a round robin y prioridad 21:
pthread_t tid;
pthread_attr_t attr;
struct sched_param newparam;
pthread_attr_init(&attr);
pthread_attr_setinheritsched(&attr,PTHREAD_EXPLICIT_SCHED);
pthread_attr_setschedpolicy(&attr,SCHED_FIFO);
attr.param.sched_priority = 15;
pthread_create(&tid, &attr, controlador, NULL);
...
newparam.sched_priority = 21;
pthread_setschedparam(tid,SCHED_RR,&newparam);
•Mecanismo Mutex:
pthread_mutex_t mutex;
pthread_mutexattr_t mutexattr;
pthread_mutexattr_init(&mutexattr);
pthread_mutexattr_setprotocol(&mutexattr,PTHREAD_PRIO_INHERI
T);
pthread_mutex_init(&mutex, &mutexattr);
...
Descargar