Source File
line_reader.go
Belonging Package
internal/runtime/cgroup
// Copyright 2025 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 cgroupimport ()// stringError is a trival implementation of error, equivalent to errors.New,// which cannot be imported from a runtime package.type stringError stringfunc ( stringError) () string {return string()}// All errors are explicit converted to type error in global initialization to// ensure that the linker allocates a static interface value. This is necessary// because these errors may be used before the allocator is available.var (// The entire line did not fit into the scratch buffer.errIncompleteLine error = stringError("incomplete line")// A system call failed.errSyscallFailed error = stringError("syscall failed")// Reached EOF.errEOF error = stringError("end of file"))// lineReader reads line-by-line using only a single fixed scratch buffer.//// When a single line is too long for the scratch buffer, the remainder of the// line will be skipped.type lineReader struct {read func(fd int, b []byte) (int, uintptr)fd intscratch []byten int // bytes of scratch in use.newline int // index of the first newline in scratch.eof bool // read reached EOF.}// newLineReader returns a lineReader which reads lines from fd.//// fd is the file descriptor to read from.//// scratch is the scratch buffer to read into. Note that len(scratch) is the// longest line that can be read. Lines longer than len(scratch) will have the// remainder of the line skipped. See next for more details.//// read is the function used to read more bytes from fd. This is usually// internal/runtime/syscall.Read. Note that this follows syscall semantics (not// io.Reader), so EOF is indicated with n=0, errno=0.func newLineReader( int, []byte, func( int, []byte) ( int, uintptr)) *lineReader {return &lineReader{read: ,fd: ,scratch: ,n: 0,newline: -1,}}// next advances to the next line.//// May return errIncompleteLine if the scratch buffer is too small to hold the// entire line, in which case [r.line] will return the beginning of the line. A// subsequent call to next will skip the remainder of the incomplete line.//// N.B. this behavior is important for /proc/self/mountinfo. Some lines// (mounts), such as overlayfs, may be extremely long due to long super-block// options, but we don't care about those. The mount type will appear early in// the line.//// Returns errEOF when there are no more lines.func ( *lineReader) () error {// Three cases://// 1. First call, no data read.// 2. Previous call had a complete line. Drop it and look for the end// of the next line.// 3. Previous call had an incomplete line. Find the end of that line// (start of the next line), and the end of the next line.:= .newline >= 0:= .n == 0for {if {// Drop the previous line.copy(.scratch, .scratch[.newline+1:.n]).n -= .newline + 1.newline = bytealg.IndexByte(.scratch[:.n], '\n')if .newline >= 0 {// We have another line already in scratch. Done.return nil}}// No newline available.if ! {// If the previous line was incomplete, we are// searching for the end of that line and have no need// for any buffered data..n = 0}, := .read(.fd, .scratch[.n:len(.scratch)])if != 0 {return errSyscallFailed}.n +=if .n == 0 {// Nothing left.//// N.B. we can't immediately return EOF when read// returns 0 as we may still need to return an// incomplete line.return errEOF}.newline = bytealg.IndexByte(.scratch[:.n], '\n')if || {// Already have the start of the line, just need to find the end.if .newline < 0 {// We filled the entire buffer or hit EOF, but// still no newline.return errIncompleteLine}// Found the end of the line. Done.return nil} else {// Don't have the start of the line. We are currently// looking for the end of the previous line.if .newline < 0 {// Not there yet.if == 0 {// No more to read.return errEOF}continue}// Found the end of the previous line. The next// iteration will drop the remainder of the previous// line and look for the next line.= true}}}// line returns a view of the current line, excluding the trailing newline.//// If [r.next] returned errIncompleteLine, then this returns only the beginning// of the line.//// Preconditions: [r.next] is called prior to the first call to line.//// Postconditions: The caller must not keep a reference to the returned slice.func ( *lineReader) () []byte {if .newline < 0 {// Incomplete linereturn .scratch[:.n]}// Complete line.return .scratch[:.newline]}
![]() |
The pages are generated with Golds v0.7.9-preview. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |