mirror of
https://github.com/samuelncui/acp.git
synced 2026-01-03 10:05:16 +00:00
feat: init for use
This commit is contained in:
56
mmap/manual_test_program.go
Normal file
56
mmap/manual_test_program.go
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2015 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 ignore
|
||||
// +build ignore
|
||||
|
||||
//
|
||||
// This build tag means that "go build" does not build this file. Use "go run
|
||||
// manual_test_program.go" to run it.
|
||||
//
|
||||
// You will also need to change "debug = false" to "debug = true" in mmap_*.go.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"golang.org/x/exp/mmap"
|
||||
)
|
||||
|
||||
var garbage []byte
|
||||
|
||||
func main() {
|
||||
const filename = "manual_test_program.go"
|
||||
|
||||
for _, explicitClose := range []bool{false, true} {
|
||||
r, err := mmap.Open(filename)
|
||||
if err != nil {
|
||||
log.Fatalf("Open: %v", err)
|
||||
}
|
||||
if explicitClose {
|
||||
r.Close()
|
||||
} else {
|
||||
// Leak the *mmap.ReaderAt returned by mmap.Open. The finalizer
|
||||
// should pick it up, if finalizers run at all.
|
||||
}
|
||||
}
|
||||
|
||||
println("Finished all explicit Close calls.")
|
||||
println("Creating and collecting garbage.")
|
||||
println("Look for two munmap log messages.")
|
||||
println("Hit Ctrl-C to exit.")
|
||||
|
||||
rng := rand.New(rand.NewSource(1))
|
||||
now := time.Now()
|
||||
for {
|
||||
garbage = make([]byte, rng.Intn(1<<20))
|
||||
if time.Since(now) > 1*time.Second {
|
||||
now = time.Now()
|
||||
print(".")
|
||||
}
|
||||
}
|
||||
}
|
||||
136
mmap/mmap_darwin.go
Normal file
136
mmap/mmap_darwin.go
Normal file
@@ -0,0 +1,136 @@
|
||||
// Copyright 2015 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 darwin
|
||||
// +build darwin
|
||||
|
||||
// Package mmap provides a way to memory-map a file.
|
||||
package mmap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// debug is whether to print debugging messages for manual testing.
|
||||
//
|
||||
// The runtime.SetFinalizer documentation says that, "The finalizer for x is
|
||||
// scheduled to run at some arbitrary time after x becomes unreachable. There
|
||||
// is no guarantee that finalizers will run before a program exits", so we
|
||||
// cannot automatically test that the finalizer runs. Instead, set this to true
|
||||
// when running the manual test.
|
||||
const debug = false
|
||||
|
||||
// ReaderAt reads a memory-mapped file.
|
||||
//
|
||||
// Like any io.ReaderAt, clients can execute parallel ReadAt calls, but it is
|
||||
// not safe to call Close and reading methods concurrently.
|
||||
type ReaderAt struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
// Close closes the reader.
|
||||
func (r *ReaderAt) Close() error {
|
||||
if r.data == nil {
|
||||
return nil
|
||||
}
|
||||
data := r.data
|
||||
r.data = nil
|
||||
if debug {
|
||||
var p *byte
|
||||
if len(data) != 0 {
|
||||
p = &data[0]
|
||||
}
|
||||
println("munmap", r, p)
|
||||
}
|
||||
runtime.SetFinalizer(r, nil)
|
||||
return syscall.Munmap(data)
|
||||
}
|
||||
|
||||
// Len returns the length of the underlying memory-mapped file.
|
||||
func (r *ReaderAt) Len() int {
|
||||
return len(r.data)
|
||||
}
|
||||
|
||||
// At returns the byte at index i.
|
||||
func (r *ReaderAt) At(i int) byte {
|
||||
return r.data[i]
|
||||
}
|
||||
|
||||
// ReadAt implements the io.ReaderAt interface.
|
||||
func (r *ReaderAt) ReadAt(p []byte, off int64) (int, error) {
|
||||
if r.data == nil {
|
||||
return 0, errors.New("mmap: closed")
|
||||
}
|
||||
if off < 0 || int64(len(r.data)) < off {
|
||||
return 0, fmt.Errorf("mmap: invalid ReadAt offset %d", off)
|
||||
}
|
||||
n := copy(p, r.data[off:])
|
||||
if n < len(p) {
|
||||
return n, io.EOF
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// ReadAt implements the io.ReaderAt interface.
|
||||
func (r *ReaderAt) Slice(off, limit int64) ([]byte, error) {
|
||||
if r.data == nil {
|
||||
return nil, errors.New("mmap: closed")
|
||||
}
|
||||
|
||||
l := int64(len(r.data))
|
||||
if off < 0 || limit < 0 || l < off {
|
||||
return nil, fmt.Errorf("mmap: invalid ReadAt offset %d", off)
|
||||
}
|
||||
|
||||
if off+limit > l {
|
||||
return r.data[off:], nil
|
||||
}
|
||||
|
||||
return r.data[off : off+limit], nil
|
||||
}
|
||||
|
||||
// Open memory-maps the named file for reading.
|
||||
func Open(filename string) (*ReaderAt, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
size := fi.Size()
|
||||
if size == 0 {
|
||||
return &ReaderAt{}, nil
|
||||
}
|
||||
if size < 0 {
|
||||
return nil, fmt.Errorf("mmap: file %q has negative size", filename)
|
||||
}
|
||||
if size != int64(int(size)) {
|
||||
return nil, fmt.Errorf("mmap: file %q is too large", filename)
|
||||
}
|
||||
|
||||
data, err := syscall.Mmap(int(f.Fd()), 0, int(size), syscall.PROT_READ, syscall.MAP_SHARED)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create mmap fail, %q, %w", filename, err)
|
||||
}
|
||||
|
||||
r := &ReaderAt{data}
|
||||
if debug {
|
||||
var p *byte
|
||||
if len(data) != 0 {
|
||||
p = &data[0]
|
||||
}
|
||||
println("mmap", r, p)
|
||||
}
|
||||
runtime.SetFinalizer(r, (*ReaderAt).Close)
|
||||
return r, nil
|
||||
}
|
||||
145
mmap/mmap_linux.go
Normal file
145
mmap/mmap_linux.go
Normal file
@@ -0,0 +1,145 @@
|
||||
// Copyright 2015 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 linux
|
||||
// +build linux
|
||||
|
||||
// Package mmap provides a way to memory-map a file.
|
||||
package mmap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
prefetchMaxSize = 16 * 1024 * 1024
|
||||
)
|
||||
|
||||
// debug is whether to print debugging messages for manual testing.
|
||||
//
|
||||
// The runtime.SetFinalizer documentation says that, "The finalizer for x is
|
||||
// scheduled to run at some arbitrary time after x becomes unreachable. There
|
||||
// is no guarantee that finalizers will run before a program exits", so we
|
||||
// cannot automatically test that the finalizer runs. Instead, set this to true
|
||||
// when running the manual test.
|
||||
const debug = false
|
||||
|
||||
// ReaderAt reads a memory-mapped file.
|
||||
//
|
||||
// Like any io.ReaderAt, clients can execute parallel ReadAt calls, but it is
|
||||
// not safe to call Close and reading methods concurrently.
|
||||
type ReaderAt struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
// Close closes the reader.
|
||||
func (r *ReaderAt) Close() error {
|
||||
if r.data == nil {
|
||||
return nil
|
||||
}
|
||||
data := r.data
|
||||
r.data = nil
|
||||
if debug {
|
||||
var p *byte
|
||||
if len(data) != 0 {
|
||||
p = &data[0]
|
||||
}
|
||||
println("munmap", r, p)
|
||||
}
|
||||
runtime.SetFinalizer(r, nil)
|
||||
return syscall.Munmap(data)
|
||||
}
|
||||
|
||||
// Len returns the length of the underlying memory-mapped file.
|
||||
func (r *ReaderAt) Len() int {
|
||||
return len(r.data)
|
||||
}
|
||||
|
||||
// At returns the byte at index i.
|
||||
func (r *ReaderAt) At(i int) byte {
|
||||
return r.data[i]
|
||||
}
|
||||
|
||||
// ReadAt implements the io.ReaderAt interface.
|
||||
func (r *ReaderAt) ReadAt(p []byte, off int64) (int, error) {
|
||||
if r.data == nil {
|
||||
return 0, errors.New("mmap: closed")
|
||||
}
|
||||
if off < 0 || int64(len(r.data)) < off {
|
||||
return 0, fmt.Errorf("mmap: invalid ReadAt offset %d", off)
|
||||
}
|
||||
n := copy(p, r.data[off:])
|
||||
if n < len(p) {
|
||||
return n, io.EOF
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// ReadAt implements the io.ReaderAt interface.
|
||||
func (r *ReaderAt) Slice(off, limit int64) ([]byte, error) {
|
||||
if r.data == nil {
|
||||
return nil, errors.New("mmap: closed")
|
||||
}
|
||||
|
||||
l := int64(len(r.data))
|
||||
if off < 0 || limit < 0 || l < off {
|
||||
return nil, fmt.Errorf("mmap: invalid ReadAt offset %d", off)
|
||||
}
|
||||
|
||||
if off+limit > l {
|
||||
return r.data[off:], nil
|
||||
}
|
||||
|
||||
return r.data[off : off+limit], nil
|
||||
}
|
||||
|
||||
// Open memory-maps the named file for reading.
|
||||
func Open(filename string) (*ReaderAt, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
size := fi.Size()
|
||||
if size == 0 {
|
||||
return &ReaderAt{}, nil
|
||||
}
|
||||
if size < 0 {
|
||||
return nil, fmt.Errorf("mmap: file %q has negative size", filename)
|
||||
}
|
||||
if size != int64(int(size)) {
|
||||
return nil, fmt.Errorf("mmap: file %q is too large", filename)
|
||||
}
|
||||
|
||||
data, err := syscall.Mmap(int(f.Fd()), 0, int(size), syscall.PROT_READ, syscall.MAP_SHARED)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create mmap fail, %q, %w", filename, err)
|
||||
}
|
||||
if size <= prefetchMaxSize {
|
||||
if err := syscall.Madvise(data, syscall.MADV_SEQUENTIAL|syscall.MADV_WILLNEED); err != nil {
|
||||
return nil, fmt.Errorf("madvise fail, %q, %w", filename, err)
|
||||
}
|
||||
}
|
||||
|
||||
r := &ReaderAt{data}
|
||||
if debug {
|
||||
var p *byte
|
||||
if len(data) != 0 {
|
||||
p = &data[0]
|
||||
}
|
||||
println("mmap", r, p)
|
||||
}
|
||||
runtime.SetFinalizer(r, (*ReaderAt).Close)
|
||||
return r, nil
|
||||
}
|
||||
86
mmap/mmap_other.go
Normal file
86
mmap/mmap_other.go
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright 2015 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 !linux && !windows && !darwin
|
||||
// +build !linux,!windows,!darwin
|
||||
|
||||
// Package mmap provides a way to memory-map a file.
|
||||
package mmap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// ReaderAt reads a memory-mapped file.
|
||||
//
|
||||
// Like any io.ReaderAt, clients can execute parallel ReadAt calls, but it is
|
||||
// not safe to call Close and reading methods concurrently.
|
||||
type ReaderAt struct {
|
||||
f *os.File
|
||||
len int
|
||||
}
|
||||
|
||||
// Close closes the reader.
|
||||
func (r *ReaderAt) Close() error {
|
||||
return r.f.Close()
|
||||
}
|
||||
|
||||
// Len returns the length of the underlying memory-mapped file.
|
||||
func (r *ReaderAt) Len() int {
|
||||
return r.len
|
||||
}
|
||||
|
||||
// At returns the byte at index i.
|
||||
func (r *ReaderAt) At(i int) byte {
|
||||
if i < 0 || r.len <= i {
|
||||
panic("index out of range")
|
||||
}
|
||||
var b [1]byte
|
||||
r.ReadAt(b[:], int64(i))
|
||||
return b[0]
|
||||
}
|
||||
|
||||
// ReadAt implements the io.ReaderAt interface.
|
||||
func (r *ReaderAt) ReadAt(p []byte, off int64) (int, error) {
|
||||
return r.f.ReadAt(p, off)
|
||||
}
|
||||
|
||||
// ReadAt implements the io.ReaderAt interface.
|
||||
func (r *ReaderAt) Slice(off, limit int64) ([]byte, error) {
|
||||
buf := make([]byte, limit)
|
||||
n, err := r.ReadAt(buf, off)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf[:n], nil
|
||||
}
|
||||
|
||||
// Open memory-maps the named file for reading.
|
||||
func Open(filename string) (*ReaderAt, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
size := fi.Size()
|
||||
if size < 0 {
|
||||
f.Close()
|
||||
return nil, fmt.Errorf("mmap: file %q has negative size", filename)
|
||||
}
|
||||
if size != int64(int(size)) {
|
||||
f.Close()
|
||||
return nil, fmt.Errorf("mmap: file %q is too large", filename)
|
||||
}
|
||||
|
||||
return &ReaderAt{
|
||||
f: f,
|
||||
len: int(fi.Size()),
|
||||
}, nil
|
||||
}
|
||||
34
mmap/mmap_test.go
Normal file
34
mmap/mmap_test.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2015 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 mmap
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOpen(t *testing.T) {
|
||||
const filename = "mmap_test.go"
|
||||
r, err := Open(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
got := make([]byte, r.Len())
|
||||
if _, err := r.ReadAt(got, 0); err != nil && err != io.EOF {
|
||||
t.Fatalf("ReadAt: %v", err)
|
||||
}
|
||||
want, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("ioutil.ReadFile: %v", err)
|
||||
}
|
||||
if len(got) != len(want) {
|
||||
t.Fatalf("got %d bytes, want %d", len(got), len(want))
|
||||
}
|
||||
if !bytes.Equal(got, want) {
|
||||
t.Fatalf("\ngot %q\nwant %q", string(got), string(want))
|
||||
}
|
||||
}
|
||||
141
mmap/mmap_windows.go
Normal file
141
mmap/mmap_windows.go
Normal file
@@ -0,0 +1,141 @@
|
||||
// Copyright 2015 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 mmap provides a way to memory-map a file.
|
||||
package mmap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// debug is whether to print debugging messages for manual testing.
|
||||
//
|
||||
// The runtime.SetFinalizer documentation says that, "The finalizer for x is
|
||||
// scheduled to run at some arbitrary time after x becomes unreachable. There
|
||||
// is no guarantee that finalizers will run before a program exits", so we
|
||||
// cannot automatically test that the finalizer runs. Instead, set this to true
|
||||
// when running the manual test.
|
||||
const debug = false
|
||||
|
||||
// ReaderAt reads a memory-mapped file.
|
||||
//
|
||||
// Like any io.ReaderAt, clients can execute parallel ReadAt calls, but it is
|
||||
// not safe to call Close and reading methods concurrently.
|
||||
type ReaderAt struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
// Close closes the reader.
|
||||
func (r *ReaderAt) Close() error {
|
||||
if r.data == nil {
|
||||
return nil
|
||||
}
|
||||
data := r.data
|
||||
r.data = nil
|
||||
if debug {
|
||||
var p *byte
|
||||
if len(data) != 0 {
|
||||
p = &data[0]
|
||||
}
|
||||
println("munmap", r, p)
|
||||
}
|
||||
runtime.SetFinalizer(r, nil)
|
||||
return syscall.UnmapViewOfFile(uintptr(unsafe.Pointer(&data[0])))
|
||||
}
|
||||
|
||||
// Len returns the length of the underlying memory-mapped file.
|
||||
func (r *ReaderAt) Len() int {
|
||||
return len(r.data)
|
||||
}
|
||||
|
||||
// At returns the byte at index i.
|
||||
func (r *ReaderAt) At(i int) byte {
|
||||
return r.data[i]
|
||||
}
|
||||
|
||||
// ReadAt implements the io.ReaderAt interface.
|
||||
func (r *ReaderAt) ReadAt(p []byte, off int64) (int, error) {
|
||||
if r.data == nil {
|
||||
return 0, errors.New("mmap: closed")
|
||||
}
|
||||
if off < 0 || int64(len(r.data)) < off {
|
||||
return 0, fmt.Errorf("mmap: invalid ReadAt offset %d", off)
|
||||
}
|
||||
n := copy(p, r.data[off:])
|
||||
if n < len(p) {
|
||||
return n, io.EOF
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// ReadAt implements the io.ReaderAt interface.
|
||||
func (r *ReaderAt) Slice(off, limit int64) ([]byte, error) {
|
||||
if r.data == nil {
|
||||
return nil, errors.New("mmap: closed")
|
||||
}
|
||||
|
||||
l := int64(len(r.data))
|
||||
if off < 0 || limit < 0 || l < off {
|
||||
return nil, fmt.Errorf("mmap: invalid ReadAt offset %d", off)
|
||||
}
|
||||
|
||||
if off+limit > l {
|
||||
return r.data[off:], nil
|
||||
}
|
||||
|
||||
return r.data[off : off+limit], nil
|
||||
}
|
||||
|
||||
// Open memory-maps the named file for reading.
|
||||
func Open(filename string) (*ReaderAt, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
size := fi.Size()
|
||||
if size == 0 {
|
||||
return &ReaderAt{}, nil
|
||||
}
|
||||
if size < 0 {
|
||||
return nil, fmt.Errorf("mmap: file %q has negative size", filename)
|
||||
}
|
||||
if size != int64(int(size)) {
|
||||
return nil, fmt.Errorf("mmap: file %q is too large", filename)
|
||||
}
|
||||
|
||||
low, high := uint32(size), uint32(size>>32)
|
||||
fmap, err := syscall.CreateFileMapping(syscall.Handle(f.Fd()), nil, syscall.PAGE_READONLY, high, low, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer syscall.CloseHandle(fmap)
|
||||
ptr, err := syscall.MapViewOfFile(fmap, syscall.FILE_MAP_READ, 0, 0, uintptr(size))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data := unsafe.Slice((*byte)(unsafe.Pointer(ptr)), size)
|
||||
|
||||
r := &ReaderAt{data: data}
|
||||
if debug {
|
||||
var p *byte
|
||||
if len(data) != 0 {
|
||||
p = &data[0]
|
||||
}
|
||||
println("mmap", r, p)
|
||||
}
|
||||
runtime.SetFinalizer(r, (*ReaderAt).Close)
|
||||
return r, nil
|
||||
}
|
||||
Reference in New Issue
Block a user