aboutsummaryrefslogtreecommitdiff
path: root/core/mem/virtual/virtual_darwin.odin
blob: d2e3c8b512a955cbf2d0c1f693a4f3fe462065a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//+build darwin
//+private
package mem_virtual

foreign import libc "system:System.framework"
import "core:c"

PROT_NONE  :: 0x0 /* [MC2] no permissions */
PROT_READ  :: 0x1 /* [MC2] pages can be read */
PROT_WRITE :: 0x2 /* [MC2] pages can be written */
PROT_EXEC  :: 0x4 /* [MC2] pages can be executed */

// Sharing options
MAP_SHARED    :: 0x1 /* [MF|SHM] share changes */
MAP_PRIVATE   :: 0x2 /* [MF|SHM] changes are private */

// Other flags
MAP_FIXED        :: 0x0010 /* [MF|SHM] interpret addr exactly */
MAP_RENAME       :: 0x0020 /* Sun: rename private pages to file */
MAP_NORESERVE    :: 0x0040 /* Sun: don't reserve needed swap area */
MAP_RESERVED0080 :: 0x0080 /* previously unimplemented MAP_INHERIT */
MAP_NOEXTEND     :: 0x0100 /* for MAP_FILE, don't change file size */
MAP_HASSEMAPHORE :: 0x0200 /* region may contain semaphores */
MAP_NOCACHE      :: 0x0400 /* don't cache pages for this mapping */
MAP_JIT          :: 0x0800 /* Allocate a region that will be used for JIT purposes */

// Mapping type
MAP_FILE         :: 0x0000  /* map from file (default) */
MAP_ANONYMOUS    :: 0x1000  /* allocated from memory, swap space */


/*
 * The MAP_RESILIENT_* flags can be used when the caller wants to map some
 * possibly unreliable memory and be able to access it safely, possibly
 * getting the wrong contents rather than raising any exception.
 * For safety reasons, such mappings have to be read-only (PROT_READ access
 * only).
 *
 * MAP_RESILIENT_CODESIGN:
 *      accessing this mapping will not generate code-signing violations,
 *	even if the contents are tainted.
 * MAP_RESILIENT_MEDIA:
 *	accessing this mapping will not generate an exception if the contents
 *	are not available (unreachable removable or remote media, access beyond
 *	end-of-file, ...).  Missing contents will be replaced with zeroes.
 */
MAP_RESILIENT_CODESIGN :: 0x2000 /* no code-signing failures */
MAP_RESILIENT_MEDIA    :: 0x4000 /* no backing-store failures */

MAP_32BIT        :: 0x8000          /* Return virtual addresses <4G only */

// Flags used to support translated processes.
MAP_TRANSLATED_ALLOW_EXECUTE :: 0x20000 /* allow execute in translated processes */
MAP_UNIX03       :: 0x40000 /* UNIX03 compliance */

// Process memory locking
MCL_CURRENT     :: 0x0001  /* [ML] Lock only current memory */
MCL_FUTURE      :: 0x0002  /* [ML] Lock all future memory as well */

MADV_NORMAL      :: 0 /* [MC1] no further special treatment */
MADV_RANDOM      :: 1 /* [MC1] expect random page refs */
MADV_SEQUENTIAL  :: 2 /* [MC1] expect sequential page refs */
MADV_WILLNEED    :: 3 /* [MC1] will need these pages */
MADV_DONTNEED    :: 4 /* [MC1] dont need these pages */
MADV_FREE        :: 5 /* pages unneeded, discard contents */
MADV_ZERO_WIRED_PAGES :: 6 /* zero the wired pages that have not been unwired before the entry is deleted */
MADV_FREE_REUSABLE :: 7 /* pages can be reused (by anyone) */
MADV_FREE_REUSE  :: 8 /* caller wants to reuse those pages */
MADV_CAN_REUSE   :: 9
MADV_PAGEOUT     :: 10 /* page out now (internal only) */

// msync() flags
MS_ASYNC        :: 0x0001  /* [MF|SIO] return immediately */
MS_INVALIDATE   :: 0x0002  /* [MF|SIO] invalidate all cached data */
MS_SYNC         :: 0x0010  /* [MF|SIO] msync synchronously */
MS_KILLPAGES    :: 0x0004  /* invalidate pages, leave mapped */
MS_DEACTIVATE   :: 0x0008  /* deactivate pages, leave mapped */

