Sistemas Operativos de Tiempo Real Sistemas embebidos para tiempo real Índice • • • • Introducción Tareas y el planificador (scheduler) Tareas y datos Semáforos y datos compartidos Introduccion a los RTOS Sistemas embebidos de tiempo real 2 Introducción • RTOS es muy diferente a un OS convencional – La aplicación y el RTOS se enlazan juntos. – Los RTOS más básicos no se protegen. – Se pueden eliminar servicios no usados para ahorrar memoria. • Existe una amplia oferta – FreeRTOS, µC/OS, eCos, QNX, Nucleus, VxWorks, LynxOS, etc. – WSN/IoT: TinyOS, ContikiOS – Algunos conformes al estándar POSIX (IEEE 1003.4) Introduccion a los RTOS Sistemas embebidos de tiempo real 3 RTOS vs. Kernel (RTK) • Para algunos: – RTOS = kernel = real-time kernel (RTK) • Para otros: – RTOS > kernel – kernel: incluye sólo los servicios más básicos – RTOS: incluye soporte de red, herramientas de depurado, gestión de memoria, etc. • Para el texto y para nosotros: – RTOS y Kernel son sinónimos Introduccion a los RTOS Sistemas embebidos de tiempo real 4 Tareas • Tarea: – bloque básico de un sist. basado en un RTOS – una función (o varias) en C, no retorna nunca (bucle infinito). – número de tareas acotado sólo por memoria. • Inicialización: – cada tarea se inicializa (mediante una llamada a una función del RTOS) especificando: • su punto de entrada (función), su prioridad, la memoria que necesita, etc. Introduccion a los RTOS Sistemas embebidos de tiempo real 5 Ejemplo: Uso de un RTOS void main(void) { /* Initialize (but don’t start) the RTOS */ InitRTOS(); /* Tell the RTOS about our tasks */ StartTask(RespondToButton, HIGH_PRIORITY); StartTask(CalculateTankLevels, LOW_PRIORITY); /* Actually start the RTOS.(This function never returns.) */ StartRTOS(); } Introduccion a los RTOS Sistemas embebidos de tiempo real 6 Tareas: estados • Running tarea de mayor prioridad lista Running – se está ejecutando – una sola tarea en este estado Ready • Blocked – nada que hacer, esperando algún evento externo es la tarea de mayor prioridad • Ready – trabajo que hacer y esperando necesita evento externo Blocked Introduccion a los RTOS ocurre el evento externo Nota: Otros estados: suspended, pended waiting, dormant. Sistemas embebidos de tiempo real 7 Planificador (scheduler) • Planificador: – es la función del kernel que decide que se ejecutará • Cada tarea tiene: – prioridad definida y estado (running, ready, blocked) • Planificador selecciona – tarea con la mayor prioridad que está lista para ejecutar. • Transiciones: – tarea se bloquea sola cuando no tiene que hacer – tarea bloqueada pasa a lista, si otra la despierta – conmutación entre Ready y Running: planificador Introduccion a los RTOS Sistemas embebidos de tiempo real 8 Planificador: implementación • Schedulers en RTOS – sencillos – no trata de ser “justo”, a diferencia de Windows/Linux/Unix, – tareas de baja prioridad pueden “morirse de hambre” – responsabilidad del diseñador (no del RTOS!) asegurarse que todas las tareas cumplen con sus requerimientos Introduccion a los RTOS Sistemas embebidos de tiempo real 9 Planificador: FAQ • ¿Cómo sabe el planificador que una tarea se ha bloqueado o desbloqueado? • ¿Qué pasa si todas las tareas están bloqueadas? • ¿Qué pasa si dos tareas con la misma prioridad están ready? • Si mientras una tarea está ejecutándose, otra de mayor prioridad se desbloquea, ¿qué pasa? Introduccion a los RTOS Sistemas embebidos de tiempo real 10 Expropiación (Preemption) • RTOS expropiativo (preemptive RTOS) – detendrá la ejecución de una tarea tan pronto como una tarea de mayor prioridad pasa a ready. – Ejemplo: una tarea se desbloquea cuando una ISR le envía un mensaje o libera un semáforo. • RTOS no-expropiativo (non-preemptive RTOS) – detendrá la ejecución de una tarea de baja prioridad solamente si esa tarea se bloquea (e.g., después de un pend or delay) o cede el control (yield) Introduccion a los RTOS Sistemas embebidos de tiempo real 11 Ejemplo de aplicación struct { } /* “Levels Task” */ long lTankLevel; void vCalculateTankLevels(void) long lTimeUpdated; { tankdata[MAX_TANKS]; /* low priority task */ int i = 0; while (TRUE) { /* “Button Task” */ !! read float levels in task i void vRespondToButton(void) !! do bunches of calculations { tankdata[i].lTimeUpdated = /* high priority task */ !! current time int i; tankdata[i].lTankLevel = while (TRUE) { !! result of long calculation !! Block until button pressed !! pick next tank to handle, etc. i = !! ID of button pressed i = !! next tank !! output ITankLevel } !! output ITimeUpdated } } } Introduccion a los RTOS Sistemas embebidos de tiempo real 12 Ejemplo Running Presionan un botón: RTOS le pasa el procesador a vButtonTask en cuanto vLevelTask queda ready. Prioridad creciente vLevelTask ocupada haciendo calculos mientras vButtonTask espera presionen un botón Ready Blocked vButtonTask termina y se bloquea de nuevo RTOS le devuelve el procesador a vLevelTask vButtonTask vLevelTask tiempo Introduccion a los RTOS Sistemas embebidos de tiempo real 13 Tareas y datos • Cada tarea tiene su contexto (privado) – Registros – Contador de programa (PC) – Pila (Stack): variables locales • Conservación del contexto – una tarea no sabe cuando dejara y volverá a ejecutarse – el contexto debe guardarse y restaurarse • El resto de los datos -variables globales, estáticaspueden ser compartidos entre tareas, entonces... Introduccion a los RTOS Sistemas embebidos de tiempo real 14 Tareas y datos: datos compartidos • Si varias tareas comparten datos, hay que tomar las mismas precauciones que cuando comparten datos rutinas de primer y segundo plano: – Deshabilitar las interrupciones – Impedir la conmutación de tareas. • Hay que ser cuidadoso, pues a veces los datos compartidos no están a la vista... Introduccion a los RTOS Sistemas embebidos de tiempo real 15 static int cErrors; void Task1(void){ ... vCountErrors (1); ... } void Task2(void) { ... vCountErrors (2); ... } LDI R16, 0x01 RCALL vCountErrors ... void vCountErrors(int cNewErrors){ cErrors += cNewErrors; } Introduccion a los RTOS vCountErrors: LDI R30,(cErrors) LDI R31,((cErrors+1) LD R17, Z ADD R16, R17 ST Z, R17 RET Sistemas embebidos de tiempo real 16 Task1: Runing void Task1(void) ... vCountErrors ... } void Task2(void) ... vCountErrors ... } LDI R16, 0x01 RCALL vCountErrors { (1); Conmuta Task1 a Task2 { ST RET (2); LDI R16, 0x02 RCALL vCountErrors void vCountErrors(int cNewErrors) { cErrors += cNewErrors; } Conmuta Task2 a Task1 (restaura contexto: R17) • Resultado final Z, R17 no se guarda cErrors = 1 R17 = 1 vCountErrors: LDI R30,(cErrors) LDI R31,((cErrors+1) LD R17, Z ADD R16, R17 ST Z, R17 RET ST Z, R17 RET – Debería ser: cErrors – Sin embargo da: cErrors Introduccion a los RTOS vCountErrors: LDI R30,(cErrors) LDI R31,((cErrors+1) LD R17, Z ADD R16, R17 cErrors = 0 cErrors = 0 R17 = 2 cErrors = 2 R17 = 1 cErrors = 1 = 3 = 1 Sistemas embebidos de tiempo real 17 Funciones reentrantes • Pueden ser llamadas por más de una tarea y siempre funcionarán correctamente – • aunque ocurra: conmutación de tareas o interrupciones Una función es reentrante si: 1) Usa variables globales -compartidas- atómicam (variables automáticas OK) 2) Llama solamente a funciones reentrantes. 3) Usa el hardware de forma atómica. Introduccion a los RTOS Sistemas embebidos de tiempo real 18 Funciones reentrantes int public_int; int initialized = 4; char *string = “Where does this string go?”; void *vPointer; void function (int parm, int *parm_ptr) { static int static_local; int local; ... } Suponer que desde ésta función se acceden a todas las variables listadas: ¿Es la función reentrante? • Recordar: donde son almacenadas las variables Introduccion a los RTOS Sistemas embebidos de tiempo real 19 Funciones reentrantes static int static_int; int public_int; int initialized = 4; char *string = “Where does this string go?”; void *vPointer; Problema: variables globales void function (int parm, int *parm_ptr) { static int static_local; int local; ... } Introduccion a los RTOS Sistemas embebidos de tiempo real 20 Funciones reentrantes static int static_int; int public_int; int initialized = 4; char *string = “Where does this string go?”; void *vPointer; void function (int parm, int *parm_ptr) { static int static_local; int local; ... } Introduccion a los RTOS Sistemas embebidos de tiempo real Problema: variables globales Sin Problema: variables locales 21 Funciones reentrantes static int static_int; int public_int; int initialized = 4; char *string = “Where does this string go?”; void *vPointer; void function (int parm, int *parm_ptr) { static int static_local; int local; ... } Introduccion a los RTOS Sistemas embebidos de tiempo real Problema: variables globales Posible Problema: copia local puntero Sin Problema: variables locales 22 Funciones reentrantes static int num_errores = 0; ¿Es ésta función reentrante? void ImprimeErrores() { if(num_errores > 10){ num_errores -= 10; printf("Se han producido otros 10 errores más\n"); } } • Motivos... Introduccion a los RTOS Sistemas embebidos de tiempo real 23 Hardware compartido • Problemas por código no entrante: – Impresión mezclada entre tareas... (Impresora) – Salida enmarañada en pantalla... (Monitor) – Paquetes mezclados en un enlace inalámbrico. • Requerimiento para código reentrante: – Una vez que una tarea comienza una “transacción” de hardware debe completarla antes de liberar el hardware. Introduccion a los RTOS Sistemas embebidos de tiempo real 24 Datos compartidos • Entonces, ¿no se pueden compartir datos? – No. Si se puede si se acceden de forma atómica. • Atomicidad no ocurre “sola” – En algún microcontrolador tal vez... • Lenguaje C: • MSP430: • ATmega: cErrors++; inc b, &cErrors LDI ... (múltiples instrucciones) – Primero identificar secciones críticas y luego... – Hacerla atómica deshabilitando/habilitando interrupciones (u otros métodos).... Introduccion a los RTOS Sistemas embebidos de tiempo real 25 Bibliografía • “An Embedded Software Primer”, David E. Simon – Chapter 6: Introduction to Real-Time Operating Systems Introduccion a los RTOS Sistemas embebidos de tiempo real 26 Sistemas Operativos de Tiempo Real (2) Sistemas embebidos para tiempo real Índice • Introducción • Tareas y el planificador (scheduler) • Tareas y datos Semáforos y datos compartidos Introduccion a los RTOS Sistemas embebidos de tiempo real 28 Datos compartidos • Comunicación entre tareas: – enfoque más sencillo: estructura/variable compartida • Exclusión mutua – asegurar acceso exclusivo para evitar datos corruptos • Métodos: – Deshabilitar interrupciones – Operación Test&Set atómica (eg. 68000) – Deshabilitar scheduling – Semáforos... Introduccion a los RTOS Sistemas embebidos de tiempo real 29 Semáforos y recursos compartidos Recurso: tramo de vía Introduccion a los RTOS Sistemas embebidos de tiempo real 30 Semáforos en RTOS • Nomenclatura: – – – – Take–Release Raise–Lower Wait–Signal Pend–Post (posta, llave) (semáforo ferroviario) (esperar-avisar) • Semáforos para exclusión mutua (MutEx) – proteger recursos compartidos: datos compartidos • Semáforos para comunicación entre tareas. Introduccion a los RTOS Sistemas embebidos de tiempo real 32 Semáforos: protección de datos /* “Levels Task” */ struct { void vCalculateTankLevels(void) long lTankLevel; { long lTimeUpdated; /* low priority task */ int i = 0; } tankdata[MAX_TANKS]; while (TRUE) { !! read float levels in task i /* “Button Task” */ !! do bunches of calculations void vRespondToButton(void) TakeSemaphore( ); { /* high priority task */ int i; tankdata[i].lTimeUpdated = while (TRUE) { !! current time !! Block until button pressed tankdata[i].lTankLevel = !! result of long calculation ReleaseSemaphore( ); i = !! ID of button pressed !! pick next tank to handle, etc. !! output ITankLevel TakeSemaphore( ); !! output ITimeUpdated ReleaseSemaphore( ); i = !! next tank } } } } Introduccion a los RTOS Sistemas embebidos de tiempo real 33 Flujo de ejecución con semáforos vCalculateTankLevel vRespondToButton TakeSemaphore( ); tankdata[i].lTimeUpdated usuario presiona un botón se desbloquea tarea botón !! Block until button pressed i = !! ID of button pressed tankdata[i].lTankLevel ReleaseSemaphore( ); semáforo no disponible se bloquea tarea botón liberando el semáforo se desbloquea la tarea botón tarea botón se bloquea continua con tarea niveles Introduccion a los RTOS Sistemas embebidos de tiempo real TakeSemaphore( ); !! output tank level, timestamp ReleaseSemaphore( ); 34 Ejemplo de semáforos: µC/OS • Notación – el prefijo OS indica funciones del kernel – Creación/inicialización: OSSemCreate() – Tomar y liberar un semáforo: OSSemPend(),OSSemPost() – Estructura OS_EVENT representa el semáforo • Parámetros: – OS_EVENT *p_semTemp; – p_semTemp = OSSemCreate(1); – OSSemPend(p_semTemp,WAIT_FOREVER); • Otro servicio del RTOS – Retardo: OSTimeDly() Introduccion a los RTOS Sistemas embebidos de tiempo real 35 #define PRIORITY_READ 11 #define PRIORITY_CONTROL 12 #define STK_SIZE 1024 static unsigned ReadStk[STK_SIZE]; static unsigned CtrlStk[STK_SIZE]; static int iTemperatures[2]; OS_EVENT *p_semTemp; void main (void) { OSInit( ); OSTaskCreate (vReadTmpTsk, NULLP, (void *) &ReadStk[STK_SIZE], PRIORITY_READ); OSTaskCreate (vCtrlTask, NULLP, (void *) &CtrlStk[STK_SIZE], PRIORITY_CONTROL); p_semTemp = OSSemCreate(1); OSStart ( ); } void vRdTmpTsk (void) { while (TRUE) { OSTimeDly(5); OSSemPend(p_semTemp,WAIT_FOREVER); !! read in iTemperatures[0]; !! read in iTemperatures[1]; OSSemPost (p_semTemp); } } void vCtrlTsk(void) { while (TRUE) { OSSemPend (p_semTemp, WAIT_FOREVER); if(iTemperatures[0] != iTemperatures[1]) !! set off howling alarm; OSSemPost (p_semTemp); !! do other useful work } } Semáforos y funciones reentrantes void Task1(void) { vCountErrors (1); } void Task2(void) { vCountErrors (2); } Introduccion a los RTOS static int cErrors; void vCountErrors(int cNewErrors) { cErrors += cNewErrors; } Sistemas embebidos de tiempo real 37 Semáforos y funciones reentrantes void Task1(void) { vCountErrors (1); } void Task2(void) { vCountErrors (2); } static int cErrors; static NU_SEMAPHORE semErrors; void vCountErrors(int cNewErrors) { NU_Obtain_Semaphore(&semError,NU_SUSPEND); cErrors += cNewErrors; NU_Release_Semaphore(&semError); } • Terminología: – Se ha "protegido” cErrors con semáforos • Notación: – En este caso RTOS: Nucleus (prefijo NU) Introduccion a los RTOS Sistemas embebidos de tiempo real 38 Múltiples semáforos • En un sistema pueden coexistir varios semáforos: – Cada semáforo protege un sólo recurso compartido. – Cada tarea sólo tiene que esperar si el recurso que tiene que utilizar está bloqueado. – El RTOS no sabe qué recursos están protegidos por qué semáforos. Eso es tarea del programador. • Counting semaforos – Control sobre un conjunto de N recursos. Introduccion a los RTOS Sistemas embebidos de tiempo real 39 Semáforos para señalización • Semáforo como método de comunic. entre tareas. • Ejemplo impresión de reportes: – Datos: • Buffer de donde se arma el reporte, números líneas totales e impresas. – Tareas: • PrinterTask: espera por el reporte y luego envía línea a línea desde el buffer a la impresora. – ISR: • La impresora interrumpe al final de cada línea y carga la siguiente línea a imprimir. Introduccion a los RTOS Sistemas embebidos de tiempo real 40 Semáforos para señalización static static static static char a_chPrint[10][21]; /*outp buf */ int iLinesTotal; int iLinesPrinted; OS_EVENT *semPrinter; void vPrinterTask(void) { BYTE byError; int wMsg; while (TRUE) { /* wait for a job to print */ wMsg = (int) OSQPend (QPrinterTask, WAIT_FOREVER, &byError); !! Format the report into a_chPrint iLinesTotal = !! count of lines in reprt /* print first line of report */ iLinesPrinted = 0; vHardwarePrinterOutputLine( a_chPrint[iLinesPrinted++]); OSSemPend(semPrinter, WAIT_FOREVER, &byError); } void vPrinterInterrupt (void) { if (iLinesPrinted == iLinesTotal) /* report done: release semaphore */ OSSemPost(semPrinter); else /* report not done: print next line */ vHardwarePrinterOutputLine( a_chPrint[iLinesPrinted++]); } } Introduccion a los RTOS Sistemas embebidos de tiempo real 41 Discusión • Semáforo usado como señal: – Tarea que envía: hace un post. – Tarea que recibe: hace un pend. – Comparación con exclusión mutua: • la misma tarea llama a pend, y luego post. • Especial cuidado con: – Valor inicial del semáforo: debe ser elegido bien. • En el ejemplo el semáforo fue inicializado como no disponible. • Depende de la aplicación. – Orden cuando existen múltiples pends. • En el ejemplo, la tarea espera por una cola y el semáforo Introduccion a los RTOS Sistemas embebidos de tiempo real 42 Problemas • Baśicos – Olvidar de tomar (pend) el semáforo. – Olvidar de liberar (post) el semáforo. – Tomar o liberar el semáforo equivocado. – Ocupar el semáforo por demasiado tiempo. • Inversión de prioridad • Deadlock, o abrazo mortal Introduccion a los RTOS Sistemas embebidos de tiempo real 43 Inversión de prioridad • Ejemplo: Prioridad creciente – Tareas C, B y A de prioridad creciente – Tareas C y A comparten un recurso Tarea A Tarea B Tarea C Introduccion a los RTOS Sistemas embebidos de tiempo real 44 Inversión de prioridad Tarea A se desbloquea. RTOS conmuta a A. Tarea A trata de tomar Tarea B se desbloquea. el semaforo que tiene C RTOS conmuta a B. y se bloquea. Prioridad creciente Tarea C toma el semaforo que comparte con A Tarea A Tarea B se ejecuta por mucho tiempo Tarea C no puede ejecutar para liberar el semaforo. Task A se pierde un deadline. Tarea B Tarea C tiempo Introduccion a los RTOS Sistemas embebidos de tiempo real 45 Abrazo mortal (bloqueo mutuo) OS_EVENT *p_sem_A, *p_sem_B; int a, b; /* Variables compartidas */ void Tarea1(void) { OSSemPend(p_sem_A, WAIT_FOREVER); OSSemPend(p_sem_B, WAIT_FOREVER); a = b; OSSemPost(p_sem_B); OSSemPost(p_sem_A); } void Tarea2(void) { OSSemPend(p_sem_B, WAIT_FOREVER); OSSemPend(p_sem_A, WAIT_FOREVER); b = a; OSSemPost(p_sem_A); OSSemPost(p_sem_B); } Introduccion a los RTOS Sistemas embebidos de tiempo real 46 Opciones para datos compartidos • Deshabilitar interrupciones – manera más drástica – afecta tiempo de respuestas de todas las tareas y ISR – único método para compartir datos con ISR • Semáforos – afecta aquellas que esperan el mismo semáforo, sin impacto en ISR – aumenta probabilidad de errores de programación • Deshabilitar conmutación de tareas (deshab. planificador) – – – – planificador (scheduler) no conmuta tareas funcionalidad presente en algunos RTOS Overhead para habilitar y deshabilitar es pequeño. Tiempo de respuesta: afecta todas las tareas pero no ISR Introduccion a los RTOS Sistemas embebidos de tiempo real 47 Resumen • RTOS – Características, diferencias con OS convencional • Tareas – Bloque fundamental, estados, contexto, scheduler... • Funciones reeentrantes • Recursos compartidos: – Datos, hardware. • Semáforos – Mutex o comunicación entre tareas, problemas • Opciones para resolver bug de datos compartidos. Introduccion a los RTOS Sistemas embebidos de tiempo real 48 Bibliografía • “An Embedded Software Primer”, David E. Simon – Chapter 6: Introduction to Real-Time Operating Systems • “MicroC OS II: The Real Time Kernel” Introduccion a los RTOS Sistemas embebidos de tiempo real 49