Clause
← All dokumentation

Översatt från det engelska originalet · 06042fa · 2026-10-09 · Läs på engelska

Portar

Beslut i plan 11 step 57A (2026-10-08). Det ersätter beslutet från step 53 (inga portar, processer): program får portar så som OTP definierar dem, och extern I/O går genom dem. Steps 57B–57F implementerar det; varje avsnitt anger sitt step. Detta kontrakt fastställer representationen, drivrutinsmodellen och I/O-tråden innan någon källkod kan öppna en port.

Implementerat: identiteter, porttabellen, portarnas inbyggda funktioner och meddelanden, länkar, monitorer, namn och exitsignaler för portar samt fd-portar som endast skriver utdata (step 57B, runtime/src/scheduler/ports.cpp, runtime/src/builtins/ports.cpp, runtime/src/ports/; OTP-referenstest (golden) executables_port_identities); I/O-tråden och indata till fd-portar med ström-, paket- och radindelning (step 57C, runtime/src/ports/io*.cpp; OTP-referenstest executables_port_input); delprocessportar, os:type/0, os:getenv/1 och os:cmd/1 (step 57D, runtime/src/ports/spawn*.cpp, library/stdlib/os.erl; OTP-referenstest executables_port_spawn); fildrivrutinen, delmängden av biblioteksmodulen file och standard-indata genom io:get_line/io:get_chars (step 57E, runtime/src/ports/file.cpp, library/stdlib/{file,io}.erl; OTP-referenstest executables_file_io); socketar (step 57F, OTP-referenstest executables_sockets); en händelsestyrd I/O-tråd för alla sorters portar (step 57G1, runtime/src/ports/reactor.cpp; OTP-referenstest executables_many_ports, runtime-test runtime_port_io); portuppgifter på schemaläggarens arbetstrådar (step 57G2, runtime/src/scheduler/ports.cpp; OTP-referenstest executables_port_fairness); upptagna portar och begränsad indata (step 57G3; OTP-referenstester executables_busy_ports, executables_slow_owner).

Identitet

Porttabell och ägarskap

Inbyggda funktioner och portmeddelanden

Inbyggd funktion eller meddelandeStep
is_port/1 sant för portar, port_to_list/1, list_to_port/1, ports/057B
port_info/1,2 (name, links, id, connected, input, output, os_pid, monitors, monitored_by, registered_name)57B
port_close/1, port_connect/2, port_command/2,357B
Port ! {Pid, {command, Data}}, {Pid, close}, {Pid, {connect, New}}57B
link/1, unlink/1, monitor(port, P), exit/2 på portar; register/2 av en port57B
port_control/3, port_call/357B (badarg för drivrutiner utan styrning); används av drivrutinerna i 57E/57F
open_port({fd, In, Out}, Opts)57B utdata; indata från 57C
open_port({spawn, Command} | {spawn_executable, File}, Opts)57D
Interna drivrutiner i projektets bibliotek (file, socketar)57E, 57F

De inbyggda funktionerna ersätter diagnostikerna [ports] notimpl från step 53; funktionen ports blir implementerad i 57B. Fel följer OTP: badarg för en stängd eller ogiltig port och felaktiga argument, POSIX-orsaken (enoent, eacces) som ett error för en öppning som misslyckas.

Meddelanden från en port går till dess anslutna process: {Port, {data, Data}}, {Port, eof} (alternativet eof), {Port, {exit_status, Status}} (alternativet exit_status), {Port, closed} (efter {Pid, close}), {Port, connected} (till den tidigare ägaren efter en anslutning).

Datalägen och alternativ

AlternativEffekt
stream (standard), {packet, N} (N = 1, 2, 4)Bytes allteftersom de anländer, eller meddelanden inramade av en N-bytes längd i big-endian som även utdata får
{line, L}{eol, Line} per rad, {noeol, Part} för delar längre än L eller ett oavslutat slut
binaryData som binaries i stället för bytelistor
eof{Port, eof} vid slutet av indata; porten förblir öppen tills den stängs
exit_status{Port, {exit_status, S}} när programmet avslutas (spawn-portar)
use_stdio (standard), nouse_stdio, stderr_to_stdout, in, out, hideSom i OTP (hide har ingen effekt)
{args, List}, {arg0, A}, {env, Env}, {cd, Dir}Spawn-portar (57D)
{busy_limits_port, {Low, High} | disabled}Köade utdatabytes som gör porten upptagen (upptagna portar, 57G3)

