// Copyright 2014 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 http2import ()// pipe is a goroutine-safe io.Reader/io.Writer pair. It's like// io.Pipe except there are no PipeReader/PipeWriter halves, and the// underlying buffer is an interface. (io.Pipe is always unbuffered)typepipestruct {musync.Mutexcsync.Cond// c.L lazily initialized to &p.mubpipeBuffer// nil when done readingunreadint// bytes unread when doneerrerror// read error once empty. non-nil means closed.breakErrerror// immediate read error (caller doesn't see rest of b)donecchanstruct{} // closed on errorreadFnfunc() // optional code to run in Read before error}typepipeBufferinterface {Len() intio.Writerio.Reader}// setBuffer initializes the pipe buffer.// It has no effect if the pipe is already closed.func ( *pipe) ( pipeBuffer) { .mu.Lock()defer .mu.Unlock()if .err != nil || .breakErr != nil {return } .b = }func ( *pipe) () int { .mu.Lock()defer .mu.Unlock()if .b == nil {return .unread }return .b.Len()}// Read waits until data is available and copies bytes// from the buffer into p.func ( *pipe) ( []byte) ( int, error) { .mu.Lock()defer .mu.Unlock()if .c.L == nil { .c.L = &.mu }for {if .breakErr != nil {return0, .breakErr }if .b != nil && .b.Len() > 0 {return .b.Read() }if .err != nil {if .readFn != nil { .readFn() // e.g. copy trailers .readFn = nil// not sticky like p.err } .b = nilreturn0, .err } .c.Wait() }}varerrClosedPipeWrite = errors.New("write on closed buffer")// Write copies bytes from p into the buffer and wakes a reader.// It is an error to write more data than the buffer can hold.func ( *pipe) ( []byte) ( int, error) { .mu.Lock()defer .mu.Unlock()if .c.L == nil { .c.L = &.mu }defer .c.Signal()if .err != nil {return0, errClosedPipeWrite }if .breakErr != nil { .unread += len()returnlen(), nil// discard when there is no reader }return .b.Write()}// CloseWithError causes the next Read (waking up a current blocked// Read if needed) to return the provided err after all data has been// read.//// The error must be non-nil.func ( *pipe) ( error) { .closeWithError(&.err, , nil) }// BreakWithError causes the next Read (waking up a current blocked// Read if needed) to return the provided err immediately, without// waiting for unread data.func ( *pipe) ( error) { .closeWithError(&.breakErr, , nil) }// closeWithErrorAndCode is like CloseWithError but also sets some code to run// in the caller's goroutine before returning the error.func ( *pipe) ( error, func()) { .closeWithError(&.err, , ) }func ( *pipe) ( *error, error, func()) {if == nil {panic("err must be non-nil") } .mu.Lock()defer .mu.Unlock()if .c.L == nil { .c.L = &.mu }defer .c.Signal()if * != nil {// Already been done.return } .readFn = if == &.breakErr {if .b != nil { .unread += .b.Len() } .b = nil } * = .closeDoneLocked()}// requires p.mu be held.func ( *pipe) () {if .donec == nil {return }// Close if unclosed. This isn't racy since we always // hold p.mu while closing.select {case<-.donec:default:close(.donec) }}// Err returns the error (if any) first set by BreakWithError or CloseWithError.func ( *pipe) () error { .mu.Lock()defer .mu.Unlock()if .breakErr != nil {return .breakErr }return .err}// Done returns a channel which is closed if and when this pipe is closed// with CloseWithError.func ( *pipe) () <-chanstruct{} { .mu.Lock()defer .mu.Unlock()if .donec == nil { .donec = make(chanstruct{})if .err != nil || .breakErr != nil {// Already hit an error. .closeDoneLocked() } }return .donec}
The pages are generated with Goldsv0.4.9. (GOOS=linux GOARCH=amd64)