Die ganze Wahrheit über RTOS. Artikel # 20. Semaphoren: Hilfsdienste und Datenstrukturen

Ursprünglicher Autor: Colin Walls
  • Übersetzung


Dieser Artikel setzt die Semaphorprüfung fort.

Support für Semaphore


Nucleus RTOS verfügt über vier API-Aufrufe, die Funktionen für Semaphore bereitstellen: Zurücksetzen eines Semaphors, Abrufen von Informationen zu einem Semaphor, Abrufen der Anzahl von Semaphoren in einer Anwendung und Empfangen von Zeigern auf alle Semaphore in einer Anwendung. Die ersten drei davon sind im Nucleus SE implementiert.

Vorherige Artikel in der Serie:
Artikel # 19. Semaphore: eine Einführung und grundlegende Dienstleistungen
Artikel # 18. Ereignis-Flag-Gruppen: Nebendienstleistungen und Datenstrukturen
Artikel # 17. Event-Flag-Gruppen: Einführung und Basisdienste
Artikel # 16. Signalisiert
Artikel 15. Speicherbereiche: Dienste und Datenstrukturen
Artikel # 14. Speicherabschnitte: Einführung und Grunddienste
Artikel # 13. Aufgabendatenstrukturen und nicht unterstützte API-Aufrufe
Artikel 12. Aufgabendienste
Artikel 11. Aufgaben: Konfiguration und Einführung in den API-
Artikel # 10. Scheduler: Zusätzliche Funktionen und Speichern des Kontext-
Artikels 9. Scheduler: Implementierung
Artikel 8. Nucleus SE: Inside und Bereitstellung
Artikel # 7. Nucleus SE: Einführungsartikel
Nr. 6. Andere RTOS-Dienste
Artikel 5. Interaktion zwischen Aufgaben und Synchronisation
Artikel 4. Aufgaben, Kontextwechsel und Interrupts
Artikel 3. Aufgaben und Planung
Artikel 2. RTOS: Struktur und Echtzeitmodus
Artikel 1. RTOS: Einführung.

Semaphor zurücksetzen


Dieser API-Aufruf setzt das Semaphor auf seinen ursprünglichen, nicht verwendeten Status zurück. Diese API-Funktion ist im Vergleich zu den Funktionen anderer Kernel-Objekte ungewöhnlich, da sie trotz des Zurücksetzens nicht nur den Zähler auf den Anfangswert setzt, sondern der neue Anfangswert des Zählers im Aufruf übertragen wird. Jede Task, die auf dem Semaphor angehalten wurde, wird fortgesetzt und gibt den NUSE_SEMAPHORE_WAS_RESET- Code im Nucleus SE und im Nucleus RTOS - NU_SEMAPHORE_RESET zurück .

Aufruf zum Zurücksetzen eines Semaphors in einem Nucleus-RTOS-

Service-Aufruf Prototyp:

STATUS NU_Reset_Semaphore (NU_SEMAPHORE * -Semaphor, UNSIGNED initial_count);

Parameter:

Semaphor - ein Zeiger auf den vom Benutzer bereitgestellten Semaphor-Steuerblock;
initial_count ist der Wert, auf den das Semaphor gesetzt wird.

Rückgabewert:

NU_SUCCESS - Der Aufruf wurde erfolgreich abgeschlossen.
NU_INVALID_SEMAPHORE - ungültiger Zeiger auf Semaphor.

Der Aufruf zum Zurücksetzen des Semaphors in Nucleus SE
Dieser API-Aufruf unterstützt die Kernfunktionen der Nucleus RTOS-API.

Prototyp des

Serviceaufrufs : STATUS NUSE_Semaphore_Reset (NUSE_SEMAPHORE-Semaphor, U8 initial_count);

Parameter:

Semaphor - Index (ID) des abgelegten Semaphors;
initial_count ist der Wert, auf den das Semaphor gesetzt wird.

