Toda la verdad sobre RTOS. Artículo # 14. Secciones de memoria: introducción y servicios básicos.



Las secciones de memoria se mencionaron anteriormente en uno de los artículos anteriores (# 6), donde se realizó una comparación con la función estándar del lenguaje C malloc () . Una partición es una región de memoria obtenida de un grupo de particiones (grupo de memoria). Compartir memoria proporciona una forma flexible de asignar y liberar memoria de manera confiable y determinista.

Artículos anteriores de la serie:
Artículo 13. Estructuras de datos de tareas y llamadas de API no compatibles
Artículo # 12. Servicios para trabajar con tareas.
Artículo # 11. Tareas: configuración e introducción a la API
Artículo # 10. Programador: funciones avanzadas y preservación del contexto
Artículo # 9. Programador: implementación
Artículo # 8. Nucleus SE: diseño interno y despliegue
Artículo # 7. Núcleo SE: Introducción
Artículo # 6. Otros servicios RTOS
Artículo # 5. Interacción de tareas y sincronización
Artículo # 4. Tareas, cambio de contexto e interrupciones
Artículo # 3. Tareas y planificación
Artículo # 2. RTOS: estructura y modo en tiempo real
Artículo # 1. RTOS: introducción.

Usando secciones


En Nucleus SE, las agrupaciones de particiones se configuran en el momento de la creación. Una sola aplicación puede tener hasta 16 grupos de particiones. Si no están configurados, las estructuras de datos y las llamadas de servicio relacionadas con estos grupos no se incluirán en la aplicación.

Un grupo de particiones es un área de memoria dividida en un cierto número de bloques de un tamaño fijo. El desarrollador tiene control total sobre el tamaño y el número de particiones en cada grupo. Las tareas pueden solicitar secciones asignadas de memoria y recibir un puntero al área de almacenamiento y no deben escribir datos fuera de la sección asignada. Cualquier sección puede liberar una sección al pasar un puntero a una función API. Una solicitud para asignar una partición cuando no hay particiones libres puede provocar un error o una suspensión de la solicitud, dependiendo de los parámetros de llamada API seleccionados y la configuración de Nucleus SE.

Configurar particiones de memoria


Número de agrupaciones de partición


Como con la mayoría de los objetos de Nucleus SE, la configuración del grupo de particiones se realiza principalmente utilizando la directiva #define en nuse_config.h . El parámetro principal es NUSE_PARTITION_POOL_NUMBER , que determina cuántos grupos de particiones se definen en la aplicación. El valor predeterminado es 0 (es decir, no se usan grupos de particiones), el desarrollador puede establecer cualquier valor de 0 a 16. Otros valores conducirán a un error de compilación, que se detectó durante la verificación en nuse_config_check.h (se incluye en nuse_config.c , y , por lo tanto, compila con este módulo), lo que lleva a la compilación de la directiva #error .

Elegir un valor distinto de cero es una forma prioritaria de activar grupos de particiones. Esto lleva a la definición de estructuras de datos y a la asignación del tamaño apropiado. Las estructuras de datos en la ROM deben inicializarse con los valores apropiados que describen cada grupo de particiones. Más detalles sobre las estructuras de datos estarán en el próximo artículo. Esta selección también activa la configuración de la API.

Activar llamadas API


Cada función API (llamada de utilidad) en Nucleus SE se activa mediante la directiva #define en nuse_config.h . Para los grupos de particiones, estos incluyen:

NUSE_PARTITION_ALLOCATE
NUSE_PARTITION_DEALLOCATE
NUSE_PARTITION_POOL_INFORMATION
NUSE_PARTITION_POOL_COUNT

Por defecto, todos están configurados en FALSO , deshabilitando así cada llamada de servicio y evitando la inclusión de un código de implementación. Para configurar los grupos de particiones en la aplicación, debe seleccionar las llamadas API necesarias y establecer las directivas correspondientes en TRUE .

Lo siguiente es un extracto del archivo predeterminado nuse_config.h :



Si la función API Partition Pools está activada, pero los pools no están configurados, se produce un error de compilación (a excepción de NUSE_Partition_Pool_Count () , que siempre está habilitado). Si su código usa una llamada API que no ha sido activada, se producirá un error de diseño porque el código de implementación no se incluyó en la aplicación.

Partition Pool Utility Calls


Nucleus RTOS admite siete llamadas de utilidad relacionadas con grupos de particiones, que proporcionan la siguiente funcionalidad:

Descripción FuncionalNúcleo RTOSNúcleo SE
Selección de secciónNU_Allocate_Partition ()NUSE_Partition_Allocate ()
Lanzamiento de secciónNU_Deallocate_Partition ()NUSE_Partition_Deallocate ()
Proporcionar información
sobre un grupo de particiones particular
NU_Partition_Pool_Information ()NUSE_Partition_Pool_Information ()
Devuelve el valor de la cantidad (actualmente) configurada
grupos de aplicaciones
NU_Established_Partition_Pools ()NUSE_Partition_Pool_Count ()
Agregar (crear) un nuevo grupo de particiones a la aplicaciónNU_Create_Partition_Pool ()No implementado
Cambiar (eliminar) un grupo de particiones de una aplicaciónNU_Delete_Partition_Pool ()No implementado
Devolución de punteros a todos los grupos de particiones actualmente existentes en la aplicaciónNU_Partition_Pool_Pointers ()No implementado

La implementación de cada llamada se discutirá en detalle.

Vale la pena señalar que ni Nucleus RTOS ni Nucleus SE tienen una función de reinicio. Esto se hace a propósito. Muy a menudo, una tarea asigna una sección y pasa un puntero a otra tarea (que luego puede liberarla). Si vuelve a cargar el grupo de particiones, todas las particiones se marcarán como no utilizadas, sin embargo, no hay ningún mecanismo para supervisar y notificar todas las tareas que pueden usar particiones.

Servicios de partición y liberación


Las operaciones fundamentales con los grupos de particiones son la asignación de particiones en el grupo (es decir, marcar la partición como utilizada y devolver su dirección) y liberar la partición (es decir, la partición se marca como no utilizada). Nucleus RTOS y Nucleus SE proporcionan dos llamadas API básicas para estas operaciones, que se describen a continuación.

Selección de sección


Llamar a la API de Nucleus RTOS para asignar una partición es muy flexible, lo que permite a los desarrolladores pausar tareas por un período de tiempo indefinido o sin un tiempo de espera si la operación no se puede completar de inmediato, por ejemplo, cuando intenta asignar una partición de un grupo en el que todas las particiones ya están distribuidas. Nucleus SE proporciona el mismo servicio, solo detener las tareas es opcional y no se implementa un tiempo de espera.

Nucleus RTOS API Call to Partition


Prototipo de llamada:

ESTADO NU_Allocate_Partition (NU_PARTITION_POOL * pool, VOID ** return_pointer, UNSIGNED suspend));

Valor de retorno:

NU_SUCCESS : la llamada se completó correctamente;
NU_NO_PARTITION : no hay secciones disponibles;
NU_INVALID_POOL : puntero de agrupación de particiones no válido;
NU_INVALID_POINTER : pasó un puntero nulo a los datos devueltos ( NULL );
NU_INVALID_SUSPEND : se realizó un intento de suspender una tarea desde un hilo no asociado con la tarea;
NU_TIMEOUT : no hay particiones disponibles, incluso después de la suspensión durante el período de espera especificado;
NU_POOL_DELETED : el grupo de particiones se eliminó cuando se suspendió la tarea.

Llamada de Nucleus SE API para resaltar una partición


Esta llamada a la API admite la funcionalidad principal de la API Nucleus RTOS.

Prototipo de llamada:

ESTADO NUSE_Partition_Allocate (grupo NUSE_PARTITION_POOL, ADDR * return_pointer, U8 suspendido);

Parámetros:

pool - índice (ID) del pool de particiones usado;
return_pointer : puntero a una variable de tipo ADDR , que toma la dirección de la sección seleccionada;
suspender : parámetro para pausar la tarea; puede tomar los valores NUSE_NO_SUSPEND o NUSE_SUSPEND .

Valor de retorno:

NUSE_SUCCESS : la llamada se completó correctamente;
NUSE_NO_PARTITION : no hay secciones disponibles;
NUSE_INVALID_POOL : índice de agrupación de particiones no válido;
NUSE_INVALID_POINTER : pasó un puntero nulo a los datos devueltos ( NULL );
NUSE_INVALID_SUSPEND: se realizó un intento de suspender una tarea desde un subproceso no asociado con la tarea o cuando las API de bloqueo estaban deshabilitadas.

Implementación de asignación de partición en Nucleus SE


