From 6c7db7ad23833ffab0f3ad6a15759aa68d133e09 Mon Sep 17 00:00:00 2001 From: visualfc Date: Sun, 28 Jul 2024 16:52:42 +0800 Subject: [PATCH] build: patch io.pipe --- cl/compile.go | 1 + internal/build/build.go | 1 + internal/build/overlay.go | 211 -------------------------------------- internal/lib/io/pipe.go | 207 +++++++++++++++++++++++++++++++++++++ 4 files changed, 209 insertions(+), 211 deletions(-) create mode 100644 internal/lib/io/pipe.go diff --git a/cl/compile.go b/cl/compile.go index b4000fbc..29f2dc54 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -195,6 +195,7 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun isInit := (f.Name() == "init" && sig.Recv() == nil) if isInit && state == pkgHasPatch { name = initFnNameOfHasPatch(name) + // pkg.init$guard has been set, change ssa.if-cond block := f.Blocks[0].Instrs[1].(*ssa.If).Block() block.Succs[0], block.Succs[1] = block.Succs[1], block.Succs[0] } diff --git a/internal/build/build.go b/internal/build/build.go index 1eafcb81..ba27fc65 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -764,6 +764,7 @@ var hasAltPkg = map[string]none{ "os": {}, "os/exec": {}, "runtime": {}, + "io": {}, } func check(err error) { diff --git a/internal/build/overlay.go b/internal/build/overlay.go index f8ad3039..19f39f24 100644 --- a/internal/build/overlay.go +++ b/internal/build/overlay.go @@ -2,215 +2,4 @@ package build var overlayFiles = map[string]string{ "math/exp_amd64.go": "package math;", - "io/pipe.go": data_io_pipe, } - -// TODO fixed chan buffer and remove it. -var data_io_pipe = ` -// 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. - -// Pipe adapter to connect code expecting an io.Reader -// with code expecting an io.Writer. - -package io - -import ( - "errors" - "sync" -) - -// onceError is an object that will only store an error once. -type onceError struct { - sync.Mutex // guards following - err error -} - -func (a *onceError) Store(err error) { - a.Lock() - defer a.Unlock() - if a.err != nil { - return - } - a.err = err -} -func (a *onceError) Load() error { - a.Lock() - defer a.Unlock() - return a.err -} - -// ErrClosedPipe is the error used for read or write operations on a closed pipe. -var ErrClosedPipe = errors.New("io: read/write on closed pipe") - -// A pipe is the shared pipe structure underlying PipeReader and PipeWriter. -type pipe struct { - wrMu sync.Mutex // Serializes Write operations - wrCh chan []byte - rdCh chan int - - once sync.Once // Protects closing done - done chan struct{} - rerr onceError - werr onceError -} - -func (p *pipe) read(b []byte) (n int, err error) { - select { - case <-p.done: - return 0, p.readCloseError() - default: - } - - select { - case bw := <-p.wrCh: - nr := copy(b, bw) - p.rdCh <- nr - return nr, nil - case <-p.done: - return 0, p.readCloseError() - } -} - -func (p *pipe) closeRead(err error) error { - if err == nil { - err = ErrClosedPipe - } - p.rerr.Store(err) - p.once.Do(func() { close(p.done) }) - return nil -} - -func (p *pipe) write(b []byte) (n int, err error) { - select { - case <-p.done: - return 0, p.writeCloseError() - default: - p.wrMu.Lock() - defer p.wrMu.Unlock() - } - - for once := true; once || len(b) > 0; once = false { - select { - case p.wrCh <- b: - nw := <-p.rdCh - b = b[nw:] - n += nw - case <-p.done: - return n, p.writeCloseError() - } - } - return n, nil -} - -func (p *pipe) closeWrite(err error) error { - if err == nil { - err = EOF - } - p.werr.Store(err) - p.once.Do(func() { close(p.done) }) - return nil -} - -// readCloseError is considered internal to the pipe type. -func (p *pipe) readCloseError() error { - rerr := p.rerr.Load() - if werr := p.werr.Load(); rerr == nil && werr != nil { - return werr - } - return ErrClosedPipe -} - -// writeCloseError is considered internal to the pipe type. -func (p *pipe) writeCloseError() error { - werr := p.werr.Load() - if rerr := p.rerr.Load(); werr == nil && rerr != nil { - return rerr - } - return ErrClosedPipe -} - -// A PipeReader is the read half of a pipe. -type PipeReader struct { - p *pipe -} - -// Read implements the standard Read interface: -// it reads data from the pipe, blocking until a writer -// arrives or the write end is closed. -// If the write end is closed with an error, that error is -// returned as err; otherwise err is EOF. -func (r *PipeReader) Read(data []byte) (n int, err error) { - return r.p.read(data) -} - -// Close closes the reader; subsequent writes to the -// write half of the pipe will return the error ErrClosedPipe. -func (r *PipeReader) Close() error { - return r.CloseWithError(nil) -} - -// CloseWithError closes the reader; subsequent writes -// to the write half of the pipe will return the error err. -// -// CloseWithError never overwrites the previous error if it exists -// and always returns nil. -func (r *PipeReader) CloseWithError(err error) error { - return r.p.closeRead(err) -} - -// A PipeWriter is the write half of a pipe. -type PipeWriter struct { - p *pipe -} - -// Write implements the standard Write interface: -// it writes data to the pipe, blocking until one or more readers -// have consumed all the data or the read end is closed. -// If the read end is closed with an error, that err is -// returned as err; otherwise err is ErrClosedPipe. -func (w *PipeWriter) Write(data []byte) (n int, err error) { - return w.p.write(data) -} - -// Close closes the writer; subsequent reads from the -// read half of the pipe will return no bytes and EOF. -func (w *PipeWriter) Close() error { - return w.CloseWithError(nil) -} - -// CloseWithError closes the writer; subsequent reads from the -// read half of the pipe will return no bytes and the error err, -// or EOF if err is nil. -// -// CloseWithError never overwrites the previous error if it exists -// and always returns nil. -func (w *PipeWriter) CloseWithError(err error) error { - return w.p.closeWrite(err) -} - -// Pipe creates a synchronous in-memory pipe. -// It can be used to connect code expecting an io.Reader -// with code expecting an io.Writer. -// -// Reads and Writes on the pipe are matched one to one -// except when multiple Reads are needed to consume a single Write. -// That is, each Write to the PipeWriter blocks until it has satisfied -// one or more Reads from the PipeReader that fully consume -// the written data. -// The data is copied directly from the Write to the corresponding -// Read (or Reads); there is no internal buffering. -// -// It is safe to call Read and Write in parallel with each other or with Close. -// Parallel calls to Read and parallel calls to Write are also safe: -// the individual calls will be gated sequentially. -func Pipe() (*PipeReader, *PipeWriter) { - p := &pipe{ - wrCh: make(chan []byte, 1), - rdCh: make(chan int, 1), - done: make(chan struct{}, 1), - } - return &PipeReader{p}, &PipeWriter{p} -} -` diff --git a/internal/lib/io/pipe.go b/internal/lib/io/pipe.go new file mode 100644 index 00000000..b3ca0570 --- /dev/null +++ b/internal/lib/io/pipe.go @@ -0,0 +1,207 @@ +// 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. + +// Pipe adapter to connect code expecting an io.Reader +// with code expecting an io.Writer. + +package io + +import ( + "errors" + "io" + "sync" +) + +// onceError is an object that will only store an error once. +type onceError struct { + sync.Mutex // guards following + err error +} + +func (a *onceError) Store(err error) { + a.Lock() + defer a.Unlock() + if a.err != nil { + return + } + a.err = err +} +func (a *onceError) Load() error { + a.Lock() + defer a.Unlock() + return a.err +} + +// ErrClosedPipe is the error used for read or write operations on a closed pipe. +var ErrClosedPipe = errors.New("io: read/write on closed pipe") + +// A pipe is the shared pipe structure underlying PipeReader and PipeWriter. +type pipe struct { + wrMu sync.Mutex // Serializes Write operations + wrCh chan []byte + rdCh chan int + + once sync.Once // Protects closing done + done chan struct{} + rerr onceError + werr onceError +} + +func (p *pipe) read(b []byte) (n int, err error) { + select { + case <-p.done: + return 0, p.readCloseError() + default: + } + + select { + case bw := <-p.wrCh: + nr := copy(b, bw) + p.rdCh <- nr + return nr, nil + case <-p.done: + return 0, p.readCloseError() + } +} + +func (p *pipe) closeRead(err error) error { + if err == nil { + err = ErrClosedPipe + } + p.rerr.Store(err) + p.once.Do(func() { close(p.done) }) + return nil +} + +func (p *pipe) write(b []byte) (n int, err error) { + select { + case <-p.done: + return 0, p.writeCloseError() + default: + p.wrMu.Lock() + defer p.wrMu.Unlock() + } + + for once := true; once || len(b) > 0; once = false { + select { + case p.wrCh <- b: + nw := <-p.rdCh + b = b[nw:] + n += nw + case <-p.done: + return n, p.writeCloseError() + } + } + return n, nil +} + +func (p *pipe) closeWrite(err error) error { + if err == nil { + err = io.EOF + } + p.werr.Store(err) + p.once.Do(func() { close(p.done) }) + return nil +} + +// readCloseError is considered internal to the pipe type. +func (p *pipe) readCloseError() error { + rerr := p.rerr.Load() + if werr := p.werr.Load(); rerr == nil && werr != nil { + return werr + } + return ErrClosedPipe +} + +// writeCloseError is considered internal to the pipe type. +func (p *pipe) writeCloseError() error { + werr := p.werr.Load() + if rerr := p.rerr.Load(); werr == nil && rerr != nil { + return rerr + } + return ErrClosedPipe +} + +// A PipeReader is the read half of a pipe. +type PipeReader struct { + p *pipe +} + +// Read implements the standard Read interface: +// it reads data from the pipe, blocking until a writer +// arrives or the write end is closed. +// If the write end is closed with an error, that error is +// returned as err; otherwise err is EOF. +func (r *PipeReader) Read(data []byte) (n int, err error) { + return r.p.read(data) +} + +// Close closes the reader; subsequent writes to the +// write half of the pipe will return the error ErrClosedPipe. +func (r *PipeReader) Close() error { + return r.CloseWithError(nil) +} + +// CloseWithError closes the reader; subsequent writes +// to the write half of the pipe will return the error err. +// +// CloseWithError never overwrites the previous error if it exists +// and always returns nil. +func (r *PipeReader) CloseWithError(err error) error { + return r.p.closeRead(err) +} + +// A PipeWriter is the write half of a pipe. +type PipeWriter struct { + p *pipe +} + +// Write implements the standard Write interface: +// it writes data to the pipe, blocking until one or more readers +// have consumed all the data or the read end is closed. +// If the read end is closed with an error, that err is +// returned as err; otherwise err is ErrClosedPipe. +func (w *PipeWriter) Write(data []byte) (n int, err error) { + return w.p.write(data) +} + +// Close closes the writer; subsequent reads from the +// read half of the pipe will return no bytes and EOF. +func (w *PipeWriter) Close() error { + return w.CloseWithError(nil) +} + +// CloseWithError closes the writer; subsequent reads from the +// read half of the pipe will return no bytes and the error err, +// or EOF if err is nil. +// +// CloseWithError never overwrites the previous error if it exists +// and always returns nil. +func (w *PipeWriter) CloseWithError(err error) error { + return w.p.closeWrite(err) +} + +// Pipe creates a synchronous in-memory pipe. +// It can be used to connect code expecting an io.Reader +// with code expecting an io.Writer. +// +// Reads and Writes on the pipe are matched one to one +// except when multiple Reads are needed to consume a single Write. +// That is, each Write to the PipeWriter blocks until it has satisfied +// one or more Reads from the PipeReader that fully consume +// the written data. +// The data is copied directly from the Write to the corresponding +// Read (or Reads); there is no internal buffering. +// +// It is safe to call Read and Write in parallel with each other or with Close. +// Parallel calls to Read and parallel calls to Write are also safe: +// the individual calls will be gated sequentially. +func Pipe() (*PipeReader, *PipeWriter) { + p := &pipe{ + wrCh: make(chan []byte, 1), + rdCh: make(chan int, 1), + done: make(chan struct{}, 1), + } + return &PipeReader{p}, &PipeWriter{p} +}