From baf7e4fa559735bf2086f80a8c602350f2e7e9c8 Mon Sep 17 00:00:00 2001
From: leongross <leon.gross@9elements.com>
Date: Mon, 2 Sep 2024 11:58:44 +0200
Subject: [PATCH 01/14] link

Signed-off-by: leongross <leon.gross@9elements.com>
---
 src/syscall/syscall_libc.go | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/syscall/syscall_libc.go b/src/syscall/syscall_libc.go
index 0ef9784283..5cacc0c8bb 100644
--- a/src/syscall/syscall_libc.go
+++ b/src/syscall/syscall_libc.go
@@ -215,7 +215,11 @@ func Truncate(path string, length int64) (err error) {
 func Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
 
 func Kill(pid int, sig Signal) (err error) {
-	return ENOSYS // TODO
+	result := libc_kill(int32(pid), int32(sig))
+	if result < 0 {
+		err = getErrno()
+	}
+	return
 }
 
 type SysProcAttr struct{}
@@ -418,3 +422,8 @@ func libc_execve(filename *byte, argv **byte, envp **byte) int
 //
 //export truncate
 func libc_truncate(path *byte, length int64) int32
+
+// int kill(pid_t pid, int sig);
+//
+//export kill
+func libc_kill(pid, sig int32) int32

From 329fef6b4a6394ebe7e5ec49e5cacfa15f61b006 Mon Sep 17 00:00:00 2001
From: leongross <leon.gross@9elements.com>
Date: Tue, 10 Sep 2024 13:45:08 +0200
Subject: [PATCH 02/14] linux support for net.Dial by stubbing out runtime
 polling

Signed-off-by: leongross <leon.gross@9elements.com>
---
 .gitmodules                    |   4 -
 loader/goroot.go               |   6 +
 src/crypto/tls/common.go       | 460 ---------------------------------
 src/crypto/tls/ticket.go       |  16 --
 src/crypto/tls/tls.go          | 114 --------
 src/net                        |   1 -
 src/runtime/netpoll.go         |  45 ++++
 src/runtime/netpoll_generic.go |  31 +++
 src/runtime/poll.go            |  15 +-
 src/runtime/sync.go            |   8 +-
 src/syscall/forklock_tinygo.go |  38 +++
 11 files changed, 134 insertions(+), 604 deletions(-)
 delete mode 100644 src/crypto/tls/common.go
 delete mode 100644 src/crypto/tls/ticket.go
 delete mode 100644 src/crypto/tls/tls.go
 delete mode 160000 src/net
 create mode 100644 src/runtime/netpoll.go
 create mode 100644 src/runtime/netpoll_generic.go
 create mode 100644 src/syscall/forklock_tinygo.go

diff --git a/.gitmodules b/.gitmodules
index 91bd14a7d7..e4f627ae1c 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -32,10 +32,6 @@
 [submodule "lib/macos-minimal-sdk"]
 	path = lib/macos-minimal-sdk
 	url = https://github.com/aykevl/macos-minimal-sdk.git
-[submodule "src/net"]
-	path = src/net
-	url = https://github.com/tinygo-org/net.git
-	branch = dev
 [submodule "lib/wasi-cli"]
 	path = lib/wasi-cli
 	url = https://github.com/WebAssembly/wasi-cli
diff --git a/loader/goroot.go b/loader/goroot.go
index 5442df9b5d..7a48ecbb1f 100644
--- a/loader/goroot.go
+++ b/loader/goroot.go
@@ -270,6 +270,12 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
 	if needsSyscallPackage {
 		paths["syscall/"] = true // include syscall/js
 	}
+
+	// to enable network support for linux systems, reuse the Go version of the net package
+	// and the according runtime functions
+	// if runtime.GOOS == "linux" {
+	// 	paths["runtime/netpoll/"] = true
+	// }
 	return paths
 }
 
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go
deleted file mode 100644
index caf0198e15..0000000000
--- a/src/crypto/tls/common.go
+++ /dev/null
@@ -1,460 +0,0 @@
-// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tls
-
-import (
-	"context"
-	"crypto"
-	"crypto/x509"
-	"fmt"
-	"io"
-	"net"
-	"sync"
-	"time"
-)
-
-// CurveID is the type of a TLS identifier for an elliptic curve. See
-// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8.
-//
-// In TLS 1.3, this type is called NamedGroup, but at this time this library
-// only supports Elliptic Curve based groups. See RFC 8446, Section 4.2.7.
-type CurveID uint16
-
-// CipherSuiteName returns the standard name for the passed cipher suite ID
-//
-// Not Implemented.
-func CipherSuiteName(id uint16) string {
-	return fmt.Sprintf("0x%04X", id)
-}
-
-// ConnectionState records basic TLS details about the connection.
-type ConnectionState struct {
-	// TINYGO: empty; TLS connection offloaded to device
-	//
-	// Minimum (empty) fields for fortio.org/log http logging and others
-	// to compile and run.
-	PeerCertificates []*x509.Certificate
-	CipherSuite      uint16
-}
-
-// ClientAuthType declares the policy the server will follow for
-// TLS Client Authentication.
-type ClientAuthType int
-
-// ClientSessionCache is a cache of ClientSessionState objects that can be used
-// by a client to resume a TLS session with a given server. ClientSessionCache
-// implementations should expect to be called concurrently from different
-// goroutines. Up to TLS 1.2, only ticket-based resumption is supported, not
-// SessionID-based resumption. In TLS 1.3 they were merged into PSK modes, which
-// are supported via this interface.
-type ClientSessionCache interface {
-	// Get searches for a ClientSessionState associated with the given key.
-	// On return, ok is true if one was found.
-	Get(sessionKey string) (session *ClientSessionState, ok bool)
-
-	// Put adds the ClientSessionState to the cache with the given key. It might
-	// get called multiple times in a connection if a TLS 1.3 server provides
-	// more than one session ticket. If called with a nil *ClientSessionState,
-	// it should remove the cache entry.
-	Put(sessionKey string, cs *ClientSessionState)
-}
-
-//go:generate stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go
-
-// SignatureScheme identifies a signature algorithm supported by TLS. See
-// RFC 8446, Section 4.2.3.
-type SignatureScheme uint16
-
-// ClientHelloInfo contains information from a ClientHello message in order to
-// guide application logic in the GetCertificate and GetConfigForClient callbacks.
-type ClientHelloInfo struct {
-	// CipherSuites lists the CipherSuites supported by the client (e.g.
-	// TLS_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).
-	CipherSuites []uint16
-
-	// ServerName indicates the name of the server requested by the client
-	// in order to support virtual hosting. ServerName is only set if the
-	// client is using SNI (see RFC 4366, Section 3.1).
-	ServerName string
-
-	// SupportedCurves lists the elliptic curves supported by the client.
-	// SupportedCurves is set only if the Supported Elliptic Curves
-	// Extension is being used (see RFC 4492, Section 5.1.1).
-	SupportedCurves []CurveID
-
-	// SupportedPoints lists the point formats supported by the client.
-	// SupportedPoints is set only if the Supported Point Formats Extension
-	// is being used (see RFC 4492, Section 5.1.2).
-	SupportedPoints []uint8
-
-	// SignatureSchemes lists the signature and hash schemes that the client
-	// is willing to verify. SignatureSchemes is set only if the Signature
-	// Algorithms Extension is being used (see RFC 5246, Section 7.4.1.4.1).
-	SignatureSchemes []SignatureScheme
-
-	// SupportedProtos lists the application protocols supported by the client.
-	// SupportedProtos is set only if the Application-Layer Protocol
-	// Negotiation Extension is being used (see RFC 7301, Section 3.1).
-	//
-	// Servers can select a protocol by setting Config.NextProtos in a
-	// GetConfigForClient return value.
-	SupportedProtos []string
-
-	// SupportedVersions lists the TLS versions supported by the client.
-	// For TLS versions less than 1.3, this is extrapolated from the max
-	// version advertised by the client, so values other than the greatest
-	// might be rejected if used.
-	SupportedVersions []uint16
-
-	// Conn is the underlying net.Conn for the connection. Do not read
-	// from, or write to, this connection; that will cause the TLS
-	// connection to fail.
-	Conn net.Conn
-
-	// config is embedded by the GetCertificate or GetConfigForClient caller,
-	// for use with SupportsCertificate.
-	config *Config
-
-	// ctx is the context of the handshake that is in progress.
-	ctx context.Context
-}
-
-// CertificateRequestInfo contains information from a server's
-// CertificateRequest message, which is used to demand a certificate and proof
-// of control from a client.
-type CertificateRequestInfo struct {
-	// AcceptableCAs contains zero or more, DER-encoded, X.501
-	// Distinguished Names. These are the names of root or intermediate CAs
-	// that the server wishes the returned certificate to be signed by. An
-	// empty slice indicates that the server has no preference.
-	AcceptableCAs [][]byte
-
-	// SignatureSchemes lists the signature schemes that the server is
-	// willing to verify.
-	SignatureSchemes []SignatureScheme
-
-	// Version is the TLS version that was negotiated for this connection.
-	Version uint16
-
-	// ctx is the context of the handshake that is in progress.
-	ctx context.Context
-}
-
-// RenegotiationSupport enumerates the different levels of support for TLS
-// renegotiation. TLS renegotiation is the act of performing subsequent
-// handshakes on a connection after the first. This significantly complicates
-// the state machine and has been the source of numerous, subtle security
-// issues. Initiating a renegotiation is not supported, but support for
-// accepting renegotiation requests may be enabled.
-//
-// Even when enabled, the server may not change its identity between handshakes
-// (i.e. the leaf certificate must be the same). Additionally, concurrent
-// handshake and application data flow is not permitted so renegotiation can
-// only be used with protocols that synchronise with the renegotiation, such as
-// HTTPS.
-//
-// Renegotiation is not defined in TLS 1.3.
-type RenegotiationSupport int
-
-// A Config structure is used to configure a TLS client or server.
-// After one has been passed to a TLS function it must not be
-// modified. A Config may be reused; the tls package will also not
-// modify it.
-type Config struct {
-	// Rand provides the source of entropy for nonces and RSA blinding.
-	// If Rand is nil, TLS uses the cryptographic random reader in package
-	// crypto/rand.
-	// The Reader must be safe for use by multiple goroutines.
-	Rand io.Reader
-
-	// Time returns the current time as the number of seconds since the epoch.
-	// If Time is nil, TLS uses time.Now.
-	Time func() time.Time
-
-	// Certificates contains one or more certificate chains to present to the
-	// other side of the connection. The first certificate compatible with the
-	// peer's requirements is selected automatically.
-	//
-	// Server configurations must set one of Certificates, GetCertificate or
-	// GetConfigForClient. Clients doing client-authentication may set either
-	// Certificates or GetClientCertificate.
-	//
-	// Note: if there are multiple Certificates, and they don't have the
-	// optional field Leaf set, certificate selection will incur a significant
-	// per-handshake performance cost.
-	Certificates []Certificate
-
-	// NameToCertificate maps from a certificate name to an element of
-	// Certificates. Note that a certificate name can be of the form
-	// '*.example.com' and so doesn't have to be a domain name as such.
-	//
-	// Deprecated: NameToCertificate only allows associating a single
-	// certificate with a given name. Leave this field nil to let the library
-	// select the first compatible chain from Certificates.
-	NameToCertificate map[string]*Certificate
-
-	// GetCertificate returns a Certificate based on the given
-	// ClientHelloInfo. It will only be called if the client supplies SNI
-	// information or if Certificates is empty.
-	//
-	// If GetCertificate is nil or returns nil, then the certificate is
-	// retrieved from NameToCertificate. If NameToCertificate is nil, the
-	// best element of Certificates will be used.
-	//
-	// Once a Certificate is returned it should not be modified.
-	GetCertificate func(*ClientHelloInfo) (*Certificate, error)
-
-	// GetClientCertificate, if not nil, is called when a server requests a
-	// certificate from a client. If set, the contents of Certificates will
-	// be ignored.
-	//
-	// If GetClientCertificate returns an error, the handshake will be
-	// aborted and that error will be returned. Otherwise
-	// GetClientCertificate must return a non-nil Certificate. If
-	// Certificate.Certificate is empty then no certificate will be sent to
-	// the server. If this is unacceptable to the server then it may abort
-	// the handshake.
-	//
-	// GetClientCertificate may be called multiple times for the same
-	// connection if renegotiation occurs or if TLS 1.3 is in use.
-	//
-	// Once a Certificate is returned it should not be modified.
-	GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error)
-
-	// GetConfigForClient, if not nil, is called after a ClientHello is
-	// received from a client. It may return a non-nil Config in order to
-	// change the Config that will be used to handle this connection. If
-	// the returned Config is nil, the original Config will be used. The
-	// Config returned by this callback may not be subsequently modified.
-	//
-	// If GetConfigForClient is nil, the Config passed to Server() will be
-	// used for all connections.
-	//
-	// If SessionTicketKey was explicitly set on the returned Config, or if
-	// SetSessionTicketKeys was called on the returned Config, those keys will
-	// be used. Otherwise, the original Config keys will be used (and possibly
-	// rotated if they are automatically managed).
-	GetConfigForClient func(*ClientHelloInfo) (*Config, error)
-
-	// VerifyPeerCertificate, if not nil, is called after normal
-	// certificate verification by either a TLS client or server. It
-	// receives the raw ASN.1 certificates provided by the peer and also
-	// any verified chains that normal processing found. If it returns a
-	// non-nil error, the handshake is aborted and that error results.
-	//
-	// If normal verification fails then the handshake will abort before
-	// considering this callback. If normal verification is disabled (on the
-	// client when InsecureSkipVerify is set, or on a server when ClientAuth is
-	// RequestClientCert or RequireAnyClientCert), then this callback will be
-	// considered but the verifiedChains argument will always be nil. When
-	// ClientAuth is NoClientCert, this callback is not called on the server.
-	// rawCerts may be empty on the server if ClientAuth is RequestClientCert or
-	// VerifyClientCertIfGiven.
-	//
-	// This callback is not invoked on resumed connections, as certificates are
-	// not re-verified on resumption.
-	//
-	// verifiedChains and its contents should not be modified.
-	VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
-
-	// VerifyConnection, if not nil, is called after normal certificate
-	// verification and after VerifyPeerCertificate by either a TLS client
-	// or server. If it returns a non-nil error, the handshake is aborted
-	// and that error results.
-	//
-	// If normal verification fails then the handshake will abort before
-	// considering this callback. This callback will run for all connections,
-	// including resumptions, regardless of InsecureSkipVerify or ClientAuth
-	// settings.
-	VerifyConnection func(ConnectionState) error
-
-	// RootCAs defines the set of root certificate authorities
-	// that clients use when verifying server certificates.
-	// If RootCAs is nil, TLS uses the host's root CA set.
-	RootCAs *x509.CertPool
-
-	// NextProtos is a list of supported application level protocols, in
-	// order of preference. If both peers support ALPN, the selected
-	// protocol will be one from this list, and the connection will fail
-	// if there is no mutually supported protocol. If NextProtos is empty
-	// or the peer doesn't support ALPN, the connection will succeed and
-	// ConnectionState.NegotiatedProtocol will be empty.
-	NextProtos []string
-
-	// ServerName is used to verify the hostname on the returned
-	// certificates unless InsecureSkipVerify is given. It is also included
-	// in the client's handshake to support virtual hosting unless it is
-	// an IP address.
-	ServerName string
-
-	// ClientAuth determines the server's policy for
-	// TLS Client Authentication. The default is NoClientCert.
-	ClientAuth ClientAuthType
-
-	// ClientCAs defines the set of root certificate authorities
-	// that servers use if required to verify a client certificate
-	// by the policy in ClientAuth.
-	ClientCAs *x509.CertPool
-
-	// InsecureSkipVerify controls whether a client verifies the server's
-	// certificate chain and host name. If InsecureSkipVerify is true, crypto/tls
-	// accepts any certificate presented by the server and any host name in that
-	// certificate. In this mode, TLS is susceptible to machine-in-the-middle
-	// attacks unless custom verification is used. This should be used only for
-	// testing or in combination with VerifyConnection or VerifyPeerCertificate.
-	InsecureSkipVerify bool
-
-	// CipherSuites is a list of enabled TLS 1.0–1.2 cipher suites. The order of
-	// the list is ignored. Note that TLS 1.3 ciphersuites are not configurable.
-	//
-	// If CipherSuites is nil, a safe default list is used. The default cipher
-	// suites might change over time.
-	CipherSuites []uint16
-
-	// PreferServerCipherSuites is a legacy field and has no effect.
-	//
-	// It used to control whether the server would follow the client's or the
-	// server's preference. Servers now select the best mutually supported
-	// cipher suite based on logic that takes into account inferred client
-	// hardware, server hardware, and security.
-	//
-	// Deprecated: PreferServerCipherSuites is ignored.
-	PreferServerCipherSuites bool
-
-	// SessionTicketsDisabled may be set to true to disable session ticket and
-	// PSK (resumption) support. Note that on clients, session ticket support is
-	// also disabled if ClientSessionCache is nil.
-	SessionTicketsDisabled bool
-
-	// SessionTicketKey is used by TLS servers to provide session resumption.
-	// See RFC 5077 and the PSK mode of RFC 8446. If zero, it will be filled
-	// with random data before the first server handshake.
-	//
-	// Deprecated: if this field is left at zero, session ticket keys will be
-	// automatically rotated every day and dropped after seven days. For
-	// customizing the rotation schedule or synchronizing servers that are
-	// terminating connections for the same host, use SetSessionTicketKeys.
-	SessionTicketKey [32]byte
-
-	// ClientSessionCache is a cache of ClientSessionState entries for TLS
-	// session resumption. It is only used by clients.
-	ClientSessionCache ClientSessionCache
-
-	// UnwrapSession is called on the server to turn a ticket/identity
-	// previously produced by [WrapSession] into a usable session.
-	//
-	// UnwrapSession will usually either decrypt a session state in the ticket
-	// (for example with [Config.EncryptTicket]), or use the ticket as a handle
-	// to recover a previously stored state. It must use [ParseSessionState] to
-	// deserialize the session state.
-	//
-	// If UnwrapSession returns an error, the connection is terminated. If it
-	// returns (nil, nil), the session is ignored. crypto/tls may still choose
-	// not to resume the returned session.
-	UnwrapSession func(identity []byte, cs ConnectionState) (*SessionState, error)
-
-	// WrapSession is called on the server to produce a session ticket/identity.
-	//
-	// WrapSession must serialize the session state with [SessionState.Bytes].
-	// It may then encrypt the serialized state (for example with
-	// [Config.DecryptTicket]) and use it as the ticket, or store the state and
-	// return a handle for it.
-	//
-	// If WrapSession returns an error, the connection is terminated.
-	//
-	// Warning: the return value will be exposed on the wire and to clients in
-	// plaintext. The application is in charge of encrypting and authenticating
-	// it (and rotating keys) or returning high-entropy identifiers. Failing to
-	// do so correctly can compromise current, previous, and future connections
-	// depending on the protocol version.
-	WrapSession func(ConnectionState, *SessionState) ([]byte, error)
-
-	// MinVersion contains the minimum TLS version that is acceptable.
-	//
-	// By default, TLS 1.2 is currently used as the minimum when acting as a
-	// client, and TLS 1.0 when acting as a server. TLS 1.0 is the minimum
-	// supported by this package, both as a client and as a server.
-	//
-	// The client-side default can temporarily be reverted to TLS 1.0 by
-	// including the value "x509sha1=1" in the GODEBUG environment variable.
-	// Note that this option will be removed in Go 1.19 (but it will still be
-	// possible to set this field to VersionTLS10 explicitly).
-	MinVersion uint16
-
-	// MaxVersion contains the maximum TLS version that is acceptable.
-	//
-	// By default, the maximum version supported by this package is used,
-	// which is currently TLS 1.3.
-	MaxVersion uint16
-
-	// CurvePreferences contains the elliptic curves that will be used in
-	// an ECDHE handshake, in preference order. If empty, the default will
-	// be used. The client will use the first preference as the type for
-	// its key share in TLS 1.3. This may change in the future.
-	CurvePreferences []CurveID
-
-	// DynamicRecordSizingDisabled disables adaptive sizing of TLS records.
-	// When true, the largest possible TLS record size is always used. When
-	// false, the size of TLS records may be adjusted in an attempt to
-	// improve latency.
-	DynamicRecordSizingDisabled bool
-
-	// Renegotiation controls what types of renegotiation are supported.
-	// The default, none, is correct for the vast majority of applications.
-	Renegotiation RenegotiationSupport
-
-	// KeyLogWriter optionally specifies a destination for TLS master secrets
-	// in NSS key log format that can be used to allow external programs
-	// such as Wireshark to decrypt TLS connections.
-	// See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format.
-	// Use of KeyLogWriter compromises security and should only be
-	// used for debugging.
-	KeyLogWriter io.Writer
-
-	// mutex protects sessionTicketKeys and autoSessionTicketKeys.
-	mutex sync.RWMutex
-	// sessionTicketKeys contains zero or more ticket keys. If set, it means
-	// the keys were set with SessionTicketKey or SetSessionTicketKeys. The
-	// first key is used for new tickets and any subsequent keys can be used to
-	// decrypt old tickets. The slice contents are not protected by the mutex
-	// and are immutable.
-	sessionTicketKeys []ticketKey
-	// autoSessionTicketKeys is like sessionTicketKeys but is owned by the
-	// auto-rotation logic. See Config.ticketKeys.
-	autoSessionTicketKeys []ticketKey
-}
-
-// ticketKey is the internal representation of a session ticket key.
-type ticketKey struct {
-	aesKey  [16]byte
-	hmacKey [16]byte
-	// created is the time at which this ticket key was created. See Config.ticketKeys.
-	created time.Time
-}
-
-// A Certificate is a chain of one or more certificates, leaf first.
-type Certificate struct {
-	Certificate [][]byte
-	// PrivateKey contains the private key corresponding to the public key in
-	// Leaf. This must implement crypto.Signer with an RSA, ECDSA or Ed25519 PublicKey.
-	// For a server up to TLS 1.2, it can also implement crypto.Decrypter with
-	// an RSA PublicKey.
-	PrivateKey crypto.PrivateKey
-	// SupportedSignatureAlgorithms is an optional list restricting what
-	// signature algorithms the PrivateKey can be used for.
-	SupportedSignatureAlgorithms []SignatureScheme
-	// OCSPStaple contains an optional OCSP response which will be served
-	// to clients that request it.
-	OCSPStaple []byte
-	// SignedCertificateTimestamps contains an optional list of Signed
-	// Certificate Timestamps which will be served to clients that request it.
-	SignedCertificateTimestamps [][]byte
-	// Leaf is the parsed form of the leaf certificate, which may be initialized
-	// using x509.ParseCertificate to reduce per-handshake processing. If nil,
-	// the leaf certificate will be parsed as needed.
-	Leaf *x509.Certificate
-}
diff --git a/src/crypto/tls/ticket.go b/src/crypto/tls/ticket.go
deleted file mode 100644
index 152efb7824..0000000000
--- a/src/crypto/tls/ticket.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tls
-
-// A SessionState is a resumable session.
-type SessionState struct {
-}
-
-// ClientSessionState contains the state needed by a client to
-// resume a previous TLS session.
-type ClientSessionState struct {
-	ticket  []byte
-	session *SessionState
-}
diff --git a/src/crypto/tls/tls.go b/src/crypto/tls/tls.go
deleted file mode 100644
index 1520c30fca..0000000000
--- a/src/crypto/tls/tls.go
+++ /dev/null
@@ -1,114 +0,0 @@
-// TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package tls partially implements TLS 1.2, as specified in RFC 5246,
-// and TLS 1.3, as specified in RFC 8446.
-package tls
-
-// BUG(agl): The crypto/tls package only implements some countermeasures
-// against Lucky13 attacks on CBC-mode encryption, and only on SHA1
-// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
-// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
-
-import (
-	"context"
-	"errors"
-	"fmt"
-	"net"
-)
-
-// Client returns a new TLS client side connection
-// using conn as the underlying transport.
-// The config cannot be nil: users must set either ServerName or
-// InsecureSkipVerify in the config.
-func Client(conn net.Conn, config *Config) *net.TLSConn {
-	panic("tls.Client() not implemented")
-	return nil
-}
-
-// A listener implements a network listener (net.Listener) for TLS connections.
-type listener struct {
-	net.Listener
-	config *Config
-}
-
-// NewListener creates a Listener which accepts connections from an inner
-// Listener and wraps each connection with Server.
-// The configuration config must be non-nil and must include
-// at least one certificate or else set GetCertificate.
-func NewListener(inner net.Listener, config *Config) net.Listener {
-	l := new(listener)
-	l.Listener = inner
-	l.config = config
-	return l
-}
-
-// DialWithDialer connects to the given network address using dialer.Dial and
-// then initiates a TLS handshake, returning the resulting TLS connection. Any
-// timeout or deadline given in the dialer apply to connection and TLS
-// handshake as a whole.
-//
-// DialWithDialer interprets a nil configuration as equivalent to the zero
-// configuration; see the documentation of Config for the defaults.
-//
-// DialWithDialer uses context.Background internally; to specify the context,
-// use Dialer.DialContext with NetDialer set to the desired dialer.
-func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*net.TLSConn, error) {
-	switch network {
-	case "tcp", "tcp4":
-	default:
-		return nil, fmt.Errorf("Network %s not supported", network)
-	}
-
-	return net.DialTLS(addr)
-}
-
-// Dial connects to the given network address using net.Dial
-// and then initiates a TLS handshake, returning the resulting
-// TLS connection.
-// Dial interprets a nil configuration as equivalent to
-// the zero configuration; see the documentation of Config
-// for the defaults.
-func Dial(network, addr string, config *Config) (*net.TLSConn, error) {
-	return DialWithDialer(new(net.Dialer), network, addr, config)
-}
-
-// Dialer dials TLS connections given a configuration and a Dialer for the
-// underlying connection.
-type Dialer struct {
-	// NetDialer is the optional dialer to use for the TLS connections'
-	// underlying TCP connections.
-	// A nil NetDialer is equivalent to the net.Dialer zero value.
-	NetDialer *net.Dialer
-
-	// Config is the TLS configuration to use for new connections.
-	// A nil configuration is equivalent to the zero
-	// configuration; see the documentation of Config for the
-	// defaults.
-	Config *Config
-}
-
-// DialContext connects to the given network address and initiates a TLS
-// handshake, returning the resulting TLS connection.
-//
-// The provided Context must be non-nil. If the context expires before
-// the connection is complete, an error is returned. Once successfully
-// connected, any expiration of the context will not affect the
-// connection.
-//
-// The returned Conn, if any, will always be of type *Conn.
-func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
-	return nil, errors.New("tls:DialContext not implemented")
-}
-
-// LoadX509KeyPair reads and parses a public/private key pair from a pair
-// of files. The files must contain PEM encoded data. The certificate file
-// may contain intermediate certificates following the leaf certificate to
-// form a certificate chain. On successful return, Certificate.Leaf will
-// be nil because the parsed form of the certificate is not retained.
-func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
-	return Certificate{}, errors.New("tls:LoadX509KeyPair not implemented")
-}
diff --git a/src/net b/src/net
deleted file mode 160000
index a237059610..0000000000
--- a/src/net
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit a2370596106a621a9b9dd6ad930f0ec24cfee8d0
diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
new file mode 100644
index 0000000000..bd0c32f168
--- /dev/null
+++ b/src/runtime/netpoll.go
@@ -0,0 +1,45 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+// For debugging purposes this is used for all target architectures, but this is only valid for linux systems.
+// TODO: add linux specific build tags
+type pollDesc struct {
+	runtimeCtx uintptr
+}
+
+func (pd *pollDesc) wait(mode int, isFile bool) error {
+	return nil
+}
+
+const (
+	pollNoError        = 0 // no error
+	pollErrClosing     = 1 // descriptor is closed
+	pollErrTimeout     = 2 // I/O timeout
+	pollErrNotPollable = 3 // general error polling descriptor
+)
+
+//go:linkname poll_runtime_pollReset internal/poll.runtime_pollReset
+func poll_runtime_pollReset(pd *pollDesc, mode int) int {
+	println("poll_runtime_pollReset not implemented", pd, mode)
+	return pollNoError
+}
+
+//go:linkname poll_runtime_pollWait internal/poll.runtime_pollWait
+func poll_runtime_pollWait(pd *pollDesc, mode int) int {
+	println("poll_runtime_pollWait not implemented", pd, mode)
+	return pollNoError
+}
+
+//go:linkname poll_runtime_pollSetDeadline internal/poll.runtime_pollSetDeadline
+func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
+	println("poll_runtime_pollSetDeadline not implemented", pd, d, mode)
+}
+
+//go:linkname poll_runtime_pollOpen internal/poll.runtime_pollOpen
+func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
+	println("poll_runtime_pollOpen not implemented", fd)
+	return &pollDesc{runtimeCtx: 0x13371337}, pollNoError
+}
diff --git a/src/runtime/netpoll_generic.go b/src/runtime/netpoll_generic.go
new file mode 100644
index 0000000000..6a41d61cbc
--- /dev/null
+++ b/src/runtime/netpoll_generic.go
@@ -0,0 +1,31 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (js && wasm) || wasip1 || windows
+
+package runtime
+
+// Network poller descriptor.
+//
+// No heap pointers.
+// For linux to call create Fds with a pollDesc, it needs a ctxRuntime pointer, so use the original pollDesc struct.
+// On linux we have a heap.
+type pollDesc struct{}
+
+//go:linkname poll_runtime_pollReset internal/poll.runtime_pollReset
+func poll_runtime_pollReset(pd *pollDesc, mode int) int {
+	println("poll_runtime_pollReset not implemented", pd, mode)
+	return 1
+}
+
+//go:linkname poll_runtime_pollWait internal/poll.runtime_pollWait
+func poll_runtime_pollWait(pd *pollDesc, mode int) int {
+	println("poll_runtime_pollWait not implemented", pd, mode)
+	return 1
+}
+
+//go:linkname poll_runtime_pollSetDeadline internal/poll.runtime_pollSetDeadline
+func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
+	println("poll_runtime_pollSetDeadline not implemented", pd, d, mode)
+}
diff --git a/src/runtime/poll.go b/src/runtime/poll.go
index 2713bbea7e..a880272c87 100644
--- a/src/runtime/poll.go
+++ b/src/runtime/poll.go
@@ -4,20 +4,21 @@ package runtime
 
 //go:linkname poll_runtime_pollServerInit internal/poll.runtime_pollServerInit
 func poll_runtime_pollServerInit() {
-	panic("todo: runtime_pollServerInit")
+	// fmt.Printf("poll_runtime_pollServerInit not implemented, skipping panic\n")
 }
 
