Clause
← Toda la documentación

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

Puertos

Decisión del plan 11 step 57A (2026-10-08). Sustituye la decisión del step 53 (sin puertos, procesos): los programas obtienen puertos tal como los define OTP, y la E/S externa pasa por ellos. Los steps 57B–57F la implementan; cada sección nombra su step. Este contrato fija la representación, el modelo de drivers y el hilo de E/S antes de que ningún código fuente pueda abrir un puerto.

Implementado: las identidades, la tabla de puertos, los builtins y mensajes de puertos, los enlaces, monitores, nombres y señales de salida de los puertos, y los puertos fd de solo salida (step 57B, runtime/src/scheduler/ports.cpp, runtime/src/builtins/ports.cpp, runtime/src/ports/; golden de OTP executables_port_identities); el hilo de E/S y la entrada de puertos fd con delimitación por flujo, por paquetes y por líneas (step 57C, runtime/src/ports/io*.cpp; golden de OTP executables_port_input); los puertos de subprocesos, os:type/0, os:getenv/1 y os:cmd/1 (step 57D, runtime/src/ports/spawn*.cpp, library/stdlib/os.erl; golden de OTP executables_port_spawn); el driver de archivos, el subconjunto file de la biblioteca y la entrada estándar mediante io:get_line/io:get_chars (step 57E, runtime/src/ports/file.cpp, library/stdlib/{file,io}.erl; golden de OTP executables_file_io); los sockets (step 57F, golden de OTP executables_sockets); un único hilo de E/S dirigido por eventos para todos los tipos de puerto (step 57G1, runtime/src/ports/reactor.cpp; golden de OTP executables_many_ports, prueba del runtime runtime_port_io); las tareas de puerto en los workers del planificador (step 57G2, runtime/src/scheduler/ports.cpp; golden de OTP executables_port_fairness); los puertos ocupados y la entrada acotada (step 57G3; goldens de OTP executables_busy_ports, executables_slow_owner).

Identidad

Tabla de puertos y propiedad

Builtins y mensajes de puerto

Builtin o mensajeStep
is_port/1 true para puertos, 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 sobre puertos; register/2 de un puerto57B
port_control/3, port_call/357B (badarg para drivers sin control); usados por los drivers de 57E/57F
open_port({fd, In, Out}, Opts)57B salida; entrada desde 57C
open_port({spawn, Command} | {spawn_executable, File}, Opts)57D
Drivers internos de la biblioteca del proyecto (file, sockets)57E, 57F

Los builtins sustituyen los diagnósticos [ports] notimpl del step 53; la funcionalidad ports pasa a estar implementada en 57B. Los errores siguen a OTP: badarg para un puerto cerrado o no válido y para argumentos incorrectos, y la razón POSIX (enoent, eacces) como error para una apertura que falla.

Los mensajes de un puerto van a su proceso conectado: {Port, {data, Data}}, {Port, eof} (opción eof), {Port, {exit_status, Status}} (opción exit_status), {Port, closed} (tras {Pid, close}), {Port, connected} (al propietario anterior tras un connect).

Modos de datos y opciones

OpciónEfecto
stream (por defecto), {packet, N} (N = 1, 2, 4)Los bytes según llegan, o mensajes delimitados por una longitud big-endian de N bytes que también recibe la salida
{line, L}{eol, Line} por línea, {noeol, Part} para las partes de más de L o un final sin terminador
binaryLos datos como binaries en lugar de listas de bytes
eof{Port, eof} al final de la entrada; el puerto sigue abierto hasta que se cierra
exit_status{Port, {exit_status, S}} cuando el programa sale (puertos spawn)
use_stdio (por defecto), nouse_stdio, stderr_to_stdout, in, out, hideComo en OTP (hide no tiene efecto)
{args, List}, {arg0, A}, {env, Env}, {cd, Dir}Puertos spawn (57D)
{busy_limits_port, {Low, High} | disabled}Bytes de salida encolados que hacen que el puerto esté ocupado (puertos ocupados, 57G3)

