Clause
← Toda a documentação

Traduzido do original em inglês · 1e3a39c8-dirty · 2026-10-26 · Ler em inglês

Runtime

clause_runtime é uma biblioteca C++23 sem LLVM. Detém os contextos, os heaps dos processos, os átomos, os módulos carregados e o registo do ciclo de vida, e executa processos Erlang em workers do escalonador (processos). Todas as APIs são internas ao projeto; as chamadas do anfitrião têm de ser serializadas por runtime e não podem sobrepor-se a uma execução do programa, cujos workers se sincronizam entre si (threads).

Ligação

Ligar exatamente um runtime compilado para o alvo através de Clause::generated_program:

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

Traz o arquivo, os cabeçalhos de ABI/runtime e o C++23, mas não o LLVM. link_consumer.cpp mostra um ciclo de vida completo.

Ciclo de vida

runtime.hpp:

Ordem de desmontagem: fechar os registos do escalonador → destruir os contextos → libertar os registos de código → destruir o serviço do escalonador → tabela de átomos por último. Os handles de funções resolvidas mantêm vivo o código após a desmontagem do runtime, mas as palavras dos seus slots de átomos não fixam grafias. O armazenamento de átomos retira os seus slots globais antes de libertar os registos; aceder à grafia através de um Term de átomo não fixo sobrevivente indica expired_context.

Memória dos processos

Cada contexto detém um ProcessHeap (process_heap.hpp); a sua disposição, áreas, dimensionamento, admissão, raízes e recolha estão especificados em runtime-heap.md. A API do anfitrião:

Servidor de código e builtins

Cada runtime detém um 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});

Termos persistentes

Uma tabela por runtime (memory/persistent_terms), pertencente a Runtime::Impl e acessível através de ProcessContext::persistent_terms(), guarda os termos de persistent_term (builtins).

Tabelas ETS

Um registo por runtime (ets/tables), pertencente a Runtime::Impl e acessível através de ProcessContext::ets_tables(), guarda as tabelas de ets (builtins).

Especificações de correspondência

runtime/src/match_spec/ compila e executa especificações de correspondência como o erl_db_util.c do OTP, para ets e erlang:match_spec_test/3 (builtins).

Registo do escalonador

SchedulerService (scheduler.hpp) é um registo do ciclo de vida dos processos virado para o anfitrião; não executa código. Os programas correm no executor (processos), que não o usa.

Threads

Os workers do escalonador (workers) executam processos em várias threads de um runtime. Os serviços que partilham são sincronizados; tudo o resto fica confinado à thread que executa o seu processo ou protegido pelo mutex do executor.

Saída padrão

RuntimeOptions::standard_output (output.hpp) recebe a saída de erlang:display/1 e de io para a saída padrão (io). Por omissão, escreve no stdout do processo através do stdio de C (com buffer); um destino do anfitrião devolve false para indicar uma escrita falhada.

erlang:display/1 apresenta o seu argumento no estilo de display, escreve o texto e uma mudança de linha numa só escrita e devolve true. Os limites de apresentação e as escritas rejeitadas tornam-se estados de infraestrutura (resource_limit, output_failure, ...) no canal verificado, nunca exceções Erlang.

Arranque do programa

CLAUSE_main_v1 (startup.hpp, runtime/src/startup/) executa um programa inteiro para o main gerado (executáveis): verifica a ABI de cada descritor, inicia um runtime, regista todos os módulos antes de qualquer código de entrada, constrói o argv no contexto de entrada, executa a entrada no executor e converte o resultado no estado de saída. Os relatórios vão para o stderr depois de o stdout ser esvaziado; o contexto e o runtime são desmontados por ordem em todos os caminhos. CLAUSE_halt_v1 implementa erlang:halt/0,1 (abort chama std::abort).

Serviços adiados

Estes emitem uma linha [feature] notimpl (funcionalidades) e não alteram nenhum estado:

FronteiraErro
TermFactory::function(FunctionIdentity)TermError::not_implemented
SchedulerService::run / executeSchedulerError::not_implemented
CodeServer::unloadCodeError::not_implemented
dispatch_builtin num BIF catalogadoStatus::not_implemented