︙ | | | ︙ | |
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
|
#import "OFNotImplementedException.h"
#import "OFOutOfMemoryException.h"
#import "OFOutOfRangeException.h"
#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON)
static const size_t chunkSize = 16;
struct page {
struct page *next, *previous;
void *map;
unsigned char *page;
};
# if defined(OF_HAVE_COMPILER_TLS)
static thread_local struct page *firstPage = NULL;
static thread_local struct page *lastPage = NULL;
static thread_local struct page **preallocatedPages = NULL;
static thread_local size_t numPreallocatedPages = 0;
# elif defined(OF_HAVE_THREADS)
static OFTLSKey firstPageKey, lastPageKey;
static OFTLSKey preallocatedPagesKey, numPreallocatedPagesKey;
# else
static struct page *firstPage = NULL;
static struct page *lastPage = NULL;
static struct page **preallocatedPages = NULL;
static size_t numPreallocatedPages = 0;
# endif
static void *
mapPages(size_t numPages)
{
size_t pageSize = [OFSystemInfo pageSize];
|
|
|
|
|
|
|
|
|
|
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
|
#import "OFNotImplementedException.h"
#import "OFOutOfMemoryException.h"
#import "OFOutOfRangeException.h"
#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON)
static const size_t chunkSize = 16;
struct Page {
struct Page *next, *previous;
void *map;
unsigned char *page;
};
# if defined(OF_HAVE_COMPILER_TLS)
static thread_local struct Page *firstPage = NULL;
static thread_local struct Page *lastPage = NULL;
static thread_local struct Page **preallocatedPages = NULL;
static thread_local size_t numPreallocatedPages = 0;
# elif defined(OF_HAVE_THREADS)
static OFTLSKey firstPageKey, lastPageKey;
static OFTLSKey preallocatedPagesKey, numPreallocatedPagesKey;
# else
static struct Page *firstPage = NULL;
static struct Page *lastPage = NULL;
static struct Page **preallocatedPages = NULL;
static size_t numPreallocatedPages = 0;
# endif
static void *
mapPages(size_t numPages)
{
size_t pageSize = [OFSystemInfo pageSize];
|
︙ | | | ︙ | |
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
|
if (numPages > SIZE_MAX / pageSize)
@throw [OFOutOfRangeException exception];
munlock(pointer, numPages * pageSize);
munmap(pointer, numPages * pageSize);
}
static struct page *
addPage(bool allowPreallocated)
{
size_t pageSize = [OFSystemInfo pageSize];
size_t mapSize = OFRoundUpToPowerOf2(CHAR_BIT, pageSize / chunkSize) /
CHAR_BIT;
struct page *page;
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
struct page *lastPage;
# endif
if (allowPreallocated) {
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
uintptr_t numPreallocatedPages =
(uintptr_t)OFTLSKeyGet(numPreallocatedPagesKey);
# endif
if (numPreallocatedPages > 0) {
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
struct page **preallocatedPages =
OFTLSKeyGet(preallocatedPagesKey);
# endif
numPreallocatedPages--;
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
OFEnsure(OFTLSKeySet(numPreallocatedPagesKey,
(void *)numPreallocatedPages) == 0);
|
|
|
|
|
|
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
|
if (numPages > SIZE_MAX / pageSize)
@throw [OFOutOfRangeException exception];
munlock(pointer, numPages * pageSize);
munmap(pointer, numPages * pageSize);
}
static struct Page *
addPage(bool allowPreallocated)
{
size_t pageSize = [OFSystemInfo pageSize];
size_t mapSize = OFRoundUpToPowerOf2(CHAR_BIT, pageSize / chunkSize) /
CHAR_BIT;
struct Page *page;
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
struct Page *lastPage;
# endif
if (allowPreallocated) {
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
uintptr_t numPreallocatedPages =
(uintptr_t)OFTLSKeyGet(numPreallocatedPagesKey);
# endif
if (numPreallocatedPages > 0) {
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
struct Page **preallocatedPages =
OFTLSKeyGet(preallocatedPagesKey);
# endif
numPreallocatedPages--;
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
OFEnsure(OFTLSKeySet(numPreallocatedPagesKey,
(void *)numPreallocatedPages) == 0);
|
︙ | | | ︙ | |
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
|
OFEnsure(OFTLSKeySet(firstPageKey, page) == 0);
# endif
return page;
}
static void
removePageIfEmpty(struct page *page)
{
unsigned char *map = page->map;
size_t pageSize = [OFSystemInfo pageSize];
size_t mapSize = OFRoundUpToPowerOf2(CHAR_BIT, pageSize / chunkSize) /
CHAR_BIT;
for (size_t i = 0; i < mapSize; i++)
|
|
|
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
|
OFEnsure(OFTLSKeySet(firstPageKey, page) == 0);
# endif
return page;
}
static void
removePageIfEmpty(struct Page *page)
{
unsigned char *map = page->map;
size_t pageSize = [OFSystemInfo pageSize];
size_t mapSize = OFRoundUpToPowerOf2(CHAR_BIT, pageSize / chunkSize) /
CHAR_BIT;
for (size_t i = 0; i < mapSize; i++)
|
︙ | | | ︙ | |
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
OFEnsure(OFTLSKeySet(lastPageKey, page->previous) == 0);
# endif
OFFreeMemory(page);
}
static void *
allocateMemory(struct page *page, size_t bytes)
{
size_t chunks, chunksLeft, pageSize, i, firstChunk;
bytes = OFRoundUpToPowerOf2(chunkSize, bytes);
chunks = chunksLeft = bytes / chunkSize;
firstChunk = 0;
pageSize = [OFSystemInfo pageSize];
|
|
|
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
OFEnsure(OFTLSKeySet(lastPageKey, page->previous) == 0);
# endif
OFFreeMemory(page);
}
static void *
allocateMemory(struct Page *page, size_t bytes)
{
size_t chunks, chunksLeft, pageSize, i, firstChunk;
bytes = OFRoundUpToPowerOf2(chunkSize, bytes);
chunks = chunksLeft = bytes / chunkSize;
firstChunk = 0;
pageSize = [OFSystemInfo pageSize];
|
︙ | | | ︙ | |
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
|
return page->page + (chunkSize * firstChunk);
}
return NULL;
}
static void
freeMemory(struct page *page, void *pointer, size_t bytes)
{
size_t chunks, chunkIndex;
bytes = OFRoundUpToPowerOf2(chunkSize, bytes);
chunks = bytes / chunkSize;
chunkIndex = ((uintptr_t)pointer - (uintptr_t)page->page) / chunkSize;
|
|
|
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
|
return page->page + (chunkSize * firstChunk);
}
return NULL;
}
static void
freeMemory(struct Page *page, void *pointer, size_t bytes)
{
size_t chunks, chunkIndex;
bytes = OFRoundUpToPowerOf2(chunkSize, bytes);
chunks = bytes / chunkSize;
chunkIndex = ((uintptr_t)pointer - (uintptr_t)page->page) / chunkSize;
|
︙ | | | ︙ | |
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
|
+ (void)preallocateUnswappableMemoryWithSize: (size_t)size
{
#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON)
size_t pageSize = [OFSystemInfo pageSize];
size_t numPages = OFRoundUpToPowerOf2(pageSize, size) / pageSize;
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
struct page **preallocatedPages = OFTLSKeyGet(preallocatedPagesKey);
size_t numPreallocatedPages;
# endif
size_t i;
if (preallocatedPages != NULL)
@throw [OFInvalidArgumentException exception];
preallocatedPages = OFAllocZeroedMemory(numPages, sizeof(struct page));
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
OFEnsure(OFTLSKeySet(preallocatedPagesKey, preallocatedPages) == 0);
# endif
@try {
for (i = 0; i < numPages; i++)
preallocatedPages[i] = addPage(false);
|
|
|
|
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
|
+ (void)preallocateUnswappableMemoryWithSize: (size_t)size
{
#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON)
size_t pageSize = [OFSystemInfo pageSize];
size_t numPages = OFRoundUpToPowerOf2(pageSize, size) / pageSize;
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
struct Page **preallocatedPages = OFTLSKeyGet(preallocatedPagesKey);
size_t numPreallocatedPages;
# endif
size_t i;
if (preallocatedPages != NULL)
@throw [OFInvalidArgumentException exception];
preallocatedPages = OFAllocZeroedMemory(numPages, sizeof(struct Page));
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
OFEnsure(OFTLSKeySet(preallocatedPagesKey, preallocatedPages) == 0);
# endif
@try {
for (i = 0; i < numPages; i++)
preallocatedPages[i] = addPage(false);
|
︙ | | | ︙ | |
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
|
memset(_items, 0, count * itemSize);
#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON)
} else if (count * itemSize >= pageSize)
_items = mapPages(OFRoundUpToPowerOf2(pageSize,
count * itemSize) / pageSize);
else {
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
struct page *lastPage = OFTLSKeyGet(lastPageKey);
# endif
for (struct page *page = lastPage; page != NULL;
page = page->previous) {
_items = allocateMemory(page, count * itemSize);
if (_items != NULL) {
_page = page;
break;
}
|
|
|
|
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
|
memset(_items, 0, count * itemSize);
#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON)
} else if (count * itemSize >= pageSize)
_items = mapPages(OFRoundUpToPowerOf2(pageSize,
count * itemSize) / pageSize);
else {
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
struct Page *lastPage = OFTLSKeyGet(lastPageKey);
# endif
for (struct Page *page = lastPage; page != NULL;
page = page->previous) {
_items = allocateMemory(page, count * itemSize);
if (_items != NULL) {
_page = page;
break;
}
|
︙ | | | ︙ | |