Toda la verdad sobre RTOS. Artículo # 20. Semáforos: servicios auxiliares y estructuras de datos



Este artículo continúa la revisión de semáforos.

Servicios de semáforo auxiliar


Nucleus RTOS tiene cuatro llamadas API que proporcionan funcionalidad relacionada con el semáforo: restablecer un semáforo, recuperar información de semáforo, recuperar el número de semáforos en una aplicación y recuperar punteros a todos los semáforos en una aplicación. Los tres primeros se implementan en Nucleus SE.

Artículos anteriores de la serie:
Artículo # 19. Semáforos: introducción y servicios básicos.
Artículo # 18. Grupos de banderas de eventos: servicios auxiliares y estructuras de datos
Artículo # 17. Grupos de banderas de eventos: Introducción y servicios básicos
Artículo # 16. Señales
Artículo # 15. Particiones de memoria: servicios y estructuras de datos
Artículo # 14. Secciones de memoria: introducción y servicios básicos.
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.

Restablecer semáforo


Esta llamada a la API restablece el semáforo a su estado inicial no utilizado. Esta función de API es inusual en comparación con las funciones de otros objetos del núcleo, porque a pesar de que realiza un reinicio, no solo establece el contador en el valor inicial, sino que se pasa un nuevo valor de contador inicial en la llamada. Cualquier tarea que se haya pausado en el semáforo se reanuda y devuelve el código NUSE_SEMAPHORE_WAS_RESET en Nucleus SE y en Nucleus RTOS, NU_SEMAPHORE_RESET .

Llamada para restablecer el semáforo en Nucleus RTOS

Prototipo de llamada de servicio:

ESTADO NU_Reset_Semaphore (NU_SEMAPHORE * semaphore, UNSIGNED initial_count);

Parámetros:

semáforo : puntero al bloque de control de semáforo proporcionado por el usuario;
initial_count : el valor al que se establecerá el semáforo.

Valor de retorno:

NU_SUCCESS : la llamada se completó correctamente;
NU_INVALID_SEMAPHORE : puntero de semáforo no válido .

Llamada para restablecer un semáforo en Nucleus SE
Esta llamada a la API admite la funcionalidad principal de la API Nucleus RTOS.

Prototipo de llamada de servicio:

ESTADO NUSE_Semaphore_Reset (NUSE_SEMAPHORE semaphore, U8 initial_count);

Parámetros:

semáforo - índice (ID) del semáforo objeto de dumping;
initial_count : el valor al que se establecerá el semáforo.

Valor de retorno:

NUSE_SUCCESS : la llamada se completó correctamente;
NUSE_INVALID_SEMAPHORE : índice de semáforo no válido.

Implementación de un reinicio de semáforo en Nucleus SE

La tarea principal de la función API NUSE_Semaphore_Reset () es establecer el elemento NUSE_Semaphore_Counter [] correspondiente en el valor especificado (después de verificar los parámetros).

Si se activa el bloqueo de tareas, se requiere el siguiente código para desbloquear tareas:

while (NUSE_Semaphore_Blocking_Count[semaphore] != 0) { U8 index; /* check whether any tasks are blocked */ /* on this semaphore */ for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_SEMAPHORE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == semaphore)) { NUSE_Task_Blocking_Return[index] = NUSE_SEMAPHORE_WAS_RESET; NUSE_Task_Status[index] = NUSE_READY; break; } } NUSE_Semaphore_Blocking_Count[semaphore]--; } #if NUSE_SCHEDULER_TYPE == NUSE_PRIORITY_SCHEDULER NUSE_Reschedule(NUSE_NO_TASK); #endif 

Cada tarea suspendida en el semáforo se marca como "terminada" y el código de suspensión de la tarea devuelve NUSE_SEMAPHORE_WAS_RESET . Una vez completado este proceso, si se utiliza el planificador prioritario, la llamada inicializa NUSE_Reschedule () , ya que una o más tareas con una prioridad más alta podrían entrar en un estado listo y están esperando para reanudarse.

Información del semáforo


