Skip to content

net: extend the host netdev to darwin - #74

Open
yohimik wants to merge 1 commit into
tinygo-org:mainfrom
yohimik:upstream-pr/darwin-host-netdev
Open

net: extend the host netdev to darwin#74
yohimik wants to merge 1 commit into
tinygo-org:mainfrom
yohimik:upstream-pr/darwin-host-netdev

Conversation

@yohimik

@yohimik yohimik commented Aug 30, 2026

Copy link
Copy Markdown

net: extend the host netdev to darwin

Repository tinygo-org/net. Branch upstream-pr/darwin-host-netdev, base
main.

What this does

The host netdev was for linux only, so a macOS binary registered no netdev and
every Dial reported "Netdev not set". Nothing in it is specific to linux.
Darwin also keeps the standard library syscall package, where the TinyGo
compiler routes the libc_*_trampoline symbols to libSystem, so the same
raw-socket implementation works there.

  • The build constraint on netdev_native.go becomes (linux || darwin).
  • The one part that is different, the socket options for every socket, moves
    into per-OS setSockDefaults functions in netdev_native_linux.go and
    netdev_native_darwin.go.
  • Linux keeps the same SO_REUSEADDR as before. Darwin adds SO_NOSIGPIPE,
    because a BSD socket raises SIGPIPE on a write to a closed connection and
    darwin has no MSG_NOSIGNAL to prevent it for one write. Without it a peer
    that hangs up in the middle of a response kills the process instead of a
    return of EPIPE from Send.
  • Accept retries on EINTR, as Connect, Send and Recv already do. Under
    the threads scheduler a GC cycle interrupts a blocking call with a signal, and
    a server must not see that as a failed accept.
  • An accepted socket gets the same defaults as a created one, which puts
    SO_NOSIGPIPE on the connections that a server writes to.

Evidence

There is no CI in this repository, so the checks were run by hand on macOS 26.6
arm64 with a TinyGo build that carries the matching toolchain change.

  • A program that calls net.LookupHost and http.Get("https://example.com/")
    builds and completes with this branch and the three other branches in this
    series.

A downstream product ships binaries built with these changes in a production
release. dispat v1.4.0 is published and is not a prerelease. It carries
dispat-tiny-linux-amd64 and dispat-tiny-linux-arm64, built by the fork
release v0.42.0-net.4 from sha256-pinned tarballs and smoke-executed under
binfmt before upload, beside six binaries from the gc toolchain.
https://github.com/yohimik/dispat/releases/tag/services%2Fdispat%2Fv1.4.0

The acceptance record of that repository is committed at
packages/docs/docs/internals/tinygo.md. It reports the net.2 to net.4
acceptance history, an integration suite of 694 rows that passes with 0 failures
and 1 documented skip on darwin, and a size table of 0.58x to 0.63x against the
gc equivalents with TinyGo -opt=z -no-debug against go build -trimpath -ldflags "-s -w". Those figures come from that document. They are not a
measurement of this branch.

The rows of that suite include DNS, TCP, TLS and x509 paths. The shipped
binaries in that release are for linux. The darwin evidence is the acceptance
record and the check above.

Dependencies

  • The darwin toolchain needs the BSD socket symbols in the libSystem stub. See
    the tinygo PR "builder: declare the BSD socket API in the darwin libSystem
    stub". Without it a darwin program that opens a socket does not link.

Known gaps

  • Deadlines use SO_RCVTIMEO and SO_SNDTIMEO, and a call that EINTR restarts
    begins its timeout again, so a deadline can be later than it should be under a
    heavy GC load.
  • Linux behaviour is unchanged.

Related

Related pull requests

This change is part of one body of work. Together the changes make programs that use the network and child processes work on hosted linux and macOS. A full CLI was tested end to end with all of them and ships binaries built this way, see dispat v1.4.0 in the evidence section.

In tinygo-org/tinygo

In this repository

A merge order that works. The three bug fixes are independent. tinygo-org/tinygo#5633 goes before tinygo-org/tinygo#5635. HTTPS on linux needs only tinygo-org/tinygo#5633 and tinygo-org/tinygo#5635. Full darwin support also needs tinygo-org/tinygo#5636, the net changes and a new src/net submodule pin.

The host netdev was for linux only, so a macOS binary registered no netdev and
every Dial reported "Netdev not set". Nothing in it is specific to linux.
Darwin also keeps the standard library syscall package, where the TinyGo
compiler routes the libc_*_trampoline symbols to libSystem, so the same
raw-socket implementation works there.

Widen the build constraint to (linux || darwin) and move the one part that is
different, the socket options for every socket, into per-OS setSockDefaults
functions. Linux keeps the same SO_REUSEADDR as before. Darwin adds
SO_NOSIGPIPE, because a BSD socket raises SIGPIPE on a write to a closed
connection and darwin has no MSG_NOSIGNAL to prevent it for one write.

Accept now retries on EINTR, as Connect, Send and Recv already do. Under the
threads scheduler a GC cycle interrupts a blocking call with a signal, and a
server must not see that as a failed accept. An accepted socket gets the same
defaults as a created one, which puts SO_NOSIGPIPE on the connections that a
server writes to.
@yohimik

yohimik commented Sep 2, 2026

Copy link
Copy Markdown
Author

tinygo-org/net main has not moved since this branch was opened. It is still
70037cf, so the branch needs no rebase and it is current. v0.42.0 of the
toolchain pins src/net at that same commit, so the change applies to the
released toolchain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant