sm – minimal threaded State Machine

Zusammenfassung

sm ist eine bewusst minimale State-Machine in C: sm_run startet einen Thread, ruft die Handler-Schleife auf (solange ein Handler true liefert) und joined den Thread danach wieder. Ein Zustand ist ein struct sm_state mit einer Handler-Funktion; der „nächste Zustand” wird dem Handler als Argument übergeben. sm liefert nur das Laufzeitgerüst – das Wissen (welche Zustände existieren, welche Übergänge erlaubt sind) liegt in den Handlern bzw. bei rbs in den Regeln.

Konzept

  • Zustand = struct sm_state { sm_state_handler_t state_function; }.
  • Handler:
    typedef bool (*sm_state_handler_t)(sm_state_t next_state, void* user_data);
    Der Handler ist der „Zustandskörper”. Rückgabe true = weiter laufen, false = Maschine terminiert. Über next_state kann er den Folgezustand durchreichen (bei rbs_sm wird die Zustandsauswahl aber von den Fakten gesteuert).
  • Laufzeit: sm_run(next_state, user_data) startet einen eigenen Thread (threading), führt die Schleife aus und joined den Thread am Ende – blockierend für den Aufrufer.

API

typedef struct sm_state *sm_state_t;
typedef bool (*sm_state_handler_t)(sm_state_t next_state, void* user_data);
 
struct sm_state { sm_state_handler_t state_function; };
void sm_run(sm_state_t next_state, void* user_data);
 
typedef struct sm_core {          /* Laufzeit-Kontext */
    struct sm_state current_state;
    pthread_t thread;
    void* user_data;
} *sm_core_t;

Nutzung

#include <sm/sm.h>
 
bool my_state(sm_state_t next_state, void* user_data)
{
    /* Zustandskörper ... */
    return false;   /* false -> Maschine terminiert */
}
 
sm_run(my_state, user_data);

Lebenszyklus-Callbacks (Konstruktor/Destruktor)

sm deklariert zwei schwache virtuelle Hooks (api-Muster) und stellt leere Defaults in sm.c bereit. Die Anwendung überschreibt sie mit einer starken callback-Definition, um Ressourcen an den Thread-Lebenszyklus zu binden (Aufbau ganz am Anfang, Aufräumen ganz am Ende des Worker-Threads):

callback_declaration(void, sm_on_start(sm_core_t core));   /* Konstruktor */
callback_declaration(void, sm_on_stop(sm_core_t core));    /* Destruktor  */

Anwendung (z. B. rbs_demo):

callback void sm_on_start(sm_core_t core) { /* Buffer anlegen, Welt setzen */ }
callback void sm_on_stop(sm_core_t core)  { /* Endfakten bilanzieren, free */ }

sm_on_start/sm_on_stop sind der Ort für Speicherverwaltung und Ausgangslage: Der Konstruktor baut die initiale Welt auf, die Slot-Handler liefern laufenden externen Input, der Destruktor bilanziert das Ergebnis.

Zusammenarbeit mit rbs

rbs_sm (in libraries/rbs) baut auf sm: Jeder Schritt führt rbs_step auf der Faktenbasis aus, sucht den ersten aktiven Slot-Marker (rbs_sm_slot) und routet dessen Handler in die sm-Schleife. Der Handler ist eine externe Faktenquelle (kein Konsumieren, siehe rbs); Beendigung über false des Handlers bzw. fehlenden Marker. Damit ist der FSM-Lebenszyklus der App über sm_on_start/sm_on_stop vollständig im Thread-sm. Abhängigkeiten: threading + api (transitiv: Thread-Erzeugung/-Joining, callback-Makros).

Build

cmake -S . -B build
cmake --build build

Einbindung: add_subdirectory(../../libraries/sm …), Header über den Include-Pfad <sm/sm.h>.

Quellen

Verwandte Artikel