Frage Erstellen einer Anwendung für den Einsatz in hochradioaktiven Umgebungen


Wir kompilieren eine eingebettete C / C ++ - Anwendung, die in einem abgeschirmten Gerät in einer mit bombardierten Umgebung eingesetzt wird ionisierende Strahlung. Wir verwenden GCC und Cross-Compiling für ARM. Bei der Bereitstellung generiert unsere Anwendung einige fehlerhafte Daten und stürzt öfter ab, als wir möchten. Die Hardware ist auf diese Umgebung ausgelegt und unsere Anwendung läuft seit mehreren Jahren auf dieser Plattform.

Gibt es Änderungen, die wir an unserem Code vornehmen können, oder Kompilierungszeitverbesserungen, die zur Identifizierung / Korrektur vorgenommen werden können? weiche Fehler und Speicher-Korruption verursacht durch einzelne Event-Upsets? Hatten andere Entwickler Erfolg damit, die schädlichen Auswirkungen von Soft Errors auf eine lange laufende Anwendung zu reduzieren?


1278
2018-04-24 19:09


Ursprung


Antworten:


Arbeite seit ca. 4-5 Jahren mit Software / Firmware Entwicklung und Umgebungstests von miniaturisierte Satelliten*, Möchte ich meine Erfahrungen hier teilen.

* (miniaturisierte Satelliten sind aufgrund ihrer relativ kleinen, begrenzten Größen für ihre elektronischen Komponenten viel anfälliger für Einzelereignisse als große Satelliten)

Um sehr kurz und direkt zu sein: Es gibt keinen Mechanismus, von dem man sich erholen kann feststellbar, fehlerhaft   Lage von der Software / Firmware selbst ohne, mindestens ein    Kopieren von Mindestarbeitsversion der Software / Firmware irgendwo zum Wiederherstellung Zweck - und mit dem Hardware, die die Wiederherstellung unterstützt (funktional).

Diese Situation wird normalerweise sowohl auf der Hardware- als auch auf der Softwareebene gehandhabt. Hier, wenn Sie es wünschen, werde ich Ihnen mitteilen, was wir auf der Softwareebene tun können.

  1. ... Wiederherstellungszweck .... Stellen Sie die Fähigkeit zur Verfügung, Ihre Software / Firmware in einer realen Umgebung zu aktualisieren / neu zu kompilieren. Das ist ein fast Must-Have Feature für jede Software / Firmware in hoch ionisierter Umgebung. Ohne das, du könnte Haben Sie so viele Software / Hardware wie Sie wollen, aber irgendwann werden sie alle in die Luft gehen. Also, bereiten Sie diese Funktion vor!

  2. ... minimale Arbeitsversion ... Responsive, mehrere Kopien, mindestens Version der Software / Firmware in Ihrem Code. Dies ist wie abgesicherter Modus in Windows. Anstatt nur eine voll funktionsfähige Version Ihrer Software zu haben, müssen Sie mehrere Kopien der Mindestversion Ihrer Software / Firmware haben. Die minimale Kopie wird normalerweise viel weniger Größe als die vollständige Kopie haben und fast immer haben nur die folgenden zwei oder drei Funktionen:

    1. fähig, Befehl von externem System zu hören,
    2. fähig, die aktuelle Software / Firmware zu aktualisieren,
    3. fähig, die Verwaltungsdaten der Grundoperation zu überwachen.
  3. ... kopiere ... irgendwo ... Habe irgendwo eine redundante Software / Firmware.

    1. Du könntest, mit oder Versuchen Sie, ohne redundante Hardware redundante Software / Firmware in Ihrem ARM-uC zu installieren. Dies geschieht normalerweise durch zwei oder mehr identische Software / Firmware in separaten Adressen die einander einen Herzschlag senden - aber nur einer wird gleichzeitig aktiv sein. Wenn bekannt ist, dass eine oder mehrere Software / Firmware nicht reagiert, wechseln Sie zur anderen Software / Firmware. Der Vorteil dieses Ansatzes besteht darin, dass wir sofort nach Auftreten eines Fehlers einen Funktionsersatz durchführen können - ohne irgendeinen Kontakt mit dem externen System / der Partei, die für die Erkennung und Behebung des Fehlers zuständig ist (im Satellitenfall ist es normalerweise das Mission Control Center). MCC)).

      Streng genommen, ohne redundante Hardware, ist der Nachteil, dass Sie dies tatsächlich tun kann nicht beseitigen alle einzelner Fehlerpunkt. Zumindest werden Sie immer noch haben ein Single Point of Failure, das ist der Schalter selbst (oder oft der Anfang des Codes). Nichtsdestoweniger ist bei einer Vorrichtung, die durch die Größe in einer stark ionisierten Umgebung (wie Pico / Femto-Satelliten) begrenzt ist, die Reduktion des einzelnen Punktes der Ausfälle auf einen Punkt ohne Zusätzliche Hardware wird noch in Betracht gezogen werden. Somemore, der Code für den Wechsel wäre sicherlich viel weniger als der Code für das gesamte Programm - erheblich reduziert das Risiko, Single Event in ihm zu bekommen.

    2. Aber wenn Sie dies nicht tun, sollten Sie mindestens eine Kopie in Ihrem externen System haben, die mit dem Gerät in Kontakt kommen kann und die Software / Firmware aktualisieren kann (im Fall des Satelliten ist es wieder das Missionskontrollzentrum).

    3. Sie können die Kopie auch in Ihrem permanenten Speicher in Ihrem Gerät haben, die ausgelöst werden kann, um die Software / Firmware des laufenden Systems wiederherzustellen
  4. ... erkennbare Fehlsituation. Der Fehler muss sein nachweisbarernormalerweise durch die Hardware Fehlerkorrektur / Erkennungsschaltung oder durch ein kleines Stück Code zur Fehlerkorrektur / Erkennung. Es ist am besten, solchen Code klein, mehrfach und zu setzen unabhängig von der Hauptsoftware / Firmware. Seine Hauptaufgabe ist nur zum Überprüfen / Korrigieren. Wenn die Hardwareschaltung / Firmware ist zuverlässig (Da es strahlungsgehärteter ist als die Pausen - oder mehrere Schaltkreise / Logiken haben), könnten Sie eine Fehlerkorrektur in Betracht ziehen. Aber wenn nicht, ist es besser, es als Fehlererkennung zu machen. Die Korrektur kann durch externes System / Gerät erfolgen. Für die Fehlerkorrektur könnten Sie einen grundlegenden Fehlerkorrekturalgorithmus wie Hamming / Golay23 in Betracht ziehen, da sie einfacher in der Schaltung / Software implementiert werden können. Aber es hängt letztlich von der Fähigkeit Ihres Teams ab. Zur Fehlererkennung wird normalerweise CRC verwendet.

  5. ... Hardware, die die Wiederherstellung unterstützt Jetzt kommt der schwierigste Aspekt zu diesem Thema. Letztlich erfordert die Wiederherstellung die Hardware, die für die Wiederherstellung verantwortlich ist mindestens funktional. Wenn die Hardware dauerhaft defekt ist (normalerweise nach dem Gesamte ionisierende Dosis erreicht ein gewisses Niveau), dann gibt es (leider) keine Möglichkeit, dass die Software bei der Wiederherstellung hilft. Daher ist die Hardware zu Recht von größter Bedeutung für ein Gerät, das einem hohen Strahlungsniveau ausgesetzt ist (z. B. Satellit).