Esta llamada de utilidad devuelve información de semáforo. La implementación de esta llamada en Nucleus SE difiere de Nucleus RTOS en que se devuelve menos información, ya que no se admite la denominación de los objetos y el orden de la suspensión, y la suspensión de las tareas en sí se puede deshabilitar.

Llame para obtener información sobre semáforos en Nucleus RTOS

Prototipo de llamada de servicio:

ESTADO NU_Semaphore_Information (NU_SEMAPHORE * semaphore, CHAR * name, UNSIGNED * current_count, OPTION * suspend_type, UNSIGNED * roles_waiting, NU_TASK ** first_task);

Parámetros:

semáforo : un puntero al bloque de control de semáforo sobre el que se requiere información;
nombre : puntero al nombre de 8 caracteres del semáforo, con cero bytes de terminación incluidos en esta área;
current_count : un puntero a una variable que tomará el valor actual del contador de semáforos;
suspend_type : un puntero a una variable que aceptará el tipo de tarea de suspensión, puede tomar los valores NU_FIFO y NU_PRIORITY ;
task_waiting : un puntero a una variable que tomará el número de tareas suspendidas en el semáforo;
first_task : un puntero a una variable de tipo NU_TASK , que llevará un puntero a la unidad de control de la primera tarea suspendida.

Valor de retorno:

NU_SUCCESS : la llamada se completó correctamente;
NU_INVALID_SEMAPHORE : puntero de semáforo no válido .

Llame para obtener información sobre semáforos en Nucleus SE
Esta llamada a la API admite la funcionalidad principal de la API Nucleus RTOS.

Prototipo de llamada de servicio:

ESTADO NUSE_Semaphore_Information (NUSE_SEMAPHORE semaphore, U8 * current_count, U8 * tareas_waiting, NUSE_TASK * first_task);

Parámetros:

semáforo : un índice de un semáforo sobre el que se requiere proporcionar información;
current_count : un puntero a una variable que tomará el valor actual del contador de semáforos;
task_waiting : un puntero a una variable que tomará el número de tareas suspendidas en este semáforo (no se devuelve nada si el soporte para suspender tareas está deshabilitado);
first_task : un puntero a una variable de tipo NUSE_TASK , que tomará el índice de la primera tarea en pausa (no se devuelve nada si el soporte para las tareas en pausa está desactivado).

Valor de retorno:

NUSE_SUCCESS : la llamada se completó correctamente;
NUSE_INVALID_SEMAPHORE : índice de semáforo no válido;
NUSE_INVALID_POINTER : uno o más parámetros de puntero son incorrectos.

Implementación de información de semáforos en Nucleus SE

Implementar esta llamada a la API es bastante simple:

 NUSE_CS_Enter(); *current_count = NUSE_Semaphore_Counter[semaphore]; #if NUSE_BLOCKING_ENABLE *tasks_waiting = NUSE_Semaphore_Blocking_Count[semaphore]; if (NUSE_Semaphore_Blocking_Count[semaphore] != 0) { U8 index; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_SEMAPHORE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == semaphore)) { *first_task = index; break; } } } else { *first_task = 0; } #else *tasks_waiting = 0; *first_task = 0; #endif NUSE_CS_Exit(); return NUSE_SUCCESS; 

La función devuelve el estado del semáforo. Luego, si se activa la funcionalidad de bloqueo de llamadas API, se devuelve el número de tareas pendientes y el índice de la primera (de lo contrario, estos parámetros se establecen en 0).

Obtener el número de semáforos


Esta llamada de utilidad devuelve el número de semáforos en la aplicación. En Nucleus RTOS, este valor cambia con el tiempo y el valor de retorno corresponde al número actual de semáforos, y en Nucleus SE, el valor de retorno se establece en la etapa de ensamblaje y ya no cambia.

Llamar a un contador de semáforos en Nucleus RTOS

Prototipo de llamada de servicio:

NU_SIGNED NU_Established_Semaphores (VOID);

Parámetros:
Están ausentes

Valor de retorno:
El número de semáforos creados en la aplicación.

Llamar a un contador de semáforos en Nucleus SE
Esta llamada a la API admite la funcionalidad principal de la API Nucleus RTOS.

Prototipo de llamada de servicio:

U8 NUSE_Semaphore_Count (nulo);