-//go:linkname poll_runtime_pollOpen internal/poll.runtime_pollOpen
-func poll_runtime_pollOpen(fd uintptr) (uintptr, int) {
-	panic("todo: runtime_pollOpen")
-}
+// //go:linkname poll_runtime_pollOpen internal/poll.runtime_pollOpen
+// func poll_runtime_pollOpen(fd uintptr) (uintptr, int) {
+// 	// fmt.Printf("poll_runtime_pollOpen not implemented, skipping panic\n")
+// 	return 0, 0
+// }
 
 //go:linkname poll_runtime_pollClose internal/poll.runtime_pollClose
 func poll_runtime_pollClose(ctx uintptr) {
-	panic("todo: runtime_pollClose")
+	// fmt.Printf("poll_runtime_pollClose not implemented, skipping panic\n")
 }
 
 //go:linkname poll_runtime_pollUnblock internal/poll.runtime_pollUnblock
 func poll_runtime_pollUnblock(ctx uintptr) {
-	panic("todo: runtime_pollUnblock")
+	// fmt.Printf("poll_runtime_pollUnblock not implemented, skipping panic\n")
 }
diff --git a/src/runtime/sync.go b/src/runtime/sync.go
index a0851401a0..98c7cf92e1 100644
--- a/src/runtime/sync.go
+++ b/src/runtime/sync.go
@@ -4,10 +4,14 @@ package runtime
 
 //go:linkname semacquire internal/poll.runtime_Semacquire
 func semacquire(sema *uint32) {
-	panic("todo: semacquire")
+	// TODO the "net" pkg calls this, so panic() isn't an option.  Right
+	// now, just ignore the call.
+	// panic("todo: semacquire")
 }
 
 //go:linkname semrelease internal/poll.runtime_Semrelease
 func semrelease(sema *uint32) {
-	panic("todo: semrelease")
+	// TODO the "net" pkg calls this, so panic() isn't an option.  Right
+	// now, just ignore the call.
+	// panic("todo: semrelease")
 }
diff --git a/src/syscall/forklock_tinygo.go b/src/syscall/forklock_tinygo.go
new file mode 100644
index 0000000000..bdca5a21ed
--- /dev/null
+++ b/src/syscall/forklock_tinygo.go
@@ -0,0 +1,38 @@
+//go:build tinygo
+
+package syscall
+
+// This is the original ForkLock:
+//
+// var ForkLock sync.RWMutex
+//
+// This requires importing sync, but importing sync causes an import loop:
+//
+// package tinygo.org/x/drivers/examples/net/tcpclient
+//        imports bytes
+//        imports io
+//        imports sync
+//        imports internal/task
+//        imports runtime/interrupt
+//        imports device/arm
+//        imports syscall
+//        imports sync: import cycle not allowed
+//
+// So for now, make our own stubbed-out ForkLock that doesn't use sync..
+
+type forklock struct{}
+
+func (f forklock) RLock()   {}
+func (f forklock) RUnlock() {}
+
+var ForkLock forklock
+
+func CloseOnExec(fd int) {
+	system.CloseOnExec(fd)
+}
+
+func SetNonblock(fd int, nonblocking bool) (err error) {
+	return system.SetNonblock(fd, nonblocking)
+}
+
+type SysProcAttr struct{}

From 3c34bbdb62ae56c7f1cedbbadece367a7b8e18ea Mon Sep 17 00:00:00 2001
From: leongross <leon.gross@9elements.com>
Date: Wed, 11 Sep 2024 14:22:33 +0200
Subject: [PATCH 03/14] remove print statements for cleaner execution

Signed-off-by: leongross <leon.gross@9elements.com>
---
 src/runtime/netpoll.go | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
index bd0c32f168..ee6a95d3b3 100644
--- a/src/runtime/netpoll.go
+++ b/src/runtime/netpoll.go
@@ -23,23 +23,23 @@ const (
 
 //go:linkname poll_runtime_pollReset internal/poll.runtime_pollReset
 func poll_runtime_pollReset(pd *pollDesc, mode int) int {
-	println("poll_runtime_pollReset not implemented", pd, mode)
+	// println("poll_runtime_pollReset not implemented", pd, mode)
 	return pollNoError
 }
 
 //go:linkname poll_runtime_pollWait internal/poll.runtime_pollWait
 func poll_runtime_pollWait(pd *pollDesc, mode int) int {
-	println("poll_runtime_pollWait not implemented", pd, mode)
+	// println("poll_runtime_pollWait not implemented", pd, mode)
 	return pollNoError
 }
 
 //go:linkname poll_runtime_pollSetDeadline internal/poll.runtime_pollSetDeadline
 func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
-	println("poll_runtime_pollSetDeadline not implemented", pd, d, mode)
+	// println("poll_runtime_pollSetDeadline not implemented", pd, d, mode)
 }
 
 //go:linkname poll_runtime_pollOpen internal/poll.runtime_pollOpen
 func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
-	println("poll_runtime_pollOpen not implemented", fd)
+	// println("poll_runtime_pollOpen not implemented", fd)
 	return &pollDesc{runtimeCtx: 0x13371337}, pollNoError
 }

From facd62e3220c8b235292281b5ee5633d7a3116a6 Mon Sep 17 00:00:00 2001
From: leongross <leon.gross@9elements.com>
Date: Wed, 18 Sep 2024 14:30:21 +0200
Subject: [PATCH 04/14] fix uncommited net exclusion

if this does not work, do the folliwing steps:
1. remove net submodule
2. remove symlink in local ~/.cache/tinygo/goroot-<hash>/net
3. manual symlink yo local golang /usr/local/bin/src/net

Signed-off-by: leongross <leon.gross@9elements.com>
---
 loader/goroot.go | 28 ++++++++++++++++++++--------
 loader/loader.go |  2 +-
 2 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/loader/goroot.go b/loader/goroot.go
