summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/blevesearch/mmap-go/mmap_windows.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/blevesearch/mmap-go/mmap_windows.go')
-rw-r--r--vendor/github.com/blevesearch/mmap-go/mmap_windows.go153
1 files changed, 153 insertions, 0 deletions
diff --git a/vendor/github.com/blevesearch/mmap-go/mmap_windows.go b/vendor/github.com/blevesearch/mmap-go/mmap_windows.go
new file mode 100644
index 0000000000..631b3825f9
--- /dev/null
+++ b/vendor/github.com/blevesearch/mmap-go/mmap_windows.go
@@ -0,0 +1,153 @@
+// Copyright 2011 Evan Shaw. 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 (
+ "errors"
+ "os"
+ "sync"
+
+ "golang.org/x/sys/windows"
+)
+
+// mmap on Windows is a two-step process.
+// First, we call CreateFileMapping to get a handle.
+// Then, we call MapviewToFile to get an actual pointer into memory.
+// Because we want to emulate a POSIX-style mmap, we don't want to expose
+// the handle -- only the pointer. We also want to return only a byte slice,
+// not a struct, so it's convenient to manipulate.
+
+// We keep this map so that we can get back the original handle from the memory address.
+
+type addrinfo struct {
+ file windows.Handle
+ mapview windows.Handle
+ writable bool
+}
+
+var handleLock sync.Mutex
+var handleMap = map[uintptr]*addrinfo{}
+
+func mmap(len int, prot, flags, hfile uintptr, off int64) ([]byte, error) {
+ flProtect := uint32(windows.PAGE_READONLY)
+ dwDesiredAccess := uint32(windows.FILE_MAP_READ)
+ writable := false
+ switch {
+ case prot&COPY != 0:
+ flProtect = windows.PAGE_WRITECOPY
+ dwDesiredAccess = windows.FILE_MAP_COPY
+ writable = true
+ case prot&RDWR != 0:
+ flProtect = windows.PAGE_READWRITE
+ dwDesiredAccess = windows.FILE_MAP_WRITE
+ writable = true
+ }
+ if prot&EXEC != 0 {
+ flProtect <<= 4
+ dwDesiredAccess |= windows.FILE_MAP_EXECUTE
+ }
+
+ // The maximum size is the area of the file, starting from 0,
+ // that we wish to allow to be mappable. It is the sum of
+ // the length the user requested, plus the offset where that length
+ // is starting from. This does not map the data into memory.
+ maxSizeHigh := uint32((off + int64(len)) >> 32)
+ maxSizeLow := uint32((off + int64(len)) & 0xFFFFFFFF)
+ // TODO: Do we need to set some security attributes? It might help portability.
+ h, errno := windows.CreateFileMapping(windows.Handle(hfile), nil, flProtect, maxSizeHigh, maxSizeLow, nil)
+ if h == 0 {
+ return nil, os.NewSyscallError("CreateFileMapping", errno)
+ }
+
+ // Actually map a view of the data into memory. The view's size
+ // is the length the user requested.
+ fileOffsetHigh := uint32(off >> 32)
+ fileOffsetLow := uint32(off & 0xFFFFFFFF)
+ addr, errno := windows.MapViewOfFile(h, dwDesiredAccess, fileOffsetHigh, fileOffsetLow, uintptr(len))
+ if addr == 0 {
+ return nil, os.NewSyscallError("MapViewOfFile", errno)
+ }
+ handleLock.Lock()
+ handleMap[addr] = &addrinfo{
+ file: windows.Handle(hfile),
+ mapview: h,
+ writable: writable,
+ }
+ handleLock.Unlock()
+
+ m := MMap{}
+ dh := m.header()
+ dh.Data = addr
+ dh.Len = len
+ dh.Cap = dh.Len
+
+ return m, nil
+}
+
+func (m MMap) flush() error {
+ addr, len := m.addrLen()
+ errno := windows.FlushViewOfFile(addr, len)
+ if errno != nil {
+ return os.NewSyscallError("FlushViewOfFile", errno)
+ }
+
+ handleLock.Lock()
+ defer handleLock.Unlock()
+ handle, ok := handleMap[addr]
+ if !ok {
+ // should be impossible; we would've errored above
+ return errors.New("unknown base address")
+ }
+
+ if handle.writable {
+ if err := windows.FlushFileBuffers(handle.file); err != nil {
+ return os.NewSyscallError("FlushFileBuffers", err)
+ }
+ }
+
+ return nil
+}
+
+func (m MMap) lock() error {
+ addr, len := m.addrLen()
+ errno := windows.VirtualLock(addr, len)
+ return os.NewSyscallError("VirtualLock", errno)
+}
+
+func (m MMap) unlock() error {
+ addr, len := m.addrLen()
+ errno := windows.VirtualUnlock(addr, len)
+ return os.NewSyscallError("VirtualUnlock", errno)
+}
+
+func (m MMap) unmap() error {
+ err := m.flush()
+ if err != nil {
+ return err
+ }
+
+ addr := m.header().Data
+ // Lock the UnmapViewOfFile along with the handleMap deletion.
+ // As soon as we unmap the view, the OS is free to give the
+ // same addr to another new map. We don't want another goroutine
+ // to insert and remove the same addr into handleMap while
+ // we're trying to remove our old addr/handle pair.
+ handleLock.Lock()
+ defer handleLock.Unlock()
+ err = windows.UnmapViewOfFile(addr)
+ if err != nil {
+ return err
+ }
+
+ handle, ok := handleMap[addr]
+ if !ok {
+ // should be impossible; we would've errored above
+ return errors.New("unknown base address")
+ }
+ delete(handleMap, addr)
+
+ e := windows.CloseHandle(windows.Handle(handle.mapview))
+ return os.NewSyscallError("CloseHandle", e)
+}