1
1
#include "THAllocator.h"
2
+ #include "THAtomic.h"
2
3
3
4
/* stuff for mapped files */
4
5
#ifdef _WIN32
@@ -36,22 +37,40 @@ THAllocator THDefaultAllocator = {
36
37
37
38
struct THMapAllocatorContext_ {
38
39
char * filename ; /* file name */
39
- int shared ; /* is shared or not */
40
+ int flags ;
40
41
long size ; /* mapped size */
41
42
};
42
43
43
- THMapAllocatorContext * THMapAllocatorContext_new (const char * filename , int shared )
44
+ #define TH_ALLOC_ALIGNMENT 64
45
+
46
+ typedef struct {
47
+ int refcount ;
48
+ } THMapInfo ;
49
+
50
+ THMapAllocatorContext * THMapAllocatorContext_new (const char * filename , int flags )
44
51
{
45
52
THMapAllocatorContext * ctx = THAlloc (sizeof (THMapAllocatorContext ));
46
53
54
+
55
+ if (!(flags & TH_ALLOCATOR_MAPPED_SHARED ) && !(flags & TH_ALLOCATOR_MAPPED_SHAREDMEM ))
56
+ flags &= ~TH_ALLOCATOR_MAPPED_NOCREATE ;
57
+ if ((flags ^ TH_ALLOCATOR_MAPPED_EXCLUSIVE ) == 0 )
58
+ THError ("TH_ALLOCATOR_MAPPED_EXCLUSIVE flag requires opening the file "
59
+ "in shared mode" );
60
+
47
61
ctx -> filename = THAlloc (strlen (filename )+ 1 );
48
62
strcpy (ctx -> filename , filename );
49
- ctx -> shared = shared ;
63
+ ctx -> flags = flags ;
50
64
ctx -> size = 0 ;
51
65
52
66
return ctx ;
53
67
}
54
68
69
+ char * THMapAllocatorContext_filename (THMapAllocatorContext * ctx )
70
+ {
71
+ return ctx -> filename ;
72
+ }
73
+
55
74
long THMapAllocatorContext_size (THMapAllocatorContext * ctx )
56
75
{
57
76
return ctx -> size ;
@@ -63,7 +82,7 @@ void THMapAllocatorContext_free(THMapAllocatorContext *ctx)
63
82
THFree (ctx );
64
83
}
65
84
66
- static void * THMapAllocator_alloc (void * ctx_ , long size )
85
+ static void * _map_alloc (void * ctx_ , long size )
67
86
{
68
87
THMapAllocatorContext * ctx = ctx_ ;
69
88
void * data = NULL ;
@@ -75,9 +94,14 @@ static void *THMapAllocator_alloc(void* ctx_, long size)
75
94
DWORD size_hi , size_lo ;
76
95
size_t hfilesz ;
77
96
97
+ if (ctx -> flags & TH_ALLOCATOR_MAPPED_EXCLUSIVE )
98
+ THError ("exclusive file mapping is not supported on Windows" );
99
+ if (ctx -> flags & TH_ALLOCATOR_MAPPED_NOCREATE )
100
+ THError ("file mapping without creation is not supported on Windows" );
101
+
78
102
/* open file */
79
103
/* FILE_FLAG_RANDOM_ACCESS ? */
80
- if (ctx -> shared )
104
+ if (ctx -> flags )
81
105
{
82
106
hfile = CreateFileA (ctx -> filename , GENERIC_READ |GENERIC_WRITE , FILE_SHARE_WRITE |FILE_SHARE_READ , 0 , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , 0 );
83
107
if (hfile == INVALID_HANDLE_VALUE )
@@ -103,7 +127,7 @@ static void *THMapAllocator_alloc(void* ctx_, long size)
103
127
{
104
128
if (size > hfilesz )
105
129
{
106
- if (ctx -> shared )
130
+ if (ctx -> flags )
107
131
{
108
132
#if SIZEOF_SIZE_T > 4
109
133
size_hi = (DWORD )((size ) >> 32 );
@@ -144,7 +168,7 @@ static void *THMapAllocator_alloc(void* ctx_, long size)
144
168
#endif
145
169
146
170
/* get map handle */
147
- if (ctx -> shared )
171
+ if (ctx -> flags )
148
172
{
149
173
if ( (hmfile = CreateFileMapping (hfile , NULL , PAGE_READWRITE , size_hi , size_lo , NULL )) == NULL )
150
174
THError ("could not create a map on file <%s>" , ctx -> filename );
@@ -156,30 +180,41 @@ static void *THMapAllocator_alloc(void* ctx_, long size)
156
180
}
157
181
158
182
/* map the stuff */
159
- if (ctx -> shared )
183
+ if (ctx -> flags )
160
184
data = MapViewOfFile (hmfile , FILE_MAP_ALL_ACCESS , 0 , 0 , 0 );
161
185
else
162
186
data = MapViewOfFile (hmfile , FILE_MAP_COPY , 0 , 0 , 0 );
163
187
164
- CloseHandle (hfile );
165
- CloseHandle (hmfile );
188
+ CloseHandle (hfile );
189
+ CloseHandle (hmfile );
166
190
}
167
191
#else /* _WIN32 */
168
192
{
169
193
/* open file */
170
194
int fd ;
195
+ int flags ;
171
196
long fdsz ;
172
197
173
- if (ctx -> shared == TH_ALLOCATOR_MAPPED_SHARED )
198
+ if (ctx -> flags )
199
+ flags = O_RDWR | O_CREAT ;
200
+ else
201
+ flags = O_RDONLY ;
202
+
203
+ if (ctx -> flags & TH_ALLOCATOR_MAPPED_EXCLUSIVE )
204
+ flags |= O_EXCL ;
205
+ if (ctx -> flags & TH_ALLOCATOR_MAPPED_NOCREATE )
206
+ flags &= ~O_CREAT ;
207
+
208
+ if (ctx -> flags & TH_ALLOCATOR_MAPPED_SHARED )
174
209
{
175
- if ((fd = open (ctx -> filename , O_RDWR | O_CREAT , (mode_t )0600 )) == -1 )
210
+ if ((fd = open (ctx -> filename , flags , (mode_t )0600 )) == -1 )
176
211
THError ("unable to open file <%s> in read-write mode" , ctx -> filename );
177
212
}
178
- else if (ctx -> shared == TH_ALLOCATOR_MAPPED_SHAREDMEM )
213
+ else if (ctx -> flags & TH_ALLOCATOR_MAPPED_SHAREDMEM )
179
214
{
180
215
#ifdef HAVE_SHM_OPEN
181
- if ((fd = shm_open (ctx -> filename , O_RDWR | O_CREAT , (mode_t )0600 )) == -1 )
182
- THError ("unable to open file <%s> in read-write mode" , ctx -> filename );
216
+ if ((fd = shm_open (ctx -> filename , flags , (mode_t )0600 )) == -1 )
217
+ THError ("unable to open shared memory object <%s> in read-write mode" , ctx -> filename );
183
218
#else
184
219
THError ("unable to open file <%s> in sharedmem mode, shm_open unavailable on this platform" );
185
220
#endif
@@ -189,19 +224,21 @@ static void *THMapAllocator_alloc(void* ctx_, long size)
189
224
if ((fd = open (ctx -> filename , O_RDONLY )) == -1 )
190
225
THError ("unable to open file <%s> in read-only mode" , ctx -> filename );
191
226
}
227
+
192
228
if ((fdsz = lseek (fd , 0 , SEEK_END )) == -1 )
193
229
{
194
230
close (fd );
195
231
THError ("unable to seek at end of file <%s>" , ctx -> filename );
196
232
}
233
+
197
234
if (size > 0 )
198
235
{
199
236
if (size > fdsz )
200
237
{
201
- if (ctx -> shared )
238
+ if (ctx -> flags )
202
239
{
203
240
/* if it is shared mem, let's put it in correct size */
204
- if (ctx -> shared == TH_ALLOCATOR_MAPPED_SHAREDMEM )
241
+ if (ctx -> flags & TH_ALLOCATOR_MAPPED_SHAREDMEM )
205
242
{
206
243
if (ftruncate (fd , size ) == -1 )
207
244
THError ("unable to resize shared memory file <%s> to the right size" , ctx -> filename );
@@ -228,9 +265,9 @@ static void *THMapAllocator_alloc(void* ctx_, long size)
228
265
size = fdsz ;
229
266
230
267
ctx -> size = size ; /* if we are here, it must be the right size */
231
-
268
+
232
269
/* map it */
233
- if (ctx -> shared )
270
+ if (ctx -> flags )
234
271
data = mmap (NULL , ctx -> size , PROT_READ |PROT_WRITE , MAP_SHARED , fd , 0 );
235
272
else
236
273
data = mmap (NULL , ctx -> size , PROT_READ |PROT_WRITE , MAP_PRIVATE , fd , 0 );
@@ -249,6 +286,10 @@ static void *THMapAllocator_alloc(void* ctx_, long size)
249
286
return data ;
250
287
}
251
288
289
+ static void * THMapAllocator_alloc (void * ctx , long size ) {
290
+ return _map_alloc (ctx , size );
291
+ }
292
+
252
293
static void * THMapAllocator_realloc (void * ctx , void * ptr , long size ) {
253
294
THError ("cannot realloc mapped data" );
254
295
return NULL ;
@@ -260,10 +301,10 @@ static void THMapAllocator_free(void* ctx_, void* data) {
260
301
#ifdef _WIN32
261
302
if (!UnmapViewOfFile ((LPINT )data ))
262
303
THError ("could not unmap the shared memory file" );
263
- #else
304
+ #else /* _WIN32 */
264
305
if (munmap (data , ctx -> size ))
265
306
THError ("could not unmap the shared memory file" );
266
- if (ctx -> shared == TH_ALLOCATOR_MAPPED_SHAREDMEM )
307
+ if (ctx -> flags & TH_ALLOCATOR_MAPPED_SHAREDMEM )
267
308
{
268
309
#ifdef HAVE_SHM_UNLINK
269
310
if (shm_unlink (ctx -> filename ) == -1 )
@@ -272,14 +313,14 @@ static void THMapAllocator_free(void* ctx_, void* data) {
272
313
THError ("could not unlink the shared memory file %s, shm_unlink not available on platform" , ctx -> filename );
273
314
#endif
274
315
}
275
- #endif
316
+ #endif /* _WIN32 */
276
317
277
318
THMapAllocatorContext_free (ctx );
278
319
}
279
320
280
321
#else
281
322
282
- THMapAllocatorContext * THMapAllocatorContext_new (const char * filename , int shared ) {
323
+ THMapAllocatorContext * THMapAllocatorContext_new (const char * filename , int flags ) {
283
324
THError ("file mapping not supported on your system" );
284
325
return NULL ;
285
326
}
@@ -304,8 +345,82 @@ static void THMapAllocator_free(void* ctx, void* data) {
304
345
305
346
#endif
306
347
348
+ #if (defined(_WIN32 ) || defined(HAVE_MMAP )) && defined(TH_ATOMIC_IPC_REFCOUNT )
349
+
350
+ static void * THRefcountedMapAllocator_alloc (void * _ctx , long size ) {
351
+ THMapAllocatorContext * ctx = _ctx ;
352
+
353
+ if (!(ctx -> flags & TH_ALLOCATOR_MAPPED_SHAREDMEM ))
354
+ THError ("THRefcountedMapAllcator requires SHAREDMEM flag" );
355
+
356
+ size = size + TH_ALLOC_ALIGNMENT ;
357
+ void * ptr = _map_alloc (ctx , size );
358
+ char * data = ((char * )ptr ) + TH_ALLOC_ALIGNMENT ;
359
+ THMapInfo * map_info = (THMapInfo * )ptr ;
360
+
361
+ if (ctx -> flags & TH_ALLOCATOR_MAPPED_EXCLUSIVE )
362
+ map_info -> refcount = 1 ;
363
+ else
364
+ THAtomicIncrementRef (& map_info -> refcount );
365
+
366
+ return (void * )data ;
367
+ }
368
+
369
+ static void * THRefcountedMapAllocator_realloc (void * ctx , void * ptr , long size ) {
370
+ THError ("cannot realloc mapped data" );
371
+ return NULL ;
372
+ }
373
+
374
+ static void THRefcountedMapAllocator_free (void * ctx_ , void * data ) {
375
+ THMapAllocatorContext * ctx = ctx_ ;
376
+
377
+ #ifdef _WIN32
378
+ if (!UnmapViewOfFile ((LPINT )data ))
379
+ THError ("could not unmap the shared memory file" );
380
+ #else /* _WIN32 */
381
+
382
+ THMapInfo * info = (THMapInfo * )(((char * )data ) - TH_ALLOC_ALIGNMENT );
383
+ if (THAtomicDecrementRef (& info -> refcount )) {
384
+ #ifdef HAVE_SHM_UNLINK
385
+ if (shm_unlink (ctx -> filename ) == -1 )
386
+ THError ("could not unlink the shared memory file %s" , ctx -> filename );
387
+ #else
388
+ THError ("could not unlink the shared memory file %s, shm_unlink not available on platform" , ctx -> filename );
389
+ #endif /* HAVE_SHM_UNLINK */
390
+ }
391
+ if (munmap (info , ctx -> size ))
392
+ THError ("could not unmap the shared memory file %s" , ctx -> filename );
393
+ #endif /* _WIN32 */
394
+
395
+ THMapAllocatorContext_free (ctx );
396
+ }
397
+
398
+ #else
399
+
400
+ static void * THRefcountedMapAllocator_alloc (void * ctx , long size ) {
401
+ THError ("refcounted file mapping not supported on your system" );
402
+ return NULL ;
403
+ }
404
+
405
+ static void * THRefcountedMapAllocator_realloc (void * ctx , void * ptr , long size ) {
406
+ THError ("refcounted file mapping not supported on your system" );
407
+ return NULL ;
408
+ }
409
+
410
+ static void THRefcountedMapAllocator_free (void * ctx_ , void * data ) {
411
+ THError ("refcounted file mapping not supported on your system" );
412
+ }
413
+
414
+ #endif
415
+
307
416
THAllocator THMapAllocator = {
308
417
& THMapAllocator_alloc ,
309
418
& THMapAllocator_realloc ,
310
419
& THMapAllocator_free
311
420
};
421
+
422
+ THAllocator THRefcountedMapAllocator = {
423
+ & THRefcountedMapAllocator_alloc ,
424
+ & THRefcountedMapAllocator_realloc ,
425
+ & THRefcountedMapAllocator_free
426
+ };
0 commit comments