gitee.com/quant1x/gox@v1.21.2/cache/mmap_windows.go (about) 1 // Copyright 2011 Evan Shaw. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package cache 6 7 import ( 8 "errors" 9 "os" 10 "sync" 11 12 "golang.org/x/sys/windows" 13 ) 14 15 // mmap on Windows is a two-step process. 16 // First, we call CreateFileMapping to get a handle. 17 // Then, we call MapviewToFile to get an actual pointer into memory. 18 // Because we want to emulate a POSIX-style mmap, we don't want to expose 19 // the handle -- only the pointer. We also want to return only a byte slice, 20 // not a struct, so it's convenient to manipulate. 21 22 // We keep this map so that we can get back the original handle from the memory address. 23 24 type addrinfo struct { 25 file windows.Handle 26 mapview windows.Handle 27 writable bool 28 } 29 30 var handleLock sync.Mutex 31 var handleMap = map[uintptr]*addrinfo{} 32 33 func mmap(len int, prot, flags, hfile uintptr, off int64) ([]byte, error) { 34 flProtect := uint32(windows.PAGE_READONLY) 35 dwDesiredAccess := uint32(windows.FILE_MAP_READ) 36 writable := false 37 switch { 38 case prot© != 0: 39 flProtect = windows.PAGE_WRITECOPY 40 dwDesiredAccess = windows.FILE_MAP_COPY 41 writable = true 42 case prot&RDWR != 0: 43 flProtect = windows.PAGE_READWRITE 44 dwDesiredAccess = windows.FILE_MAP_WRITE 45 writable = true 46 } 47 if prot&EXEC != 0 { 48 flProtect <<= 4 49 dwDesiredAccess |= windows.FILE_MAP_EXECUTE 50 } 51 52 // The maximum size is the area of the file, starting from 0, 53 // that we wish to allow to be mappable. It is the sum of 54 // the length the user requested, plus the offset where that length 55 // is starting from. This does not map the data into memory. 56 maxSizeHigh := uint32((off + int64(len)) >> 32) 57 maxSizeLow := uint32((off + int64(len)) & 0xFFFFFFFF) 58 // TODO: Do we need to set some security attributes? It might help portability. 59 h, errno := windows.CreateFileMapping(windows.Handle(hfile), nil, flProtect, maxSizeHigh, maxSizeLow, nil) 60 if h == 0 { 61 return nil, os.NewSyscallError("CreateFileMapping", errno) 62 } 63 64 // Actually map a view of the data into memory. The view's size 65 // is the length the user requested. 66 fileOffsetHigh := uint32(off >> 32) 67 fileOffsetLow := uint32(off & 0xFFFFFFFF) 68 addr, errno := windows.MapViewOfFile(h, dwDesiredAccess, fileOffsetHigh, fileOffsetLow, uintptr(len)) 69 if addr == 0 { 70 windows.CloseHandle(windows.Handle(h)) 71 return nil, os.NewSyscallError("MapViewOfFile", errno) 72 } 73 handleLock.Lock() 74 handleMap[addr] = &addrinfo{ 75 file: windows.Handle(hfile), 76 mapview: h, 77 writable: writable, 78 } 79 handleLock.Unlock() 80 81 m := MMap{} 82 dh := m.header() 83 dh.Data = addr 84 dh.Len = len 85 dh.Cap = dh.Len 86 87 return m, nil 88 } 89 90 func (m MMap) flush() error { 91 addr, len := m.addrLen() 92 errno := windows.FlushViewOfFile(addr, len) 93 if errno != nil { 94 return os.NewSyscallError("FlushViewOfFile", errno) 95 } 96 97 handleLock.Lock() 98 defer handleLock.Unlock() 99 handle, ok := handleMap[addr] 100 if !ok { 101 // should be impossible; we would've errored above 102 return errors.New("unknown base address") 103 } 104 105 if handle.writable && handle.file != windows.Handle(^uintptr(0)) { 106 if err := windows.FlushFileBuffers(handle.file); err != nil { 107 return os.NewSyscallError("FlushFileBuffers", err) 108 } 109 } 110 111 return nil 112 } 113 114 func (m MMap) lock() error { 115 addr, len := m.addrLen() 116 errno := windows.VirtualLock(addr, len) 117 return os.NewSyscallError("VirtualLock", errno) 118 } 119 120 func (m MMap) unlock() error { 121 addr, len := m.addrLen() 122 errno := windows.VirtualUnlock(addr, len) 123 return os.NewSyscallError("VirtualUnlock", errno) 124 } 125 126 func (m MMap) unmap() error { 127 err := m.flush() 128 if err != nil { 129 return err 130 } 131 132 addr := m.header().Data 133 // Lock the UnmapViewOfFile along with the handleMap deletion. 134 // As soon as we unmap the view, the OS is free to give the 135 // same addr to another new map. We don't want another goroutine 136 // to insert and remove the same addr into handleMap while 137 // we're trying to remove our old addr/handle pair. 138 handleLock.Lock() 139 defer handleLock.Unlock() 140 err = windows.UnmapViewOfFile(addr) 141 if err != nil { 142 return err 143 } 144 145 handle, ok := handleMap[addr] 146 if !ok { 147 // should be impossible; we would've errored above 148 return errors.New("unknown base address") 149 } 150 delete(handleMap, addr) 151 152 e := windows.CloseHandle(windows.Handle(handle.mapview)) 153 return os.NewSyscallError("CloseHandle", e) 154 }