@ -5,6 +5,7 @@ package memory_map
import (
"os"
"reflect"
"runtime"
"syscall"
"unsafe"
@ -33,32 +34,41 @@ type DWORD = uint32
type WORD = uint16
var (
procGetSystemInfo = syscall . NewLazyDLL ( "kernel32.dll" ) . NewProc ( "GetSystemInfo" )
modkernel32 = syscall . NewLazyDLL ( "kernel32.dll" )
procGetSystemInfo = modkernel32 . NewProc ( "GetSystemInfo" )
procGetProcessWorkingSetSize = modkernel32 . NewProc ( "GetProcessWorkingSetSize" )
procSetProcessWorkingSetSize = modkernel32 . NewProc ( "SetProcessWorkingSetSize" )
)
var system_info , err = getSystemInfo ( )
var currentProcess , _ = windows . GetCurrentProcess ( )
var currentMinWorkingSet uint64 = 0
var currentMaxWorkingSet uint64 = 0
var _ = getProcessWorkingSetSize ( uintptr ( currentProcess ) , & currentMinWorkingSet , & currentMaxWorkingSet )
var chunk_size = uint64 ( system_info . dwAllocationGranularity ) * 256
var systemInfo , _ = getSystemInfo ( )
var chunkSize = uint64 ( systemInfo . dwAllocationGranularity ) * 256
func ( mMap * MemoryMap ) CreateMemoryMap ( file * os . File , maxl ength uint64 ) {
func ( mMap * MemoryMap ) CreateMemoryMap ( file * os . File , maxL ength uint64 ) {
chunks := ( maxlength / chunk_s ize )
if chunks * chunk_size < maxl ength {
chunks := ( maxLength / chunkS ize )
if chunks * chunkSize < maxL ength {
chunks = chunks + 1
}
alignedMaxLength := chunks * chunk_s ize
alignedMaxLength := chunks * chunkS ize
maxl ength_high := uint32 ( alignedMaxLength >> 32 )
maxl ength_low := uint32 ( alignedMaxLength & 0xFFFFFFFF )
file_memory_map_handle , err := windows . CreateFileMapping ( windows . Handle ( file . Fd ( ) ) , nil , windows . PAGE_READWRITE , maxlength_high , maxl ength_low , nil )
maxL ength_high := uint32 ( alignedMaxLength >> 32 )
maxL ength_low := uint32 ( alignedMaxLength & 0xFFFFFFFF )
file_memory_map_handle , err := windows . CreateFileMapping ( windows . Handle ( file . Fd ( ) ) , nil , windows . PAGE_READWRITE , maxLength_high , maxL ength_low , nil )
if err == nil {
mMap . File = file
mMap . file_memory_map_handle = uintptr ( file_memory_map_handle )
mMap . write_map_views = make ( [ ] MemoryBuffer , 0 , alignedMaxLength / chunk_s ize )
mMap . write_map_views = make ( [ ] MemoryBuffer , 0 , alignedMaxLength / chunkS ize )
mMap . max_length = alignedMaxLength
mMap . End_of_file = - 1
runtime . SetFinalizer ( mMap , mMap . DeleteFileAndMemoryMap )
}
}
@ -84,7 +94,7 @@ func min(x, y uint64) uint64 {
func ( mMap * MemoryMap ) WriteMemory ( offset uint64 , length uint64 , data [ ] byte ) {
for {
if ( ( offset + length ) / chunk_s ize ) + 1 > uint64 ( len ( mMap . write_map_views ) ) {
if ( ( offset + length ) / chunkS ize ) + 1 > uint64 ( len ( mMap . write_map_views ) ) {
allocateChunk ( mMap )
} else {
break
@ -92,19 +102,19 @@ func (mMap *MemoryMap) WriteMemory(offset uint64, length uint64, data []byte) {
}
remaining_length := length
slice_i ndex := offset / chunk_s ize
slice_o ffset := offset - ( slice_index * chunk_s ize )
data_o ffset := uint64 ( 0 )
sliceI ndex := offset / chunkS ize
sliceO ffset := offset - ( sliceIndex * chunkS ize )
dataO ffset := uint64 ( 0 )
for {
write_e nd := min ( ( remaining_length + slice_offset ) , chunk_s ize )
copy ( mMap . write_map_views [ slice_i ndex ] . Buffer [ slice_offset : write_e nd ] , data [ data_o ffset : ] )
remaining_length -= ( write_end - slice_o ffset )
data_offset += ( write_end - slice_o ffset )
writeE nd := min ( ( remaining_length + sliceOffset ) , chunkS ize )
copy ( mMap . write_map_views [ sliceI ndex ] . Buffer [ sliceOffset : writeE nd ] , data [ dataO ffset : ] )
remaining_length -= ( writeEnd - sliceO ffset )
dataOffset += ( writeEnd - sliceO ffset )
if remaining_length > 0 {
slice_i ndex += 1
slice_o ffset = 0
sliceI ndex += 1
sliceO ffset = 0
} else {
break
}
@ -120,8 +130,15 @@ func (mMap *MemoryMap) ReadMemory(offset uint64, length uint64) (MemoryBuffer, e
}
func ( mBuffer * MemoryBuffer ) ReleaseMemory ( ) {
currentMinWorkingSet = currentMinWorkingSet - mBuffer . aligned_length
currentMaxWorkingSet = currentMaxWorkingSet - mBuffer . aligned_length
windows . VirtualUnlock ( mBuffer . aligned_ptr , uintptr ( mBuffer . aligned_length ) )
windows . UnmapViewOfFile ( mBuffer . aligned_ptr )
var _ = setProcessWorkingSetSize ( uintptr ( currentProcess ) , uintptr ( currentMinWorkingSet ) , uintptr ( currentMaxWorkingSet ) )
mBuffer . ptr = 0
mBuffer . aligned_ptr = 0
mBuffer . length = 0
@ -131,11 +148,12 @@ func (mBuffer *MemoryBuffer) ReleaseMemory() {
func allocateChunk ( mMap * MemoryMap ) {
start := uint64 ( len ( mMap . write_map_views ) ) * chunk_s ize
mBuffer , err := allocate ( windows . Handle ( mMap . file_memory_map_handle ) , start , chunk_s ize , true )
start := uint64 ( len ( mMap . write_map_views ) ) * chunkS ize
mBuffer , err := allocate ( windows . Handle ( mMap . file_memory_map_handle ) , start , chunkS ize , true )
if err == nil {
mMap . write_map_views = append ( mMap . write_map_views , mBuffer )
windows . VirtualLock ( mBuffer . aligned_ptr , uintptr ( mBuffer . aligned_length ) )
}
}
@ -143,7 +161,7 @@ func allocate(hMapFile windows.Handle, offset uint64, length uint64, write bool)
mBuffer := MemoryBuffer { }
dwSysGran := system_i nfo . dwAllocationGranularity
dwSysGran := systemI nfo . dwAllocationGranularity
start := ( offset / uint64 ( dwSysGran ) ) * uint64 ( dwSysGran )
diff := offset - start
@ -158,6 +176,11 @@ func allocate(hMapFile windows.Handle, offset uint64, length uint64, write bool)
access = windows . FILE_MAP_WRITE
}
currentMinWorkingSet = currentMinWorkingSet + aligned_length
currentMaxWorkingSet = currentMaxWorkingSet + aligned_length
var _ = setProcessWorkingSetSize ( uintptr ( currentProcess ) , uintptr ( currentMinWorkingSet ) , uintptr ( currentMaxWorkingSet ) )
addr_ptr , errno := windows . MapViewOfFile ( hMapFile ,
uint32 ( access ) , // read/write permission
offset_high ,
@ -227,3 +250,35 @@ func getSystemInfo() (_SYSTEM_INFO, error) {
}
return si , nil
}
// BOOL GetProcessWorkingSetSize(
// HANDLE hProcess,
// PSIZE_T lpMinimumWorkingSetSize,
// PSIZE_T lpMaximumWorkingSetSize
// );
func getProcessWorkingSetSize ( process uintptr , dwMinWorkingSet * uint64 , dwMaxWorkingSet * uint64 ) error {
r1 , _ , err := syscall . Syscall ( procGetProcessWorkingSetSize . Addr ( ) , 3 , process , uintptr ( unsafe . Pointer ( dwMinWorkingSet ) ) , uintptr ( unsafe . Pointer ( dwMaxWorkingSet ) ) )
if r1 == 0 {
if err != syscall . Errno ( 0 ) {
return err
}
}
return nil
}
// BOOL SetProcessWorkingSetSize(
// HANDLE hProcess,
// SIZE_T dwMinimumWorkingSetSize,
// SIZE_T dwMaximumWorkingSetSize
// );
func setProcessWorkingSetSize ( process uintptr , dwMinWorkingSet uintptr , dwMaxWorkingSet uintptr ) error {
r1 , _ , err := syscall . Syscall ( procSetProcessWorkingSetSize . Addr ( ) , 3 , process , ( dwMinWorkingSet ) , ( dwMaxWorkingSet ) )
if r1 == 0 {
if err != syscall . Errno ( 0 ) {
return err
}
}
return nil
}