Update
This commit is contained in:
1 parent
3530afb854
commit
6903fcff27
2146 files changed
+112256
-190703
No files matched your search
+40
-32
@@ -120,7 +120,7 @@ func (c *Conn) ReadContext(ctx context.Context, b []byte) (int, error) {
|
||||
b = b[:maxRW]
|
||||
}
|
||||
|
||||
n, err := readT(c, ctx, "read", func(fd int) (int, error) {
|
||||
n, err := readT(ctx, c, "read", func(fd int) (int, error) {
|
||||
return unix.Read(fd, b)
|
||||
})
|
||||
if n == 0 && err == nil && c.facts.zeroReadIsEOF {
|
||||
@@ -142,12 +142,12 @@ func (c *Conn) WriteContext(ctx context.Context, b []byte) (int, error) {
|
||||
)
|
||||
|
||||
doErr := c.write(ctx, "write", func(fd int) error {
|
||||
max := len(b)
|
||||
if c.facts.isStream && max-nn > maxRW {
|
||||
max = nn + maxRW
|
||||
lenb := len(b)
|
||||
if c.facts.isStream && lenb-nn > maxRW {
|
||||
lenb = nn + maxRW
|
||||
}
|
||||
|
||||
n, err = unix.Write(fd, b[nn:max])
|
||||
n, err = unix.Write(fd, b[nn:lenb])
|
||||
if n > 0 {
|
||||
nn += n
|
||||
}
|
||||
@@ -418,7 +418,7 @@ func (c *Conn) Accept(ctx context.Context, flags int) (*Conn, unix.Sockaddr, err
|
||||
sa unix.Sockaddr
|
||||
}
|
||||
|
||||
r, err := readT(c, ctx, sysAccept, func(fd int) (ret, error) {
|
||||
r, err := readT(ctx, c, sysAccept, func(fd int) (ret, error) {
|
||||
// Either accept(2) or accept4(2) depending on the OS.
|
||||
nfd, sa, err := accept(fd, flags|socketFlags)
|
||||
return ret{nfd, sa}, err
|
||||
@@ -464,7 +464,7 @@ func (c *Conn) Connect(ctx context.Context, sa unix.Sockaddr) (unix.Sockaddr, er
|
||||
// have an explicit WaitWrite call like internal/poll does, so we have
|
||||
// to wait until the runtime calls the closure again to indicate we can
|
||||
// write.
|
||||
progress uint32
|
||||
progress atomic.Uint32
|
||||
|
||||
// Capture closure sockaddr and error.
|
||||
rsa unix.Sockaddr
|
||||
@@ -472,7 +472,7 @@ func (c *Conn) Connect(ctx context.Context, sa unix.Sockaddr) (unix.Sockaddr, er
|
||||
)
|
||||
|
||||
doErr := c.write(ctx, op, func(fd int) error {
|
||||
if atomic.AddUint32(&progress, 1) == 1 {
|
||||
if progress.Add(1) == 1 {
|
||||
// First call: initiate connect.
|
||||
return unix.Connect(fd, sa)
|
||||
}
|
||||
@@ -569,7 +569,7 @@ func (c *Conn) Recvmsg(ctx context.Context, p, oob []byte, flags int) (int, int,
|
||||
from unix.Sockaddr
|
||||
}
|
||||
|
||||
r, err := readT(c, ctx, "recvmsg", func(fd int) (ret, error) {
|
||||
r, err := readT(ctx, c, "recvmsg", func(fd int) (ret, error) {
|
||||
n, oobn, recvflags, from, err := unix.Recvmsg(fd, p, oob, flags)
|
||||
return ret{n, oobn, recvflags, from}, err
|
||||
})
|
||||
@@ -587,7 +587,7 @@ func (c *Conn) Recvfrom(ctx context.Context, p []byte, flags int) (int, unix.Soc
|
||||
addr unix.Sockaddr
|
||||
}
|
||||
|
||||
out, err := readT(c, ctx, "recvfrom", func(fd int) (ret, error) {
|
||||
out, err := readT(ctx, c, "recvfrom", func(fd int) (ret, error) {
|
||||
n, addr, err := unix.Recvfrom(fd, p, flags)
|
||||
return ret{n, addr}, err
|
||||
})
|
||||
@@ -600,11 +600,18 @@ func (c *Conn) Recvfrom(ctx context.Context, p []byte, flags int) (int, unix.Soc
|
||||
|
||||
// Sendmsg wraps sendmsg(2).
|
||||
func (c *Conn) Sendmsg(ctx context.Context, p, oob []byte, to unix.Sockaddr, flags int) (int, error) {
|
||||
return writeT(c, ctx, "sendmsg", func(fd int) (int, error) {
|
||||
return writeT(ctx, c, "sendmsg", func(fd int) (int, error) {
|
||||
return unix.SendmsgN(fd, p, oob, to, flags)
|
||||
})
|
||||
}
|
||||
|
||||
// SendmsgBuffers wraps sendmsg(2) with scatter-gather I/O support.
|
||||
func (c *Conn) SendmsgBuffers(ctx context.Context, buffers [][]byte, oob []byte, to unix.Sockaddr, flags int) (int, error) {
|
||||
return writeT(ctx, c, "sendmsg", func(fd int) (int, error) {
|
||||
return unix.SendmsgBuffers(fd, buffers, oob, to, flags)
|
||||
})
|
||||
}
|
||||
|
||||
// Sendto wraps sendto(2).
|
||||
func (c *Conn) Sendto(ctx context.Context, p []byte, flags int, to unix.Sockaddr) error {
|
||||
return c.write(ctx, "sendto", func(fd int) error {
|
||||
@@ -645,7 +652,7 @@ func (c *Conn) Shutdown(how int) error {
|
||||
// read wraps readT to execute a function and capture its error result. This is
|
||||
// a convenience wrapper for functions which don't return any extra values.
|
||||
func (c *Conn) read(ctx context.Context, op string, f func(fd int) error) error {
|
||||
_, err := readT(c, ctx, op, func(fd int) (struct{}, error) {
|
||||
_, err := readT(ctx, c, op, func(fd int) (struct{}, error) {
|
||||
return struct{}{}, f(fd)
|
||||
})
|
||||
return err
|
||||
@@ -654,7 +661,7 @@ func (c *Conn) read(ctx context.Context, op string, f func(fd int) error) error
|
||||
// write executes f, a write function, against the associated file descriptor.
|
||||
// op is used to create an *os.SyscallError if the file descriptor is closed.
|
||||
func (c *Conn) write(ctx context.Context, op string, f func(fd int) error) error {
|
||||
_, err := writeT(c, ctx, op, func(fd int) (struct{}, error) {
|
||||
_, err := writeT(ctx, c, op, func(fd int) (struct{}, error) {
|
||||
return struct{}{}, f(fd)
|
||||
})
|
||||
return err
|
||||
@@ -662,7 +669,7 @@ func (c *Conn) write(ctx context.Context, op string, f func(fd int) error) error
|
||||
|
||||
// readT executes c.rc.Read for op using the input function, returning a newly
|
||||
// allocated result T.
|
||||
func readT[T any](c *Conn, ctx context.Context, op string, f func(fd int) (T, error)) (T, error) {
|
||||
func readT[T any](ctx context.Context, c *Conn, op string, f func(fd int) (T, error)) (T, error) {
|
||||
return rwT(c, rwContext[T]{
|
||||
Context: ctx,
|
||||
Type: read,
|
||||
@@ -673,7 +680,7 @@ func readT[T any](c *Conn, ctx context.Context, op string, f func(fd int) (T, er
|
||||
|
||||
// writeT executes c.rc.Write for op using the input function, returning a newly
|
||||
// allocated result T.
|
||||
func writeT[T any](c *Conn, ctx context.Context, op string, f func(fd int) (T, error)) (T, error) {
|
||||
func writeT[T any](ctx context.Context, c *Conn, op string, f func(fd int) (T, error)) (T, error) {
|
||||
return rwT(c, rwContext[T]{
|
||||
Context: ctx,
|
||||
Type: write,
|
||||
@@ -750,12 +757,6 @@ func rwT[T any](c *Conn, rw rwContext[T]) (T, error) {
|
||||
needDisarm atomic.Bool
|
||||
)
|
||||
|
||||
// On cancel, clean up the watcher.
|
||||
defer func() {
|
||||
close(doneC)
|
||||
wg.Wait()
|
||||
}()
|
||||
|
||||
if d, ok := rw.Context.Deadline(); ok {
|
||||
// The context has an explicit deadline. We will use it for cancelation
|
||||
// but disarm it after poll for the next call.
|
||||
@@ -764,17 +765,17 @@ func rwT[T any](c *Conn, rw rwContext[T]) (T, error) {
|
||||
}
|
||||
setDeadline = true
|
||||
needDisarm.Store(true)
|
||||
} else {
|
||||
// The context does not have an explicit deadline. We have to watch for
|
||||
// cancelation so we can propagate that signal to immediately unblock
|
||||
// the runtime network poller.
|
||||
//
|
||||
// TODO(mdlayher): is it possible to detect a background context vs a
|
||||
// context with possible future cancel?
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
}
|
||||
|
||||
if rw.Context.Done() != nil {
|
||||
// The context can be canceled, regardless of whether or not it also
|
||||
// carries a deadline. We have to watch for cancelation so we can
|
||||
// propagate that signal to immediately unblock the runtime network
|
||||
// poller rather than waiting for a possibly distant deadline to expire.
|
||||
//
|
||||
// A nil Done channel means the context can never be canceled (such as
|
||||
// context.Background), so no watcher is necessary.
|
||||
wg.Go(func() {
|
||||
select {
|
||||
case <-rw.Context.Done():
|
||||
// Cancel the operation. Make the caller disarm after poll
|
||||
@@ -784,7 +785,7 @@ func rwT[T any](c *Conn, rw rwContext[T]) (T, error) {
|
||||
case <-doneC:
|
||||
// Nothing to do.
|
||||
}
|
||||
}()
|
||||
})
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -797,6 +798,13 @@ func rwT[T any](c *Conn, rw rwContext[T]) (T, error) {
|
||||
return ready(err)
|
||||
})
|
||||
|
||||
// Stop the watcher and wait for it to exit before checking whether we
|
||||
// must disarm the deadline. Otherwise the watcher could observe
|
||||
// cancelation and arm a deadline in the past after we have already
|
||||
// disarmed, leaving the next call to fail immediately.
|
||||
close(doneC)
|
||||
wg.Wait()
|
||||
|
||||
if needDisarm.Load() {
|
||||
_ = deadline(time.Time{})
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user