El código de función API NUSE_Partition_Allocate se selecciona mediante compilación condicional después de verificar los parámetros, dependiendo de si la llamada API a bloquear (suspender tareas) está activada o no. A continuación, consideraremos por separado estas dos opciones.

Si las llamadas de bloqueo están desactivadas, la llamada API es bastante simple:



Primero, se verifica la disponibilidad de particiones gratuitas. Si no hay tales particiones, se devuelve un error ( NUSE_NO_PARTITION ). Luego hay una enumeración de secciones, durante la cual los primeros bytes se verifican para valores cero (lo que indica que la sección no se usa). Cuando se encuentra dicha partición, se le asigna el indicador "usado", que incluye el índice del grupo de particiones (consulte "Liberar la partición" a continuación) y devuelve un puntero al siguiente byte (el comienzo del área de datos real). Las explicaciones sobre las estructuras de datos de los grupos de particiones se presentarán en el siguiente artículo en la sección Estructuras de datos.

Si el bloqueo está activado, el código para esta llamada API se vuelve un poco más complicado:



El código está encerrado en un bucle do ... while que continúa ejecutándose mientras el parámetro de pausa sea NUSE_SUSPEND .

Si no hay particiones disponibles y el parámetro de pausa es NUSE_NO_SUSPEND , la llamada a la API se detiene y devuelve NUSE_NO_PARTITION . Si el parámetro de pausa se estableció en NUSE_SUSPEND , la tarea se detiene. Al regresar (por ejemplo, cuando se reanuda una tarea), el valor de retorno de NUSE_SUCCESS indica que la tarea se reanudó porque la sección de memoria se liberó y el código vuelve al comienzo del bucle. Dado que no hay funciones de API para recargar los grupos de particiones, las tareas no se pueden reanudar por otras razones, sino por la estabilidad de bloquear otros tipos de objetos, el proceso de validación NUSE_Task_Blocking_Return [] se conserva.

Lanzamiento de sección


El lanzamiento de la sección en Nucleus RTOS y Nucleus SE lo vuelve a poner a disposición. Antes del lanzamiento, no verifica si esta sección es utilizada por alguna tarea o no, el programador de la aplicación es responsable de esto. Solo se necesita un puntero a un área de datos para liberar una sección.

Nucleus RTOS API Call to Free Partition


Prototipo de llamada:

ESTADO NU_Deallocate_Partition (VOID * partición);

Parámetros:

partición : un puntero al área de datos (devuelto por la función NU_Allocate_Partition () ) de la partición que se va a liberar;

Valor de retorno:

NU_SUCCESS : la llamada se completó correctamente;
NU_INVALID_POINTER : puntero de sección NULL o no indica que se haya usado una sección válida.

Llamada de Nucleus SE API a partición libre


Esta llamada a la API admite la funcionalidad principal de la API Nucleus RTOS.

Prototipo de llamada:

ESTADO NUSE_Partition_Deallocate (partición ADDR);

Parámetros:

partición : un puntero al área de datos (devuelto por la función NUSE_Partition_Allocate () ) de la partición a liberar

Valor de retorno:

NUSE_SUCCESS : la llamada se completó correctamente;
NUSE_INVALID_POINTER : el puntero de sección es nulo ( NULL ) o no indica una sección válida utilizada

Implementación


En lugar de implementar usando las funciones API de bloqueo y no bloqueo, la función NUSE_Partition_Deallocate () simplemente contiene una sección compilada condicionalmente que es responsable de desbloquear las tareas. Este código implementa la liberación de secciones:



Primero, el índice de sección se recupera del byte de estado. Luego, el estado de la partición cambia a "no utilizado", el contador de particiones usadas disminuye y la función informa la finalización exitosa de la operación.

Si el bloqueo está activado, el siguiente código se utiliza para reanudar las tareas que esperan el grupo de particiones disponible:



Si las tareas se bloquearon al asignar particiones en este grupo, se reanuda la primera tabla.

En el próximo artículo, hablaremos sobre llamadas API adicionales relacionadas con particiones de memoria, así como estructuras de datos relacionadas.

Sobre el autor: Colin Walls ha trabajado en la industria electrónica durante más de treinta años, dedicando la mayor parte de su tiempo al firmware. Ahora es ingeniero de firmware en Mentor Embedded (una división de Mentor Graphics). Colin Walls a menudo habla en conferencias y seminarios, autor de numerosos artículos técnicos y dos libros sobre firmware. Vive en el Reino Unido.

Source: https://habr.com/ru/post/es426425/


All Articles