1package tsm1 2 3import ( 4 "errors" 5 "os" 6 "reflect" 7 "sync" 8 "syscall" 9 "unsafe" 10) 11 12// mmap implementation for Windows 13// Based on: https://github.com/edsrzf/mmap-go 14// Based on: https://github.com/boltdb/bolt/bolt_windows.go 15// Ref: https://groups.google.com/forum/#!topic/golang-nuts/g0nLwQI9www 16 17// We keep this map so that we can get back the original handle from the memory address. 18var handleLock sync.Mutex 19var handleMap = map[uintptr]syscall.Handle{} 20var fileMap = map[uintptr]*os.File{} 21 22func openSharedFile(f *os.File) (file *os.File, err error) { 23 24 var access, createmode, sharemode uint32 25 var sa *syscall.SecurityAttributes 26 27 access = syscall.GENERIC_READ 28 sharemode = uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE | syscall.FILE_SHARE_DELETE) 29 createmode = syscall.OPEN_EXISTING 30 fileName := f.Name() 31 32 pathp, err := syscall.UTF16PtrFromString(fileName) 33 if err != nil { 34 return nil, err 35 } 36 37 h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, syscall.FILE_ATTRIBUTE_NORMAL, 0) 38 39 if e != nil { 40 return nil, e 41 } 42 //NewFile does not add finalizer, need to close this manually 43 return os.NewFile(uintptr(h), fileName), nil 44} 45 46func mmap(f *os.File, offset int64, length int) (out []byte, err error) { 47 // TODO: Add support for anonymous mapping on windows 48 if f == nil { 49 return make([]byte, length), nil 50 } 51 52 // Open a file mapping handle. 53 sizelo := uint32(length >> 32) 54 sizehi := uint32(length) & 0xffffffff 55 56 sharedHandle, errno := openSharedFile(f) 57 if errno != nil { 58 return nil, os.NewSyscallError("CreateFile", errno) 59 } 60 61 h, errno := syscall.CreateFileMapping(syscall.Handle(sharedHandle.Fd()), nil, syscall.PAGE_READONLY, sizelo, sizehi, nil) 62 if h == 0 { 63 return nil, os.NewSyscallError("CreateFileMapping", errno) 64 } 65 66 // Create the memory map. 67 addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, uintptr(length)) 68 if addr == 0 { 69 return nil, os.NewSyscallError("MapViewOfFile", errno) 70 } 71 72 handleLock.Lock() 73 handleMap[addr] = h 74 fileMap[addr] = sharedHandle 75 handleLock.Unlock() 76 77 // Convert to a byte array. 78 hdr := (*reflect.SliceHeader)(unsafe.Pointer(&out)) 79 hdr.Data = uintptr(unsafe.Pointer(addr)) 80 hdr.Len = length 81 hdr.Cap = length 82 83 return 84} 85 86// munmap Windows implementation 87// Based on: https://github.com/edsrzf/mmap-go 88// Based on: https://github.com/boltdb/bolt/bolt_windows.go 89func munmap(b []byte) (err error) { 90 handleLock.Lock() 91 defer handleLock.Unlock() 92 93 addr := (uintptr)(unsafe.Pointer(&b[0])) 94 if err := syscall.UnmapViewOfFile(addr); err != nil { 95 return os.NewSyscallError("UnmapViewOfFile", err) 96 } 97 98 handle, ok := handleMap[addr] 99 if !ok { 100 // should be impossible; we would've seen the error above 101 return errors.New("unknown base address") 102 } 103 delete(handleMap, addr) 104 105 e := syscall.CloseHandle(syscall.Handle(handle)) 106 if e != nil { 107 return os.NewSyscallError("CloseHandle", e) 108 } 109 110 file, ok := fileMap[addr] 111 if !ok { 112 // should be impossible; we would've seen the error above 113 return errors.New("unknown base address") 114 } 115 delete(fileMap, addr) 116 117 e = file.Close() 118 if e != nil { 119 return errors.New("close file" + e.Error()) 120 } 121 return nil 122} 123 124// madviseWillNeed is unsupported on Windows. 125func madviseWillNeed(b []byte) error { return nil } 126 127// madviseDontNeed is unsupported on Windows. 128func madviseDontNeed(b []byte) error { return nil } 129 130func madvise(b []byte, advice int) error { 131 // Not implemented 132 return nil 133} 134