Rückgabewert:

NUSE_SUCCESS - Der Aufruf wurde erfolgreich abgeschlossen.
NUSE_INVALID_SEMAPHORE- falscher Semaphorindex.

Semaphor-Reset in Nucleus SE implementieren

Die Hauptaufgabe der API-Funktion NUSE_Semaphore_Reset () besteht darin, das entsprechende NUSE_Semaphore_Counter [] -Element auf den angegebenen Wert zu setzen (nach Überprüfung der Parameter).

Wenn die Aufgabensperre aktiviert ist, wird der folgende Code zum Entsperren von Aufgaben benötigt:

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

Jede angehaltene Aufgabe auf dem Semaphor wird als "abgeschlossen" markiert, und der Aufhebungscode für die Aufgabe gibt NUSE_SEMAPHORE_WAS_RESET zurück . Wenn dieser Prozess abgeschlossen ist und der Prioritätsplaner verwendet wird, initialisiert der Aufruf NUSE_Reschedule () , da eine oder mehrere Tasks mit einer höheren Priorität in den Bereitschaftsstatus wechseln und auf die Wiederaufnahme warten können.

Semaphor-Informationen


Dieser Serviceabruf gibt Semaphorinformationen zurück. Die Implementierung dieses Aufrufs im Nucleus SE unterscheidet sich vom Nucleus RTOS dadurch, dass weniger Informationen zurückgegeben werden, da die Benennung von Objekten und die Reihenfolge der Suspendierung nicht unterstützt werden und die Suspendierung von Aufgaben selbst deaktiviert werden kann.

Semaphore-Informationen in Nucleus RTOS- Serviceaufruf anfordern

Prototyp:

STATUS NU_Semaphore_Information (NU_SEMAPHORE * Semaphor, CHAR * Name, UNSIGNED * aktuelle_Anzahl, OPTION * Suspend_type, UNSIGNED * Aufgaben_waiting, NU_TASK ** first_task)

Parameter:

Semaphor - ein Zeiger auf den Semaphor-Steuerblock, zu dem Informationen benötigt werden;
name ist ein Zeiger auf den 8-stelligen Semaphorennamen, wobei das nullende-Byte in diesem Bereich enthalten ist.
current_count - Ein Zeiger auf eine Variable, die den aktuellen Wert des Semaphorzählers akzeptiert.
suspend_type - ein Zeiger auf eine Variable, die den Typ der Aufgabenpause akzeptiert, kann NU_FIFO und NU_PRIORITY sein ;
task_waiting - Ein Zeiger auf eine Variable, die die Anzahl der angehaltenen Aufgaben im Semaphor akzeptiert.
first_task ist ein Zeiger auf eine Variable vom Typ NU_TASK , die einen Zeiger auf die Steuereinheit der ersten angehaltenen Task erhält.

Rückgabewert:

NU_SUCCESS - Der Aufruf wurde erfolgreich abgeschlossen.
NU_INVALID_SEMAPHORE - ungültiger Zeiger auf Semaphor.

Aufruf zum Abrufen von Informationen zum Semaphor in Nucleus SE
Dieser API-Aufruf unterstützt die Kernfunktionen der Nucleus RTOS-API.

Dienstaufruf-Prototyp:

STATUS NUSE_Semaphore_Information (NUSE_SEMAPHORE-Semaphore, U8 * current_count, U8 * task_waiting, NUSE_TASK * first_task);

Parameter:

Semaphor - Index des Semaphors, über den Sie Informationen bereitstellen möchten;
current_count - Ein Zeiger auf eine Variable, die den aktuellen Wert des Semaphorzählers akzeptiert.
task_waiting - Ein Zeiger auf eine Variable, die die Anzahl der auf diesem Semaphor angehaltenen Aufgaben akzeptiert (nichts wird zurückgegeben, wenn die Unterstützung für das Unterbrechen von Aufgaben deaktiviert ist).
first_task - Ein Zeiger auf eine Variable vom Typ NUSE_TASKdie den Index der ersten angehaltenen Aufgabe akzeptiert (gibt nichts zurück, wenn die Unterstützung für das Anhalten von Aufgaben deaktiviert ist).

Rückgabewert:

NUSE_SUCCESS - Der Aufruf wurde erfolgreich abgeschlossen.
NUSE_INVALID_SEMAPHORE - falscher Semaphorindex;
NUSE_INVALID_POINTER - ein oder mehrere Zeigerparameter sind falsch.

Implementieren von Semaphor-Informationen in Nucleus SE

Die Implementierung dieses API-Aufrufs ist recht einfach:

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;

Die Funktion gibt den Semaphorstatus zurück. Wenn die API-Aufrufblockierungsfunktion aktiviert ist, werden dann die Anzahl der anstehenden Aufgaben und der Index der ersten zurückgegeben (andernfalls wird diesen Parametern der Wert 0 zugewiesen).

Anzahl der Semaphoren ermitteln


Dieser Serviceaufruf gibt die Anzahl der Semaphore in der Anwendung zurück. In Nucleus RTOS ändert sich dieser Wert im Laufe der Zeit, und der Rückgabewert entspricht der aktuellen Anzahl der Semaphoren, und in Nucleus SE wird der Rückgabewert in der Assemblierungsphase festgelegt und ändert sich nicht mehr.

Aufruf zur Semaphorenzählung in Nucleus RTOS

Service Call Prototyp:

UNSIGNED NU_Established_Semaphores (VOID);

Parameter:
Keine.

Rückgabewert: Die
Anzahl der in der Anwendung erstellten Semaphoren.

Aufruf der Semaphorenzählung in Nucleus SE
Dieser API-Aufruf unterstützt die Kernfunktionalität der Nucleus RTOS-API.

Prototyp des

Serviceaufrufs : U8 NUSE_Semaphore_Count (void);

Parameter:
Keine.

Rückgabewert: Die
Anzahl der konfigurierten Semaphore in der Anwendung.

Die Implementierung von Semaphor-Zählern in Nucleus SE
Die Implementierung dieses API-Aufrufs ist recht einfach: Der Wert des Symbols #define NUSE_SEMAPHORE_NUMBER wird zurückgegeben .

Datenstrukturen


Semaphore verwenden zwei oder drei Arrays von Datenstrukturen (in RAM und ROM), die wie alle anderen Objekte von Nucleus SE eine Menge von Tabellen sind, deren Größe von der Anzahl der Semaphoren in der Anwendung und den ausgewählten Parametern abhängt.

Ich empfehle dringend, dass der Anwendungscode nicht direkt auf diese Datenstrukturen, sondern über die bereitgestellten API-Funktionen zugreift. Dadurch werden Inkompatibilitäten mit zukünftigen Versionen des Nucleus SE und unerwünschte Nebenwirkungen vermieden und die Portierung der Anwendung auf das Nucleus RTOS vereinfacht. Zum besseren Verständnis der Funktionsweise des Serviceabrufcodes und zum Debuggen wird nachstehend ein detaillierter Überblick über die Datenstrukturen gegeben.

Daten in RAM


Diese Daten haben die folgende Struktur:
NUSE_Semaphore_Counter [] ist ein Array vom Typ U8 mit einem Eintrag für jedes konfigurierte Semaphor. Es speichert den Wert des Zählers.
NUSE_Semaphore_Blocking_Count [] ist ein Array vom Typ U8 . Es enthält Zähler blockierter Aufgaben für jedes Semaphor. Dieses Array ist nur vorhanden, wenn die Anruf-API-Blockierungsfunktion aktiviert ist.
NUSE_Semaphore_Counter [] wird mit dem Anfangswert initialisiert (siehe „Daten im ROM“ weiter unten), und NUSE_Semaphore_Blocking_Count [] wird mit NUSE_Init_Semaphore () auf Null gesetzt, wenn Nucleus SE gestartet wird. Einer der folgenden Artikel enthält eine vollständige Beschreibung der Startprozeduren von Nucleus SE.

