Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit b84771a
Showing
12 changed files
with
587 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
*.out | ||
*.5 | ||
*.6 | ||
*.8 | ||
*.swp | ||
_obj | ||
_test | ||
testdata |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
Copyright (c) 2011, Evan Shaw <edsrzf@gmail.com> | ||
All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are met: | ||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
* Redistributions in binary form must reproduce the above copyright | ||
notice, this list of conditions and the following disclaimer in the | ||
documentation and/or other materials provided with the distribution. | ||
* Neither the name of the copyright holder nor the | ||
names of its contributors may be used to endorse or promote products | ||
derived from this software without specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | ||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# 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. | ||
|
||
include $(GOROOT)/src/Make.inc | ||
|
||
TARG=github.com/edsrzf/mmap-go | ||
GOFILES=\ | ||
const_unix.go\ | ||
mmap.go\ | ||
|
||
GOFILES_freebsd=\ | ||
mmap_unix.go\ | ||
mmap_unix_syscall.go | ||
|
||
GOFILES_darwin=\ | ||
mmap_unix.go\ | ||
mmap_unix_syscall.go | ||
|
||
GOFILES_linux=\ | ||
mmap_unix.go | ||
ifeq ($(GOARCH),amd64) | ||
GOFILES_linux+=\ | ||
mmap_unix_syscall.go | ||
else | ||
GOFILES_linux+=\ | ||
mmap_linux32_syscall.go | ||
endif | ||
|
||
GOFILES_windows=\ | ||
mmap_windows.go | ||
|
||
GOFILES+=$(GOFILES_$(GOOS)) | ||
include $(GOROOT)/src/Make.pkg | ||
|
||
const_unix.go: const_unix.c | ||
godefs -gmmap const_unix.c > const_unix.go |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
mmap-go | ||
======= | ||
|
||
mmap-go is a portable mmap package for the [Go programming language](http://golang.org). | ||
It has been tested on Linux (386, amd64) and Windows (386). It should also work on | ||
other Unix-like platforms, but hasn't been tested with them. I'm interested to | ||
hear about the results. | ||
|
||
I haven't been able to add more features without adding significant complexity, | ||
so mmap-go doesn't support as many features as a non-portable package might. | ||
If you're running on a Unix-like platform and need some of these features, | ||
I suggest Gustavo Niemeyer's [gommap](http://labix.org/gommap). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// 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. | ||
|
||
#include <sys/mman.h> | ||
|
||
enum { | ||
$_PROT_READ = PROT_READ, | ||
$_PROT_WRITE = PROT_WRITE, | ||
$_PROT_EXEC = PROT_EXEC, | ||
|
||
$_MAP_ANONYMOUS = MAP_ANONYMOUS, | ||
$_MAP_SHARED = MAP_SHARED, | ||
$_MAP_PRIVATE = MAP_PRIVATE, | ||
|
||
$_MS_SYNC = MS_SYNC, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// godefs -gmmap const_unix.c | ||
|
||
// MACHINE GENERATED - DO NOT EDIT. | ||
|
||
package mmap | ||
|
||
// Constants | ||
const ( | ||
_PROT_READ = 0x1; | ||
_PROT_WRITE = 0x2; | ||
_PROT_EXEC = 0x4; | ||
_MAP_ANONYMOUS = 0x20; | ||
_MAP_SHARED = 0x1; | ||
_MAP_PRIVATE = 0x2; | ||
_MS_SYNC = 0x4; | ||
) | ||
|
||
// Types |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// 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. | ||
|
||
// This file defines the common package interface and contains a little bit of | ||
// factored out logic. | ||
|
||
// Package mmap allows mapping files into memory. It tries to provide a simple, reasonably portable interface, | ||
// but doesn't go out of its way to abstract away every little platform detail. | ||
// This specifically means: | ||
// * forked processes may or may not inherit mappings | ||
// * a file's timestamp may or may not be updated by writes through mappings | ||
// * specifying a size larger than the file's actual size can increase the file's size | ||
// * If the mapped file is being modified by another process while your program's running, don't expect consistent results between platforms | ||
package mmap | ||
|
||
import ( | ||
"os" | ||
"reflect" | ||
"unsafe" | ||
) | ||
|
||
const ( | ||
// RDONLY maps the memory read-only. | ||
// Attempts to write to the MMap object will result in undefined behavior. | ||
RDONLY = 0 | ||
// RDWR maps the memory as read-write. Writes to the MMap object will update the | ||
// underlying file. | ||
RDWR = 1 << iota | ||
// COPY maps the memory as copy-on-write. Writes to the MMap object will affect | ||
// memory, but the underlying file will remain unchanged. | ||
COPY | ||
// If EXEC is set, the mapped memory is marked as executable. | ||
EXEC | ||
) | ||
|
||
const ( | ||
// If the ANON flag is set, the mapped memory will not be backed by a file. | ||
ANON = 1 << iota | ||
) | ||
|
||
// MMap represents a file mapped into memory. | ||
type MMap []byte | ||
|
||
// Map maps an entire file into memory. | ||
// If ANON is set in flags, f is ignored. | ||
func Map(f *os.File, prot, flags int) (MMap, os.Error) { | ||
return MapRegion(f, -1, prot, flags, 0) | ||
} | ||
|
||
// MapRegion maps part of a file into memory. | ||
// The offset parameter must be a multiple of the system's page size. | ||
// If length < 0, the entire file will be mapped. | ||
// If ANON is set in flags, f is ignored. | ||
func MapRegion(f *os.File, length int64, prot, flags int, offset int64) (MMap, os.Error) { | ||
var fd uintptr | ||
if flags&ANON == 0 { | ||
fd = uintptr(f.Fd()) | ||
if length < 0 { | ||
fi, err := f.Stat() | ||
if err != nil { | ||
return nil, err | ||
} | ||
length = fi.Size | ||
} | ||
} else { | ||
if length <= 0 { | ||
return nil, os.NewError("anonymous mapping requires non-zero length") | ||
} | ||
fd = ^uintptr(0) | ||
} | ||
addr, err := mmap(length, uintptr(prot), uintptr(flags), fd, offset) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
m := MMap{} | ||
dh := m.header() | ||
dh.Data = addr | ||
// TODO: eek, truncation | ||
dh.Len = int(length) | ||
dh.Cap = dh.Len | ||
return m, nil | ||
} | ||
|
||
func (m *MMap) header() *reflect.SliceHeader { | ||
return (*reflect.SliceHeader)(unsafe.Pointer(m)) | ||
} | ||
|
||
// Lock keeps the mapped region in physical memory, ensuring that it will not be | ||
// swapped out. | ||
func (m MMap) Lock() os.Error { | ||
dh := m.header() | ||
return lock(dh.Data, uintptr(dh.Len)) | ||
} | ||
|
||
// Unlock reverses the effect of Lock, allowing the mapped region to potentially | ||
// be swapped out. | ||
// If m is already unlocked, aan error will result. | ||
func (m MMap) Unlock() os.Error { | ||
dh := m.header() | ||
return unlock(dh.Data, uintptr(dh.Len)) | ||
} | ||
|
||
// Flush synchronizes the mapping's contents to the file's contents on disk. | ||
func (m MMap) Flush() os.Error { | ||
dh := m.header() | ||
return flush(dh.Data, uintptr(dh.Len)) | ||
} | ||
|
||
// Unmap deletes the memory mapped region, flushes any remaining changes, and sets | ||
// m to nil. | ||
// Trying to read or write any remaining references to m after Unmap is called will | ||
// result in undefined behavior. | ||
// Unmap should only be called on the slice value that was originally returned from | ||
// a call to Map. Calling Unmap on a derived slice may cause errors. | ||
func (m *MMap) Unmap() os.Error { | ||
dh := m.header() | ||
err := unmap(dh.Data, uintptr(dh.Len)) | ||
*m = nil | ||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// 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 | ||
|
||
// 32-bit Linux architectures (namely x86 and ARM) have two mmap system calls, both | ||
// of which are incompatible with mmap on other platforms: | ||
// - syscall.MMAP (old_mmap) expects a single pointer argument | ||
// - syscall.MMAP2 (mmap2) takes an offset in pages, not bytes | ||
// Thus, 32-bit Linux gets its own special file. | ||
import ( | ||
"syscall" | ||
) | ||
|
||
func mmap_syscall(len, prot, flags, fd uintptr, off int64) (uintptr, uintptr) { | ||
// assuming page size is 4096; the runtime does it, so it should be okay | ||
if off&0xFFF != 0 { | ||
return 0, syscall.EINVAL | ||
} | ||
off >>= 12 | ||
ptr, _, errno := syscall.Syscall6(syscall.SYS_MMAP2, 0, len, prot, | ||
flags, fd, uintptr(off)) | ||
return ptr, errno | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
// 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. | ||
|
||
// These tests are adapted from gommap: http://labix.org/gommap | ||
// Copyright (c) 2010, Gustavo Niemeyer <gustavo@niemeyer.net> | ||
|
||
package mmap | ||
|
||
import ( | ||
"bytes" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
) | ||
|
||
var testData = []byte("0123456789ABCDEF") | ||
var testPath = filepath.Join(os.TempDir(), "testdata") | ||
|
||
func init() { | ||
f := openFile(os.O_RDWR|os.O_CREATE) | ||
f.Write(testData) | ||
f.Close() | ||
} | ||
|
||
func openFile(flags int) *os.File { | ||
f, err := os.Open(testPath, flags, 0644) | ||
if err != nil { | ||
panic(err.String()) | ||
} | ||
return f | ||
} | ||
|
||
func TestUnmap(t *testing.T) { | ||
f := openFile(os.O_RDONLY) | ||
defer f.Close() | ||
mmap, err := Map(f, RDONLY, 0) | ||
if err != nil { | ||
t.Errorf("error mapping: %s", err) | ||
} | ||
if err := mmap.Unmap(); err != nil { | ||
t.Errorf("error unmapping: %s", err) | ||
} | ||
} | ||
|
||
func TestReadWrite(t *testing.T) { | ||
f := openFile(os.O_RDWR) | ||
defer f.Close() | ||
mmap, err := Map(f, RDWR, 0) | ||
if err != nil { | ||
t.Errorf("error mapping: %s", err) | ||
} | ||
defer mmap.Unmap() | ||
if !bytes.Equal(testData, mmap) { | ||
t.Errorf("mmap != testData: %q, %q", mmap, testData) | ||
} | ||
|
||
mmap[9] = 'X' | ||
mmap.Flush() | ||
|
||
fileData, err := ioutil.ReadAll(f) | ||
if err != nil { | ||
t.Errorf("error reading file: %s", err) | ||
} | ||
if !bytes.Equal(fileData, []byte("012345678XABCDEF")) { | ||
t.Errorf("file wasn't modified") | ||
} | ||
|
||
// leave things how we found them | ||
mmap[9] = '9' | ||
mmap.Flush() | ||
} | ||
|
||
func TestProtFlagsAndErr(t *testing.T) { | ||
f := openFile(os.O_RDONLY) | ||
defer f.Close() | ||
if _, err := Map(f, RDWR, 0); err == nil { | ||
t.Errorf("expected error") | ||
} | ||
} | ||
|
||
func TestFlags(t *testing.T) { | ||
f := openFile(os.O_RDWR) | ||
defer f.Close() | ||
mmap, err := Map(f, COPY, 0) | ||
if err != nil { | ||
t.Errorf("error mapping: %s", err) | ||
} | ||
defer mmap.Unmap() | ||
|
||
mmap[9] = 'X' | ||
mmap.Flush() | ||
|
||
fileData, err := ioutil.ReadAll(f) | ||
if err != nil { | ||
t.Errorf("error reading file: %s", err) | ||
} | ||
if !bytes.Equal(fileData, testData) { | ||
t.Errorf("file was modified") | ||
} | ||
} |
Oops, something went wrong.