Sin eof, el final de la entrada cierra el puerto con la razón normal, después del mensaje exit_status cuando se ha pedido. Las opciones desconocidas son badarg.

Drivers

Un driver es un objeto C++ detrás de un puerto (runtime/src/ports/): abre el recurso, acepta la salida (port_command), responde a port_control/3 cuando admite control, informa de la entrada y de los errores como eventos y se cierra. Drivers:

Los drivers internos de file y de los sockets se abren con {spawn_driver, Name} bajo nombres de Clause, y sus operaciones de port_control/3 son un protocolo de Clause: los programas usan los módulos de la biblioteca, no los protocolos prim_inet/efile de OTP.

Hilo de E/S

Un hilo de E/S por runtime (detail::Reactor, runtime/src/ports/reactor.hpp, step 57G1) ejecuta un io_context de Boost.Asio: un puerto de finalización de E/S (I/O completion port) en Windows, epoll en Linux, kqueue en macOS. El primer puerto que lo necesita lo arranca; sirve a todos los tipos de puerto, así que un puerto no cuesta ningún hilo propio:

runtime/src/ports/io*.cpp contienen la E/S de puertos (detail::IoService): sus métodos solo envían trabajo al hilo de E/S, donde vive todo el estado de E/S.

Tareas de puerto

Step 57G2. Un puerto se planifica como un proceso: lo que entrega el hilo de E/S espera en el puerto, y el puerto espera en la cola de puertos del ejecutor hasta que un worker del planificador ejecuta su tarea.

El prototipo tests/prototypes/poller/ (run.py --wsl) muestra el despertar en Windows (puerto de finalización) y en Linux bajo WSL (poll()): un hilo planificador inactivo despierta 9–91 µs después de la entrada, y el apagado detiene el hilo de E/S sin entrada.

Al final del programa se cierran todos los puertos (los programas hijos ven el final de la entrada; no se matan, como en OTP) y el hilo de E/S se detiene: se espera (join) fuera del mutex del ejecutor, porque una entrega en curso lo toma; un lector fd de Windows bloqueado en una lectura que no se puede cancelar se desacopla y ya no entrega nada más.

Puertos ocupados

Step 57G3. La salida que un driver encola para el hilo de E/S (las tuberías de los programas lanzados) cuenta para los límites de ocupación del puerto, el busy_limits_port de OTP (por defecto: alto 8.192 bytes, bajo 4.096; {busy_limits_port, {Low, High}} o disabled como opción de open_port/2, límites de al menos 1, y un límite bajo superior al alto se rebaja a este):

Un puerto también acota la entrada que retiene:

Subprocesos

Step 57D. open_port({spawn, Command}, Options) y open_port({spawn_executable, File}, Options) arrancan un programa cuyos stdin y stdout son tuberías del puerto:

E/S estándar y archivos

Step 57E.

Sockets (57F)

Un socket es un puerto, como con el backend inet_drv de OTP: is_port(Socket) es true y los mensajes en modo activo son {tcp, Socket, Data}, {tcp_closed, Socket}, {tcp_error, Socket, Reason}, {udp, Socket, Address, Port, Data}. El subconjunto: 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; los modos {active, true | false | once}, binary/list, {packet, 0 | 1 | 2 | 4 | raw}, {reuseaddr, Bool}, {backlog, N}, {ip, Address}/{ifaddr, Address}, inet/inet6; direcciones IPv4 e IPv6 como tuplas, nombres de host como cadenas o átomos (incluido loopback). Las opciones de ajuste nodelay, keepalive, send_timeout, send_timeout_close, delay_send y exit_on_close se aceptan pero no se aplican; cualquier otra opción es exit(badarg), como una opción no válida en OTP.

Implementación (runtime/src/ports/sockets.cpp):

No proporcionado

Los drivers enlazados (linked-in drivers) y los NIF, erlang:open_port({spawn_driver, Name}) para nombres de drivers de OTP, los puertos de distribución, port_call/3 sobre los drivers proporcionados fuera del protocolo propio de la biblioteca, los puertos de socket ocupados, y las opciones overlapped_io, parallelism y busy_limits_msgq.