Clause
← Toute la documentation

Traduit de l'original anglais · 1e3a39c8-dirty · 2026-10-26 · Lire en anglais

Runtime

clause_runtime est une bibliothèque C++23 sans LLVM. Elle possède les contextes, les tas de processus, les atomes, les modules chargés et la gestion du cycle de vie, et exécute les processus Erlang sur des workers de l'ordonnanceur (processus). Toutes les API sont internes au projet ; les appels de l'hôte doivent être sérialisés par runtime et ne pas chevaucher l'exécution d'un programme, dont les workers se synchronisent entre eux (threads).

Édition de liens

Lier exactement un runtime compilé pour la cible via Clause::generated_program :

add_executable(harness harness.cpp)
target_link_libraries(harness PRIVATE Clause::generated_program)

Cela apporte l'archive, les en-têtes ABI/runtime et C++23, mais pas LLVM. link_consumer.cpp montre un cycle de vie complet.

Cycle de vie

runtime.hpp :

Ordre de destruction : fermer les enregistrements de l'ordonnanceur → détruire les contextes → libérer les enregistrements de code → détruire le service d'ordonnancement → la table des atomes en dernier. Les handles de fonction résolus maintiennent le code en vie après la destruction du runtime, mais les mots de leurs emplacements d'atomes n'épinglent aucune orthographe. Le stockage des atomes retire ses emplacements globaux avant de libérer les enregistrements ; l'accès à l'orthographe par un Term d'atome non fixe survivant signale expired_context.

Mémoire des processus

Chaque contexte possède un ProcessHeap (process_heap.hpp) ; sa disposition, ses zones, son dimensionnement, son admission, ses racines et sa collecte sont spécifiés dans runtime-heap.md. L'API de l'hôte :

Serveur de code et builtins

Chaque runtime possède un CodeServer (code_server.hpp, callable.hpp) :

auto functions = std::make_unique<ModuleRegistry>();
auto added = functions->add("identity", 1,
    [](ProcessContext &, std::span<const Term> args) -> CallResult<Term> { return args.front(); });
auto loaded = context.code_server().load({"native_demo", CodeImage::linked(), std::move(functions)});
auto fn = context.code_server().resolve({.module = "native_demo", .function = "identity", .arity = 1});

Termes persistants

Une table par runtime (memory/persistent_terms), détenue par Runtime::Impl et atteinte via ProcessContext::persistent_terms(), conserve les termes de persistent_term (builtins).

Tables ETS

Un registre par runtime (ets/tables), détenu par Runtime::Impl et atteint via ProcessContext::ets_tables(), conserve les tables de ets (builtins).

Spécifications de filtrage

runtime/src/match_spec/ compile et exécute les spécifications de filtrage comme le fait erl_db_util.c d'OTP, pour ets et erlang:match_spec_test/3 (builtins).

Gestion de l'ordonnanceur

SchedulerService (scheduler.hpp) est un registre du cycle de vie des processus destiné à l'hôte ; il n'exécute aucun code. Les programmes s'exécutent sur l'exécuteur (processus), qui ne l'utilise pas.

Threads

Les workers de l'ordonnanceur (workers) exécutent les processus sur plusieurs threads d'un même runtime. Les services qu'ils partagent sont synchronisés ; tout le reste reste confiné au thread qui exécute son processus ou protégé par le mutex de l'exécuteur.

Sortie standard

RuntimeOptions::standard_output (output.hpp) reçoit la sortie de erlang:display/1 et de io vers la sortie standard (io). Par défaut, l'écriture se fait sur le stdout du processus via stdio de C (avec tampon) ; un récepteur de l'hôte renvoie false pour signaler une écriture échouée.

erlang:display/1 rend son argument dans le style d'affichage, écrit le texte et un saut de ligne en une seule écriture et renvoie true. Les limites de rendu et les écritures refusées deviennent des statuts d'infrastructure (resource_limit, output_failure, ...) dans le canal vérifié, jamais des exceptions Erlang.

Démarrage du programme

CLAUSE_main_v1 (startup.hpp, runtime/src/startup/) exécute un programme entier pour le main généré (exécutables) : il vérifie l'ABI de chaque descripteur, démarre un runtime, enregistre tous les modules avant tout code d'entrée, construit argv dans le contexte d'entrée, exécute l'entrée sur l'exécuteur et convertit le résultat en code de sortie. Les rapports vont sur stderr après le vidage de stdout ; le contexte et le runtime sont détruits dans l'ordre sur chaque chemin. CLAUSE_halt_v1 implémente erlang:halt/0,1 (abort appelle std::abort).

Services différés

Ceux-ci rapportent une ligne [feature] notimpl (fonctionnalités) et ne changent aucun état :

FrontièreErreur
TermFactory::function(FunctionIdentity)TermError::not_implemented
SchedulerService::run / executeSchedulerError::not_implemented
CodeServer::unloadCodeError::not_implemented
dispatch_builtin sur un BIF cataloguéStatus::not_implemented