index 7a48ecbb1f..ecf4ac51e2 100644
--- a/loader/goroot.go
+++ b/loader/goroot.go
@@ -45,7 +45,7 @@ func GetCachedGoroot(config *compileopts.Config) (string, error) {
 	}
 
 	// Find the overrides needed for the goroot.
-	overrides := pathsToOverride(config.GoMinorVersion, needsSyscallPackage(config.BuildTags()))
+	overrides := pathsToOverride(config.GoMinorVersion, config.BuildTags())
 
 	// Resolve the merge links within the goroot.
 	merge, err := listGorootMergeLinks(goroot, tinygoroot, overrides)
@@ -225,9 +225,20 @@ func needsSyscallPackage(buildTags []string) bool {
 	return false
 }
 
+// linuxNetworking returns whether the unmodified go linux net stack should be used
+// until the full rework of the net package is done.
+func linuxNetworking(buildTags []string) bool {
+	for _, tag := range buildTags {
+		if tag == "linux" {
+			return true
+		}
+	}
+	return false
+}
+
 // The boolean indicates whether to merge the subdirs. True means merge, false
 // means use the TinyGo version.
-func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
+func pathsToOverride(goMinor int, buildTags []string) map[string]bool {
 	paths := map[string]bool{
 		"":                            true,
 		"crypto/":                     true,
@@ -267,15 +278,16 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
 		paths["crypto/internal/boring/sig/"] = false
 	}
 
-	if needsSyscallPackage {
+	if needsSyscallPackage(buildTags) {
 		paths["syscall/"] = true // include syscall/js
 	}
 
-	// to enable network support for linux systems, reuse the Go version of the net package
-	// and the according runtime functions
-	// if runtime.GOOS == "linux" {
-	// 	paths["runtime/netpoll/"] = true
-	// }
+	if linuxNetworking(buildTags) {
+		for _, v := range []string{"crypto/tls/", "net/http/", "net/"} {
+			delete(paths, v) // remote entries so go stdlib is used
+		}
+	}
+
 	return paths
 }
 
diff --git a/loader/loader.go b/loader/loader.go
index e935a9de3a..f94fc70f8e 100644
--- a/loader/loader.go
+++ b/loader/loader.go
@@ -279,7 +279,7 @@ func (p *Program) getOriginalPath(path string) string {
 			originalPath = realgorootPath
 		}
 		maybeInTinyGoRoot := false
-		for prefix := range pathsToOverride(p.config.GoMinorVersion, needsSyscallPackage(p.config.BuildTags())) {
+		for prefix := range pathsToOverride(p.config.GoMinorVersion, p.config.BuildTags()) {
 			if runtime.GOOS == "windows" {
 				prefix = strings.ReplaceAll(prefix, "/", "\\")
 			}

From 90532f1069eb3d3d13cd6eb4afb2adb47d57072a Mon Sep 17 00:00:00 2001
From: leongross <leon.gross@9elements.com>
Date: Thu, 3 Oct 2024 17:36:40 +0200
Subject: [PATCH 05/14] bring back old net

---
 .gitmodules              |  50 ++---
 src/crypto/tls/common.go | 460 +++++++++++++++++++++++++++++++++++++++
 src/crypto/tls/ticket.go |  16 ++
 src/crypto/tls/tls.go    | 114 ++++++++++
 src/net                  |   1 +
 5 files changed, 616 insertions(+), 25 deletions(-)
 create mode 100644 src/crypto/tls/common.go
 create mode 100644 src/crypto/tls/ticket.go
 create mode 100644 src/crypto/tls/tls.go
 create mode 160000 src/net

diff --git a/.gitmodules b/.gitmodules
index e4f627ae1c..2749d21f6a 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,37 +1,37 @@
 [submodule "lib/nrfx"]
-	path = lib/nrfx
-	url = https://github.com/NordicSemiconductor/nrfx.git
+    path = lib/nrfx
+    url = https://github.com/NordicSemiconductor/nrfx.git
 [submodule "lib/CMSIS"]
-	path = lib/CMSIS
-	url = https://github.com/ARM-software/CMSIS.git
+    path = lib/CMSIS
+    url = https://github.com/ARM-software/CMSIS.git
 [submodule "lib/avr"]
-	path = lib/avr
-	url = https://github.com/avr-rust/avr-mcu.git
+    path = lib/avr
+    url = https://github.com/avr-rust/avr-mcu.git
 [submodule "lib/cmsis-svd"]
-	path = lib/cmsis-svd
-	url = https://github.com/cmsis-svd/cmsis-svd-data.git
-	branch = main
+    path = lib/cmsis-svd
+    url = https://github.com/cmsis-svd/cmsis-svd-data.git
+    branch = main
 [submodule "lib/wasi-libc"]
-	path = lib/wasi-libc
-	url = https://github.com/WebAssembly/wasi-libc
+    path = lib/wasi-libc
+    url = https://github.com/WebAssembly/wasi-libc
 [submodule "lib/picolibc"]
-	path = lib/picolibc
-	url = https://github.com/keith-packard/picolibc.git
+    path = lib/picolibc
+    url = https://github.com/keith-packard/picolibc.git
 [submodule "lib/stm32-svd"]
-	path = lib/stm32-svd
-	url = https://github.com/tinygo-org/stm32-svd
+    path = lib/stm32-svd
+    url = https://github.com/tinygo-org/stm32-svd
 [submodule "lib/musl"]
-	path = lib/musl
-	url = git://git.musl-libc.org/musl
+    path = lib/musl
+    url = git://git.musl-libc.org/musl
 [submodule "lib/binaryen"]
-	path = lib/binaryen
-	url = https://github.com/WebAssembly/binaryen.git
+    path = lib/binaryen
+    url = https://github.com/WebAssembly/binaryen.git
 [submodule "lib/mingw-w64"]
-	path = lib/mingw-w64
-	url = https://github.com/mingw-w64/mingw-w64.git
+    path = lib/mingw-w64
+    url = https://github.com/mingw-w64/mingw-w64.git
 [submodule "lib/macos-minimal-sdk"]
-	path = lib/macos-minimal-sdk
-	url = https://github.com/aykevl/macos-minimal-sdk.git
+    path = lib/macos-minimal-sdk
+    url = https://github.com/aykevl/macos-minimal-sdk.git
 [submodule "lib/wasi-cli"]
-	path = lib/wasi-cli
-	url = https://github.com/WebAssembly/wasi-cli
+    path = lib/wasi-cli
+    url = https://github.com/WebAssembly/wasi-cli
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go
new file mode 100644
index 0000000000..caf0198e15
--- /dev/null
+++ b/src/crypto/tls/common.go
@@ -0,0 +1,460 @@
+// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"context"
+	"crypto"
+	"crypto/x509"
+	"fmt"
+	"io"
+	"net"
+	"sync"
+	"time"
+)
+
+// CurveID is the type of a TLS identifier for an elliptic curve. See
+// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8.
+//
+// In TLS 1.3, this type is called NamedGroup, but at this time this library
+// only supports Elliptic Curve based groups. See RFC 8446, Section 4.2.7.
+type CurveID uint16
+
+// CipherSuiteName returns the standard name for the passed cipher suite ID
+//
+// Not Implemented.
+func CipherSuiteName(id uint16) string {
+	return fmt.Sprintf("0x%04X", id)
+}
+
+// ConnectionState records basic TLS details about the connection.
+type ConnectionState struct {
+	// TINYGO: empty; TLS connection offloaded to device
+	//
+	// Minimum (empty) fields for fortio.org/log http logging and others
+	// to compile and run.
+	PeerCertificates []*x509.Certificate
+	CipherSuite      uint16
+}
+
+// ClientAuthType declares the policy the server will follow for
+// TLS Client Authentication.
+type ClientAuthType int
+
+// ClientSessionCache is a cache of ClientSessionState objects that can be used
+// by a client to resume a TLS session with a given server. ClientSessionCache
+// implementations should expect to be called concurrently from different
+// goroutines. Up to TLS 1.2, only ticket-based resumption is supported, not
+// SessionID-based resumption. In TLS 1.3 they were merged into PSK modes, which
+// are supported via this interface.
+type ClientSessionCache interface {
+	// Get searches for a ClientSessionState associated with the given key.
+	// On return, ok is true if one was found.
+	Get(sessionKey string) (session *ClientSessionState, ok bool)
+
+	// Put adds the ClientSessionState to the cache with the given key. It might
+	// get called multiple times in a connection if a TLS 1.3 server provides
+	// more than one session ticket. If called with a nil *ClientSessionState,
+	// it should remove the cache entry.
+	Put(sessionKey string, cs *ClientSessionState)
+}
+
+//go:generate stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go
+
+// SignatureScheme identifies a signature algorithm supported by TLS. See
+// RFC 8446, Section 4.2.3.
+type SignatureScheme uint16
+
+// ClientHelloInfo contains information from a ClientHello message in order to
+// guide application logic in the GetCertificate and GetConfigForClient callbacks.
+type ClientHelloInfo struct {
+	// CipherSuites lists the CipherSuites supported by the client (e.g.
+	// TLS_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).
+	CipherSuites []uint16
+
+	// ServerName indicates the name of the server requested by the client
+	// in order to support virtual hosting. ServerName is only set if the
+	// client is using SNI (see RFC 4366, Section 3.1).
+	ServerName string
+
+	// SupportedCurves lists the elliptic curves supported by the client.
+	// SupportedCurves is set only if the Supported Elliptic Curves
+	// Extension is being used (see RFC 4492, Section 5.1.1).
+	SupportedCurves []CurveID
+
+	// SupportedPoints lists the point formats supported by the client.
+	// SupportedPoints is set only if the Supported Point Formats Extension
+	// is being used (see RFC 4492, Section 5.1.2).
+	SupportedPoints []uint8
+
+	// SignatureSchemes lists the signature and hash schemes that the client
+	// is willing to verify. SignatureSchemes is set only if the Signature
+	// Algorithms Extension is being used (see RFC 5246, Section 7.4.1.4.1).
+	SignatureSchemes []SignatureScheme
+
+	// SupportedProtos lists the application protocols supported by the client.
+	// SupportedProtos is set only if the Application-Layer Protocol
+	// Negotiation Extension is being used (see RFC 7301, Section 3.1).
+	//
+	// Servers can select a protocol by setting Config.NextProtos in a
+	// GetConfigForClient return value.
+	SupportedProtos []string
+
+	// SupportedVersions lists the TLS versions supported by the client.
+	// For TLS versions less than 1.3, this is extrapolated from the max
+	// version advertised by the client, so values other than the greatest
+	// might be rejected if used.
+	SupportedVersions []uint16
+
+	// Conn is the underlying net.Conn for the connection. Do not read
+	// from, or write to, this connection; that will cause the TLS
+	// connection to fail.
+	Conn net.Conn
+
+	// config is embedded by the GetCertificate or GetConfigForClient caller,
+	// for use with SupportsCertificate.
+	config *Config
+
+	// ctx is the context of the handshake that is in progress.
+	ctx context.Context
+}
+
+// CertificateRequestInfo contains information from a server's
+// CertificateRequest message, which is used to demand a certificate and proof
+// of control from a client.
+type CertificateRequestInfo struct {
+	// AcceptableCAs contains zero or more, DER-encoded, X.501
+	// Distinguished Names. These are the names of root or intermediate CAs
+	// that the server wishes the returned certificate to be signed by. An
+	// empty slice indicates that the server has no preference.
+	AcceptableCAs [][]byte
+
+	// SignatureSchemes lists the signature schemes that the server is
+	// willing to verify.
+	SignatureSchemes []SignatureScheme
+
+	// Version is the TLS version that was negotiated for this connection.
+	Version uint16
+
+	// ctx is the context of the handshake that is in progress.
+	ctx context.Context
+}
+
+// RenegotiationSupport enumerates the different levels of support for TLS
+// renegotiation. TLS renegotiation is the act of performing subsequent
+// handshakes on a connection after the first. This significantly complicates
+// the state machine and has been the source of numerous, subtle security
+// issues. Initiating a renegotiation is not supported, but support for
+// accepting renegotiation requests may be enabled.
+//
+// Even when enabled, the server may not change its identity between handshakes
+// (i.e. the leaf certificate must be the same). Additionally, concurrent
+// handshake and application data flow is not permitted so renegotiation can
+// only be used with protocols that synchronise with the renegotiation, such as
+// HTTPS.
+//
+// Renegotiation is not defined in TLS 1.3.
+type RenegotiationSupport int
+
+// A Config structure is used to configure a TLS client or server.
+// After one has been passed to a TLS function it must not be
+// modified. A Config may be reused; the tls package will also not
+// modify it.
+type Config struct {
+	// Rand provides the source of entropy for nonces and RSA blinding.
+	// If Rand is nil, TLS uses the cryptographic random reader in package
+	// crypto/rand.
+	// The Reader must be safe for use by multiple goroutines.
+	Rand io.Reader
+
+	// Time returns the current time as the number of seconds since the epoch.
+	// If Time is nil, TLS uses time.Now.
+	Time func() time.Time
+
+	// Certificates contains one or more certificate chains to present to the
+	// other side of the connection. The first certificate compatible with the
+	// peer's requirements is selected automatically.
+	//
+	// Server configurations must set one of Certificates, GetCertificate or
+	// GetConfigForClient. Clients doing client-authentication may set either
+	// Certificates or GetClientCertificate.
+	//
+	// Note: if there are multiple Certificates, and they don't have the
+	// optional field Leaf set, certificate selection will incur a significant
+	// per-handshake performance cost.
+	Certificates []Certificate
+
+	// NameToCertificate maps from a certificate name to an element of
+	// Certificates. Note that a certificate name can be of the form
+	// '*.example.com' and so doesn't have to be a domain name as such.
+	//
+	// Deprecated: NameToCertificate only allows associating a single
+	// certificate with a given name. Leave this field nil to let the library
+	// select the first compatible chain from Certificates.
+	NameToCertificate map[string]*Certificate
+
+	// GetCertificate returns a Certificate based on the given
+	// ClientHelloInfo. It will only be called if the client supplies SNI
+	// information or if Certificates is empty.
+	//
+	// If GetCertificate is nil or returns nil, then the certificate is
+	// retrieved from NameToCertificate. If NameToCertificate is nil, the
+	// best element of Certificates will be used.
+	//
+	// Once a Certificate is returned it should not be modified.
+	GetCertificate func(*ClientHelloInfo) (*Certificate, error)
+
+	// GetClientCertificate, if not nil, is called when a server requests a
+	// certificate from a client. If set, the contents of Certificates will
+	// be ignored.
+	//
+	// If GetClientCertificate returns an error, the handshake will be
+	// aborted and that error will be returned. Otherwise
+	// GetClientCertificate must return a non-nil Certificate. If
+	// Certificate.Certificate is empty then no certificate will be sent to
+	// the server. If this is unacceptable to the server then it may abort
+	// the handshake.
+	//
+	// GetClientCertificate may be called multiple times for the same
+	// connection if renegotiation occurs or if TLS 1.3 is in use.
+	//
+	// Once a Certificate is returned it should not be modified.
+	GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error)
+
+	// GetConfigForClient, if not nil, is called after a ClientHello is
+	// received from a client. It may return a non-nil Config in order to
+	// change the Config that will be used to handle this connection. If
+	// the returned Config is nil, the original Config will be used. The
+	// Config returned by this callback may not be subsequently modified.
+	//
+	// If GetConfigForClient is nil, the Config passed to Server() will be
+	// used for all connections.
+	//
+	// If SessionTicketKey was explicitly set on the returned Config, or if
+	// SetSessionTicketKeys was called on the returned Config, those keys will
+	// be used. Otherwise, the original Config keys will be used (and possibly
+	// rotated if they are automatically managed).
+	GetConfigForClient func(*ClientHelloInfo) (*Config, error)
+
+	// VerifyPeerCertificate, if not nil, is called after normal
+	// certificate verification by either a TLS client or server. It
+	// receives the raw ASN.1 certificates provided by the peer and also
+	// any verified chains that normal processing found. If it returns a
+	// non-nil error, the handshake is aborted and that error results.
+	//
+	// If normal verification fails then the handshake will abort before
+	// considering this callback. If normal verification is disabled (on the
+	// client when InsecureSkipVerify is set, or on a server when ClientAuth is
+	// RequestClientCert or RequireAnyClientCert), then this callback will be
+	// considered but the verifiedChains argument will always be nil. When
+	// ClientAuth is NoClientCert, this callback is not called on the server.
+	// rawCerts may be empty on the server if ClientAuth is RequestClientCert or
+	// VerifyClientCertIfGiven.
+	//
+	// This callback is not invoked on resumed connections, as certificates are
+	// not re-verified on resumption.
+	//
+	// verifiedChains and its contents should not be modified.
+	VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
+
+	// VerifyConnection, if not nil, is called after normal certificate
+	// verification and after VerifyPeerCertificate by either a TLS client
+	// or server. If it returns a non-nil error, the handshake is aborted
+	// and that error results.
+	//
+	// If normal verification fails then the handshake will abort before
+	// considering this callback. This callback will run for all connections,
+	// including resumptions, regardless of InsecureSkipVerify or ClientAuth
+	// settings.
+	VerifyConnection func(ConnectionState) error
+
+	// RootCAs defines the set of root certificate authorities
+	// that clients use when verifying server certificates.
+	// If RootCAs is nil, TLS uses the host's root CA set.
+	RootCAs *x509.CertPool
+
+	// NextProtos is a list of supported application level protocols, in
+	// order of preference. If both peers support ALPN, the selected
+	// protocol will be one from this list, and the connection will fail
+	// if there is no mutually supported protocol. If NextProtos is empty
+	// or the peer doesn't support ALPN, the connection will succeed and
+	// ConnectionState.NegotiatedProtocol will be empty.
+	NextProtos []string
+
+	// ServerName is used to verify the hostname on the returned
+	// certificates unless InsecureSkipVerify is given. It is also included
+	// in the client's handshake to support virtual hosting unless it is
+	// an IP address.
+	ServerName string
+
+	// ClientAuth determines the server's policy for
+	// TLS Client Authentication. The default is NoClientCert.
+	ClientAuth ClientAuthType
+
+	// ClientCAs defines the set of root certificate authorities
+	// that servers use if required to verify a client certificate
+	// by the policy in ClientAuth.
+	ClientCAs *x509.CertPool
+
+	// InsecureSkipVerify controls whether a client verifies the server's
+	// certificate chain and host name. If InsecureSkipVerify is true, crypto/tls
+	// accepts any certificate presented by the server and any host name in that
+	// certificate. In this mode, TLS is susceptible to machine-in-the-middle
+	// attacks unless custom verification is used. This should be used only for
+	// testing or in combination with VerifyConnection or VerifyPeerCertificate.
+	InsecureSkipVerify bool
+
+	// CipherSuites is a list of enabled TLS 1.0–1.2 cipher suites. The order of
+	// the list is ignored. Note that TLS 1.3 ciphersuites are not configurable.
+	//
+	// If CipherSuites is nil, a safe default list is used. The default cipher
+	// suites might change over time.
+	CipherSuites []uint16
+
+	// PreferServerCipherSuites is a legacy field and has no effect.
+	//
+	// It used to control whether the server would follow the client's or the
+	// server's preference. Servers now select the best mutually supported
+	// cipher suite based on logic that takes into account inferred client
+	// hardware, server hardware, and security.
+	//
+	// Deprecated: PreferServerCipherSuites is ignored.
+	PreferServerCipherSuites bool
+
+	// SessionTicketsDisabled may be set to true to disable session ticket and
+	// PSK (resumption) support. Note that on clients, session ticket support is
+	// also disabled if ClientSessionCache is nil.
+	SessionTicketsDisabled bool
+
+	// SessionTicketKey is used by TLS servers to provide session resumption.
+	// See RFC 5077 and the PSK mode of RFC 8446. If zero, it will be filled
+	// with random data before the first server handshake.
+	//
+	// Deprecated: if this field is left at zero, session ticket keys will be
+	// automatically rotated every day and dropped after seven days. For
+	// customizing the rotation schedule or synchronizing servers that are
+	// terminating connections for the same host, use SetSessionTicketKeys.
+	SessionTicketKey [32]byte
+
+	// ClientSessionCache is a cache of ClientSessionState entries for TLS
+	// session resumption. It is only used by clients.
+	ClientSessionCache ClientSessionCache
+
+	// UnwrapSession is called on the server to turn a ticket/identity
+	// previously produced by [WrapSession] into a usable session.
+	//
+	// UnwrapSession will usually either decrypt a session state in the ticket
+	// (for example with [Config.EncryptTicket]), or use the ticket as a handle
+	// to recover a previously stored state. It must use [ParseSessionState] to
+	// deserialize the session state.
+	//
+	// If UnwrapSession returns an error, the connection is terminated. If it
+	// returns (nil, nil), the session is ignored. crypto/tls may still choose
+	// not to resume the returned session.
+	UnwrapSession func(identity []byte, cs ConnectionState) (*SessionState, error)
+
+	// WrapSession is called on the server to produce a session ticket/identity.
+	//
+	// WrapSession must serialize the session state with [SessionState.Bytes].
+	// It may then encrypt the serialized state (for example with
+	// [Config.DecryptTicket]) and use it as the ticket, or store the state and
+	// return a handle for it.
+	//
+	// If WrapSession returns an error, the connection is terminated.
+	//
+	// Warning: the return value will be exposed on the wire and to clients in
+	// plaintext. The application is in charge of encrypting and authenticating
+	// it (and rotating keys) or returning high-entropy identifiers. Failing to
+	// do so correctly can compromise current, previous, and future connections
+	// depending on the protocol version.
+	WrapSession func(ConnectionState, *SessionState) ([]byte, error)
+
+	// MinVersion contains the minimum TLS version that is acceptable.
+	//
+	// By default, TLS 1.2 is currently used as the minimum when acting as a
+	// client, and TLS 1.0 when acting as a server. TLS 1.0 is the minimum
+	// supported by this package, both as a client and as a server.
+	//
+	// The client-side default can temporarily be reverted to TLS 1.0 by
+	// including the value "x509sha1=1" in the GODEBUG environment variable.
+	// Note that this option will be removed in Go 1.19 (but it will still be
+	// possible to set this field to VersionTLS10 explicitly).
+	MinVersion uint16
+
+	// MaxVersion contains the maximum TLS version that is acceptable.
+	//
+	// By default, the maximum version supported by this package is used,
+	// which is currently TLS 1.3.
+	MaxVersion uint16
+
+	// CurvePreferences contains the elliptic curves that will be used in
+	// an ECDHE handshake, in preference order. If empty, the default will
+	// be used. The client will use the first preference as the type for
+	// its key share in TLS 1.3. This may change in the future.
+	CurvePreferences []CurveID
+
+	// DynamicRecordSizingDisabled disables adaptive sizing of TLS records.
+	// When true, the largest possible TLS record size is always used. When
+	// false, the size of TLS records may be adjusted in an attempt to
+	// improve latency.
+	DynamicRecordSizingDisabled bool
+
+	// Renegotiation controls what types of renegotiation are supported.
+	// The default, none, is correct for the vast majority of applications.
+	Renegotiation RenegotiationSupport
+
+	// KeyLogWriter optionally specifies a destination for TLS master secrets
+	// in NSS key log format that can be used to allow external programs
+	// such as Wireshark to decrypt TLS connections.
+	// See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format.
+	// Use of KeyLogWriter compromises security and should only be
+	// used for debugging.
+	KeyLogWriter io.Writer
+
+	// mutex protects sessionTicketKeys and autoSessionTicketKeys.
+	mutex sync.RWMutex
+	// sessionTicketKeys contains zero or more ticket keys. If set, it means
+	// the keys were set with SessionTicketKey or SetSessionTicketKeys. The
+	// first key is used for new tickets and any subsequent keys can be used to
+	// decrypt old tickets. The slice contents are not protected by the mutex
+	// and are immutable.
+	sessionTicketKeys []ticketKey
+	// autoSessionTicketKeys is like sessionTicketKeys but is owned by the
+	// auto-rotation logic. See Config.ticketKeys.
+	autoSessionTicketKeys []ticketKey
+}
+
+// ticketKey is the internal representation of a session ticket key.
+type ticketKey struct {
+	aesKey  [16]byte
+	hmacKey [16]byte
+	// created is the time at which this ticket key was created. See Config.ticketKeys.
+	created time.Time
+}
+
+// A Certificate is a chain of one or more certificates, leaf first.
+type Certificate struct {
+	Certificate [][]byte
+	// PrivateKey contains the private key corresponding to the public key in
+	// Leaf. This must implement crypto.Signer with an RSA, ECDSA or Ed25519 PublicKey.
+	// For a server up to TLS 1.2, it can also implement crypto.Decrypter with
+	// an RSA PublicKey.
+	PrivateKey crypto.PrivateKey
+	// SupportedSignatureAlgorithms is an optional list restricting what
+	// signature algorithms the PrivateKey can be used for.
+	SupportedSignatureAlgorithms []SignatureScheme
+	// OCSPStaple contains an optional OCSP response which will be served
+	// to clients that request it.
+	OCSPStaple []byte
+	// SignedCertificateTimestamps contains an optional list of Signed
+	// Certificate Timestamps which will be served to clients that request it.
+	SignedCertificateTimestamps [][]byte
+	// Leaf is the parsed form of the leaf certificate, which may be initialized
+	// using x509.ParseCertificate to reduce per-handshake processing. If nil,
+	// the leaf certificate will be parsed as needed.
+	Leaf *x509.Certificate
+}
diff --git a/src/crypto/tls/ticket.go b/src/crypto/tls/ticket.go
new file mode 100644
index 0000000000..152efb7824
--- /dev/null
+++ b/src/crypto/tls/ticket.go
@@ -0,0 +1,16 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+// A SessionState is a resumable session.
+type SessionState struct {
+}
+
+// ClientSessionState contains the state needed by a client to
+// resume a previous TLS session.
+type ClientSessionState struct {
+	ticket  []byte
+	session *SessionState
+}
diff --git a/src/crypto/tls/tls.go b/src/crypto/tls/tls.go
new file mode 100644
index 0000000000..1520c30fca
--- /dev/null
+++ b/src/crypto/tls/tls.go
@@ -0,0 +1,114 @@
+// TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tls partially implements TLS 1.2, as specified in RFC 5246,
+// and TLS 1.3, as specified in RFC 8446.
+package tls
+
+// BUG(agl): The crypto/tls package only implements some countermeasures
+// against Lucky13 attacks on CBC-mode encryption, and only on SHA1
+// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
+// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"net"
+)
+
+// Client returns a new TLS client side connection
+// using conn as the underlying transport.
+// The config cannot be nil: users must set either ServerName or
+// InsecureSkipVerify in the config.
+func Client(conn net.Conn, config *Config) *net.TLSConn {
+	panic("tls.Client() not implemented")
+	return nil
+}
+
+// A listener implements a network listener (net.Listener) for TLS connections.
+type listener struct {
+	net.Listener
+	config *Config
+}
+
+// NewListener creates a Listener which accepts connections from an inner
+// Listener and wraps each connection with Server.
+// The configuration config must be non-nil and must include
+// at least one certificate or else set GetCertificate.
+func NewListener(inner net.Listener, config *Config) net.Listener {
+	l := new(listener)
+	l.Listener = inner
+	l.config = config
+	return l
+}
+
+// DialWithDialer connects to the given network address using dialer.Dial and
+// then initiates a TLS handshake, returning the resulting TLS connection. Any
+// timeout or deadline given in the dialer apply to connection and TLS
+// handshake as a whole.
+//
+// DialWithDialer interprets a nil configuration as equivalent to the zero
+// configuration; see the documentation of Config for the defaults.
+//
+// DialWithDialer uses context.Background internally; to specify the context,
+// use Dialer.DialContext with NetDialer set to the desired dialer.
+func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*net.TLSConn, error) {
+	switch network {
+	case "tcp", "tcp4":
+	default:
+		return nil, fmt.Errorf("Network %s not supported", network)
+	}
+
+	return net.DialTLS(addr)
+}
+
+// Dial connects to the given network address using net.Dial
+// and then initiates a TLS handshake, returning the resulting
+// TLS connection.
+// Dial interprets a nil configuration as equivalent to
+// the zero configuration; see the documentation of Config
+// for the defaults.
+func Dial(network, addr string, config *Config) (*net.TLSConn, error) {
+	return DialWithDialer(new(net.Dialer), network, addr, config)
+}
+
+// Dialer dials TLS connections given a configuration and a Dialer for the
+// underlying connection.
+type Dialer struct {
+	// NetDialer is the optional dialer to use for the TLS connections'
+	// underlying TCP connections.
+	// A nil NetDialer is equivalent to the net.Dialer zero value.
+	NetDialer *net.Dialer
+
+	// Config is the TLS configuration to use for new connections.
+	// A nil configuration is equivalent to the zero
+	// configuration; see the documentation of Config for the
+	// defaults.
+	Config *Config
+}
+
+// DialContext connects to the given network address and initiates a TLS
+// handshake, returning the resulting TLS connection.
+//
+// The provided Context must be non-nil. If the context expires before
+// the connection is complete, an error is returned. Once successfully
+// connected, any expiration of the context will not affect the
+// connection.
+//
+// The returned Conn, if any, will always be of type *Conn.
+func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
+	return nil, errors.New("tls:DialContext not implemented")
+}
+
+// LoadX509KeyPair reads and parses a public/private key pair from a pair
+// of files. The files must contain PEM encoded data. The certificate file
+// may contain intermediate certificates following the leaf certificate to
+// form a certificate chain. On successful return, Certificate.Leaf will
+// be nil because the parsed form of the certificate is not retained.
+func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
+	return Certificate{}, errors.New("tls:LoadX509KeyPair not implemented")
+}
diff --git a/src/net b/src/net
new file mode 160000
index 0000000000..a237059610
--- /dev/null
+++ b/src/net
@@ -0,0 +1 @@
+Subproject commit a2370596106a621a9b9dd6ad930f0ec24cfee8d0

From 8224b0e3a4fdd2488fd065325af96e77e609e4a3 Mon Sep 17 00:00:00 2001
From: leongross <leon.gross@9elements.com>
Date: Fri, 4 Oct 2024 16:01:00 +0200
Subject: [PATCH 06/14] switch net via build tags

Signed-off-by: leongross <leon.gross@9elements.com>
---
 .gitmodules      |  3 +++
 loader/goroot.go | 10 +++++++---
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/.gitmodules b/.gitmodules
index 2749d21f6a..29778d6709 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -35,3 +35,6 @@
 [submodule "lib/wasi-cli"]
     path = lib/wasi-cli
     url = https://github.com/WebAssembly/wasi-cli
+[submodule "src/net"]
+	path = src/net
+	url = https://github.com/tinygo-org/net
diff --git a/loader/goroot.go b/loader/goroot.go
index ecf4ac51e2..40f46877d0 100644
--- a/loader/goroot.go
+++ b/loader/goroot.go
@@ -236,8 +236,10 @@ func linuxNetworking(buildTags []string) bool {
 	return false
 }
 
-// The boolean indicates whether to merge the subdirs. True means merge, false
-// means use the TinyGo version.
+// The boolean indicates whether to merge the subdirs.
+//
+// True: Merge the golang and tinygo source directories.
+// False: Uses the TinyGo version exclusively.
 func pathsToOverride(goMinor int, buildTags []string) map[string]bool {
 	paths := map[string]bool{
 		"":                            true,
@@ -261,7 +263,7 @@ func pathsToOverride(goMinor int, buildTags []string) map[string]bool {
 		"internal/task/":              false,
 		"internal/wasi/":              false,
 		"machine/":                    false,
-		"net/":                        true,
+		"net/":                        true, // this is important if the GOOS != linux
 		"net/http/":                   false,
 		"os/":                         true,
 		"reflect/":                    false,
@@ -282,6 +284,8 @@ func pathsToOverride(goMinor int, buildTags []string) map[string]bool {
 		paths["syscall/"] = true // include syscall/js
 	}
 
+	// To make sure the correct version of the net package is used, it is advised
+	// to clean the go cache before building
 	if linuxNetworking(buildTags) {
 		for _, v := range []string{"crypto/tls/", "net/http/", "net/"} {
 			delete(paths, v) // remote entries so go stdlib is used

From 82f1b96c289de753caf864286818ff52574fe8a5 Mon Sep 17 00:00:00 2001
From: leongross <leon.gross@9elements.com>
Date: Fri, 4 Oct 2024 16:12:57 +0200
Subject: [PATCH 07/14] adjust target os specific build tags

---
 src/runtime/netpoll.go         | 4 +++-
 src/runtime/netpoll_generic.go | 2 +-
 src/syscall/forklock_tinygo.go | 4 ++--
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
index ee6a95d3b3..1a182e3491 100644
--- a/src/runtime/netpoll.go
+++ b/src/runtime/netpoll.go
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build linux
+
 package runtime
 
 // For debugging purposes this is used for all target architectures, but this is only valid for linux systems.
@@ -41,5 +43,5 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
 //go:linkname poll_runtime_pollOpen internal/poll.runtime_pollOpen
 func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
 	// println("poll_runtime_pollOpen not implemented", fd)
-	return &pollDesc{runtimeCtx: 0x13371337}, pollNoError
+	return &pollDesc{runtimeCtx: uintptr(0xdeadbeef)}, pollNoError
 }
diff --git a/src/runtime/netpoll_generic.go b/src/runtime/netpoll_generic.go
index 6a41d61cbc..123d190770 100644
--- a/src/runtime/netpoll_generic.go
+++ b/src/runtime/netpoll_generic.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build (js && wasm) || wasip1 || windows
+//go:build !linux
 
 package runtime
 
diff --git a/src/syscall/forklock_tinygo.go b/src/syscall/forklock_tinygo.go
index bdca5a21ed..db9469e2fa 100644
--- a/src/syscall/forklock_tinygo.go
+++ b/src/syscall/forklock_tinygo.go
@@ -1,4 +1,4 @@
-//go:build tinygo
+//go:build tinygo && linux && !wasip1 && !wasip2 && !darwin
 
 package syscall
 
@@ -35,4 +35,4 @@ func SetNonblock(fd int, nonblocking bool) (err error) {
 	return system.SetNonblock(fd, nonblocking)
 }
 
-type SysProcAttr struct{}
+// type SysProcAttr struct{}

From 46394c1bb0654fa311aeb19fb0557b69727168dc Mon Sep 17 00:00:00 2001
From: leongross <leon.gross@9elements.com>
Date: Tue, 8 Oct 2024 11:46:13 +0200
Subject: [PATCH 08/14] chnage macos build

---
 src/syscall/{forklock_tinygo.go => forklock.go} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename src/syscall/{forklock_tinygo.go => forklock.go} (100%)

diff --git a/src/syscall/forklock_tinygo.go b/src/syscall/forklock.go
similarity index 100%
rename from src/syscall/forklock_tinygo.go
rename to src/syscall/forklock.go

From 42348c87e5580e601b5513ea8c469f086f907729 Mon Sep 17 00:00:00 2001
From: leongross <leon.gross@9elements.com>
Date: Fri, 11 Oct 2024 13:14:50 +0200
Subject: [PATCH 09/14] add integration tests for net

---
 testdata/net.go  | 82 ++++++++++++++++++++++++++++++++++++++++++++++++
 testdata/net.txt |  2 ++
 2 files changed, 84 insertions(+)
 create mode 100644 testdata/net.go
 create mode 100644 testdata/net.txt

diff --git a/testdata/net.go b/testdata/net.go
new file mode 100644
index 0000000000..746becbce4
--- /dev/null
+++ b/testdata/net.go
@@ -0,0 +1,82 @@
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"net"
+	"strconv"
+	"time"
+)
+
+// Test golang network package integration for tinygo.
+// This test is not exhaustive and only tests the basic functionality of the package.
+
+const (
+	TEST_PORT = 9000
+)
+
+var (
+	testsPassed uint
+	err         error
+	sendBuf     = &bytes.Buffer{}
+	recvBuf     = &bytes.Buffer{}
+)
+
+var (
+	testDialListenData = []byte("Hello tinygo :)")
+)
+
+func TestDialListen() {
+	// listen thread
+	go func() {
+		ln, err := net.Listen("tcp", ":"+strconv.FormatInt(TEST_PORT, 10))
+		if err != nil {
+			fmt.Printf("error listening: %v\n", err)
+			return
+		}
+
+		conn, err := ln.Accept()
+		if err != nil {
+			fmt.Printf("error accepting: %v\n", err)
+			return
+		}
+
+		recvBuf.Reset()
+		_, err = conn.Read(recvBuf.Bytes())
+		if err != nil {
+			fmt.Printf("error reading: %v\n", err)
+			return
+		}
+
+		// TODO: this is racy
+		if recvBuf.String() != string(testDialListenData) {
+			fmt.Printf("error: received data does not match sent data: '%s' != '%s'\n", recvBuf.String(), string(testDialListenData))
+			return
+		}
+		conn.Close()
+
+		return
+	}()
+
+	// hacky way to wait for the listener to start
+	time.Sleep(1 * time.Second)
+
+	sendBuf.Reset()
+	fmt.Fprint(sendBuf, testDialListenData)
+	conn, err := net.Dial("tcp4", "127.0.0.1:"+strconv.FormatInt(TEST_PORT, 10))
+	if err != nil {
+		fmt.Printf("error dialing: %v\n", err)
+		return
+	}
+
+	if _, err = conn.Write(sendBuf.Bytes()); err != nil {
+		fmt.Printf("error writing: %v\n", err)
+		return
+	}
+}
+
+func main() {
+	fmt.Printf("test: net start\n")
+	TestDialListen()
+	fmt.Printf("test: net end\n")
+}
diff --git a/testdata/net.txt b/testdata/net.txt
new file mode 100644
index 0000000000..82681e45a0
--- /dev/null
+++ b/testdata/net.txt
@@ -0,0 +1,2 @@
+test: net start
+test: net end
\ No newline at end of file

From a695ab6b2ca3a07953d348701a100e4ff4761544 Mon Sep 17 00:00:00 2001
From: leongross <leon.gross@9elements.com>
Date: Fri, 11 Oct 2024 16:33:19 +0200
Subject: [PATCH 10/14] further restrict net package usage

Signed-off-by: leongross <leon.gross@9elements.com>
---
 loader/goroot.go        | 10 ++++++++--
 src/runtime/netpoll.go  |  2 +-
 src/syscall/forklock.go |  2 +-
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/loader/goroot.go b/loader/goroot.go
index 40f46877d0..ca56c4d49b 100644
--- a/loader/goroot.go
+++ b/loader/goroot.go
@@ -227,13 +227,19 @@ func needsSyscallPackage(buildTags []string) bool {
 
 // linuxNetworking returns whether the unmodified go linux net stack should be used
 // until the full rework of the net package is done.
+// To ensure the correct build target, check for the following tags:
+// linux && !baremetal && !nintendoswitch && !tinygo.wasm
 func linuxNetworking(buildTags []string) bool {
+	targetLinux := false
 	for _, tag := range buildTags {
 		if tag == "linux" {
-			return true
+			targetLinux = true
+		}
+		if tag == "baremetal" || tag == "nintendoswitch" || tag == "tinygo.wasm" {
+			return false
 		}
 	}
-	return false
+	return targetLinux
 }
 
 // The boolean indicates whether to merge the subdirs.
diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
index 1a182e3491..e4157b994f 100644
--- a/src/runtime/netpoll.go
+++ b/src/runtime/netpoll.go
@@ -43,5 +43,5 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
 //go:linkname poll_runtime_pollOpen internal/poll.runtime_pollOpen
 func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
 	// println("poll_runtime_pollOpen not implemented", fd)
-	return &pollDesc{runtimeCtx: uintptr(0xdeadbeef)}, pollNoError
+	return &pollDesc{runtimeCtx: uintptr(0x1337)}, pollNoError
 }
diff --git a/src/syscall/forklock.go b/src/syscall/forklock.go
index db9469e2fa..cab4721400 100644
--- a/src/syscall/forklock.go
+++ b/src/syscall/forklock.go
@@ -1,4 +1,4 @@
-//go:build tinygo && linux && !wasip1 && !wasip2 && !darwin
+//go:build tinygo && linux && !wasip1 && !wasip2 && !darwin && !baremetal
 
 package syscall
 

From a39597ca455f7262377f15cd2e30c09f5d017d64 Mon Sep 17 00:00:00 2001
From: leongross <leon.gross@9elements.com>
Date: Mon, 4 Nov 2024 10:57:00 +0100
Subject: [PATCH 11/14] add preliminary semaphore implementation

Signed-off-by: leongross <leon.gross@9elements.com>
---
 .gitmodules                    | 55 ++++++++++++++--------------
 src/runtime/netpoll_generic.go | 11 +++++-
 src/runtime/sync.go            | 67 +++++++++++++++++++++++++++++++---
 testdata/net.go                | 51 +++++++++++---------------
 4 files changed, 119 insertions(+), 65 deletions(-)

diff --git a/.gitmodules b/.gitmodules
index 29778d6709..91bd14a7d7 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,40 +1,41 @@
 [submodule "lib/nrfx"]
-    path = lib/nrfx
-    url = https://github.com/NordicSemiconductor/nrfx.git
+	path = lib/nrfx
+	url = https://github.com/NordicSemiconductor/nrfx.git
 [submodule "lib/CMSIS"]
-    path = lib/CMSIS
-    url = https://github.com/ARM-software/CMSIS.git
+	path = lib/CMSIS
+	url = https://github.com/ARM-software/CMSIS.git
 [submodule "lib/avr"]
-    path = lib/avr
-    url = https://github.com/avr-rust/avr-mcu.git
+	path = lib/avr
+	url = https://github.com/avr-rust/avr-mcu.git
 [submodule "lib/cmsis-svd"]
-    path = lib/cmsis-svd
-    url = https://github.com/cmsis-svd/cmsis-svd-data.git
-    branch = main
+	path = lib/cmsis-svd
+	url = https://github.com/cmsis-svd/cmsis-svd-data.git
+	branch = main
 [submodule "lib/wasi-libc"]
-    path = lib/wasi-libc
-    url = https://github.com/WebAssembly/wasi-libc
+	path = lib/wasi-libc
+	url = https://github.com/WebAssembly/wasi-libc
 [submodule "lib/picolibc"]
-    path = lib/picolibc
-    url = https://github.com/keith-packard/picolibc.git
+	path = lib/picolibc
+	url = https://github.com/keith-packard/picolibc.git
 [submodule "lib/stm32-svd"]
-    path = lib/stm32-svd
-    url = https://github.com/tinygo-org/stm32-svd
+	path = lib/stm32-svd
+	url = https://github.com/tinygo-org/stm32-svd
 [submodule "lib/musl"]
-    path = lib/musl
-    url = git://git.musl-libc.org/musl
+	path = lib/musl
+	url = git://git.musl-libc.org/musl
 [submodule "lib/binaryen"]
-    path = lib/binaryen
-    url = https://github.com/WebAssembly/binaryen.git
+	path = lib/binaryen
+	url = https://github.com/WebAssembly/binaryen.git
 [submodule "lib/mingw-w64"]
-    path = lib/mingw-w64
-    url = https://github.com/mingw-w64/mingw-w64.git
+	path = lib/mingw-w64
+	url = https://github.com/mingw-w64/mingw-w64.git
 [submodule "lib/macos-minimal-sdk"]
-    path = lib/macos-minimal-sdk
-    url = https://github.com/aykevl/macos-minimal-sdk.git
-[submodule "lib/wasi-cli"]
-    path = lib/wasi-cli
-    url = https://github.com/WebAssembly/wasi-cli
+	path = lib/macos-minimal-sdk
+	url = https://github.com/aykevl/macos-minimal-sdk.git
 [submodule "src/net"]
 	path = src/net
-	url = https://github.com/tinygo-org/net
+	url = https://github.com/tinygo-org/net.git
+	branch = dev
+[submodule "lib/wasi-cli"]
+	path = lib/wasi-cli
+	url = https://github.com/WebAssembly/wasi-cli
diff --git a/src/runtime/netpoll_generic.go b/src/runtime/netpoll_generic.go
index 123d190770..f5f26d84d9 100644
--- a/src/runtime/netpoll_generic.go
+++ b/src/runtime/netpoll_generic.go
@@ -6,6 +6,13 @@
 
 package runtime
 
+const (
+	pollNoError        = 0 // no error
+	pollErrClosing     = 1 // descriptor is closed
+	pollErrTimeout     = 2 // I/O timeout
+	pollErrNotPollable = 3 // general error polling descriptor
+)
+
 // Network poller descriptor.
 //
 // No heap pointers.
@@ -16,13 +23,13 @@ type pollDesc struct{}
 //go:linkname poll_runtime_pollReset internal/poll.runtime_pollReset
 func poll_runtime_pollReset(pd *pollDesc, mode int) int {
 	println("poll_runtime_pollReset not implemented", pd, mode)
-	return 1
+	return pollErrClosing
 }
 
 //go:linkname poll_runtime_pollWait internal/poll.runtime_pollWait
 func poll_runtime_pollWait(pd *pollDesc, mode int) int {
 	println("poll_runtime_pollWait not implemented", pd, mode)
-	return 1
+	return pollErrClosing
 }
 
 //go:linkname poll_runtime_pollSetDeadline internal/poll.runtime_pollSetDeadline
diff --git a/src/runtime/sync.go b/src/runtime/sync.go
index 98c7cf92e1..3d302ec7d2 100644
--- a/src/runtime/sync.go
+++ b/src/runtime/sync.go
@@ -1,17 +1,72 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package runtime
 
+import (
+	"sync/atomic"
+	"unsafe"
+)
+
 // This file contains stub implementations for internal/poll.
+// The official golang implementation states:
+//
+// "That is, don't think of these as semaphores.
+// Think of them as a way to implement sleep and wakeup
+// such that every sleep is paired with a single wakeup,
+// even if, due to races, the wakeup happens before the sleep."
+//
+// This is an experimental and probably incomplete implementation of the
+// semaphore system, tailed to the network use case. That means, that it does not
+// implement the modularity that the semacquire/semacquire1 implementation model
+// offers, which in fact is emitted here entirely.
+// This means we assume the following constant settings from the golang standard
+// library: lifo=false,profile=semaBlock,skipframe=0,reason=waitReasonSemaquire
+
+type semaRoot struct {
+	nwait atomic.Uint32
+}
+
+var semtable semTable
+
+// Prime to not correlate with any user patterns.
+const semTabSize = 251
+
+type semTable [semTabSize]struct {
+	root semaRoot
+	pad  [64 - unsafe.Sizeof(semaRoot{})]byte // only 64 x86_64, make this variable
+}
+
+func (t *semTable) rootFor(addr *uint32) *semaRoot {
+	return &t[(uintptr(unsafe.Pointer(addr))>>3)%semTabSize].root
+}
 
 //go:linkname semacquire internal/poll.runtime_Semacquire
 func semacquire(sema *uint32) {
-	// TODO the "net" pkg calls this, so panic() isn't an option.  Right
-	// now, just ignore the call.
-	// panic("todo: semacquire")
+	if cansemacquire(sema) {
+		return
+	}
+}
+
+// Copied from src/runtime/sema.go
+func cansemacquire(addr *uint32) bool {
+	for {
+		v := atomic.LoadUint32(addr)
+		if v == 0 {
+			return false
+		}
+		if atomic.CompareAndSwapUint32(addr, v, v-1) {
+			return true
+		}
+	}
 }
 
 //go:linkname semrelease internal/poll.runtime_Semrelease
 func semrelease(sema *uint32) {
-	// TODO the "net" pkg calls this, so panic() isn't an option.  Right
-	// now, just ignore the call.
-	// panic("todo: semrelease")
+	root := semtable.rootFor(sema)
+	atomic.AddUint32(sema, 1)
+	if root.nwait.Load() == 0 {
+		return
+	}
 }
diff --git a/testdata/net.go b/testdata/net.go
index 746becbce4..2a7908fa1c 100644
--- a/testdata/net.go
+++ b/testdata/net.go
@@ -1,25 +1,19 @@
 package main
 
 import (
-	"bytes"
-	"fmt"
+	"io"
 	"net"
 	"strconv"
-	"time"
 )
 
 // Test golang network package integration for tinygo.
 // This test is not exhaustive and only tests the basic functionality of the package.
 
-const (
-	TEST_PORT = 9000
-)
-
 var (
 	testsPassed uint
+	lnPort      int
 	err         error
-	sendBuf     = &bytes.Buffer{}
-	recvBuf     = &bytes.Buffer{}
+	recvBuf     []byte
 )
 
 var (
@@ -28,29 +22,30 @@ var (
 
 func TestDialListen() {
 	// listen thread
+	listenReady := make(chan bool, 1)
 	go func() {
-		ln, err := net.Listen("tcp", ":"+strconv.FormatInt(TEST_PORT, 10))
+		ln, err := net.Listen("tcp4", ":0")
 		if err != nil {
-			fmt.Printf("error listening: %v\n", err)
+			println("error listening: ", err)
 			return
 		}
+		lnPort = ln.Addr().(*net.TCPAddr).Port
 
+		listenReady <- true
 		conn, err := ln.Accept()
 		if err != nil {
-			fmt.Printf("error accepting: %v\n", err)
+			println("error accepting:", err)
 			return
 		}
 
-		recvBuf.Reset()
-		_, err = conn.Read(recvBuf.Bytes())
-		if err != nil {
-			fmt.Printf("error reading: %v\n", err)
+		recvBuf = make([]byte, len(testDialListenData))
+		if _, err := io.ReadFull(conn, recvBuf); err != nil {
+			println("error reading: ", err)
 			return
 		}
 
-		// TODO: this is racy
-		if recvBuf.String() != string(testDialListenData) {
-			fmt.Printf("error: received data does not match sent data: '%s' != '%s'\n", recvBuf.String(), string(testDialListenData))
+		if string(recvBuf) != string(testDialListenData) {
+			println("error: received data does not match sent data", string(recvBuf), " != ", string(testDialListenData))
 			return
 		}
 		conn.Close()
@@ -58,25 +53,21 @@ func TestDialListen() {
 		return
 	}()
 
-	// hacky way to wait for the listener to start
-	time.Sleep(1 * time.Second)
-
-	sendBuf.Reset()
-	fmt.Fprint(sendBuf, testDialListenData)
-	conn, err := net.Dial("tcp4", "127.0.0.1:"+strconv.FormatInt(TEST_PORT, 10))
+	<-listenReady
+	conn, err := net.Dial("tcp4", "127.0.0.1:"+strconv.FormatInt(int64(lnPort), 10))
 	if err != nil {
-		fmt.Printf("error dialing: %v\n", err)
+		println("error dialing: ", err)
 		return
 	}
 
-	if _, err = conn.Write(sendBuf.Bytes()); err != nil {
-		fmt.Printf("error writing: %v\n", err)
+	if _, err = conn.Write(testDialListenData); err != nil {
+		println("error writing: ", err)
 		return
 	}
 }
 
 func main() {
-	fmt.Printf("test: net start\n")
+	println("test: net start")
 	TestDialListen()
-	fmt.Printf("test: net end\n")
+	println("test: net end")
 }

From 2e04cc2f5ce6d042dafad4da551bc3a96fe591a9 Mon Sep 17 00:00:00 2001
From: leongross <leon.gross@9elements.com>
Date: Mon, 11 Nov 2024 11:55:47 +0100
Subject: [PATCH 12/14] remove old forklock stub and replace it with
 sync.RWMutex

Signed-off-by: leongross <leon.gross@9elements.com>
---
 src/syscall/forklock.go | 31 +++++--------------------------
 1 file changed, 5 insertions(+), 26 deletions(-)

diff --git a/src/syscall/forklock.go b/src/syscall/forklock.go
index cab4721400..a158b24871 100644
--- a/src/syscall/forklock.go
+++ b/src/syscall/forklock.go
@@ -1,31 +1,12 @@
-//go:build tinygo && linux && !wasip1 && !wasip2 && !darwin && !baremetal
+//go:build tinygo && linux && !wasip1 && !wasip2 && tinygo.wasm && !wasm_unknown && !darwin && !baremetal && !nintendoswitch
 
 package syscall
 
-// This is the original ForkLock:
-//
-// var ForkLock sync.RWMutex
-//
-// This requires importing sync, but importing sync causes an import loop:
-//
-// package tinygo.org/x/drivers/examples/net/tcpclient
-//        imports bytes
-//        imports io
-//        imports sync
-//        imports internal/task
-//        imports runtime/interrupt
-//        imports device/arm
-//        imports syscall
-//        imports sync: import cycle not allowed
-//
-// So for now, make our own stubbed-out ForkLock that doesn't use sync..
+import (
+	"sync"
+)
 
-type forklock struct{}
-
-func (f forklock) RLock()   {}
-func (f forklock) RUnlock() {}
-
-var ForkLock forklock
+var ForkLock sync.RWMutex
 
 func CloseOnExec(fd int) {
 	system.CloseOnExec(fd)
@@ -34,5 +15,3 @@ func CloseOnExec(fd int) {
 func SetNonblock(fd int, nonblocking bool) (err error) {
 	return system.SetNonblock(fd, nonblocking)
 }
-
-// type SysProcAttr struct{}

From da0f694df53bf1a0c7e43c85de6724d75928d412 Mon Sep 17 00:00:00 2001
From: leongross <leon.gross@9elements.com>
Date: Sun, 17 Nov 2024 10:04:03 +0100
Subject: [PATCH 13/14] wip

Signed-off-by: leongross <leon.gross@9elements.com>
---
 src/runtime/sync.go | 73 +++++++++++++++++++++++++++++++--------------
 1 file changed, 51 insertions(+), 22 deletions(-)

diff --git a/src/runtime/sync.go b/src/runtime/sync.go
index 3d302ec7d2..83ddcab064 100644
--- a/src/runtime/sync.go
+++ b/src/runtime/sync.go
@@ -5,8 +5,9 @@
 package runtime
 
 import (
+	"internal/task"
+	"sync"
 	"sync/atomic"
-	"unsafe"
 )
 
 // This file contains stub implementations for internal/poll.
@@ -24,22 +25,35 @@ import (
 // This means we assume the following constant settings from the golang standard
 // library: lifo=false,profile=semaBlock,skipframe=0,reason=waitReasonSemaquire
 
-type semaRoot struct {
-	nwait atomic.Uint32
+// The global state of the semaphore table.
+// Semaphores are identified by their address.
+// The table maps the address to the task that is currently holding the semaphore.
+// The table is protected by a mutex.
+// When a task acquires a semaphore, the mapping is added to the map.
+// When a task releases a semaphore, the mapping is removed from the map.
+//
+// The table is used to implement the cansemacquire function.
+// The cansemacquire function is called by the semacquire function.
+// The cansemacquire function checks if the semaphore is available.
+// If the semaphore is available, the function returns true.
+// If the semaphore is not available, the function returns false.
+type semTable struct {
+	table map[*uint32]*task.Task
+	lock  sync.Mutex
 }
 
 var semtable semTable
 
-// Prime to not correlate with any user patterns.
-const semTabSize = 251
+func init() {
+	semtable.table = make(map[*uint32]*task.Task)
+}
 
-type semTable [semTabSize]struct {
-	root semaRoot
-	pad  [64 - unsafe.Sizeof(semaRoot{})]byte // only 64 x86_64, make this variable
+func (s *semTable) Lock() {
+	s.lock.Lock()
 }
 
-func (t *semTable) rootFor(addr *uint32) *semaRoot {
-	return &t[(uintptr(unsafe.Pointer(addr))>>3)%semTabSize].root
+func (s *semTable) Unlock() {
+	s.lock.Unlock()
 }
 
 //go:linkname semacquire internal/poll.runtime_Semacquire
@@ -51,22 +65,37 @@ func semacquire(sema *uint32) {
 
 // Copied from src/runtime/sema.go
 func cansemacquire(addr *uint32) bool {
-	for {
-		v := atomic.LoadUint32(addr)
-		if v == 0 {
-			return false
-		}
-		if atomic.CompareAndSwapUint32(addr, v, v-1) {
-			return true
-		}
+	// Busy Looping until a lookup to the global semaphore table can be made
+	semtable.Lock()
+
+	if _, ok := semtable.table[addr]; !ok {
+		semtable.table[addr] = task.Current()
+		semtable.Unlock()
+		return true
+	}
+
+	v := atomic.LoadUint32(addr)
+	if v == 0 {
+		semtable.Unlock()
+		return false
+	}
+	if atomic.CompareAndSwapUint32(addr, v, v-1) {
+		semtable.Unlock()
+		return true
 	}
+	return true
 }
 
 //go:linkname semrelease internal/poll.runtime_Semrelease
 func semrelease(sema *uint32) {
-	root := semtable.rootFor(sema)
-	atomic.AddUint32(sema, 1)
-	if root.nwait.Load() == 0 {
-		return
+	// Check if the semaphore is in the table
+	semtable.Lock()
+	if _, ok := semtable.table[sema]; !ok {
+		panic("invalid semaphore")
 	}
+
+	atomic.AddUint32(sema, 1)
+	semtable.Unlock()
+
+	Gosched()
 }

From c16ff80f46f24e7545ecb8eb7a0a0c98670ed9ab Mon Sep 17 00:00:00 2001
From: leongross <leon.gross@9elements.com>
Date: Fri, 29 Nov 2024 13:26:10 +0100
Subject: [PATCH 14/14] implement semrealse and semacquire using futex

Signed-off-by: leongross <leon.gross@9elements.com>
---
 src/runtime/sync.go | 81 +++++++++------------------------------------
 1 file changed, 16 insertions(+), 65 deletions(-)

diff --git a/src/runtime/sync.go b/src/runtime/sync.go
index 83ddcab064..bf0499fe9e 100644
--- a/src/runtime/sync.go
+++ b/src/runtime/sync.go
@@ -5,9 +5,7 @@
 package runtime
 
 import (
-	"internal/task"
-	"sync"
-	"sync/atomic"
+	"internal/futex"
 )
 
 // This file contains stub implementations for internal/poll.
@@ -25,77 +23,30 @@ import (
 // This means we assume the following constant settings from the golang standard
 // library: lifo=false,profile=semaBlock,skipframe=0,reason=waitReasonSemaquire
 
-// The global state of the semaphore table.
-// Semaphores are identified by their address.
-// The table maps the address to the task that is currently holding the semaphore.
-// The table is protected by a mutex.
-// When a task acquires a semaphore, the mapping is added to the map.
-// When a task releases a semaphore, the mapping is removed from the map.
-//
-// The table is used to implement the cansemacquire function.
-// The cansemacquire function is called by the semacquire function.
-// The cansemacquire function checks if the semaphore is available.
-// If the semaphore is available, the function returns true.
-// If the semaphore is not available, the function returns false.
-type semTable struct {
-	table map[*uint32]*task.Task
-	lock  sync.Mutex
-}
-
-var semtable semTable
-
-func init() {
-	semtable.table = make(map[*uint32]*task.Task)
-}
-
-func (s *semTable) Lock() {
-	s.lock.Lock()
-}
-
-func (s *semTable) Unlock() {
-	s.lock.Unlock()
-}
-
 //go:linkname semacquire internal/poll.runtime_Semacquire
 func semacquire(sema *uint32) {
-	if cansemacquire(sema) {
-		return
-	}
-}
-
-// Copied from src/runtime/sema.go
-func cansemacquire(addr *uint32) bool {
-	// Busy Looping until a lookup to the global semaphore table can be made
-	semtable.Lock()
+	var semaBlock futex.Futex
+	semaBlock.Store(*sema)
 
-	if _, ok := semtable.table[addr]; !ok {
-		semtable.table[addr] = task.Current()
-		semtable.Unlock()
-		return true
-	}
+	// check if we can acquire the semaphore
+	semaBlock.Wait(1)
 
-	v := atomic.LoadUint32(addr)
-	if v == 0 {
-		semtable.Unlock()
-		return false
-	}
-	if atomic.CompareAndSwapUint32(addr, v, v-1) {
-		semtable.Unlock()
-		return true
+	// the semaphore is free to use so we can acquire it
+	if semaBlock.Swap(0) != 1 {
+		panic("semaphore is already acquired, racy")
 	}
-	return true
 }
 
 //go:linkname semrelease internal/poll.runtime_Semrelease
 func semrelease(sema *uint32) {
-	// Check if the semaphore is in the table
-	semtable.Lock()
-	if _, ok := semtable.table[sema]; !ok {
-		panic("invalid semaphore")
-	}
+	var semaBlock futex.Futex
+	semaBlock.Store(*sema)
 
-	atomic.AddUint32(sema, 1)
-	semtable.Unlock()
+	// check if we can release the semaphore
+	if semaBlock.Swap(1) != 0 {
+		panic("semaphore is not acquired, racy")
+	}
 
-	Gosched()
+	// wake up the next waiter
+	semaBlock.Wake()
 }