git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/mmdb/mmap_windows.go (about)

     1  //go:build windows && !appengine
     2  // +build windows,!appengine
     3  
     4  package mmdb
     5  
     6  // Windows support largely borrowed from mmap-go.
     7  //
     8  // Copyright 2011 Evan Shaw. All rights reserved.
     9  // Use of this source code is governed by a BSD-style
    10  // license that can be found in the LICENSE file.
    11  
    12  import (
    13  	"errors"
    14  	"os"
    15  	"reflect"
    16  	"sync"
    17  	"unsafe"
    18  
    19  	"golang.org/x/sys/windows"
    20  )
    21  
    22  type memoryMap []byte
    23  
    24  // Windows
    25  var handleLock sync.Mutex
    26  var handleMap = map[uintptr]windows.Handle{}
    27  
    28  func mmap(fd int, length int) (data []byte, err error) {
    29  	h, errno := windows.CreateFileMapping(windows.Handle(fd), nil,
    30  		uint32(windows.PAGE_READONLY), 0, uint32(length), nil)
    31  	if h == 0 {
    32  		return nil, os.NewSyscallError("CreateFileMapping", errno)
    33  	}
    34  
    35  	addr, errno := windows.MapViewOfFile(h, uint32(windows.FILE_MAP_READ), 0,
    36  		0, uintptr(length))
    37  	if addr == 0 {
    38  		return nil, os.NewSyscallError("MapViewOfFile", errno)
    39  	}
    40  	handleLock.Lock()
    41  	handleMap[addr] = h
    42  	handleLock.Unlock()
    43  
    44  	m := memoryMap{}
    45  	dh := m.header()
    46  	dh.Data = addr
    47  	dh.Len = length
    48  	dh.Cap = dh.Len
    49  
    50  	return m, nil
    51  }
    52  
    53  func (m *memoryMap) header() *reflect.SliceHeader {
    54  	return (*reflect.SliceHeader)(unsafe.Pointer(m))
    55  }
    56  
    57  func flush(addr, len uintptr) error {
    58  	errno := windows.FlushViewOfFile(addr, len)
    59  	return os.NewSyscallError("FlushViewOfFile", errno)
    60  }
    61  
    62  func munmap(b []byte) (err error) {
    63  	m := memoryMap(b)
    64  	dh := m.header()
    65  
    66  	addr := dh.Data
    67  	length := uintptr(dh.Len)
    68  
    69  	flush(addr, length)
    70  	err = windows.UnmapViewOfFile(addr)
    71  	if err != nil {
    72  		return err
    73  	}
    74  
    75  	handleLock.Lock()
    76  	defer handleLock.Unlock()
    77  	handle, ok := handleMap[addr]
    78  	if !ok {
    79  		// should be impossible; we would've errored above
    80  		return errors.New("unknown base address")
    81  	}
    82  	delete(handleMap, addr)
    83  
    84  	e := windows.CloseHandle(windows.Handle(handle))
    85  	return os.NewSyscallError("CloseHandle", e)
    86  }