Semaforos en Nucleus SE: Visión general, configuración y API esenciales
Ver la serie RTOS Revealed
Los semáforos son un mecanismo fundamental para sincronizar el acceso a recursos compartidos en sistemas embebidos. Permiten a las tareas obtener y liberar control sobre un recurso sin conflictos de forma segura.
Uso de Semáforos
En Nucleus SE, el soporte de semáforos se habilita durante el proceso de compilación. Una sola aplicación puede configurar hasta 16 semáforos. Si opta por no usar ningún semáforo, las estructuras de datos y código API relacionados se excluyen del binario final, reduciendo la huella.
Un semáforo es simplemente un contador de 8 bits cuyo valor está protegido para que múltiples tareas puedan manipularlo de forma segura. Las tareas llaman a Obtain para decrementar el contador y Release para incrementarlo. Si una tarea intenta obtener un semáforo cuyo contador es cero, el resultado depende de las opciones de la API y la configuración del sistema: la llamada puede devolver un error o suspender la tarea hasta que el semáforo esté disponible.
Configuración de Semáforos
Número de Semáforos
Los semáforos se definen mediante sentencias #define en nuse_config.h. La macro clave es NUSE_SEMAPHORE_NUMBER, que especifica cuántas ranuras de semáforo usará la aplicación. El valor por defecto es 0, significando sin soporte de semáforo. Los valores válidos van de 0 a 16. Un valor inválido dispara un error en tiempo de compilación generado por nuse_config_check.h (incluido a través de nuse_config.c).
Establecer NUSE_SEMAPHORE_NUMBER a un valor no cero activa el subsistema de semáforos: las estructuras de datos se dimensionan apropiadamente y los símbolos de habilitación de API se procesan.
Habilitación de API
Cada llamada API de Nucleus SE está protegida por una macro de habilitación dedicada en nuse_config.h. Para semáforos, los símbolos relevantes son:
NUSE_SEMAPHORE_OBTAINNUSE_SEMAPHORE_RELEASENUSE_SEMAPHORE_RESETNUSE_SEMAPHORE_INFORMATIONNUSE_SEMAPHORE_COUNT
Por defecto, todas estas macros están en FALSE, lo que deshabilita las llamadas de servicio correspondientes y excluye su implementación de la compilación. Para habilitar una API particular, establezca su macro en TRUE.
A continuación, un fragmento del nuse_config.h por defecto:
#define NUSE_SEMAPHORE_NUMBER 0 /* Número de semáforos en el sistema – 0‑16 */ #define NUSE_SEMAPHORE_OBTAIN FALSE /* Habilitador de llamada de servicio */ #define NUSE_SEMAPHORE_RELEASE FALSE /* Habilitador de llamada de servicio */ #define NUSE_SEMAPHORE_RESET FALSE /* Habilitador de llamada de servicio */ #define NUSE_SEMAPHORE_INFORMATION FALSE /* Habilitador de llamada de servicio */ #define NUSE_SEMAPHORE_COUNT FALSE /* Habilitador de llamada de servicio */
Habilitar una llamada API sin configurar ningún semáforo (excepto NUSE_Semaphore_Count(), que siempre está disponible) resulta en un error en tiempo de compilación. Si llama a una API que no ha sido habilitada, ocurre un error en tiempo de enlace porque la implementación fue omitida.
Llamadas de Servicio de Semáforo
Nucleus SE ofrece ocho llamadas de servicio relacionadas con semáforos. Las primeras cinco están completamente implementadas; las tres restantes son placeholders para futuras extensiones.
- Obtain –
NUSE_Semaphore_Obtain() - Release –
NUSE_Semaphore_Release() - Reset –
NUSE_Semaphore_Reset() - Information –
NUSE_Semaphore_Information() - Count –
NUSE_Semaphore_Count() - Create – no implementado en Nucleus SE
- Delete – no implementado en Nucleus SE
- List All – no implementado en Nucleus SE
Operaciones Obtain y Release
Las operaciones centrales de semáforo son obtener (decrementar) y liberar (incrementar). Nucleus RTOS proporciona una API obtain flexible con suspensión opcional y timeouts. Nucleus SE refleja este comportamiento, aunque la suspensión de tareas es opcional y los timeouts no se soportan.
API Obtain de Nucleus RTOS
Prototipo:
STATUS NU_Obtain_Semaphore(NU_SEMAPHORE *semaphore, UNSIGNED suspend);
Parámetros:
semaphore– puntero al bloque de control del semáforo.
suspend– puede serNU_NO_SUSPEND,NU_SUSPENDo un valor de timeout.
Valores de retorno:
NU_SUCCESS – operación exitosa.
NU_UNAVAILABLE – valor del semáforo era cero.
NU_INVALID_SEMAPHORE – puntero de semáforo inválido.
NU_INVALID_SUSPEND – suspensión intentada desde contexto no-tarea.
NU_SEMAPHORE_WAS_RESET – semáforo reiniciado mientras la tarea estaba suspendida.
API Obtain de Nucleus SE
Prototipo:
STATUS NUSE_Semaphore_Obtain(NUSE_SEMAPHORE semaphore, U8 suspend);
Parámetros:
semaphore– el índice del semáforo.
suspend– puede serNUSE_NO_SUSPENDoNUSE_SUSPEND.
Valores de retorno:
NUSE_SUCCESS – operación exitosa.
NUSE_UNAVAILABLE – valor del semáforo era cero.
NUSE_INVALID_SEMAPHORE – índice de semáforo inválido.
NUSE_INVALID_SUSPEND – suspensión intentada desde no-tarea o APIs de bloqueo deshabilitadas.
NUSE_SEMAPHORE_WAS_RESET – semáforo reiniciado durante suspensión.
Aspectos Destacados de la Implementación
Cuando el bloqueo está deshabilitado, la implementación simplemente comprueba si el contador es no-cero, lo decrementa y retorna NUSE_SUCCESS. Si el contador es cero, retorna NUSE_UNAVAILABLE. if (NUSE_Semaphore_Counter[semaphore] != 0) { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; } else { return_value = NUSE_UNAVAILABLE; } Cuando el bloqueo está habilitado, la rutina entra en un bucle do…while que intenta adquirir el semáforo. Si el contador es cero y suspend es NUSE_SUSPEND, la tarea se bloquea. Al liberar, la primera tarea en espera es despertada y el bucle reintenta la adquisición. do { if (NUSE_Semaphore_Counter[semaphore] != 0) { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; } else { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_UNAVAILABLE; } else { NUSE_Semaphore_Blocking_Count[semaphore]++; NUSE_Suspend_Task(NUSE_Task_Active, semaphore << 4 | NUSE_SEMAPHORE_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } } } while (suspend == NUSE_SUSPEND);
API Release de Nucleus RTOS
Prototipo:
STATUS NU_Release_Semaphore(NU_SEMAPHORE *semaphore);
Parámetros:
semaphore– puntero al bloque de control del semáforo.
Valores de retorno:
NU_SUCCESS – operación exitosa.
NU_INVALID_SEMAPHORE – puntero de semáforo inválido.
API Release de Nucleus SE
Prototipo:
STATUS NUSE_Semaphore_Release(NUSE_SEMAPHORE semaphore);
Parámetros:
semaphore– el índice del semáforo.
Valores de retorno:
NUSE_SUCCESS – operación exitosa.
NUSE_INVALID_SEMAPHORE – índice de semáforo inválido.
NUSE_UNAVAILABLE – contador ya en 255; no puede incrementar.
Aspectos Destacados de la Implementación
La rutina de liberación primero comprueba que el contador esté por debajo de su máximo (255). Si es así, incrementa el contador. Si el bloqueo está habilitado y hay tareas esperando en este semáforo, la primera es despertada.
NUSE_CS_Enter(); if (NUSE_Semaphore_Counter[semaphore] < 255) { NUSE_Semaphore_Counter[semaphore]++; return_value = NUSE_SUCCESS; #if NUSE_BLOCKING_ENABLE if (NUSE_Semaphore_Blocking_Count[semaphore] != 0) { NUSE_Semaphore_Blocking_Count[semaphore]--; for (U8 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_SUCCESS; NUSE_Wake_Task(index); break; } } } #endif } else { return_value = NUSE_UNAVAILABLE; } NUSE_CS_Exit(); return return_value;
Cuando las tareas están suspendidas en un semáforo, liberarlo despierta a la primera tarea en espera, permitiéndole continuar la ejecución.
El próximo artículo explorará grupos de banderas de evento y sus estructuras de datos relacionadas.
Colin Walls tiene más de treinta años de experiencia en la industria electrónica, enfocándose principalmente en software embebido. Presenta frecuentemente en conferencias, escribe artículos técnicos y ha escrito dos libros sobre software embebido. Colin es tecnólogo de software embebido en Mentor Embedded (División de Software Embebido de Mentor Graphics) y está basado en el Reino Unido. Su blog está en https://blogs.mentor.com/colinwalls. Contacte por email en colin_walls@mentor.com.
Incrustado
- UCAS amplía su contrato con Infosys por tres años para impulsar la automatización
- Cerraduras de leva (cam locks) explicadas: cómo aseguran gabinetes discretamente
- ¿Qué Son los Tornillos de Ojo (Eye Screws)? Guía Profesional de Diseño y Usos
- Acero inoxidable explicado: composición, producción e impacto global
- Escritor de Servicio Automotriz: Rol, Deberes y Trayectoria Profesional
- Buzones en Nucleus SE: Guía práctica de configuración y uso
- Semaforos en Nucleus RTOS: Servicios de utilidad y estructuras de datos
- Dominando grupos de banderas de evento: Servicios de utilidad y estructuras de datos en Nucleus RTOS/SE
- Grupos de banderas de evento en Nucleus SE: Guía introductoria de configuración y uso de API
- Colas en Nucleus SE: Introducción y llamadas de servicio principales
- Fundamentos de C#: Entrada y salida esenciales