You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
3.6 KiB

  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. // This file defines the common package interface and contains a little bit of
  5. // factored out logic.
  6. // Package mmap allows mapping files into memory. It tries to provide a simple, reasonably portable interface,
  7. // but doesn't go out of its way to abstract away every little platform detail.
  8. // This specifically means:
  9. // * forked processes may or may not inherit mappings
  10. // * a file's timestamp may or may not be updated by writes through mappings
  11. // * specifying a size larger than the file's actual size can increase the file's size
  12. // * If the mapped file is being modified by another process while your program's running, don't expect consistent results between platforms
  13. package mmap
  14. import (
  15. "errors"
  16. "os"
  17. "reflect"
  18. "unsafe"
  19. )
  20. const (
  21. // RDONLY maps the memory read-only.
  22. // Attempts to write to the MMap object will result in undefined behavior.
  23. RDONLY = 0
  24. // RDWR maps the memory as read-write. Writes to the MMap object will update the
  25. // underlying file.
  26. RDWR = 1 << iota
  27. // COPY maps the memory as copy-on-write. Writes to the MMap object will affect
  28. // memory, but the underlying file will remain unchanged.
  29. COPY
  30. // If EXEC is set, the mapped memory is marked as executable.
  31. EXEC
  32. )
  33. const (
  34. // If the ANON flag is set, the mapped memory will not be backed by a file.
  35. ANON = 1 << iota
  36. )
  37. // MMap represents a file mapped into memory.
  38. type MMap []byte
  39. // Map maps an entire file into memory.
  40. // If ANON is set in flags, f is ignored.
  41. func Map(f *os.File, prot, flags int) (MMap, error) {
  42. return MapRegion(f, -1, prot, flags, 0)
  43. }
  44. // MapRegion maps part of a file into memory.
  45. // The offset parameter must be a multiple of the system's page size.
  46. // If length < 0, the entire file will be mapped.
  47. // If ANON is set in flags, f is ignored.
  48. func MapRegion(f *os.File, length int, prot, flags int, offset int64) (MMap, error) {
  49. if offset%int64(os.Getpagesize()) != 0 {
  50. return nil, errors.New("offset parameter must be a multiple of the system's page size")
  51. }
  52. var fd uintptr
  53. if flags&ANON == 0 {
  54. fd = uintptr(f.Fd())
  55. if length < 0 {
  56. fi, err := f.Stat()
  57. if err != nil {
  58. return nil, err
  59. }
  60. length = int(fi.Size())
  61. }
  62. } else {
  63. if length <= 0 {
  64. return nil, errors.New("anonymous mapping requires non-zero length")
  65. }
  66. fd = ^uintptr(0)
  67. }
  68. return mmap(length, uintptr(prot), uintptr(flags), fd, offset)
  69. }
  70. func (m *MMap) header() *reflect.SliceHeader {
  71. return (*reflect.SliceHeader)(unsafe.Pointer(m))
  72. }
  73. // Lock keeps the mapped region in physical memory, ensuring that it will not be
  74. // swapped out.
  75. func (m MMap) Lock() error {
  76. dh := m.header()
  77. return lock(dh.Data, uintptr(dh.Len))
  78. }
  79. // Unlock reverses the effect of Lock, allowing the mapped region to potentially
  80. // be swapped out.
  81. // If m is already unlocked, aan error will result.
  82. func (m MMap) Unlock() error {
  83. dh := m.header()
  84. return unlock(dh.Data, uintptr(dh.Len))
  85. }
  86. // Flush synchronizes the mapping's contents to the file's contents on disk.
  87. func (m MMap) Flush() error {
  88. dh := m.header()
  89. return flush(dh.Data, uintptr(dh.Len))
  90. }
  91. // Unmap deletes the memory mapped region, flushes any remaining changes, and sets
  92. // m to nil.
  93. // Trying to read or write any remaining references to m after Unmap is called will
  94. // result in undefined behavior.
  95. // Unmap should only be called on the slice value that was originally returned from
  96. // a call to Map. Calling Unmap on a derived slice may cause errors.
  97. func (m *MMap) Unmap() error {
  98. dh := m.header()
  99. err := unmap(dh.Data, uintptr(dh.Len))
  100. *m = nil
  101. return err
  102. }