Die ganze Wahrheit über RTOS. Artikel # 14. Speicherbereiche: Einführung und Grundversorgung



Speicherabschnitte wurden bereits in einem der vorherigen Artikel (Nr. 6) erwähnt, in denen ein Vergleich mit der Standardfunktion der Sprache C malloc () durchgeführt wurde . Eine Partition ist ein Speicherbereich, der aus einem Partitionspool (Speicherpool) abgerufen wird. Die gemeinsame Nutzung von Speicher bietet eine flexible Möglichkeit, Speicher zuverlässig und deterministisch zuzuweisen und freizugeben.

Frühere Artikel in der Reihe:
Artikel Nr. 13. Aufgabendatenstrukturen und nicht unterstützte API-Aufrufe
Artikel 12. Dienstleistungen für die Arbeit mit Aufgaben
Artikel 11. Aufgaben: Konfiguration und Einführung in die API
Artikel 10. Scheduler: Erweiterte Funktionen und Kontexterhaltung
Artikel 9. Scheduler: Implementierung
Artikel 8. Nucleus SE: Internes Design und Bereitstellung
Artikel 7. Nucleus SE: Einführung
Artikel 6. Andere RTOS-Dienste
Artikel 5. Aufgabeninteraktion und Synchronisation
Artikel 4. Aufgaben, Kontextwechsel und Interrupts
Artikel 3. Aufgaben und Planung
Artikel 2. RTOS: Struktur und Echtzeitmodus
Artikel 1. RTOS: Einführung.

Abschnitte verwenden


In Nucleus SE werden Partitionspools zur Erstellungszeit konfiguriert. Eine einzelne Anwendung kann bis zu 16 Partitionspools haben. Wenn sie nicht konfiguriert sind, werden Datenstrukturen und Serviceaufrufe, die sich auf diese Pools beziehen, nicht in die Anwendung aufgenommen.

Ein Partitionspool ist ein Speicherbereich, der in eine bestimmte Anzahl von Blöcken fester Größe unterteilt ist. Der Entwickler kontrolliert die Größe und Anzahl der Partitionen in jedem Pool vollständig. Aufgaben können zugewiesene Speicherabschnitte anfordern und einen Zeiger auf den Speicherbereich empfangen und sollten keine Daten außerhalb des zugewiesenen Abschnitts schreiben. Ein Abschnitt kann von jeder Aufgabe freigegeben werden, wenn ein Zeiger auf eine API-Funktion übergeben wird. Eine Anforderung zum Zuweisen einer Partition, wenn keine freien Partitionen vorhanden sind, kann abhängig von den ausgewählten API-Aufrufparametern und der Nucleus SE-Konfiguration zu einem Fehler oder einer Unterbrechung der Anforderung führen.

Speicherpartitionen einrichten


Anzahl der Partitionspools


Wie bei den meisten Nucleus SE-Objekten erfolgt die Konfiguration des Partitionspools hauptsächlich mithilfe der Direktive #define in nuse_config.h . Der Hauptparameter ist NUSE_PARTITION_POOL_NUMBER , der bestimmt, wie viele Partitionspools in der Anwendung definiert sind. Der Standardwert ist 0 ( dh Partitionspools werden nicht verwendet). Der Entwickler kann einen beliebigen Wert zwischen 0 und 16 festlegen. Andere Werte führen zu einem Kompilierungsfehler, der bei der Überprüfung in nuse_config_check.h festgestellt wurde (er ist in nuse_config.c und enthalten) wird daher mit diesem Modul kompiliert), was zur Kompilierung der Direktive #error führt .

Die Auswahl eines Werts ungleich Null ist eine vorrangige Methode zum Aktivieren von Partitionspools. Dies führt zur Definition von Datenstrukturen und zur Zuordnung der entsprechenden Größe. Die Datenstrukturen im ROM müssen mit den entsprechenden Werten initialisiert werden, die jeden Partitionspool beschreiben. Weitere Details zu Datenstrukturen finden Sie im nächsten Artikel. Diese Auswahl aktiviert auch die API-Einstellungen.

API-Aufrufe aktivieren


Jede API-Funktion (Dienstprogrammaufruf) in Nucleus SE wird durch die Direktive #define in nuse_config.h aktiviert. Zu Partitionspools gehören:

NUSE_PARTITION_ALLOCATE
NUSE_PARTITION_DEALLOCATE
NUSE_PARTITION_POOL_INFORMATION
NUSE_PARTITION_POOL_COUNT

Standardmäßig sind alle auf FALSE eingestellt , wodurch jeder Serviceabruf deaktiviert und die Aufnahme eines Implementierungscodes verhindert wird. Um die Partitionspools in der Anwendung zu konfigurieren, müssen Sie die erforderlichen API-Aufrufe auswählen und die entsprechenden Anweisungen auf TRUE setzen .

Das Folgende ist ein Auszug aus der Standarddatei nuse_config.h :



Wenn die API-Funktion Partition Pools aktiviert ist, die Pools jedoch nicht konfiguriert sind, tritt ein Kompilierungsfehler auf (mit Ausnahme von NUSE_Partition_Pool_Count () , das immer aktiviert ist). Wenn Ihr Code einen API-Aufruf verwendet, der nicht aktiviert wurde, tritt ein Layoutfehler auf, da der Implementierungscode nicht in der Anwendung enthalten war.

Partition Pool Utility-Aufrufe


Nucleus RTOS unterstützt sieben Dienstprogrammaufrufe für Partitionspools, die die folgenden Funktionen bieten:

FunktionsbeschreibungNucleus RTOSNucleus SE
AbschnittsauswahlNU_Allocate_Partition ()NUSE_Partition_Allocate ()
AbschnittsfreigabeNU_Deallocate_Partition ()NUSE_Partition_Deallocate ()
Bereitstellung von Informationen
über einen bestimmten Partitionspool
NU_Partition_Pool_Information ()NUSE_Partition_Pool_Information ()
Gibt den Wert der (aktuell) konfigurierten Menge zurück
Anwendungspools
NU_Established_Partition_Pools ()NUSE_Partition_Pool_Count ()
Hinzufügen (Erstellen) eines neuen Partitionspools zur AnwendungNU_Create_Partition_Pool ()Nicht implementiert.
Ändern (Löschen) eines Partitionspools aus einer AnwendungNU_Delete_Partition_Pool ()Nicht implementiert.
Rückgabe von Zeigern auf alle derzeit in der Anwendung vorhandenen PartitionspoolsNU_Partition_Pool_Pointers ()Nicht implementiert.

Die Implementierung jedes Aufrufs wird ausführlich besprochen.

Es ist erwähnenswert, dass weder Nucleus RTOS noch Nucleus SE eine Neustartfunktion haben. Dies geschieht absichtlich. Sehr oft weist eine Aufgabe einen Abschnitt zu und übergibt einen Zeiger auf eine andere Aufgabe (die ihn möglicherweise später freigibt). Wenn Sie den Partitionspool neu laden, werden alle Partitionen als nicht verwendet markiert. Es gibt jedoch keinen Mechanismus zum Überwachen und Benachrichtigen aller Aufgaben, die Partitionen verwenden können.

Partitions- und Release-Services


Die grundlegenden Operationen mit Partitionspools sind die Zuweisung von Partitionen im Pool (d. H. Markieren der Partition als verwendet und Zurückgeben ihrer Adresse) und Freigeben der Partition (d. H. Die Partition wird als nicht verwendet markiert). Nucleus RTOS und Nucleus SE bieten zwei grundlegende API-Aufrufe für diese Vorgänge, die im Folgenden beschrieben werden.

Abschnittsauswahl


Das Aufrufen der Nucleus RTOS-API zum Zuweisen einer Partition ist sehr flexibel. Dadurch können Entwickler Aufgaben auf unbestimmte Zeit oder ohne Zeitüberschreitung anhalten, wenn der Vorgang nicht sofort abgeschlossen werden kann, z. B. wenn Sie versuchen, eine Partition aus einem Pool zuzuweisen, in dem alle Partitionen bereits verteilt sind. Nucleus SE bietet denselben Service, nur das Anhalten von Aufgaben ist optional, und eine Zeitüberschreitung ist nicht implementiert.

Aufruf der Nucleus RTOS-API zur Partition


Prototyp aufrufen:

STATUS NU_Allocate_Partition (NU_PARTITION_POOL * -Pool, VOID ** return_pointer, UNSIGNED suspend);

Rückgabewert:

NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_NO_PARTITION - Es sind keine Abschnitte verfügbar.
NU_INVALID_POOL - ungültiger Partitionspoolzeiger;
NU_INVALID_POINTER - hat einen Nullzeiger auf die zurückgegebenen Daten übergeben ( NULL );
NU_INVALID_SUSPEND - Es wurde versucht, eine Aufgabe von einem Thread aus anzuhalten , der der Aufgabe nicht zugeordnet ist.
NU_TIMEOUT - Auch nach dem Anhalten für die angegebene Wartezeit sind keine Partitionen verfügbar.
NU_POOL_DELETED - Der Partitionspool wurde gelöscht, als die Aufgabe angehalten wurde.

Nucleus SE-API-Aufruf zum Hervorheben einer Partition


Dieser API-Aufruf unterstützt die Kernfunktionalität der Nucleus RTOS-API.

Prototyp aufrufen:

STATUS NUSE_Partition_Allocate (Pool NUSE_PARTITION_POOL, ADDR * return_pointer, U8 suspend);

Parameter:

Pool - Index (ID) des verwendeten Partitionspools;
return_pointer - Zeiger auf eine Variable vom Typ ADDR , die die Adresse des ausgewählten Abschnitts übernimmt;
suspend - Parameter zum Anhalten der Aufgabe, der die Werte NUSE_NO_SUSPEND oder NUSE_SUSPEND annehmen kann .

Rückgabewert:

NUSE_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NUSE_NO_PARTITION - Es sind keine Abschnitte verfügbar.
NUSE_INVALID_POOL - ungültiger Partitionspoolindex;
NUSE_INVALID_POINTER - hat einen Nullzeiger auf die zurückgegebenen Daten übergeben ( NULL );
NUSE_INVALID_SUSPEND - Ein Versuch, eine Aufgabe anzuhalten , wurde von einem Thread aus durchgeführt, der der Aufgabe nicht zugeordnet war oder als die Sperr-APIs deaktiviert waren.

Implementierung der Partitionszuweisung in Nucleus SE


Der API-Funktionscode NUSE_Partition_Allocate wird nach Überprüfung der Parameter mithilfe der bedingten Kompilierung ausgewählt, je nachdem, ob der API-Aufruf zum Blockieren (Anhalten von Aufgaben) aktiviert ist oder nicht. Im Folgenden werden diese beiden Optionen separat betrachtet.

Wenn blockierende Aufrufe deaktiviert sind, ist der API-Aufruf ziemlich einfach:



Zunächst wird die Verfügbarkeit freier Partitionen überprüft. Wenn keine solchen Partitionen vorhanden sind, wird ein Fehler zurückgegeben ( NUSE_NO_PARTITION ). Dann gibt es eine Aufzählung von Abschnitten, bei der die ersten Bytes auf Nullwerte überprüft werden (was anzeigt, dass der Abschnitt nicht verwendet wird). Wenn eine solche Partition gefunden wird, wird ihr das Flag "used" zugewiesen, das den Index des Partitionspools enthält (siehe "Partition freigeben" weiter unten), und es wird ein Zeiger auf das nächste Byte (den Anfang des realen Datenbereichs) zurückgegeben. Erläuterungen zu den Datenstrukturen der Partitionspools werden im nächsten Artikel im Abschnitt Datenstrukturen vorgestellt.

Wenn die Sperre aktiviert ist, wird der Code für diesen API-Aufruf etwas komplizierter:



Der Code ist in einer do ... while-Schleife eingeschlossen , die so lange ausgeführt wird, wie der pause-Parameter NUSE_SUSPEND lautet .

Wenn keine Partitionen verfügbar sind und der Parameter pause NUSE_NO_SUSPEND lautet , wird der API-Aufruf gestoppt und NUSE_NO_PARTITION zurückgegeben . Wenn der Parameter pause auf NUSE_SUSPEND gesetzt wurde , wird die Task angehalten . Bei der Rückgabe (z. B. wenn eine Aufgabe fortgesetzt wird ) gibt der Rückgabewert von NUSE_SUCCESS an, dass die Aufgabe fortgesetzt wurde, weil der Speicherabschnitt freigegeben wurde und der Code zum Anfang der Schleife zurückkehrt. Da es keine API-Funktionen zum erneuten Laden von Partitionspools gibt, können Aufgaben aus anderen Gründen nicht fortgesetzt werden. Aus Gründen der Stabilität beim Blockieren anderer Objekttypen bleibt der Validierungsprozess NUSE_Task_Blocking_Return [] erhalten.

Abschnittsfreigabe


Die Veröffentlichung des Abschnitts in Nucleus RTOS und Nucleus SE macht ihn wieder verfügbar. Vor der Veröffentlichung wird nicht geprüft, ob dieser Abschnitt von einer Aufgabe verwendet wird oder nicht. Der Anwendungsprogrammierer ist dafür verantwortlich. Zum Freigeben eines Abschnitts ist nur ein Zeiger auf einen Datenbereich erforderlich.

Nucleus RTOS API-Aufruf zur freien Partition


Prototyp aufrufen:

STATUS NU_Deallocate_Partition (VOID * -Partition);

Parameter:

Partition - ein Zeiger auf den Datenbereich (von der Funktion NU_Allocate_Partition () zurückgegeben ) der freizugebenden Partition;

Rückgabewert:

NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_INVALID_POINTER - NULL-Abschnittszeiger oder zeigt keinen gültigen verwendeten Abschnitt an.

Nucleus SE API-Aufruf zur freien Partition


Dieser API-Aufruf unterstützt die Kernfunktionalität der Nucleus RTOS-API.

Prototyp aufrufen:

STATUS NUSE_Partition_Deallocate (ADDR-Partition);

Parameter:

Partition - Ein Zeiger auf den Datenbereich (von der Funktion NUSE_Partition_Allocate () zurückgegeben ) der freizugebenden Partition

Rückgabewert:

NUSE_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NUSE_INVALID_POINTER - Der Abschnittszeiger ist null ( NULL ) oder gibt keinen gültigen verwendeten Abschnitt an

Implementierung


Anstatt die blockierenden und nicht blockierenden API-Funktionen zu implementieren, enthält die Funktion NUSE_Partition_Deallocate () einfach einen bedingt kompilierten Abschnitt, der für das Entsperren von Aufgaben verantwortlich ist. Dieser Code implementiert die Freigabe von Abschnitten:



Zunächst wird der Abschnittsindex aus dem Statusbyte abgerufen. Dann ändert sich der Status der Partition in "nicht verwendet", der Zähler der verwendeten Partitionen nimmt ab und die Funktion meldet den erfolgreichen Abschluss des Vorgangs.

Wenn die Sperre aktiviert ist, wird der folgende Code verwendet, um Aufgaben fortzusetzen, die auf den verfügbaren Partitionspool warten:



Wenn beim Zuweisen von Partitionen in diesem Pool Aufgaben blockiert wurden, wird die erste Tabelle fortgesetzt.

Im nächsten Artikel werden wir über zusätzliche API-Aufrufe in Bezug auf Speicherpartitionen sowie verwandte Datenstrukturen sprechen.

Ü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.

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


All Articles