Parámetros:
Están ausentes

Valor de retorno:
El número de semáforos configurados en la aplicación.

Implementación de contadores de semáforos en Nucleus SE
La implementación de esta llamada a la API es bastante simple: se devuelve el valor del símbolo #define NUSE_SEMAPHORE_NUMBER .

Estructuras de datos


Los semáforos usan dos o tres matrices de estructuras de datos (en RAM y ROM), que, como todos los demás objetos de Nucleus SE, son un conjunto de tablas cuyo tamaño depende del número de semáforos en la aplicación y los parámetros seleccionados.

Recomiendo encarecidamente que el código de la aplicación no utilice el acceso directo a estas estructuras de datos, sino que se refiera a ellas a través de las funciones API proporcionadas. Esto evitará la incompatibilidad con futuras versiones de Nucleus SE y los efectos secundarios no deseados, además de simplificar la transferencia de la aplicación a Nucleus RTOS. Para una mejor comprensión de cómo funciona el código de llamada de servicio y para la depuración, a continuación se ofrece una descripción detallada de las estructuras de datos.

Datos de RAM


Estos datos tienen la siguiente estructura:
NUSE_Semaphore_Counter [] : una matriz de tipo U8 que tiene una entrada para cada semáforo configurado, almacena el valor del contador.
NUSE_Semaphore_Blocking_Count [] : una matriz de tipo U8 , contiene contadores de tareas bloqueadas en cada semáforo. Esta matriz existe solo si la funcionalidad de bloqueo de llamadas API está activada.
NUSE_Semaphore_Counter [] se inicializa al valor inicial (consulte "Datos en ROM" a continuación), y NUSE_Semaphore_Blocking_Count [] se restablece usando NUSE_Init_Semaphore () cuando se inicia Nucleus SE. Uno de los siguientes artículos proporcionará una descripción completa de los procedimientos de inicio de Nucleus SE.

Las siguientes son las definiciones de estas estructuras de datos en el archivo nuse_init.c .

 RAM U8 NUSE_Semaphore_Counter[NUSE_SEMAPHORE_NUMBER]; #if NUSE_BLOCKING_ENABLE RAM U8 NUSE_Semaphore_Blocking_Count[NUSE_SEMAPHORE_NUMBER]; #endif 

Datos ROM


Estructura de datos:
NUSE_Semaphore_Initial_Value [] : una matriz de tipo U8 , que tiene un registro para cada semáforo, estos son los valores iniciales de los semáforos.

Esta estructura de datos se declara e inicializa (estáticamente) en nuse_config.c :

 ROM U8 NUSE_Semaphore_Initial_Value[NUSE_SEMAPHORE_NUMBER] = { /* semaphore initial count values */ }; 

La cantidad de memoria para los semáforos.


Como todos los objetos del núcleo de Nucleus SE, la cantidad de datos necesarios para los semáforos es predecible.

La cantidad de memoria en ROM (en bytes) para todos los semáforos en la aplicación es NUSE_SEMAPHORE_NUMBER .

La cantidad de memoria en RAM (en bytes) para todos los semáforos en la aplicación con llamadas activadas a la API de bloqueo se puede calcular de la siguiente manera:
NUSE_SEMAPHORE_NUMBER * 2

De lo contrario, es NUSE_SEMAPHORE_NUMBER .

Llamadas API no realizadas


Tres llamadas API para semáforos que están presentes en Nucleus RTOS no se implementan en Nucleus SE.

Crear semáforos


Esta llamada a la API crea un semáforo. No hay necesidad de Nucleus SE porque los semáforos se crean estáticamente.

Prototipo de llamada de servicio:
ESTADO NU_Create_Semaphore (NU_SEMAPHORE * semaphore, CHAR * name, UNSIGNED initial_count, OPTION suspend_type);

Parámetros:

semáforo : un puntero a un bloque de control de semáforo proporcionado por el usuario; se utiliza para controlar semáforos en otras llamadas API;
nombre : un puntero al nombre del semáforo de 8 caracteres, con el byte nulo de terminación activado;
initial_count : el valor inicial del semáforo;
suspend_type : indica el principio de pausar una tarea en un semáforo. Puede tomar los valores NU_FIFO y NU_PRIORITY , correspondientes al principio de FIFO (Primero en entrar , primero en salir) y el orden de prioridad de la suspensión de tareas.

