
Dieser Artikel setzt die Überprüfung der Semaphoren fort.
Hilfssemaphor-Dienste
Nucleus RTOS verfügt über vier API-Aufrufe, die semaphorbezogene Funktionen bereitstellen: Zurücksetzen eines Semaphors, Abrufen von Semaphorinformationen, Abrufen der Anzahl von Semaphoren in einer Anwendung und Abrufen von Zeigern auf alle Semaphore in einer Anwendung. Die ersten drei sind in Nucleus SE implementiert.
Frühere Artikel in der Reihe:
Artikel Nr. 19. Semaphoren: Einführung und GrundversorgungArtikel Nr. 18. Ereignisflag-Gruppen: Hilfsdienste und DatenstrukturenArtikel Nr. 17. Ereignisflag-Gruppen: Einführung und BasisdiensteArtikel 16. SignaleArtikel Nr. 15. Speicherpartitionen: Dienste und DatenstrukturenArtikel # 14. Speicherbereiche: Einführung und GrundversorgungArtikel Nr. 13. Aufgabendatenstrukturen und nicht unterstützte API-AufrufeArtikel 12. Dienstleistungen für die Arbeit mit AufgabenArtikel 11. Aufgaben: Konfiguration und Einführung in die APIArtikel 10. Scheduler: Erweiterte Funktionen und KontexterhaltungArtikel 9. Scheduler: ImplementierungArtikel 8. Nucleus SE: Internes Design und BereitstellungArtikel 7. Nucleus SE: EinführungArtikel 6. Andere RTOS-DiensteArtikel 5. Aufgabeninteraktion und SynchronisationArtikel 4. Aufgaben, Kontextwechsel und InterruptsArtikel 3. Aufgaben und PlanungArtikel 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 Zustand zurück. Diese API-Funktion ist im Vergleich zu den Funktionen anderer Kernelobjekte ungewöhnlich, da trotz der Tatsache, dass ein Reset durchgeführt wird, nicht nur der Zähler auf den Anfangswert gesetzt wird, sondern im Aufruf ein neuer Anfangszählerwert übergeben wird. Jede Aufgabe, die auf dem Semaphor angehalten wurde, wird
fortgesetzt und gibt den
NUSE_SEMAPHORE_WAS_RESET- Code in Nucleus SE und in Nucleus RTOS,
NU_SEMAPHORE_RESET, zurück .
Aufruf zum Zurücksetzen des Semaphors in Nucleus RTOSPrototyp eines Serviceabrufs:
STATUS NU_Reset_Semaphore (NU_SEMAPHORE * -Semaphor, UNSIGNED initial_count);Parameter:
Semaphor - Zeiger auf den vom Benutzer bereitgestellten Semaphor-Steuerblock;
initial_count - Der Wert, auf den das Semaphor gesetzt wird.
Rückgabewert:
NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_INVALID_SEMAPHORE -
Ungültiger Semaphorzeiger.
Aufruf zum Zurücksetzen eines Semaphors in Nucleus SEDieser API-Aufruf unterstützt die Kernfunktionalität der Nucleus RTOS-API.
Prototyp eines Serviceabrufs:
STATUS NUSE_Semaphore_Reset (NUSE_SEMAPHORE-Semaphor, U8 initial_count);Parameter:
Semaphor - Index (ID) des gedumpten Semaphors;
initial_count - Der Wert, auf den das Semaphor gesetzt wird.
Rückgabewert:
NUSE_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NUSE_INVALID_SEMAPHORE - ungültiger Semaphorindex.
Implementieren eines Semaphor-Resets in Nucleus SEDie Hauptaufgabe der API-Funktion
NUSE_Semaphore_Reset () besteht darin, das entsprechende Element
NUSE_Semaphore_Counter [] auf den angegebenen Wert zu setzen (nach Überprüfung der Parameter).
Wenn die Task-Sperre aktiviert ist, ist der folgende Code erforderlich, um Aufgaben zu entsperren:
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 auf dem Semaphor angehaltene Aufgabe wird als "
erledigt " markiert, und der Aufgabenunterbrechungscode gibt
NUSE_SEMAPHORE_WAS_RESET zurück . Wenn dieser Vorgang abgeschlossen ist und der Prioritätsplaner verwendet wird, initialisiert der Aufruf
NUSE_Reschedule () , da eine oder mehrere Aufgaben mit einer höheren Priorität in einen Bereitschaftszustand versetzt werden können und auf die Wiederaufnahme warten.
Semaphorinformationen
Dieser Dienstprogrammaufruf gibt Semaphorinformationen zurück. Die Implementierung dieses Aufrufs in Nucleus SE unterscheidet sich von Nucleus RTOS darin, 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.
Fordern Sie Semaphorinformationen in Nucleus RTOS anPrototyp eines Serviceabrufs:
STATUS NU_Semaphore_Information (NU_SEMAPHORE * Semaphor, CHAR * Name, UNSIGNED * current_count, OPTION * suspend_type, UNSIGNED * task_waiting, NU_TASK ** first_task);Parameter:
Semaphor - ein Zeiger auf den Semaphor-Steuerblock, über den Informationen benötigt werden;
name - Zeiger auf den 8-stelligen Namen des Semaphors, wobei in diesem Bereich ein Null-Abschlussbyte enthalten ist;
current_count - ein Zeiger auf eine Variable, die den aktuellen Wert des Semaphorzählers annimmt;
suspend_type - Ein Zeiger auf eine Variable, die den Typ der Suspend-Task
akzeptiert und die Werte
NU_FIFO und
NU_PRIORITY annehmen kann .
task_waiting - ein Zeiger auf eine Variable, die die Anzahl der angehaltenen Aufgaben im Semaphor übernimmt;
first_task - Ein Zeiger auf eine Variable vom Typ
NU_TASK , der einen Zeiger auf die Steuereinheit der ersten angehaltenen Task nimmt.
Rückgabewert:
NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_INVALID_SEMAPHORE -
Ungültiger Semaphorzeiger.
Fordern Sie Semaphorinformationen in Nucleus SE anDieser API-Aufruf unterstützt die Kernfunktionalität der Nucleus RTOS-API.
Prototyp eines Serviceabrufs:
STATUS NUSE_Semaphore_Information (NUSE_SEMAPHORE-Semaphor, U8 * current_count, U8 *asks_waiting, NUSE_TASK * first_task);Parameter:
Semaphor - ein Index eines Semaphors, über den Informationen bereitgestellt werden müssen;
current_count - ein Zeiger auf eine Variable, die den aktuellen Wert des Semaphorzählers annimmt;
task_waiting - ein Zeiger auf eine Variable, die die Anzahl der auf diesem Semaphor angehaltenen Aufgaben übernimmt (nichts wird zurückgegeben, wenn die Unterstützung für das Anhalten von Aufgaben deaktiviert ist);
first_task - Ein Zeiger auf eine Variable vom Typ
NUSE_TASK , die den Index der ersten angehaltenen Aufgabe übernimmt (nichts wird zurückgegeben, wenn die Unterstützung für angehaltene Aufgaben deaktiviert ist).
Rückgabewert:
NUSE_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NUSE_INVALID_SEMAPHORE - ungültiger Semaphorindex;
NUSE_INVALID_POINTER - Ein oder mehrere
Zeigerparameter sind falsch.
Implementieren von Semaphorinformationen in Nucleus SEDie Implementierung dieses API-Aufrufs ist ziemlich 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 Status des Semaphors zurück. Wenn dann die API-Aufrufblockierungsfunktion aktiviert ist, werden die Anzahl der ausstehenden Aufgaben und der Index der ersten zurückgegeben (andernfalls werden diese Parameter auf 0 gesetzt).
Ermitteln der Anzahl der Semaphoren
Dieser Dienstprogrammaufruf gibt die Anzahl der Semaphoren in der Anwendung zurück. In Nucleus RTOS ändert sich dieser Wert im Laufe der Zeit und der Rückgabewert entspricht der aktuellen Anzahl von Semaphoren. In Nucleus SE wird der Rückgabewert in der Montagephase festgelegt und ändert sich nicht mehr.
Aufrufen eines Semaphorzählers in Nucleus RTOSPrototyp eines Serviceabrufs:
UNSIGNED NU_Established_Semaphores (VOID);Parameter:
Sind abwesend.
Rückgabewert:
Die Anzahl der in der Anwendung erstellten Semaphoren.
Aufrufen eines Semaphorzählers in Nucleus SEDieser API-Aufruf unterstützt die Kernfunktionalität der Nucleus RTOS-API.
Prototyp eines Serviceabrufs:
U8 NUSE_Semaphore_Count (void);Parameter:
Sind abwesend.
Rückgabewert:
Die Anzahl der in der Anwendung konfigurierten Semaphoren.
Implementierung von Semaphorzählern in Nucleus SEDie Implementierung dieses API-Aufrufs ist recht einfach: Der Wert des Symbols
#define NUSE_SEMAPHORE_NUMBER wird
zurückgegeben .
Datenstrukturen
Semaphoren verwenden zwei oder drei Arrays von Datenstrukturen (in RAM und ROM), die wie alle anderen Nucleus SE-Objekte eine Reihe 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 keinen direkten Zugriff auf diese Datenstrukturen verwendet, sondern über die bereitgestellten API-Funktionen auf sie verweist. Dies vermeidet Inkompatibilität mit zukünftigen Versionen von Nucleus SE und unerwünschte Nebenwirkungen und vereinfacht die Portierung der Anwendung auf Nucleus RTOS. Zum besseren Verständnis der Funktionsweise des Serviceabrufcodes und zum Debuggen wird im Folgenden eine detaillierte Übersicht über die Datenstrukturen gegeben.
RAM-Daten
Diese Daten haben folgende Struktur:
NUSE_Semaphore_Counter [] - Ein Array vom Typ
U8 , das für jedes konfigurierte Semaphor einen Eintrag enthält und den Wert des Zählers speichert.
NUSE_Semaphore_Blocking_Count [] - Ein Array vom Typ
U8 enthält Zähler für Aufgaben, die auf jedem Semaphor blockiert sind. Dieses Array ist nur vorhanden, wenn die API-Aufrufblockierungsfunktion aktiviert ist.
NUSE_Semaphore_Counter [] wird auf den Anfangswert initialisiert (siehe "Daten im ROM" unten), und
NUSE_Semaphore_Blocking_Count [] wird beim Start von Nucleus SE mit
NUSE_Init_Semaphore () zurückgesetzt . Einer der folgenden Artikel enthält eine vollständige Beschreibung der Startvorgänge 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
ROM-Daten
Datenstruktur:
NUSE_Semaphore_Initial_Value [] - Ein Array vom Typ
U8 mit einem Datensatz für jedes Semaphor. Dies sind die Anfangswerte der Semaphoren.
Diese Datenstruktur wird in
nuse_config.c deklariert und (statisch)
initialisiert :
ROM U8 NUSE_Semaphore_Initial_Value[NUSE_SEMAPHORE_NUMBER] = { /* semaphore initial count values */ };
Die Speichermenge für Semaphoren
Wie bei allen Nucleus SE-Kernelobjekten ist die für Semaphoren benötigte Datenmenge vorhersehbar.
Die Speichermenge im ROM (in Byte) für alle Semaphoren in der Anwendung beträgt
NUSE_SEMAPHORE_NUMBER .
Die Speichermenge im RAM (in Byte) für alle Semaphore in der Anwendung mit aktivierten Aufrufen der Sperr-API kann wie folgt berechnet werden:
NUSE_SEMAPHORE_NUMBER * 2
Andernfalls ist es
NUSE_SEMAPHORE_NUMBER .
Nicht realisierte API-Aufrufe
Drei API-Aufrufe für Semaphoren, die in Nucleus RTOS vorhanden sind, sind in Nucleus SE nicht implementiert.
Semaphore erstellen
Dieser API-Aufruf erstellt ein Semaphor. Nucleus SE ist nicht erforderlich, da Semaphoren statisch erstellt werden.
Prototyp eines Serviceabrufs:
STATUS NU_Create_Semaphore (NU_SEMAPHORE * -Semaphor, CHAR * -Name, UNSIGNED initial_count, OPTION suspend_type);Parameter:
Semaphor - ein Zeiger auf einen vom Benutzer bereitgestellten Semaphor-Steuerblock, der zum Steuern von Semaphoren in anderen API-Aufrufen verwendet wird;
name - ein Zeiger auf den 8-stelligen Semaphornamen mit dem abschließenden Nullbyte;
initial_count - der Anfangswert des Semaphors;
suspend_type - Gibt das Prinzip an, eine Aufgabe auf einem Semaphor
anzuhalten . Es kann die Werte
NU_FIFO und
NU_PRIORITY annehmen , die dem FIFO-Prinzip (First-in-First-Out) und der Prioritätsreihenfolge der Aussetzung von Aufgaben entsprechen.
Rückgabewert:
NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_INVALID_SEMAPHORE -
Gibt an, dass der Zeiger auf den Semaphor-Steuerblock
NULL ist oder bereits verwendet wird.
NU_INVALID_SUSPEND - ungültiger
suspend_type- Parameter.
Semaphorentfernung
Dieser API-Aufruf entfernt das zuvor erstellte Semaphor. Nucleus SE wird nicht benötigt, da Semaphoren statisch erstellt werden und nicht gelöscht werden können.
Prototyp eines Serviceabrufs:
STATUS NU_Delete_Semaphore (NU_SEMAPHORE * -Semaphor);Parameter:
Semaphor - Zeiger auf den Semaphor-Steuerblock.
Rückgabewert:
NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_INVALID_SEMAPHORE -
Ungültiger Semaphorzeiger.
Zeiger auf Semaphoren
Dieser API-Aufruf bildet eine sequentielle Liste von Zeigern auf alle Semaphoren im System. Nucleus SE wird nicht benötigt, da Semaphoren durch einen einfachen Index und nicht durch einen Zeiger identifiziert werden.
Prototyp eines Serviceabrufs:
UNSIGNED NU_Semaphore_Pointers (NU_SEMAPHORE ** Zeigerliste, 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.
Nucleus RTOS-kompatibel
Wie bei allen anderen Nucleus SE-Objekten bestand das Ziel darin, die Kompatibilität des Anwendungscodes mit Nucleus RTOS zu maximieren. Semaphoren sind keine Ausnahme und werden aus Anwendersicht auf die gleiche Weise wie in Nucleus RTOS implementiert. Es gibt auch eine gewisse Inkompatibilität, die ich als akzeptabel angesehen habe, da der endgültige Code in Bezug auf die erforderliche Speichermenge verständlicher und effizienter wird. Andernfalls können Nucleus RTOS-API-Aufrufe fast direkt als Nucleus SE-Aufrufe verwendet werden.
Objektkennungen
In Nucleus RTOS werden alle Objekte durch Datenstrukturen (Steuereinheiten) eines bestimmten Typs beschrieben. Ein Zeiger auf diese Steuereinheit dient als Kennung für das Semaphor. Ich entschied, dass in Nucleus SE ein anderer Ansatz für die effiziente Nutzung des Speichers erforderlich ist: 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 Kennung eines bestimmten Objekts ist der Index in dieser Tabelle. Also habe ich
NUSE_SEMAPHORE als das Äquivalent von
U8 definiert . Eine Variable (kein Zeiger) dieses Typs dient als Kennung für das Semaphor. Diese leichte Inkompatibilität ist leicht zu handhaben, wenn der Code von Nucleus SE nach Nucleus RTOS und umgekehrt portiert wird. In der Regel werden keine anderen Operationen an Objektkennungen als Verschieben und Speichern ausgeführt.
Nucleus RTOS unterstützt auch die Benennung von Semaphoren. Diese Namen werden nur zum Debuggen verwendet. Ich habe sie von Nucleus SE ausgeschlossen, um Speicherplatz zu sparen.
Zählergröße
Unter Nucleus RTOS ist der Semaphorzähler vom Typ
ohne Vorzeichen , bei dem es sich normalerweise um eine 32-Bit-Variable handelt. Nucleus SE verfügt über einen 8-Bit-Zähler, der jedoch leicht geändert werden kann. Normalerweise prüft Nucleus RTOS nicht, ob ein Semaphor überläuft. Durch Aufrufen der Nucleus SE-API können dem Zähler keine Werte über 255 zugewiesen werden.
Nicht realisierte API-Aufrufe
Nucleus RTOS unterstützt acht Dienstprogrammaufrufe für die Arbeit mit Semaphoren. Von diesen sind drei in Nucleus SE nicht implementiert. Die Details dieser Herausforderungen sowie die Entscheidung, sie von Nucleus SE auszuschließen, wurden oben beschrieben.
Der folgende Artikel untersucht Postfächer.
Über den Autor: Colin Walls ist seit über dreißig Jahren in der Elektronikindustrie tätig und widmet sich die meiste Zeit der Firmware. Heute ist er Firmware-Ingenieur bei Mentor Embedded (einer Abteilung von Mentor Graphics). Colin Walls spricht häufig auf Konferenzen und Seminaren, Autor zahlreicher technischer Artikel und zweier Bücher über Firmware. Lebt in Großbritannien.
Colins professioneller
Blog , E-Mail: colin_walls@mentor.com.