Im Folgenden sind die Definitionen dieser Datenstrukturen in der Datei nuse_init.c aufgeführt .

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

Daten im ROM


Datenstruktur:
NUSE_Semaphore_Initial_Value [] - ein Array vom Typ U8 mit einem Eintrag für jedes Semaphor. Dies sind die Anfangswerte der Semaphore.

Diese Datenstruktur wird in nuse_config.c (statisch) deklariert und initialisiert :

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

Speicherkapazität für Semaphoren


Wie bei allen Nucleus SE-Kernobjekten ist die für Semaphoren erforderliche Datenmenge vorhersehbar.

Der Speicherplatz im ROM (in Bytes) für alle Semaphore in der Anwendung ist NUSE_SEMAPHORE_NUMBER .

Die Größe des Arbeitsspeichers im RAM (in Byte) für alle Semaphore in der Anwendung mit aktivierten blockierenden API-Aufrufen kann wie folgt berechnet werden:
NUSE_SEMAPHORE_NUMBER * 2

Andernfalls ist es NUSE_SEMAPHORE_NUMBER .

Nicht realisierte API-Aufrufe


Drei API-Aufrufe für Semaphore, die im Nucleus RTOS vorhanden sind, sind nicht im Nucleus SE implementiert.

Semaphore erstellen


Dieser API-Aufruf erstellt ein Semaphor. Für den Nucleus SE ist dies nicht erforderlich, da die Semaphoren statisch erstellt werden.

Prototyp des
Serviceaufrufs : STATUS NU_Create_Semaphore (NU_SEMAPHORE * Semaphor, CHAR * Name, UNSIGNED initial_count, OPTION suspend_type);

Parameter:

Semaphore - Ein Zeiger auf einen vom Benutzer bereitgestellten Semaphor-Steuerblock. Er wird verwendet, um Semaphore in anderen API-Aufrufen zu steuern.
name - Zeiger auf den 8-stelligen Semaphorennamen mit abschließendem Null-Byte;
initial_count - der Anfangswert des Semaphors;
suspend_type - Gibt das Prinzip des Suspendierens der Task auf dem Semaphor an. Kann Werte NU_FIFO und NU_PRIORITYdie dem FIFO-Prinzip (First-in-First-Out) und der Rangfolge der Suspendierung von Aufgaben entsprechen.

Rückgabewert:

NU_SUCCESS - Der Aufruf wurde erfolgreich abgeschlossen.
NU_INVALID_SEMAPHORE - Gibt an , dass der Zeiger auf den Semaphor-Steuerblock null ( NULL ) ist oder bereits verwendet wird.
NU_INVALID_SUSPEND ist ein ungültiger Parameter suspend_type .

Semaphor löschen


Dieser API-Aufruf entfernt das zuvor erstellte Semaphor. Für den Nucleus SE ist dies nicht erforderlich, da die Semaphoren statisch erstellt werden und nicht gelöscht werden können.

Prototyp

eines Serviceaufrufs : STATUS NU_Delete_Semaphore (NU_SEMAPHORE * Semaphore);

Parameter:

Semaphore - Zeiger auf den Semaphor-Steuerblock.

Rückgabewert:

NU_SUCCESS - Der Aufruf wurde erfolgreich abgeschlossen.
NU_INVALID_SEMAPHORE - ungültiger Zeiger auf Semaphor.

Verweise auf Semaphoren


Dieser API-Aufruf generiert eine sequentielle Liste von Zeigern auf alle Semaphore im System. Für den Nucleus SE ist dies nicht erforderlich, da die Semaphoren durch einen einfachen Index und nicht durch einen Zeiger identifiziert werden.

Dienstaufruf-Prototyp:

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

Parameter:

pointer_list - Ein Zeiger auf ein Array von Zeigern. NU_SEMAPHORE . Dieses Array ist mit Zeigern auf Semaphoren gefüllt.
maximum_pointers - die maximale Anzahl von Zeigern im Array.

Rückgabewert: Die
Anzahl der NU_SEMAPHORE- Zeiger im Array.

RTOS-Kompatibilität von Nucleus


Wie bei allen anderen Nucleus SE-Objekten war es das Ziel, eine maximale Kompatibilität des Anwendungscodes mit Nucleus RTOS sicherzustellen. Semaphore sind keine Ausnahme und werden aus Anwendersicht genauso implementiert wie in Nucleus RTOS. Es gibt eine gewisse Inkompatibilität, die ich für akzeptabel hielt, da der endgültige Code in Bezug auf die benötigte Speichermenge verständlicher und effizienter wird. Ansonsten können Nucleus RTOS-API-Aufrufe fast direkt als Nucleus SE-Aufrufe verwendet werden.

Objekt-IDs


In Nucleus RTOS werden alle Objekte durch Datenstrukturen (Steuereinheiten) eines bestimmten Typs beschrieben. Ein Zeiger auf diese Steuereinheit dient als Semaphoridentifikation. Ich entschied, dass in Nucleus SE ein anderer Ansatz erforderlich ist, um Speicher effizient zu nutzen: Alle Kernelobjekte werden durch eine Reihe von Tabellen im RAM und / oder ROM beschrieben. Die Größe dieser Tabellen wird durch die Anzahl der konfigurierten Objekte jedes Typs bestimmt. Die spezifische Objektkennung ist ein Index in dieser Tabelle. Also habe ich NUSE_SEMAPHORE als Entsprechung zu U8 definiertEine Variable (und kein Zeiger) dieses Typs dient als Semaphor-ID. Diese kleine Inkompatibilität ist einfach zu handhaben, wenn der Code vom Nucleus SE zum Nucleus RTOS und umgekehrt portiert wird. Normalerweise werden keine Vorgänge für Objektkennungen ausgeführt, außer zum Verschieben und Speichern.

Nucleus RTOS unterstützt auch die Benennung von Semaphoren. Diese Namen werden nur zum Debuggen verwendet. Ich habe sie aus dem Nucleus SE ausgeschlossen, um Speicher zu sparen.

Zählergröße


In Nucleus RTOS ist der Semaphorenzähler vom Typ ohne Vorzeichen , der normalerweise eine 32-Bit-Variable ist. Der Nucleus SE-Zähler ist 8-Bit, dies kann jedoch leicht geändert werden. Normalerweise wird im RTOS-Nukleus keine Semaphorüberlaufprüfung durchgeführt. Wenn Sie die Nucleus SE-API aufrufen, können Sie dem Zähler keine höheren Werte als 255 zuweisen.

Nicht realisierte API-Aufrufe


Nucleus RTOS unterstützt acht Service-Aufrufe für Semaphore. Davon sind drei nicht im Nucleus SE implementiert. Die Details dieser Aufrufe sowie die Entscheidung, sie von Nucleus SE auszuschließen, wurden oben beschrieben.

Der folgende Artikel wird als Postfächer betrachtet.

Über den Autor: Colin Walls ist seit über dreißig Jahren in der Elektronikbranche tätig und verbrachte viel Zeit mit eingebetteter Software. Er ist jetzt ein Embedded Software Engineer in Mentor Embedded (einer Abteilung von Mentor Graphics). Colin Walls spricht häufig auf Konferenzen und Seminaren, Autor zahlreicher Fachartikel und zwei Bücher über eingebettete Software. Lebt in Großbritannien. Colins professioneller Blog , E-Mail: colin_walls@mentor.com.

Jetzt auch beliebt: