Forum: Projekte & Code Multithreading-OS für AVRs


von Mark .. (mork)


Lesenswert?

Hallo,

möchte euch hier mein Betriebssystem für AVRs (momentan ATmega32) 
vorstellen.

Es kann
- Multithreading
- Prozesssynchronisation mit Mutex
- verschiedene Timerfunktionen
- FIFOs

Das OS ist an Win32 angelehnt und hat auch entsprechend ähnlich 
klingende Funktionsnamen. Die Threads können dynamisch erstellt und 
beendet werden, man kann auf Threads warten und mit Mutex verwendete 
Ressourcen blockieren/freigeben. Zusätlich sind ein einfaches 
Massage-Event-System und dynamische 10-ms Timer implementiert.

Im Zip-Ordner befindet sich zusätzlich ein Bespiel, welches die 
Funktionen des OS demonstriert und sich mit einem ATmega32 mit RS232 
(z.b. Pollin Evaluation Board) ausprobieren lässt.

Vor der Verwendung bitte die readme.txt lesen.

MfG Mark

von Gast (Gast)


Lesenswert?

Da fehlt noch der Anhang.
Klassiker ;-)

von Mark .. (mork)


Angehängte Dateien:

Lesenswert?

Hm, ich wusste doch, dass ich igendwas vergessen habe :).
Danke für den Hinweis.

von Gast (Gast)


Lesenswert?

Moin,

... und wo ist die Multithreading fähige C-Laufzeitbibliothek

MfG

von Mark .. (mork)


Lesenswert?

Was verstehst Du unter Laufzeitbibliothek? Da der AVR architekturbedingt 
nur einen Prozess (Prozess != Thread) ausführen kann, macht so etwas wie 
eine Laufzeitbibliothek keinen Sinn.

von Stefan E. (sternst)


Lesenswert?

Mark P. wrote:
> Was verstehst Du unter Laufzeitbibliothek?

Schlag es nach. Das ist kein Begriff, bei dem es einen sonderlich großen 
"was verstehst du darunter"-Spielraum gibt.

> Da der AVR architekturbedingt
> nur einen Prozess (Prozess != Thread) ausführen kann, macht so etwas wie
> eine Laufzeitbibliothek keinen Sinn.

Sorry, aber das ist schlicht Unsinn.

Worauf Gast hinaus wollte, ist, dass die AVR-Libc nicht unbedingt mit 
dem Hintergedanken Multithreading-OS entwickelt wurde. Die eine oder 
andere Funktion darin ist nicht reentrant.

von Mark .. (mork)


Lesenswert?

@ Stefan
Dann hab ich wohl etwas falsch verstanden. Eine Laufzeitbibliothek ist 
für mich eine Lib, die von mehreren Prozessen, die nichts von einander 
wissen, benutzt weden kann um Platz zu sparen, weil dann gleicher Code 
nicht mehrmals vorhanden sein muss. Der AVR kann aber keine unabhängigen 
Prozesse ausführen, da er weder eine MMU hat, noch Code aus dem RAM 
ausführen kann.

Dass die avr-libc nicht unbedingt thread-save ist, ist mir klar. Das ist 
aber bei Verwendung von Interrupts dann genauso, dass der Anwender bei 
"gefährdeten" Funkionen genauer hinschauen muss. Und bei meinem OS gibt 
es Funktionen, die einen Thread blockieren, so dass er nicht von anderen 
unterbrochen werden kann. Eine spezielle c-lib wird deshalb meiner 
Mainung nach nicht benötigt.

MfG Mark

von Stefan E. (sternst)


Lesenswert?

Mark P. wrote:

> Dann hab ich wohl etwas falsch verstanden.

Ja, hast du.
Schlag den Begriff einfach nach (z.B. bei Wikipedia).

> Der AVR kann aber keine unabhängigen
> Prozesse ausführen, da er weder eine MMU hat, noch Code aus dem RAM
> ausführen kann.

Beides sind keine Ausschlusskriterien für "unabhängige Prozesse".

> Dass die avr-libc nicht unbedingt thread-save ist, ist mir klar. Das ist
> aber bei Verwendung von Interrupts dann genauso, dass der Anwender bei
> "gefährdeten" Funkionen genauer hinschauen muss.

Ja, aber bei der Verwendung von Threads rückt das Problem deutlich 
stärker in den Vordergrund.

> Und bei meinem OS gibt
> es Funktionen, die einen Thread blockieren, so dass er nicht von anderen
> unterbrochen werden kann. Eine spezielle c-lib wird deshalb meiner
> Mainung nach nicht benötigt.

"Nötig" nicht (sagt ja auch keiner), aber eine Lib mit threadsicheren 
Varianten der Funktionen (eben unter Zuhilfenahme der vom OS angebotenen 
Funktionalität) wäre nicht unbedingt eine überflüssige Zugabe.

von Harald F. (snuggles)


Lesenswert?

Hört sich sehr interessant an. Deine Implementierung werd ich mir mal 
anschauen. Ich hatte vor ein paar Tagen selbst ein bischen Assemblercode 
geposted (siehe 'multithreading auf dem AVR') der es erlaubt genau einen 
weiteren Thread aufzumachen. Mein Gedanke war, das ganze so klein wie 
möglich zu halten. Immerhin braucht ja jeder Thread seinen eigenen Stack 
Space und zusammen mit z.B. einem Ethernet Device Driver + TCP/IP Stack 
+ Webserver wird es ja dann irgendwann schon ein bischen eng bez. RAM.
Mich interressiert vor allem, wie du das ganze pop/push aller Register 
beim Thread Wechsel gelößt hast...

von Mark .. (mork)


Lesenswert?

@Stefan
Ok ok hab mir die Definition von Laufzeitbibliothek nochmal genau 
angeguckt und Du hattest da recht. Ich hab es mit einer dynamischen 
Bibliothek verwechelt.

>> Der AVR kann aber keine unabhängigen
>> Prozesse ausführen, da er weder eine MMU hat, noch Code aus dem RAM
>> ausführen kann.

>Beides sind keine Ausschlusskriterien für "unabhängige Prozesse".

Man könnte natürlich einen Compiler+Linker bauen, der Code für den AVR 
erzeugt, bei dem sowohl das text- als auch das data-Segment zur Laufzeit 
beliebig verschoben werden könnten. Mit dem normalen avr-gcc geht das 
aber nicht, weder das eine noch das andere.

>> Dass die avr-libc nicht unbedingt thread-save ist, ist mir klar. Das ist
>> aber bei Verwendung von Interrupts dann genauso, dass der Anwender bei
>> "gefährdeten" Funkionen genauer hinschauen muss.

>Ja, aber bei der Verwendung von Threads rückt das Problem deutlich
>stärker in den Vordergrund.

>> Und bei meinem OS gibt
>> es Funktionen, die einen Thread blockieren, so dass er nicht von anderen
>> unterbrochen werden kann. Eine spezielle c-lib wird deshalb meiner
>> Mainung nach nicht benötigt.

>"Nötig" nicht (sagt ja auch keiner), aber eine Lib mit threadsicheren
>Varianten der Funktionen (eben unter Zuhilfenahme der vom OS angebotenen
>Funktionalität) wäre nicht unbedingt eine überflüssige Zugabe.

Mein OS war nicht dazu gedacht, um einen PC durch einen AVR ersetzen zu 
können, sondern ist nur deswegen entstanden, weil man mit Threads 
gewisse Sachen einfacher bzw. schneller lösen kann als ohne. Deshalb 
bein ich persönlich der Meinung, dass eine extra angepasste C-Bibliothek 
komplett oversized wäre.

MfG Mark

von Mark .. (mork)


Lesenswert?

@Harald

