-
Notifications
You must be signed in to change notification settings - Fork 2
/
mmap_other.go
144 lines (128 loc) · 2.97 KB
/
mmap_other.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright (c) 2020 Meng Huang (mhboy@outlook.com)
// This package is licensed under a MIT license that can be found in the LICENSE file.
// +build !darwin,!linux,!windows,!dragonfly,!freebsd,!netbsd,!openbsd
package mmap
import (
"errors"
"os"
"sync"
"sync/atomic"
"syscall"
"unsafe"
)
var (
buffers = sync.Map{}
assign int32
)
func assignPool(size int) *sync.Pool {
for {
if p, ok := buffers.Load(size); ok {
return p.(*sync.Pool)
}
if atomic.CompareAndSwapInt32(&assign, 0, 1) {
var pool = &sync.Pool{New: func() interface{} {
return make([]byte, size)
}}
buffers.Store(size, pool)
atomic.StoreInt32(&assign, 0)
return pool
}
}
}
// Offset returns the valid offset.
func Offset(offset int64) int64 {
pageSize := int64(os.Getpagesize())
return offset / pageSize * pageSize
}
func protFlags(p Prot) (prot int, flags int) {
return 0, 0
}
type mmapper struct {
sync.Mutex
active map[*byte]*f
}
type f struct {
fd int
offset int64
buf []byte
}
func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
if length <= 0 {
return nil, syscall.EINVAL
}
pool := assignPool(length)
buf := pool.Get().([]byte)
cursor, _ := syscall.Seek(fd, 0, os.SEEK_CUR)
syscall.Seek(fd, offset, os.SEEK_SET)
n, err := syscall.Read(fd, buf)
syscall.Seek(fd, cursor, os.SEEK_SET)
if err != nil {
return nil, err
}
if n < length {
return nil, errors.New("length > file size")
}
var sl = struct {
addr uintptr
len int
cap int
}{uintptr(unsafe.Pointer(&buf[0])), length, length}
b := *(*[]byte)(unsafe.Pointer(&sl))
p := &b[cap(b)-1]
m.Lock()
defer m.Unlock()
m.active[p] = &f{fd, offset, b}
return b, nil
}
func (m *mmapper) Msync(b []byte) (err error) {
if len(b) == 0 || len(b) != cap(b) {
return syscall.EINVAL
}
p := &b[cap(b)-1]
m.Lock()
f := m.active[p]
m.Unlock()
if f == nil || f.buf == nil || &f.buf[0] != &b[0] {
return syscall.EINVAL
}
cursor, _ := syscall.Seek(f.fd, 0, os.SEEK_CUR)
syscall.Seek(f.fd, f.offset, os.SEEK_SET)
_, err = syscall.Write(f.fd, b)
syscall.Seek(f.fd, cursor, os.SEEK_SET)
return err
}
func (m *mmapper) Munmap(data []byte) (err error) {
if len(data) == 0 || len(data) != cap(data) {
return syscall.EINVAL
}
p := &data[cap(data)-1]
m.Lock()
f := m.active[p]
m.Unlock()
if f == nil || f.buf == nil || &f.buf[0] != &data[0] {
return syscall.EINVAL
}
cursor, _ := syscall.Seek(f.fd, 0, os.SEEK_CUR)
syscall.Seek(f.fd, 0, os.SEEK_SET)
_, err = syscall.Write(f.fd, data)
syscall.Seek(f.fd, cursor, os.SEEK_SET)
m.Lock()
delete(m.active, p)
m.Unlock()
pool := assignPool(cap(f.buf))
pool.Put(f.buf)
f = nil
return err
}
var mapper = &mmapper{
active: make(map[*byte]*f),
}
func mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
return mapper.Mmap(fd, offset, length, prot, flags)
}
func msync(b []byte) (err error) {
return mapper.Msync(b)
}
func munmap(b []byte) (err error) {
return mapper.Munmap(b)
}