Utan eof stänger slutet av indata porten med orsaken normal, efter meddelandet exit_status om ett sådant begärdes. Okända alternativ ger badarg.

Drivrutiner

En drivrutin är ett C++-objekt bakom en port (runtime/src/ports/): den öppnar resursen, tar emot utdata (port_command), svarar på port_control/3 när den stöder styrning, rapporterar indata och fel som händelser och stänger. Drivrutiner:

De interna drivrutinerna för file och socketarna öppnas med {spawn_driver, Name} under Clause-namn, och deras port_control/3-operationer är ett Clause-protokoll: program använder biblioteksmodulerna, inte OTP:s protokoll prim_inet/efile.

I/O-tråd

En I/O-tråd per runtime (detail::Reactor, runtime/src/ports/reactor.hpp, step 57G1) kör en Boost.Asio-io_context: en I/O-kompletteringsport (I/O completion port) på Windows, epoll på Linux, kqueue på macOS. Den första porten som behöver den startar den; den betjänar alla sorters portar, så en port kostar ingen egen tråd:

runtime/src/ports/io*.cpp innehåller port-I/O:n (detail::IoService): dess metoder lägger endast upp arbete på I/O-tråden, där allt I/O-tillstånd finns.

Portuppgifter

Step 57G2. En port schemaläggs som en process: det som I/O-tråden lämnar över väntar i porten, och porten väntar i exekutorns portkö tills en arbetstråd i schemaläggaren kör dess uppgift.

Prototypen tests/prototypes/poller/ (run.py --wsl) visar väckningen på Windows (kompletteringsport) och WSL Linux (poll()): en ledig schemaläggartråd vaknar 9–91 µs efter indata, och nedstängning stoppar I/O-tråden utan indata.

Vid programmets slut stängs varje port (barnprogram ser slutet av indata; de dödas inte, som i OTP) och I/O-tråden stoppas: den förenas (join) utanför exekutorns mutex, eftersom en pågående leverans tar mutexen; en Windows-läsare för fd som är blockerad i en läsning som inte kan avbrytas kopplas loss och levererar inget mer.

Upptagna portar

Step 57G3. Utdata som en drivrutin köar för I/O-tråden (rör för startade program) räknas mot portens gränser för upptagenhet, OTP:s busy_limits_port (standardvärden: hög 8 192 bytes, låg 4 096; {busy_limits_port, {Low, High}} eller disabled som ett alternativ till open_port/2, gränser minst 1, en låg gräns över den höga sänks till den):

En port begränsar även den indata den håller:

Delprocesser

Step 57D. open_port({spawn, Command}, Options) och open_port({spawn_executable, File}, Options) startar ett program vars stdin och stdout är portens rör:

Standard-I/O och filer

Step 57E.

Socketar (57F)

En socket är en port, som med OTP:s backend inet_drv: is_port(Socket) är sant och meddelanden i aktivt läge är {tcp, Socket, Data}, {tcp_closed, Socket}, {tcp_error, Socket, Reason}, {udp, Socket, Address, Port, Data}. Delmängden: gen_tcp:connect/3,4, listen/2, accept/1,2, send/2, recv/2,3, close/1, controlling_process/2, shutdown/2; gen_udp:open/1,2, send/4, recv/2,3, close/1; inet:setopts/2, inet:port/1, inet:peername/1, inet:sockname/1; lägena {active, true | false | once}, binary/list, {packet, 0 | 1 | 2 | 4 | raw}, {reuseaddr, Bool}, {backlog, N}, {ip, Address}/{ifaddr, Address}, inet/inet6; IPv4- och IPv6-adresser som tupler, värdnamn som strängar eller atomer (loopback inräknat). Justeringsalternativen nodelay, keepalive, send_timeout, send_timeout_close, delay_send och exit_on_close accepteras men tillämpas inte; alla andra alternativ ger exit(badarg), som för ett ogiltigt alternativ i OTP.

Implementation (runtime/src/ports/sockets.cpp):

Tillhandahålls inte

Inlänkade drivrutiner (linked-in drivers) och NIF:ar, erlang:open_port({spawn_driver, Name}) för OTP-drivrutinsnamn, distributionsportar, port_call/3 på de tillhandahållna drivrutinerna utöver bibliotekets eget protokoll, upptagna socketportar samt alternativen overlapped_io, parallelism och busy_limits_msgq.