Ich hab mir mal Deinen Code angeschaut, und im Prinzip macht es das 
selbe wie meiner, nur dass bei mir der nächste Thread aus einem 
Ringbuffer ausgelesen wird.

>Mich interressiert vor allem, wie du das ganze pop/push aller Register
>beim Thread Wechsel gelößt hast...

Genauso wie Du, sprich es werden alle Register gepusht, der SP 
gewechselt und alle Register wieder gepoppt. Hab das mal nechgerechnet, 
bei 1000Hz Threadwechsel @16MHz sind es etwa 1.1% Rechenleistung. Geht 
eben nicht anders.

MfG Mark

von Stefan E. (sternst)


Lesenswert?

Mark P. wrote:

> Man könnte natürlich einen Compiler+Linker bauen, der Code für den AVR
> erzeugt, bei dem sowohl das text- als auch das data-Segment zur Laufzeit
> beliebig verschoben werden könnten. Mit dem normalen avr-gcc geht das
> aber nicht, weder das eine noch das andere.

text-Segment zur Laufzeit verschieben:
Unnötig.

data-Segment zur Laufzeit verschieben:
Umkopieren des Speichers, was vom OS beim Prozesswechsel zu erledigen 
wäre.

Startupcode und Linkerscript wären zu ändern, aber mit dem Compiler an 
sich hat das alles nichts zu tun. Auch mit dem avr-gcc in seiner 
jetzigen Form wäre ein OS mit "unabhängigen Prozessen" machbar. 
Natürlich wäre das weit entfernt von "effizient" oder "sinnvoll", aber 
prinzipiell machbar wäre es schon.

> Mein OS war nicht dazu gedacht, um einen PC durch einen AVR ersetzen zu
> können, sondern ist nur deswegen entstanden, weil man mit Threads
> gewisse Sachen einfacher bzw. schneller lösen kann als ohne.

Wass soll das denn jetzt mit dem Vergleich zum PC?
Wie ich bereits sagte, ist es natürlich nicht absolut nötig, aber es 
wäre auch alles andere als "oversized" oder "überflüssiger Luxus", wenn 
man z.B. eine malloc-Variante anbieten würde, die einfach das vorhandene 
malloc im Rahmen der OS-Möglichkeiten kapselt.

von Mark .. (mork)


Lesenswert?

@Stefan

>text-Segment zur Laufzeit verschieben:
>Unnötig.

Und wie soll das gehen? Wenn auf einem Controller ohne MMU zwei Prozesse 
laufen sollen, die nichts von einander wissen, dann bedeutet es, dass 
sie sich an verschiedenen Stellen im Speicher befinden. Da der Compiler 
aber nicht zu compile-Zeit weiss, wo sich die erstellte Anwendung im 
Flash befinden wird, muss er den Code so schreiben, dass er von jedem 
Ort aus lauffähig wär. Und das kann_ der normale avr-gcc _nicht.

>data-Segment zur Laufzeit verschieben:
>Umkopieren des Speichers, was vom OS beim Prozesswechsel zu erledigen
>wäre.

Sollen da bei jedem einzelnen Prozesswechsel Kilobytes an Speicher 
bewegt werden oder wie stellst Du Dir das vor?

>Wass soll das denn jetzt mit dem Vergleich zum PC?

Das war eine sehr starke Übertreibung, um mein Anliegen zu 
verdeutlichen.

>Wie ich bereits sagte, ist es natürlich nicht absolut nötig, aber es
>wäre auch alles andere als "oversized" oder "überflüssiger Luxus", wenn
>man z.B. eine malloc-Variante anbieten würde, die einfach das vorhandene
>malloc im Rahmen der OS-Möglichkeiten kapselt.

Finde ich nicht. Wenn Du solche Funktionen haben willst, kannst Du sie 
ja gerne schreiben. Ich benutze das OS seit ein paar Monaten (kein allzu 
langer Zeitraum, ich weiss) und hab sowas noch nie benötigt.

MfG Mark

von Stefan E. (sternst)


Lesenswert?

Mark P. wrote:

> Und wie soll das gehen? Wenn auf einem Controller ohne MMU zwei Prozesse
> laufen sollen, die nichts von einander wissen, dann bedeutet es, dass
> sie sich an verschiedenen Stellen im Speicher befinden. Da der Compiler
> aber nicht zu compile-Zeit weiss, wo sich die erstellte Anwendung im
> Flash befinden wird, muss er den Code so schreiben, dass er von jedem
> Ort aus lauffähig wär. Und das kann_ der normale avr-gcc _nicht.

Totaler Quatsch. Auch jetzt weiß der Compiler nicht, wo im Flash der 
Code letztlich landen wird. Schlag mal nach, was der Linker ist und 
macht.

> Sollen da bei jedem einzelnen Prozesswechsel Kilobytes an Speicher
> bewegt werden oder wie stellst Du Dir das vor?

Ja natürlich. Was meinst du, wie es ein "richtiges" Multitasking-BS (wie 
z.B. Linux) auf einem Prozessor ohne MMU (z.B. 68000) macht?
Außerdem sagte ich ja bereits, dass es ineffizient ist. Es geht ja auch 
nur ums Prinzipielle, schließlich hast du behauptet, dass es 
grundsätzlich nicht gehen würde.

von Mark .. (mork)


Lesenswert?

@Stefan

>Totaler Quatsch. Auch jetzt weiß der Compiler nicht, wo im Flash der
>Code letztlich landen wird. Schlag mal nach, was der Linker ist und
>macht.

Dann weiss es eben der Linker. Und dieser muss nun mal z.B. beim 
jmp-Befehl die Labels in absolute Adressen auflösen können. Und das ist 
der Knackpunkt.

>Ja natürlich. Was meinst du, wie es ein "richtiges" Multitasking-BS (wie
>z.B. Linux) auf einem Prozessor ohne MMU (z.B. 68000) macht?
>Außerdem sagte ich ja bereits, dass es ineffizient ist. Es geht ja auch
>nur ums Prinzipielle, schließlich hast du behauptet, dass es
>grundsätzlich nicht gehen würde.

Das bei z.B. µCLinux bei jedem Prozesswechsel das ganze data-Segment, 
welches durchaus einige MB haben kann, umkopiert, wird glaube ich nicht. 
Ich weiss zwar nicht wie es gemacht wird, aber ich vermute, dass das OS 
dem Prozess beim Start das Offset des data-Segments übergibt, sodass der 
Prozess auf globale Variablen immer über dieses Offset zugreift.

MfG Mark

von Benedikt K. (benedikt)


Lesenswert?

Da der Thread sowieso schon stark off topic ist, mal eine eher 
allgemeine Frage zum Multithreading auf AVRs:
Wie sieht das eigentlich bei 16bit Zugriffen auf Register aus? Diese 
benutzen doch dieses interne Highbyte Register. Wenn genau zwischen dem 
Zugriff auf die beiden High/Low Register umgeschaltet wird, und der 
andere Thread auch ein 16bit Register liest oder schreibt, dürfte im 
ersten Thread Mist rauskommen, da der alter Wert in dem Highbyte 
Register dann überschrieben ist. Oder sehe ich das falsch?

von Mark .. (mork)


Lesenswert?

@ Benedikt

Du siehst es richtig. Deshalb sollte man den Zugriff auf Ressourcen, die 
von mehreren Threads verwendet werden, mit Mutex regeln oder bei kurzen 
Zugriffen die Interrupts abschalten. Um zu vermeiden, dass ein Thread 
über einen längeren Zeitraum nicht von einem anderen Thread unterbrochen 
werden darf, aber die Interrupts trotzdem aktiviert bleiben sollen, gibt 
es bei meinem OS extra Funktionen, die das regeln.

MfG Mark

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.