// Return bits from mincore
MINCORE_INCORE           :: 0x1      /* Page is incore */
MINCORE_REFERENCED       :: 0x2      /* Page has been referenced by us */
MINCORE_MODIFIED         :: 0x4      /* Page has been modified by us */
MINCORE_REFERENCED_OTHER :: 0x8      /* Page has been referenced */
MINCORE_MODIFIED_OTHER   :: 0x10     /* Page has been modified */
MINCORE_PAGED_OUT        :: 0x20     /* Page has been paged out */
MINCORE_COPIED           :: 0x40     /* Page has been copied */
MINCORE_ANONYMOUS        :: 0x80     /* Page belongs to an anonymous object */

// Allocation failure result
MAP_FAILED : rawptr = rawptr(~uintptr(0))

foreign libc {
	@(link_name="mlockall")         _mlockall           :: proc(flags: c.int) -> c.int ---
	@(link_name="munlockall")       _munlockall         :: proc() -> c.int ---
	@(link_name="mlock")            _mlock              :: proc(addr: rawptr, len: c.size_t) -> c.int ---
	@(link_name="mmap")             _mmap               :: proc(addr: rawptr, len: c.size_t, prot: c.int, flags: c.int, fd: c.int, offset: int) -> rawptr ---
	@(link_name="mprotect")         _mprotect           :: proc(addr: rawptr, len: c.size_t, prot: c.int) -> c.int ---
	@(link_name="msync")            _msync              :: proc(addr: rawptr, len: c.size_t) -> c.int ---
	@(link_name="munlock")          _munlock            :: proc(addr: rawptr, len: c.size_t) -> c.int ---
	@(link_name="munmap")           _munmap             :: proc(addr: rawptr, len: c.size_t) -> c.int ---
	@(link_name="shm_open")         _shm_open           :: proc(name: cstring, oflag: c.int, #c_vararg args: ..any) -> c.int ---
	@(link_name="shm_unlink")       _shm_unlink         :: proc(name: cstring) -> c.int ---
	@(link_name="posix_madvise")    _posix_madvise      :: proc(addr: rawptr, len: c.size_t, advice: c.int) -> c.int ---
	@(link_name="madvise")          _madvise            :: proc(addr: rawptr, len: c.size_t, advice: c.int) -> c.int ---
	@(link_name="mincore")          _mincore            :: proc(addr: rawptr, len: c.size_t, vec: cstring) -> c.int ---
	@(link_name="minherit")         _minherit           :: proc(addr: rawptr, len: c.size_t, inherit: c.int) -> c.int ---
}


_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
	result := _mmap(nil, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
	if result == MAP_FAILED {
		return nil, .Out_Of_Memory
	}
	return ([^]byte)(uintptr(result))[:size], nil
}

_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
	result := _mprotect(data, size, PROT_READ|PROT_WRITE)
	if result != 0 {
		return .Out_Of_Memory
	}
	return nil
}
_decommit :: proc "contextless" (data: rawptr, size: uint) {
	_mprotect(data, size, PROT_NONE)
	_madvise(data, size, MADV_FREE)
}
_release :: proc "contextless" (data: rawptr, size: uint) {
	_munmap(data, size)
}
_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
	pflags: c.int
	pflags = PROT_NONE
	if .Read    in flags { pflags |= PROT_READ  }
	if .Write   in flags { pflags |= PROT_WRITE }
	if .Execute in flags { pflags |= PROT_EXEC  }
	err := _mprotect(data, size, pflags)
	return err == 0
}


_platform_memory_init :: proc() {
	DEFAULT_PAGE_SIZE = 4096
	
	// is power of two
	assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
}


_map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) {
	prot, mflags: c.int
	if .Read in flags {
		prot |= PROT_READ
	}
	if .Write in flags {
		prot |= PROT_WRITE
	}
	mflags |= MAP_SHARED
	addr := _mmap(nil, c.size_t(size), prot, mflags, i32(fd), 0)
	if addr == nil {
		return nil, .Map_Failure
	}
	return ([^]byte)(addr)[:size], nil
}