Clause
← Toda la documentación

Traducido del original en inglés · 06042fa · 2026-10-09 · Leer en inglés

Runtime

clause_runtime es una biblioteca C++23 sin LLVM. Gestiona los contextos, los heaps de los procesos, los átomos, los módulos cargados y la contabilidad del ciclo de vida, y ejecuta los procesos Erlang en workers del planificador (procesos). Todas las API son internas del proyecto; las llamadas del anfitrión deben serializarse por runtime y no solaparse con una ejecución del programa, cuyos workers se sincronizan entre sí (hilos).

Enlazado

Se enlaza exactamente un runtime compilado para el destino mediante Clause::generated_program:

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

Aporta el archivo, las cabeceras de la ABI y del runtime y C++23, pero no LLVM. link_consumer.cpp muestra un ciclo de vida completo.

Ciclo de vida

runtime.hpp:

Orden de desmontaje: cerrar los registros del planificador → destruir los contextos → liberar los registros de código → destruir el servicio del planificador → la tabla de átomos al final. Los manejadores de funciones resueltas mantienen vivos el código y las grafías de los átomos tras el desmontaje del runtime, pero nunca un proceso.

Memoria de los procesos

Cada contexto posee un ProcessHeap: un único bloque de heap creado por su primera asignación, de tamaño max(min_heap_words, request), más una cadena de fragmentos de heap del mismo proceso. Las palabras solo se mueven cuando el anfitrión llama a collect() en un punto seguro.

El heap sigue el diseño clásico de ERTS; runtime-heap.md es su contrato (disposición, áreas, dimensionado, admisión, raíces, recolección).

Servidor de código y builtins

Cada runtime posee 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});

Contabilidad del planificador

SchedulerService (scheduler.hpp) solo registra el ciclo de vida de los procesos; no ejecuta código.

Los bocetos de diseño de workers y procesos están en runtime/design/ y en runtime/include/{scheduler,process}.hpp. Los mensajes están implementados (procesos): un envío copia el mensaje en el heap del receptor y lo añade a su buzón de señales (runtime/include/mailbox.hpp).

Hilos

Los workers del planificador (plan step 56, workers) ejecutan procesos en varios hilos de un mismo runtime. Los servicios que comparten están sincronizados; todo lo demás queda confinado al hilo que ejecuta su proceso o protegido por el mutex del ejecutor.

Salida estándar

RuntimeOptions::standard_output (output.hpp) recibe los bytes de erlang:display/1 y, más adelante, los de standard_io. Por defecto escribe en el stdout del proceso a través de C stdio (con búfer); un sumidero del anfitrión devuelve false para indicar una escritura fallida.

erlang:display/1 representa su argumento en estilo display, escribe el texto y un salto de línea en una sola escritura y devuelve true. Los límites de representación y las escrituras rechazadas se convierten en estados de infraestructura (resource_limit, output_failure, ...) en el canal comprobado, nunca en excepciones de Erlang.

Arranque del programa

CLAUSE_main_v1 (startup.hpp, runtime/src/startup/) ejecuta un programa completo para el main generado: comprueba la ABI de cada descriptor, arranca un runtime por defecto, registra todos los módulos antes de cualquier código de entrada, construye argv en el contexto de entrada, llama a la entrada y convierte el resultado en el estado de salida de los ejecutables. Los informes van a stderr después de vaciar stdout; el contexto y el runtime se desmontan en orden en todas las rutas. CLAUSE_halt_v1 implementa erlang:halt/0,1 (abort llama a std::abort).

Servicios diferidos

Estos informan una línea [feature] notimpl (funcionalidades) y no cambian ningún estado:

FronteraError
TermFactory::port (aún sin puertos, plan step 53), reference(ReferenceIdentity) y function(FunctionIdentity)TermError::not_implemented
SchedulerService::run / executeSchedulerError::not_implemented
CodeServer::unloadCodeError::not_implemented
dispatch_builtin sobre un BIF catalogadoStatus::not_implemented