Zusätzlich zu dem obigen Vorschlag, den Fehler der Firmware aufgrund eines einzelnen Ereignisses zu antizipieren, möchte ich Ihnen auch vorschlagen zu haben:

  1. Fehlererkennung und / oder Fehlerkorrekturalgorithmus im Kommunikationsprotokoll zwischen den Subsystemen. Dies ist ein weiteres Muss, um unvollständige / falsche Signale von anderen Systemen zu erhalten

  2. Filter in Ihrem ADC lesen. Machen nicht Verwenden Sie den ADC-Messwert direkt. Filtere es durch Medianfilter, Mittelwertfilter oder andere Filter - noch nie Vertraulichkeit einzelner Lesewerte. Sample mehr, nicht weniger - vernünftig.


729
2018-04-25 02:58



Die NASA hat ein Papier über Strahlung gehärtet Software. Es beschreibt drei Hauptaufgaben:

  1. Regelmäßige Überwachung des Speichers auf Fehler, dann Ausmerzen dieser Fehler,
  2. robuste Fehlerbehebungsmechanismen und
  3. die Fähigkeit, sich neu zu konfigurieren, wenn etwas nicht mehr funktioniert.

Beachten Sie, dass die Speicher-Scan-Rate häufig genug sein sollte, dass Multi-Bit-Fehler am seltensten auftreten ECC Speicher kann sich von Einzelbitfehlern erholen, nicht von Mehrbitfehlern.

Die robuste Fehlerkorrektur umfasst die Übertragung des Steuerungsflusses (in der Regel einen Neustart des Prozesses zu einem Zeitpunkt vor dem Fehler), die Ressourcenfreigabe und die Datenwiederherstellung.

Ihre Hauptempfehlung für die Datenwiederherstellung besteht darin, die Notwendigkeit zu vermeiden, indem Zwischendaten als temporär behandelt werden, so dass ein Neustart vor dem Fehler auch die Daten in einen zuverlässigen Zustand zurückversetzt. Dies klingt ähnlich wie das Konzept von "Transaktionen" in Datenbanken.

Sie diskutieren Techniken, die besonders für objektorientierte Sprachen wie C ++ geeignet sind. Beispielsweise

  1. Software-basierte ECCs für zusammenhängende Speicherobjekte
  2. Programmieren nach VertragVerifizieren von Vorbedingungen und Nachbedingungen, dann Prüfen des Objekts, um zu überprüfen, ob es sich noch in einem gültigen Zustand befindet.

370
2018-04-24 19:32



Hier sind einige Gedanken und Ideen:

Verwenden Sie ROM kreativer.

Speichern Sie alles, was Sie in ROM können. Anstatt Dinge zu berechnen, speichern Sie Look-Up-Tabellen im ROM. (Stellen Sie sicher, dass Ihr Compiler Ihre Nachschlagetabellen an den schreibgeschützten Abschnitt ausgibt! Drucken Sie Speicheradressen zur Laufzeit aus, um sie zu überprüfen!) Speichern Sie Ihre Interrupt-Vektortabelle im ROM. Natürlich, führen Sie einige Tests durch, um zu sehen, wie zuverlässig Ihr ROM mit Ihrem RAM verglichen wird.

Verwenden Sie Ihren besten RAM für den Stapel.

SEUs im Stapel sind wahrscheinlich die wahrscheinlichste Quelle für Abstürze, da dort normalerweise Variablen wie Indexvariablen, Statusvariablen, Rückgabeadressen und Zeiger verschiedener Arten vorkommen.

Implementieren Sie Timer-Tick- und Watchdog-Timer-Routinen.

Sie können bei jedem Timer-Tick eine "Vernunftprüfung" -Routine ausführen sowie eine Überwachungsroutine, um das System zu schützen. Ihr Hauptcode könnte auch periodisch einen Zähler inkrementieren, um den Fortschritt anzuzeigen, und die Routineprüfung könnte sicherstellen, dass dies geschehen ist.

Implementieren Fehlerkorrektur-Codes in Software.

Sie können Ihren Daten Redundanz hinzufügen, um Fehler erkennen und / oder korrigieren zu können. Dies erhöht die Verarbeitungszeit und kann dazu führen, dass der Prozessor längere Zeit der Strahlung ausgesetzt ist. Dadurch erhöht sich die Wahrscheinlichkeit von Fehlern, sodass Sie den Kompromiss in Betracht ziehen müssen.

Erinnere dich an die Caches.

Überprüfen Sie die Größe Ihrer CPU-Caches. Daten, auf die Sie kürzlich zugegriffen oder Änderungen vorgenommen haben, befinden sich wahrscheinlich in einem Cache. Ich glaube, Sie können zumindest einige der Caches deaktivieren (zu einem hohen Preis). Sie sollten dies versuchen, um zu sehen, wie anfällig die Caches für SEUs sind. Wenn die Caches robuster als RAM sind, können Sie kritische Daten regelmäßig lesen und neu schreiben, um sicherzustellen, dass sie im Cache bleiben und den RAM wieder in Einklang bringen.

Verwenden Sie Seitenfehlerhandler geschickt.

Wenn Sie eine Speicherseite als nicht vorhanden markieren, gibt die CPU beim Versuch, auf sie zuzugreifen, einen Seitenfehler aus. Sie können einen Seitenfehler-Handler erstellen, der einige Prüfungen vor der Bearbeitung der Leseanforderung durchführt. (PC-Betriebssysteme verwenden dies, um Seiten transparent zu laden, die auf die Festplatte ausgelagert wurden.)

Verwenden Sie Assembler für kritische Dinge (was alles sein könnte).

Mit Assembler, Sie kennt Was ist in Registern und was ist im RAM? Sie kennt Welche speziellen RAM-Tabellen die CPU verwendet, und Sie können Dinge auf Umwegen entwerfen, um Ihr Risiko gering zu halten.

Benutzen objdump um die generierte Assemblersprache zu betrachten und herauszufinden, wie viel Code jede Ihrer Routinen belegt.

Wenn Sie ein großes Betriebssystem wie Linux verwenden, dann fragen Sie nach Ärger. Es gibt einfach so viel Komplexität und so viele Dinge, die schiefgehen können.

Denken Sie daran, es ist ein Spiel der Wahrscheinlichkeiten.

Ein Kommentator sagte

Jede Routine, die Sie schreiben, um Fehler zu finden, wird davon abhängig gemacht, dass sie sich aus der gleichen Ursache löst.

Während dies wahr ist, ist die Wahrscheinlichkeit von Fehlern in den (etwa) 100 Bytes von Code und Daten, die für eine Prüfroutine erforderlich sind, um korrekt zu funktionieren, viel kleiner als die Wahrscheinlichkeit von Fehlern an anderer Stelle. Wenn dein ROM ziemlich zuverlässig ist und fast alle Codes / Daten tatsächlich in ROM sind, dann sind deine Chancen noch besser.

Verwenden Sie redundante Hardware.

Verwenden Sie 2 oder mehr identische Hardware-Setups mit identischem Code. Wenn sich die Ergebnisse unterscheiden, sollte ein Reset ausgelöst werden. Bei 3 oder mehr Geräten können Sie ein "Abstimmungs" -System verwenden, um zu ermitteln, welches gefährdet ist.


107
2018-04-24 23:11



Vielleicht interessiert Sie auch die reichhaltige Literatur zum Thema algorithmische Fehlertoleranz. Dies schließt die alte Zuweisung ein: Schreibe eine Sortierung, die ihre Eingabe richtig sortiert, wenn eine konstante Anzahl von Vergleichen fehlschlägt (oder die etwas bösere Version, wenn die asymptotische Anzahl von fehlgeschlagenen Vergleichen als skaliert wird) log(n) zum n Vergleiche).

Ein Ort zum Lesen ist Huang und Abrahams 1984-Papier "Algorithmusbasierte Fehlertoleranz für Matrixoperationen"Ihre Idee ist vage der homomorphen verschlüsselten Berechnung ähnlich (aber es ist nicht wirklich dasselbe, da sie Fehlererkennung / -korrektur auf der Operationsebene versuchen).

Ein jüngerer Nachkomme dieser Zeitung ist Bosilca, Delmas, Dongarra und Langous "Algorithm-basierte Fehlertoleranz für Hochleistungs-Computing".


93
2018-04-24 21:13



Das Schreiben von Code für radioaktive Umgebungen unterscheidet sich nicht wirklich davon, Code für eine geschäftskritische Anwendung zu schreiben.

Zusätzlich zu dem, was bereits erwähnt wurde, sind hier einige verschiedene Tipps:

  • Verwenden Sie tägliche "Brot & Butter" -Sicherheitsmaßnahmen, die auf jedem semiprofessionellen Embedded-System vorhanden sein sollten: Interner Watchdog, interne Niederspannungserkennung, interner Uhrenmonitor. Diese Dinge sollten nicht einmal im Jahr 2016 erwähnt werden müssen und sie sind Standard auf so ziemlich jedem modernen Mikrocontroller.
  • Wenn Sie eine sicherheitsgerichtete und / oder automotive-orientierte MCU haben, verfügt sie über bestimmte Watchdog-Funktionen, z. B. ein gegebenes Zeitfenster, in dem Sie den Watchdog aktualisieren müssen. Dies wird bevorzugt, wenn Sie ein unternehmenskritisches Echtzeitsystem haben.
  • Im Allgemeinen verwenden Sie eine MCU, die für diese Art von Systemen geeignet ist, und nicht einige allgemeine Mainstream-Flaum, die Sie in einer Packung Cornflakes erhalten haben. Fast jeder MCU-Hersteller hat heutzutage spezialisierte MCUs für Sicherheitsanwendungen (TI, Freescale, Renesas, ST, Infineon usw.). Diese verfügen über viele integrierte Sicherheitsfunktionen, einschließlich Lock-Step-Cores: Dies bedeutet, dass zwei CPU-Cores denselben Code ausführen und dass sie übereinstimmen müssen.
  • WICHTIG: Sie müssen die Integrität der internen MCU-Register sicherstellen. Alle Steuer- und Statusregister von beschreibbaren Hardware-Peripheriegeräten können sich im RAM-Speicher befinden und sind daher anfällig.

    Um sich gegen Registerbeschädigungen zu schützen, wählen Sie am besten einen Mikrocontroller mit eingebauten "Write-Once" -Merkmalen von Registern. Darüber hinaus müssen Sie die Standardwerte aller Hardwareregister in NVM speichern und diese Werte in regelmäßigen Abständen in Ihre Register kopieren. Sie können die Integrität wichtiger Variablen auf die gleiche Weise sicherstellen.

    Hinweis: Verwenden Sie immer defensive Programmierung. Das heißt, dass Sie einrichten müssen alle Register in der MCU und nicht nur diejenigen, die von der Anwendung verwendet werden. Sie möchten nicht, dass zufällige Hardware-Peripheriegeräte plötzlich aufwachen.

  • Es gibt alle Arten von Methoden, um auf Fehler im RAM oder NVM zu prüfen: Prüfsummen, "Laufmuster", Software-ECC usw. Die beste Lösung heutzutage ist, keine von diesen zu verwenden, sondern eine MCU mit eingebautem ECC zu verwenden ähnliche Überprüfungen. Da dies in Software sehr komplex ist, könnte die Fehlerüberprüfung selbst zu Fehlern und unerwarteten Problemen führen.

  • Verwenden Sie Redundanz. Sie können sowohl flüchtigen als auch nichtflüchtigen Speicher in zwei identischen "Spiegel" -Segmenten speichern, die immer äquivalent sein müssen. Jedem Segment könnte eine CRC-Prüfsumme angehängt sein.
  • Vermeiden Sie die Verwendung externer Speicher außerhalb der MCU.
  • Implementieren Sie eine Standard-Interrupt-Serviceroutine / Standardausnahmebehandler für alle möglichen Interrupts / Exceptions. Sogar diejenigen, die du nicht benutzt. Die Standardroutine sollte nichts außer dem Ausschalten ihrer eigenen Interrupt-Quelle tun.
  • Das Konzept der defensiven Programmierung verstehen und annehmen. Das bedeutet, dass Ihr Programm alle möglichen Fälle behandeln muss, auch solche, die theoretisch nicht auftreten können. Beispiele.

    Eine hochwertige geschäftskritische Firmware erkennt so viele Fehler wie möglich und ignoriert sie dann auf sichere Weise.

  • Schreiben Sie niemals Programme, die auf schlecht spezifiziertes Verhalten angewiesen sind. Es ist wahrscheinlich, dass sich dieses Verhalten bei unerwarteten Hardwareänderungen, die durch Strahlung oder EMI verursacht werden, drastisch ändern kann. Der beste Weg, um sicherzustellen, dass Ihr Programm frei von solchen Mist ist, ist die Verwendung eines Kodierungsstandards wie MISRA zusammen mit einem statischen Analysetool. Dies hilft auch bei der defensiven Programmierung und beim Aussortieren von Fehlern (warum sollten Sie keine Fehler in irgendeiner Anwendung entdecken wollen?).
  • WICHTIG: Implementieren Sie kein Vertrauen in die Standardwerte der statischen Speicherdauervariablen. Das heißt, trauen Sie nicht den Standardinhalten der .data oder .bss. Zwischen dem Punkt der Initialisierung und dem Punkt, an dem die Variable tatsächlich verwendet wird, könnte eine gewisse Zeit liegen. Es hätte viel Zeit für die Beschädigung des RAMs geben können. Schreiben Sie stattdessen das Programm so, dass alle diese Variablen in NVM in der Laufzeit festgelegt werden, kurz vor dem Zeitpunkt, zu dem eine solche Variable das erste Mal verwendet wird.

    In der Praxis bedeutet dies, dass wenn eine Variable im Dateibereich oder als deklariert ist staticsolltest du niemals benutzen = um es zu initialisieren (oder Sie könnten, aber es ist sinnlos, weil Sie sich auf den Wert sowieso nicht verlassen können). Stellen Sie es immer in der Laufzeit kurz vor dem Gebrauch ein. Wenn es möglich ist, solche Variablen wiederholt von NVM zu aktualisieren, dann tun Sie dies.

    Verwenden Sie in C ++ in ähnlicher Weise keine Konstruktoren für statische Speicherdauervariablen. Lassen Sie den oder die Konstruktoren eine öffentliche "set-up" -Routine aufrufen, die Sie später in der Runtime direkt von der aufrufenden Anwendung aus aufrufen können.

    Wenn möglich, entfernen Sie den Startup-Code "copy-down", der initialisiert wird .data und .bss (und ruft C ++ - Konstruktoren auf), so dass Sie Linker-Fehler erhalten, wenn Sie Code schreiben, der auf solchen basiert. Viele Compiler haben die Möglichkeit, dies zu überspringen, normalerweise "minimaler / schneller Start" oder ähnliches genannt.

    Dies bedeutet, dass alle externen Bibliotheken überprüft werden müssen, damit sie kein solches Vertrauen haben.

  • Implementieren und definieren Sie einen sicheren Zustand für das Programm, zu dem Sie im Falle von kritischen Fehlern zurückkehren.

  • Die Implementierung eines Fehlermeldungs- / Fehlerprotokollsystems ist immer hilfreich.

36
2018-04-27 14:11



Es kann möglich sein, C zu verwenden, um Programme zu schreiben, die sich in solchen Umgebungen robust verhalten, aber nur, wenn die meisten Formen der Compiler-Optimierung deaktiviert sind. Die Optimierung von Compilern wurde entwickelt, um viele scheinbar redundante Codierungsmuster durch "effizientere" zu ersetzen, und hat möglicherweise keine Ahnung, dass der Programmierer Tests durchführt x==42 wenn der Compiler weiß, dass es keinen Weg gibt x könnte möglicherweise etwas anderes halten, weil der Programmierer die Ausführung bestimmter Code mit verhindern will xeinen anderen Wert behalten - selbst in Fällen, wo der einzige Weg, diesen Wert zu halten, wäre, wenn das System irgendeine Art von elektrischem Störimpuls erhalten würde.

Variablen deklarieren als volatile ist oft hilfreich, aber vielleicht kein Allheilmittel. Besonders wichtig ist, dass eine sichere Codierung oft gefährlich ist Operationen haben Hardware-Interlocks, die mehrere Schritte zum Aktivieren erfordern, und dieser Code wird mit dem Muster geschrieben:

... code that checks system state
if (system_state_favors_activation)
{
  prepare_for_activation();
  ... code that checks system state again
  if (system_state_is_valid)
  {
    if (system_state_favors_activation)
      trigger_activation();
  }
  else
    perform_safety_shutdown_and_restart();
}
cancel_preparations();

Wenn ein Compiler den Code relativ wörtlich und wenn alles übersetzt Die Prüfungen auf den Systemzustand werden nach dem prepare_for_activation(), das System kann robust gegen fast jedes plausible einzelne Glitch-Ereignis sein, sogar solche, die den Programmzähler und den Stack beliebig korrumpieren würden. Ob ein Glitch tritt direkt nach einem Anruf auf prepare_for_activation()Das würde bedeuten diese Aktivierung wäre angemessen gewesen (da es keinen anderen Grund gibt prepare_for_activation() wäre vor dem Störschub angerufen worden). Wenn die Glitch verursacht Code zu erreichen prepare_for_activation() unangemessen, aber da Es gibt keine nachfolgenden Glitch-Ereignisse, danach gibt es keinen Code mehr erreichen trigger_activation() ohne zuvor die Validierungsprüfung durchlaufen zu haben oder cancel_preparations zuerst aufzurufen [falls der Stack Störungen aufweist, kann die Ausführung zu einem Punkt unmittelbar davor fortschreiten trigger_activation() nach dem Kontext, der aufgerufen hat prepare_for_activation() kehrt zurück, aber der Aufruf an cancel_preparations() wäre zwischen den Anrufen aufgetreten prepare_for_activation() und trigger_activation()so dass letzterer als unschädlich zu bezeichnen ist.

Ein solcher Code kann in herkömmlichem C sicher sein, aber nicht mit modernen C-Compilern. Solche Compiler können in einer solchen Umgebung sehr gefährlich sein, weil sie aggressiv sind, nur Code einzubeziehen, der in Situationen relevant ist, die über einen klar definierten Mechanismus zustande kommen und deren Konsequenzen ebenfalls gut definiert sind. Ein Code, dessen Zweck es ist, nach Ausfällen zu erkennen und zu bereinigen, kann in einigen Fällen die Situation verschlimmern. Wenn der Compiler feststellt, dass die versuchte Wiederherstellung in einigen Fällen ein undefiniertes Verhalten auslösen würde, kann er folgern, dass die Bedingungen, die eine solche Wiederherstellung in solchen Fällen erforderlich machen könnten, unmöglich auftreten können, wodurch der Code eliminiert wird, der nach ihnen gesucht hätte.


30
2018-04-25 16:14



Das ist ein sehr weites Thema. Im Grunde genommen können Sie die Speicherbeschädigung nicht wirklich wiederherstellen, aber Sie können es zumindest versuchen scheitern prompt. Hier sind ein paar Techniken, die Sie verwenden könnten:

  • Prüfsummenkonstante Daten. Wenn Sie Konfigurationsdaten haben, die für lange Zeit konstant bleiben (einschließlich der von Ihnen konfigurierten Hardwareregister), berechnen Sie ihre Prüfsumme bei der Initialisierung und überprüfen Sie sie regelmäßig. Wenn Sie eine Nichtübereinstimmung sehen, ist es Zeit, neu zu initialisieren oder zurückzusetzen.

  • Speichern Sie Variablen mit Redundanz. Wenn Sie eine wichtige Variable haben x, schreibe seinen Wert in x1, x2 und x3 und lies es als (x1 == x2) ? x2 : x3.

  • implementieren Programmablaufüberwachung. XOR ein globales Flag mit einem eindeutigen Wert in wichtigen Funktionen / Verzweigungen, die von der Hauptschleife aufgerufen werden. Wenn das Programm in einer strahlenfreien Umgebung mit einer Testabdeckung von nahezu 100% ausgeführt wird, sollten Sie die Liste der akzeptablen Werte der Flagge am Ende des Zyklus erhalten. Zurücksetzen, wenn Sie Abweichungen sehen.

  • Überwachen Sie den Stapelzeiger. Vergleichen Sie zu Beginn der Hauptschleife den Stack-Zeiger mit seinem erwarteten Wert. Bei Abweichung zurücksetzen.


27
2018-04-25 17:05



Was dir helfen könnte, ist a Wachhund. Watchdogs wurden in den 1980er Jahren intensiv im industriellen Computing eingesetzt. Hardware-Ausfälle waren viel häufiger - eine andere Antwort bezieht sich auch auf diesen Zeitraum.

Ein Watchdog ist eine kombinierte Hardware / Software-Funktion. Die Hardware ist ein einfacher Zähler, der von einer Zahl (z. B. 1023) auf Null zählt. TTL oder eine andere Logik könnte verwendet werden.

Die Software wurde so konzipiert, dass eine Routine den korrekten Betrieb aller wesentlichen Systeme überwacht. Wenn diese Routine korrekt ausgeführt wird = der Computer läuft einwandfrei, setzt er den Zähler zurück auf 1023.

Das Gesamtdesign ist so, dass unter normalen Umständen verhindert wird, dass der Hardware-Zähler Null erreicht. Wenn der Zähler Null erreicht, führt die Hardware des Zählers ihre Einzelaufgabe aus und setzt das gesamte System zurück. Aus Zählerperspektive ist Null gleich 1024 und der Zähler zählt weiter rückwärts.

Dieser Watchdog stellt sicher, dass der angeschlossene Computer in vielen, vielen Fällen eines Fehlers neu gestartet wird. Ich muss zugeben, dass ich mit Hardware, die eine solche Funktion auf heutigen Computern ausführen kann, nicht vertraut bin. Schnittstellen zu externer Hardware sind heute viel komplexer als früher.

Ein inhärenter Nachteil des Watchdogs besteht darin, dass das System von dem Zeitpunkt an, an dem es fehlschlägt, nicht verfügbar ist, bis der Watchdog-Zähler Null + Neustart-Zeit erreicht. Während diese Zeit im Allgemeinen viel kürzer ist als jede externe oder menschliche Intervention, muss die unterstützte Ausrüstung in der Lage sein, ohne Computersteuerung für diesen Zeitraum fortzufahren.


26
2018-04-26 22:41



Diese Antwort geht davon aus, dass es sich um ein System handelt, das korrekt funktioniert, das über ein System hinausgeht, das mit minimalen Kosten oder schnell arbeitet. die meisten Leute, die mit radioaktiven Sachen spielen, schätzen Korrektheit / Sicherheit über Geschwindigkeit / Kosten

Einige Leute haben Hardware-Änderungen vorgeschlagen, die Sie vornehmen können (gut - es gibt bereits viele gute Sachen in den Antworten und ich habe nicht vor, alles zu wiederholen), und andere haben Redundanz vorgeschlagen (großartig im Prinzip), aber ich denke nicht Jeder hat vorgeschlagen, wie diese Redundanz in der Praxis funktionieren könnte. Wie versagen Sie? Woher weißt du, wann etwas schief gelaufen ist? Viele Technologien arbeiten auf der Grundlage, alles wird funktionieren, und Fehler ist somit eine schwierige Sache zu behandeln. Einige verteilte Computertechnologien sind jedoch auf Skalierung ausgelegt erwarten von Misserfolg (schließlich mit genug Maßstab, Ausfall eines Knotens von vielen ist unvermeidlich mit irgendeiner MTBF für einen einzelnen Knoten); Sie können dies für Ihre Umgebung nutzen.

Hier sind ein paar Ideen:

  • Stellen Sie sicher, dass die gesamte Hardware repliziert wird n Zeiten (wo n ist größer als 2 und vorzugsweise ungerade), und jedes Hardwareelement kann mit jedem anderen Hardwareelement kommunizieren. Ethernet ist eine naheliegende Möglichkeit, dies zu tun, aber es gibt viele andere viel einfachere Routen, die einen besseren Schutz bieten würden (z. B. CAN). Minimieren Sie häufige Komponenten (sogar Netzteile). Dies kann bedeuten, dass ADC-Eingänge beispielsweise an mehreren Stellen abgetastet werden.

  • Stellen Sie sicher, dass sich der Anwendungsstatus an einem einzigen Ort befindet, z. in einer endlichen Zustandsmaschine. Dies kann vollständig auf RAM basieren, schließt jedoch stabilen Speicher nicht aus. Es wird somit an mehreren Stellen gespeichert.

  • Übernehmen Sie ein Quorum-Protokoll für Zustandsänderungen. Sehen FLOSS beispielsweise. Da Sie in C ++ arbeiten, gibt es dafür bekannte Bibliotheken. Änderungen an der FSM würden nur vorgenommen, wenn eine Mehrheit der Knoten zustimmt. Verwenden Sie eine bekannte gute Bibliothek für den Protokollstapel und das Quorumprotokoll, anstatt selbst eines zu rollen, oder Ihre ganze gute Arbeit an Redundanz wird verschwendet, wenn das Quorumprotokoll aufhört.

  • Stellen Sie sicher, dass Sie eine Prüfsumme (z. B. CRC / SHA) Ihrer FSM haben, und speichern Sie die CRC / SHA in der FSM selbst (und senden Sie sie in der Nachricht sowie die Prüfsummen der Nachrichten selbst). Veranlassen Sie die Knoten, ihre FSM regelmäßig auf diese Prüfsumme zu überprüfen, eingehende Prüfsummen zu überprüfen und ihre Prüfsumme mit der Prüfsumme des Quorums zu vergleichen.

  • Erstellen Sie so viele interne Überprüfungen wie möglich in Ihrem System, damit Knoten, die ihren eigenen Fehler erkennen, neu gestartet werden (das ist besser, als wenn Sie halb arbeiten, vorausgesetzt, Sie haben genug Knoten). Versuchen Sie, sie während des Neustarts sauber aus dem Quorum zu entfernen, falls sie nicht erneut auftauchen. Lassen Sie sie beim Neustart das Software-Image (und alles, was sie sonst noch laden) und führen Sie einen vollständigen RAM-Test durch, bevor Sie sich wieder im Quorum wiederfinden.

  • Verwenden Sie Hardware, um Sie zu unterstützen, aber tun Sie dies vorsichtig. Sie können zum Beispiel ECC-RAM erhalten und regelmäßig lesen / schreiben, um ECC-Fehler zu korrigieren (und Panik, wenn der Fehler nicht korrigierbar ist). Jedoch (aus dem Speicher) ist statisches RAM viel toleranter gegenüber ionisierender Strahlung als DRAM in erster Linie, so ist es kann besser wäre es, stattdessen einen statischen DRAM zu verwenden. Siehe den ersten Punkt unter "Dinge, die ich nicht tun würde".

Angenommen, Sie haben eine Wahrscheinlichkeit von 1%, dass ein Knoten innerhalb eines Tages ausfällt, und lassen Sie uns so tun, als könnten Sie Fehler völlig unabhängig machen. Bei 5 Knoten müssen drei innerhalb eines Tages fehlschlagen, was einer Wahrscheinlichkeit von 0,00001% entspricht. Mit mehr, nun, Sie bekommen die Idee.

Dinge, die ich würde nicht machen:

  • Unterschätzen Sie den Wert, nicht mit dem Problem zu beginnen. Wenn das Gewicht keine Rolle spielt, wird ein großer Metallblock um Ihr Gerät eine weitaus billigere und zuverlässigere Lösung sein, als ein Team von Programmierern sich vorstellen kann. Dito optische Kopplung der Eingänge von EMI ist ein Problem, usw. Was auch immer, versuchen Sie, wenn Sie Ihre Komponenten so beschaffen, dass diejenigen, die am besten gegen ionisierende Strahlung eingestuft sind.

  • Roll deine eigenen Algorithmen. Die Leute haben das schon mal gemacht. Nutze ihre Arbeit. Fehlertoleranz und verteilte Algorithmen sind schwer. Nutze die Arbeit anderer Leute wo immer möglich.

  • Verwenden Sie komplizierte Compiler-Einstellungen in der naiven Hoffnung, dass Sie mehr Fehler entdecken. Wenn Sie Glück haben, können Sie weitere Fehler feststellen. Wahrscheinlicher ist, dass Sie innerhalb des Compilers einen Code-Pfad verwenden, der weniger getestet wurde, insbesondere wenn Sie ihn selbst gerollt haben.

  • Verwenden Sie Techniken, die in Ihrer Umgebung noch nicht getestet wurden. Die meisten Leute, die Hochverfügbarkeitssoftware schreiben, müssen Fehlermodi simulieren, um zu überprüfen, ob ihre HA korrekt funktioniert, und dadurch viele Fehlermodi übersehen. Sie sind in der glücklichen Lage, auf Nachfrage häufig zu scheitern. Also teste jede Technik und stelle sicher, dass ihre Anwendung die MTBF um einen Betrag verbessert, der die Komplexität übersteigt, um sie einzuführen (mit Komplexität kommt Bugs). Insbesondere gilt dies für meine Rat-Quorum-Algorithmen etc.


22
2018-04-27 15:41



Da Sie speziell nach Softwarelösungen fragen und C ++ verwenden, sollten Sie nicht das Überladen von Operatoren verwenden, um eigene, sichere Datentypen zu erstellen. Beispielsweise:

Anstatt zu verwenden uint32_t (und double, int64_t usw.), machen Sie Ihre eigenen SAFE_uint32_t welches ein Vielfaches (Minimum 3) von uint32_t enthält. Überladen Sie alle gewünschten Operationen (* + - / << >> ===! = Etc) und machen Sie die überladenen Operationen unabhängig von jedem internen Wert, dh tun Sie es nicht einmal und kopieren Sie das Ergebnis. Überprüfen Sie vorher und nachher, ob alle internen Werte übereinstimmen. Wenn die Werte nicht übereinstimmen, können Sie den falschen Wert auf den am häufigsten verwendeten Wert aktualisieren. Wenn es keinen gebräuchlichsten Wert gibt, können Sie sicher mitteilen, dass ein Fehler vorliegt.

Auf diese Weise ist es egal, ob Korruption in der ALU, den Registern, dem RAM oder auf einem Bus auftritt, Sie haben immer noch mehrere Versuche und eine sehr gute Chance, Fehler zu finden. Beachten Sie jedoch, dass dies nur für die Variablen funktioniert, die Sie ersetzen können - Ihr Stack-Pointer zum Beispiel wird weiterhin anfällig sein.

Eine Nebengeschichte: Ich stieß auf ein ähnliches Problem, auch auf einem alten ARM-Chip. Es stellte sich heraus, dass es sich um eine Toolchain handelte, die eine alte Version von GCC verwendete, die zusammen mit dem von uns verwendeten Chip in bestimmten Randfällen einen Fehler auslöste, der (manchmal) Werte in Funktionen verfälschte. Stellen Sie sicher, dass Ihr Gerät keine Probleme hat, bevor Sie es für Radioaktivität verantwortlich machen, und ja, manchmal ist es ein Compiler-Fehler =)


21
2018-04-27 15:32