Clause
← All dokumentation

Det engelska originalet har ändrats sedan översättningen gjordes, så delar av den kan vara inaktuella. Läs på engelska

Översatt från det engelska originalet · 1e3a39c8-dirty · 2026-10-26

Portar

Program får portar så som OTP definierar dem, och extern I/O går genom dem. Porttabellen, reglerna för avslut och portuppgifterna finns i runtime/src/scheduler/ports.cpp, de inbyggda funktionerna i runtime/src/builtins/erlang/ports.cpp, drivrutinerna och I/O-tråden i runtime/src/ports/. OTP-referenstester (goldens): executables_port_identities, executables_port_input, executables_port_spawn, executables_file_io, executables_sockets, executables_many_ports, executables_port_fairness, executables_busy_ports, executables_slow_owner; runtime-test runtime_port_io.

Identitet

Porttabell och ägarskap

Inbyggda funktioner och portmeddelanden

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 (delprocesser)
{busy_limits_port, {Low, High} | disabled}Köade utdatabytes som gör porten upptagen (upptagna portar)

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, socketarna och registret ö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) 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. I/O-tråden lämnar över indata så som den lästes: råa bytes, slutet av indata, ett läsfel, ett programs avslutsstatus. Sockethändelser (meddelanden, accepterade anslutningar) lämnas över på samma sätt.

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.

Portuppgifter

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.

Upptagna portar

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

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

Socketar

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/2,3,4 (en värd och port, eller en socketadress som map), listen/2, accept/1,2, send/2, recv/2,3, close/1, controlling_process/2, shutdown/2; gen_udp:open/1,2, connect/2,3, send/2,3,4,5 (OTP:s destinationsformer och tilläggsdata), recv/2,3, close/1; inet:setopts/2, getopts/2, getstat/1,2, info/1, i/0,1,2, monitor/1, cancel_monitor/1, port/1, peername/1, peernames/1,2, sockname/1, socknames/1,2; lägena {active, true | false | once}, binary/list ({mode, M}), {packet, 0 | 1 | 2 | 4 | raw}, {backlog, N}, {ip, Address}/{ifaddr, Address}, inet/inet6; IPv4- och IPv6-adresser som tupler, värdnamn som strängar eller atomer (loopback inräknat).

Alternativ utöver dataläget (ports/socket_options.cpp, library/kernel/clause_socket_options.erl) är drivrutinsrecord med en kod och ett värde, angivna när en socket öppnas (sätts innan den binds eller ansluts) eller med setopts/2; varje alternativ i ett setopts/2-anrop kontrolleras innan något sätts. Systemets alternativ (reuseaddr, keepalive, dontroute, linger, broadcast, sndbuf, recbuf, nodelay, tos, tclass, ipv6_v6only, multicast_ttl, multicast_loop, multicast_if, add_membership, drop_membership, exclusiveaddruse på Windows, priority och reuseport där systemet har dem) går till setsockopt och läses tillbaka med getsockopt; de alternativ OTP:s inet_drv behåller självt (buffer, header, deliver, exit_on_close, send_timeout, vattenmärken, packet_size, ...) behålls med inet_drv:s standardvärden och tillämpas inte (skillnader). Som i inet_drv höjer en mottagningsbuffert buffer tills det sätts, och getopts/2 utelämnar alternativ som en sockettyp saknar (broadcast för en TCP-socket, nodelay för en UDP-socket, tclass för IPv4) och avvisar okända med {error, einval}. En accepterad anslutning övertar sin lyssnande sockets alternativ. send/5 med tilläggsdata sätter tos, tclass eller ttl enbart för det datagrammet; på Windows är det {error, einval}, som i OTP.

Varje socket räknar sin trafik som inet_drv gör för getstat/1,2: mottagna paket är läsningar (TCP) eller datagram, skickade paket är send-anrop (med sitt pakethuvud) eller datagram, med inet_drv:s löpande medelvärden; send_pend är köad utdata som inte skrivits. getstatus ger inet_drv:s statusflaggor (open, connected, connecting, listen, accepting), som info/1 och i/0,1,2 skriver ut med OTP:s namn och modulkolumn (inet_tcp, inet6_udp, ...). Frågor om en stängd socket besvaras med {error, einval}, som i OTP.

Modulen socket (library/kernel/socket.erl) använder samma drivrutinsportar i passivt binärläge. En strömsocket kan bindas innan den lyssnar eller ansluter (operation 22 öppnar och binder systemsocketen, som listen gör till accepterare eller connect ansluter); en datagramsocket binds av udp_open, implicit vid sin första sändning. Slutet på en anslutning besvarar varje väntande recv (även en som begär fler bytes än som återstår). socket behåller de bytes som en recv inte tog i sin egen buffert, så recv/2,3,4 ger OTP:s {error, {timeout, Data}} och {error, {closed, Data}}.

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

Registret

win32reg öppnar {spawn_driver, "clause_registry"} på Windows (runtime/src/ports/registry_windows.cpp). Drivrutinen behåller tillståndet hos OTP:s registerdrivrutin (begärd åtkomst, aktuell nyckel och dess rot, inledningsvis HKEY_CLASSES_ROOT) och besvarar OTP:s nio kommandon som synkrona port_control/3-operationer med de svar OTP:s drivrutin skickar som portdata: o, e och errno-namnet (registerskada är eio, en borttagen nyckel einval, andra Windows-fel så som C-runtime mappar dem), k och ett nyckelnamn, v, typ, namn och data (strängar utan sin avslutande nolla, DWORD-värden i big-endian), s och aktuell nyckel. Listningar returnerar varje svar, vart och ett föregånget av sin 32-bitars storlek. Namn och strängar använder ANSI-teckentabellen, som OTP:s drivrutin.

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.