Valor de retorno:

NU_SUCCESS : la llamada se completó correctamente;
NU_INVALID_SEMAPHORE : dice que el puntero al bloque de control del semáforo es NULL o ya está en uso;
NU_INVALID_SUSPEND : parámetro inválido suspend_type .

Eliminación de semáforos


Esta llamada a la API elimina el semáforo creado previamente. Nucleus SE no es necesario porque los semáforos se crean estáticamente y no se pueden eliminar.

Prototipo de llamada de servicio:

ESTADO NU_Delete_Semaphore (NU_SEMAPHORE * semaphore);

Parámetros:

semáforo : puntero al bloque de control de semáforo.

Valor de retorno:

NU_SUCCESS : la llamada se completó correctamente;
NU_INVALID_SEMAPHORE : puntero de semáforo no válido .

Punteros a semáforos


Esta llamada a la API forma una lista secuencial de punteros a todos los semáforos del sistema. No necesita Nucleus SE, ya que los semáforos se identifican mediante un índice simple, no un puntero.

Prototipo de llamada de servicio:

UNSIGNED NU_Semaphore_Pointers (NU_SEMAPHORE ** pointer_list, UNSIGNED maximum_pointers);

Parámetros:

pointer_list : un puntero a una matriz de punteros NU_SEMAPHORE , esta matriz está llena de punteros a semáforos;
maximum_pointers : el número máximo de punteros en la matriz.

Valor de retorno:
El número de punteros NU_SEMAPHORE en la matriz.

Nucleus RTOS Compatible


Al igual que con todos los demás objetos de Nucleus SE, el objetivo era maximizar la compatibilidad del código de la aplicación con Nucleus RTOS. Los semáforos no son una excepción y, desde el punto de vista del usuario, se implementan de la misma manera que en Nucleus RTOS. También hay una cierta incompatibilidad, que consideré aceptable dado que el código final será más comprensible y más eficiente en términos de la cantidad de memoria requerida. De lo contrario, las llamadas a la API Nucleus RTOS se pueden usar casi directamente como llamadas a Nucleus SE.

Identificadores de objetos


En Nucleus RTOS, todos los objetos se describen mediante estructuras de datos (unidades de control) de un tipo específico. Un puntero a esta unidad de control sirve como un identificador para el semáforo. Decidí que en Nucleus SE, se necesita un enfoque diferente para el uso eficiente de la memoria: todos los objetos del núcleo se describen mediante un conjunto de tablas en RAM y / o ROM. El tamaño de estas tablas está determinado por el número de objetos configurados de cada tipo. El identificador de un objeto particular es el índice en esta tabla. Así que definí NUSE_SEMAPHORE como el equivalente de U8 , una variable (no un puntero) de este tipo sirve como identificador para el semáforo. Esta ligera incompatibilidad es fácil de manejar si el código se transfiere de Nucleus SE a Nucleus RTOS y viceversa. Por lo general, no se realizan operaciones en identificadores de objetos que no sean mover y almacenar.

Nucleus RTOS también admite nombres de semáforos. Estos nombres se usan solo para la depuración. Los excluí de Nucleus SE para ahorrar memoria.

Tamaño de mostrador


En Nucleus RTOS, el contador de semáforo es de tipo sin signo , que suele ser una variable de 32 bits. Nucleus SE tiene un contador de 8 bits, pero esto se puede cambiar fácilmente. Normalmente, Nucleus RTOS no verifica el desbordamiento del semáforo. Llamar a la API de Nucleus SE no permitirá que al contador se le asignen valores superiores a 255.

Llamadas API no realizadas


Nucleus RTOS admite ocho llamadas de servicios públicos para trabajar con semáforos. De estos, tres no se implementan en Nucleus SE. Los detalles de estos desafíos, así como la decisión de excluirlos de Nucleus SE, se han descrito anteriormente.

El siguiente artículo examinará los buzones.

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. Blog profesional de Colin , correo electrónico: colin_walls@mentor.com.

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


All Articles