File Coverage

lib/File/Map.xs
Criterion Covered Total %
statement 198 241 82.1
branch 124 212 58.4
condition n/a
subroutine n/a
pod n/a
total 322 453 71.0


line stmt bran cond sub pod time code
1             /*
2             * This software is copyright (c) 2008, 2009 by Leon Timmermans .
3             *
4             * This is free software; you can redistribute it and/or modify it under
5             * the same terms as perl itself.
6             *
7             */
8              
9             #if defined(linux) && !defined(_GNU_SOURCE)
10             # define _GNU_SOURCE
11             #endif
12              
13             #include
14             #include "mmap-compat.c"
15              
16             #ifndef MIN
17             # define MIN(a, b) ((a) < (b) ? (a) : (b))
18             #endif
19              
20             #define PERL_NO_GET_CONTEXT
21             #define PERL_REENTR_API 1
22             #include "EXTERN.h"
23             #include "perl.h"
24             #include "XSUB.h"
25             #include "perliol.h"
26             #define NEED_mg_findext
27             #define NEED_sv_unmagicext
28             #include "ppport.h"
29              
30             #ifndef SvPV_free
31             # define SvPV_free(arg) sv_setpvn_mg(arg, NULL, 0);
32             #endif
33              
34             #ifndef SV_CHECK_THINKFIRST_COW_DROP
35             #define SV_CHECK_THINKFIRST_COW_DROP(sv) SV_CHECK_THINKFIRST(sv)
36             #endif
37              
38             struct mmap_info {
39             void* real_address;
40             void* fake_address;
41             size_t real_length;
42             size_t fake_length;
43             int flags;
44             #ifdef USE_ITHREADS
45             perl_mutex count_mutex;
46             perl_mutex data_mutex;
47             PerlInterpreter* owner;
48             perl_cond cond;
49             int count;
50             #endif
51             };
52              
53             #define die_sys(format) Perl_croak(aTHX_ format, strerror(errno))
54              
55             static void reset_var(SV* var, struct mmap_info* info) {
56 30           SvPVX(var) = info->fake_address;
57 30           SvLEN(var) = 0;
58 30           SvCUR(var) = info->fake_length;
59 30           SvPOK_only_UTF8(var);
60             }
61              
62 9           static void S_mmap_fixup(pTHX_ SV* var, struct mmap_info* info, const char* string, STRLEN len) {
63 9 100         if (ckWARN(WARN_SUBSTR)) {
64 6           Perl_warn(aTHX_ "Writing directly to a memory mapped file is not recommended");
65 6 100         if (SvCUR(var) > info->fake_length)
66 1           Perl_warn(aTHX_ "Truncating new value to size of the memory map");
67             }
68              
69 9 100         if (string && len)
70 8           Copy(string, info->fake_address, MIN(len, info->fake_length), char);
71 9 50         SV_CHECK_THINKFIRST_COW_DROP(var);
72 9 50         if (SvROK(var))
73 0           sv_unref_flags(var, SV_IMMEDIATE_UNREF);
74 9 100         if (SvPOK(var))
75 5 50         SvPV_free(var);
    50          
    0          
    0          
76             reset_var(var, info);
77 9           }
78             #define mmap_fixup(var, info, string, len) S_mmap_fixup(aTHX_ var, info, string, len)
79              
80 26           static int mmap_write(pTHX_ SV* var, MAGIC* magic) {
81 26           struct mmap_info* info = (struct mmap_info*) magic->mg_ptr;
82 26 100         if (info->real_length) {
83 25 100         if (!SvOK(var))
    50          
    50          
84 1           mmap_fixup(var, info, NULL, 0);
85 24 100         else if (!SvPOK(var)) {
86             STRLEN len;
87 3 50         const char* string = SvPV(var, len);
88 3           mmap_fixup(var, info, string, len);
89             }
90 21 100         else if (SvPVX(var) != info->fake_address)
91 5           mmap_fixup(var, info, SvPVX(var), SvCUR(var));
92             else {
93 16 50         if (ckWARN(WARN_SUBSTR) && SvCUR(var) != info->fake_length) {
    100          
94 1           Perl_warn(aTHX_ "Writing directly to a memory mapped file is not recommended");
95 1           SvCUR(var) = info->fake_length;
96             }
97 16           SvPOK_only_UTF8(var);
98             }
99             }
100             else {
101 1 50         if (!SvPOK(var) || sv_len(var) != 0) {
    50          
102 1           sv_setpvn(var, "", 0);
103 1 50         if (ckWARN(WARN_SUBSTR))
104 1           Perl_warn(aTHX_ "Can't overwrite an empty map");
105             }
106 1           SvPOK_only_UTF8(var);
107             }
108 26           return 0;
109             }
110              
111 0           static int mmap_clear(pTHX_ SV* var, MAGIC* magic) {
112 0           Perl_die(aTHX_ "Can't clear a mapped variable");
113             return 0;
114             }
115              
116 18           static int mmap_free(pTHX_ SV* var, MAGIC* magic) {
117 18           struct mmap_info* info = (struct mmap_info*) magic->mg_ptr;
118             #ifdef USE_ITHREADS
119             MUTEX_LOCK(&info->count_mutex);
120             if (--info->count == 0) {
121             if (info->real_length && munmap(info->real_address, info->real_length) == -1)
122             die_sys("Could not unmap: %s");
123             COND_DESTROY(&info->cond);
124             MUTEX_DESTROY(&info->data_mutex);
125             MUTEX_UNLOCK(&info->count_mutex);
126             MUTEX_DESTROY(&info->count_mutex);
127             PerlMemShared_free(info);
128             }
129             else {
130             if (info->real_length && msync(info->real_address, info->real_length, MS_ASYNC) == -1)
131             die_sys("Could not sync: %s");
132             MUTEX_UNLOCK(&info->count_mutex);
133             }
134             #else
135 18 100         if (info->real_length && munmap(info->real_address, info->real_length) == -1)
    50          
136 0           die_sys("Could not unmap: %s");
137 18           PerlMemShared_free(info);
138             #endif
139 18           SvREADONLY_off(var);
140 18           SvPVX(var) = NULL;
141 18           SvCUR(var) = 0;
142 18           return 0;
143             }
144              
145             #ifdef USE_ITHREADS
146             static int mmap_dup(pTHX_ MAGIC* magic, CLONE_PARAMS* param) {
147             struct mmap_info* info = (struct mmap_info*) magic->mg_ptr;
148             MUTEX_LOCK(&info->count_mutex);
149             assert(info->count);
150             ++info->count;
151             MUTEX_UNLOCK(&info->count_mutex);
152             return 0;
153             }
154             #else
155             #define mmap_dup 0
156             #endif
157              
158             #ifdef MGf_LOCAL
159 1           static int mmap_local(pTHX_ SV* var, MAGIC* magic) {
160 1           Perl_croak(aTHX_ "Can't localize file map");
161             }
162             #define mmap_local_tail , mmap_local
163             #else
164             #define mmap_local_tail
165             #endif
166              
167             static const MGVTBL mmap_table = { 0, mmap_write, 0, mmap_clear, mmap_free, 0, mmap_dup mmap_local_tail };
168              
169 1           static Off_t S_sv_to_offset(pTHX_ SV* var) {
170             #if IV_SIZE >= 8
171             return (Off_t)SvUV(var);
172             #else
173 1 50         return (Off_t)floor(SvNV(var) + 0.5); /* hic sunt dracones */
174             #endif
175             }
176             #define sv_to_offset(var) S_sv_to_offset(aTHX_ var)
177              
178 21           static void check_new_variable(pTHX_ SV* var) {
179 21 50         if (SvTYPE(var) > SVt_PVMG && SvTYPE(var) != SVt_PVLV)
180 0           Perl_croak(aTHX_ "Trying to map into a nonscalar!\n");
181 21 100         SV_CHECK_THINKFIRST_COW_DROP(var);
182 20 50         if (SvREADONLY(var))
183 0           Perl_croak(aTHX_ "%s", PL_no_modify);
184 20 100         if (SvMAGICAL(var) && mg_findext(var, PERL_MAGIC_ext, &mmap_table))
    50          
185 0           sv_unmagicext(var, PERL_MAGIC_ext, (MGVTBL*)&mmap_table);
186 20 50         if (SvROK(var))
187 0           sv_unref_flags(var, SV_IMMEDIATE_UNREF);
188 20 50         if (SvNIOK(var))
189 0           SvNIOK_off(var);
190 20 50         if (SvPOK(var))
191 0 0         SvPV_free(var);
    0          
    0          
    0          
192 20 100         SvUPGRADE(var, SVt_PVMG);
193 20           }
194              
195 17           static void* do_mapping(pTHX_ size_t length, int prot, int flags, int fd, Off_t offset) {
196             void* address;
197 17           address = mmap(0, length, prot, flags | MAP_VARIABLE, fd, offset);
198 17 50         if (address == MAP_FAILED)
199 0           die_sys("Could not map: %s");
200 17           return address;
201             }
202              
203             static void S_set_mmap_info(pTHX_ struct mmap_info* magical, void* address, size_t length, ptrdiff_t correction) {
204 21           magical->real_address = address;
205 21           magical->fake_address = (char*)address + correction;
206 21           magical->real_length = length + correction;
207 21           magical->fake_length = length;
208             #ifdef USE_ITHREADS
209             MUTEX_INIT(&magical->count_mutex);
210             MUTEX_INIT(&magical->data_mutex);
211             COND_INIT(&magical->cond);
212             magical->count = 1;
213             #endif
214             }
215             #define set_mmap_info(magical, addres, length, correction) S_set_mmap_info(aTHX_ magical, addres, length, correction)
216              
217             static struct mmap_info* initialize_mmap_info(pTHX_ void* address, size_t length, ptrdiff_t correction, int flags) {
218 19           struct mmap_info* magical = PerlMemShared_malloc(sizeof *magical);
219             set_mmap_info(magical, address, length, correction);
220 19           magical->flags = flags;
221             return magical;
222             }
223              
224 19           static void add_magic(pTHX_ SV* var, struct mmap_info* magical, int writable, int utf8) {
225 19           MAGIC* magic = sv_magicext(var, NULL, PERL_MAGIC_ext, &mmap_table, (const char*) magical, 0);
226             #ifdef MGf_LOCAL
227 19           magic->mg_flags |= MGf_LOCAL;
228             #endif
229             #ifdef USE_ITHREADS
230             magic->mg_flags |= MGf_DUP;
231             #endif
232 19 100         SvTAINTED_on(var);
233 19 100         if (utf8 && !sv_utf8_decode(var))
    50          
234 0           Perl_croak(aTHX_ "Invalid utf8 in memory mapping");
235 19 100         if (!writable)
236 9           SvREADONLY_on(var);
237 19           }
238              
239 3           static int _is_mappable(pTHX_ int fd) {
240             Stat_t info;
241 3 50         return Fstat(fd, &info) == 0 && (S_ISREG(info.st_mode) || S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
    100          
    50          
242             }
243              
244             #define is_mappable(fd) _is_mappable(aTHX_ fd)
245              
246 12           static struct mmap_info* S_get_mmap_magic(pTHX_ SV* var, const char* funcname) {
247             MAGIC* magic;
248 12 100         if (!SvMAGICAL(var) || (magic = mg_findext(var, PERL_MAGIC_ext, &mmap_table)) == NULL)
    50          
249 3           Perl_croak(aTHX_ "Could not %s: this variable is not memory mapped", funcname);
250 9           return (struct mmap_info*) magic->mg_ptr;
251             }
252             #define get_mmap_magic(var, funcname) S_get_mmap_magic(aTHX_ var, funcname)
253              
254             #ifdef USE_ITHREADS
255             static void magic_end(pTHX_ void* pre_info) {
256             struct mmap_info* info = (struct mmap_info*) pre_info;
257             info->owner = NULL;
258             MUTEX_UNLOCK(&info->data_mutex);
259             }
260             #endif
261              
262             typedef struct { const char* key; size_t length; int value; } map[];
263              
264             static map prots = {
265             { STR_WITH_LEN("<"), PROT_READ },
266             { STR_WITH_LEN("+<"), PROT_READ | PROT_WRITE },
267             { STR_WITH_LEN(">"), PROT_WRITE },
268             { STR_WITH_LEN("+>"), PROT_READ | PROT_WRITE },
269             };
270              
271 16           static int S_protection_pvn(pTHX_ const char* mode, size_t mode_len) {
272             int i;
273 24 50         for (i = 0; i < sizeof prots / sizeof *prots; ++i) {
274 24 100         if (prots[i].length == mode_len && strnEQ(mode, prots[i].key, mode_len))
    100          
275 16           return prots[i].value;
276             }
277 0           Perl_croak(aTHX_ "No such mode '%s' known", mode);
278             }
279             #define protection_pvn(mode, mode_len) S_protection_pvn(aTHX_ mode, mode_len)
280              
281 16           static int S_protection_sv(pTHX_ SV* mode_sv) {
282             STRLEN mode_len;
283 16 50         const char* mode = SvPV(mode_sv, mode_len);
284 16           const char* end = memchr(mode, ':', mode_len);
285 16 100         return protection_pvn(mode, end ? end - mode : mode_len);
286             }
287             #define protection_sv(mode) S_protection_sv(aTHX_ mode)
288              
289             #define MAP_CONSTANT(cons) newCONSTSUB(stash, #cons, newSVuv(cons))
290             #define ADVISE_CONSTANT(key, value) hv_store(advise_constants, key, sizeof key - 1, newSVuv(value), 0)
291              
292             #define EMPTY_MAP(info) ((info)->real_length == 0)
293              
294 7           static void S_boot(pTHX) {
295 7           HV* stash = get_hv("File::Map::", FALSE);
296 7           HV* advise_constants = newHV();
297              
298 7           MAP_CONSTANT(PROT_NONE);
299 7           MAP_CONSTANT(PROT_READ);
300 7           MAP_CONSTANT(PROT_WRITE);
301 7           MAP_CONSTANT(PROT_EXEC);
302 7           MAP_CONSTANT(MAP_ANONYMOUS);
303 7           MAP_CONSTANT(MAP_SHARED);
304 7           MAP_CONSTANT(MAP_PRIVATE);
305 7           MAP_CONSTANT(MAP_ANON);
306 7           MAP_CONSTANT(MAP_FILE);
307             /**/
308            
309 7           hv_store(PL_modglobal, "File::Map::ADVISE_CONSTANTS", 27, (SV*)advise_constants, 0);
310 7           ADVISE_CONSTANT("normal", MADV_NORMAL);
311 7           ADVISE_CONSTANT("random", MADV_RANDOM);
312 7           ADVISE_CONSTANT("sequential", MADV_SEQUENTIAL);
313 7           ADVISE_CONSTANT("willneed", MADV_WILLNEED);
314 7           ADVISE_CONSTANT("dontneed", MADV_DONTNEED);
315             /* Linux specific advices */
316             #ifdef MADV_REMOVE
317 7           ADVISE_CONSTANT("remove", MADV_REMOVE);
318             #endif
319             #ifdef MADV_DONTFORK
320 7           ADVISE_CONSTANT("dontfork", MADV_DONTFORK);
321             #endif
322             #ifdef MADV_DOFORK
323 7           ADVISE_CONSTANT("dofork", MADV_DOFORK);
324             #endif
325             #ifdef MADV_MERGEABLE
326 7           ADVISE_CONSTANT("mergeable", MADV_MERGEABLE);
327             #endif
328             #ifdef MADV_UNMERGEABLE
329 7           ADVISE_CONSTANT("unmergeable", MADV_UNMERGEABLE);
330             #endif
331             /* BSD, Mac OS X & Solaris specific advice */
332             #ifdef MADV_FREE
333             ADVISE_CONSTANT("free", MADV_FREE);
334             #endif
335             /* FreeBSD specific advices */
336             #ifdef MADV_NOSYNC
337             ADVISE_CONSTANT("nosync", MADV_NOSYNC);
338             #endif
339             #ifdef MADV_AUTOSYNC
340             ADVISE_CONSTANT("autosync", MADV_AUTOSYNC);
341             #endif
342             #ifdef MADV_NOCORE
343             ADVISE_CONSTANT("nocore", MADV_NOCORE);
344             #endif
345             #ifdef MADV_CORE
346             ADVISE_CONSTANT("core", MADV_CORE);
347             #endif
348             #ifdef MADV_PROTECT
349             ADVISE_CONSTANT("protect", MADV_PROTECT);
350             #endif
351             #ifdef MADV_SPACEAVAIL
352             ADVISE_CONSTANT("spaceavail", MADV_SPACEAVAIL);
353             #endif
354 7           }
355             #define boot() S_boot(aTHX)
356              
357             #if PTRSIZE == 8 && (defined(WIN32) || defined(__CYGWIN__))
358             #ifndef ULLONG_MAX
359             #define PTR_MAX _UI64_MAX /* MS Platform SDK crt */
360             #else
361             #define PTR_MAX ULLONG_MAX
362             #endif
363             #else
364             #define PTR_MAX ULONG_MAX
365             #endif
366              
367 21           void S_mmap_impl(pTHX_ SV* var, size_t length, int prot, int flags, int fd, Off_t offset, int utf8) {
368 21           check_new_variable(aTHX_ var);
369              
370 40           ptrdiff_t correction = offset % page_size();
371             void* address;
372             struct mmap_info* magical;
373 20 50         if (length > PTR_MAX - correction)
374 0           Perl_croak(aTHX_ "can't map: length + offset overflows");
375              
376 20 100         if (length)
377 17           address = do_mapping(aTHX_ length + correction, prot, flags, fd, offset - correction);
378             else {
379 3 100         if (!is_mappable(fd)) {
380 1           errno = EACCES;
381 1           die_sys("Could not map: %s");
382             }
383             address = "";
384             correction = 0;
385             }
386              
387             magical = initialize_mmap_info(aTHX_ address, length, correction, flags);
388             reset_var(var, magical);
389 19 100         SvSETMAGIC(var);
390 19           add_magic(aTHX_ var, magical, prot & PROT_WRITE, utf8);
391 19           }
392             #define mmap_impl(var, length, prot, flags, fd, offset, utf8) S_mmap_impl(aTHX_ var, length, prot, flags, fd, offset, utf8)
393              
394             static const map mappable = {
395             { STR_WITH_LEN("unix"), 1 },
396             { STR_WITH_LEN("perlio"), 1 },
397             { STR_WITH_LEN("crlf"), 1 },
398             { STR_WITH_LEN("stdio"), 1 },
399             { STR_WITH_LEN("flock"), 1 },
400             { STR_WITH_LEN("creat"), 1 },
401             { STR_WITH_LEN("mmap"), 1 },
402             };
403              
404             static int S_map_get(pTHX_ const map table, size_t table_size, const char* name, int fallback) {
405             int i;
406 54 50         for (i = 0; i < table_size; ++i) {
    50          
407 54 100         if (strEQ(name, table[i].key))
    100          
408 38           return table[i].value;
409             }
410             return fallback;
411             }
412             #define map_get(table, name, default) S_map_get(aTHX_ table, sizeof table / sizeof *table, name, default)
413              
414 16           int S_check_layers(pTHX_ PerlIO* fh) {
415             PerlIO* current;
416 16 100         if (PerlIO_fileno(fh) < 0)
417 1           Perl_croak(aTHX_ "Can't map fake filehandle");
418 45 100         for (current = fh; *current; current = PerlIONext(current)) {
419 60 50         if (!map_get(mappable, (*current)->tab->name, 0) || (*current)->flags & PERLIO_F_CRLF)
    50          
420 0           Perl_croak(aTHX_ "Shouldn't map non-binary filehandle");
421             }
422 15           return (*fh)->flags & PERLIO_F_UTF8;
423             }
424             #define check_layers(fh) S_check_layers(aTHX_ fh)
425              
426 15           size_t S_get_length(pTHX_ PerlIO* fh, Off_t offset, SV* length_sv) {
427             Stat_t info;
428 15           Fstat(PerlIO_fileno(fh), &info);
429 15 100         size_t length = SvOK(length_sv) ? SvIV(length_sv) : info.st_size - offset;
    50          
    50          
    50          
430 15           size_t end = offset + length;
431 15 100         if (offset < 0 || end > info.st_size && !S_ISCHR(info.st_mode))
    50          
    0          
432 1           Perl_croak(aTHX_ "Window (%ld,%lu) is outside the file", offset, length);
433 14           return length;
434             }
435             #define get_length(fh, offset, length) S_get_length(aTHX_ fh, offset, length)
436              
437             #define READONLY sv_2mortal(newSVpvs("<"))
438             #define undef &PL_sv_undef
439              
440 16           void S_map_handle(pTHX_ SV* var, PerlIO* fh, SV* mode, Off_t offset, SV* length_sv) {
441 16           int utf8 = check_layers(fh);
442 15           size_t length = get_length(fh, offset, length_sv);
443 14           mmap_impl(var, length, protection_sv(mode), MAP_SHARED | MAP_FILE, PerlIO_fileno(fh), offset, utf8);
444 13           }
445             #define map_handle(var, fh, mode, offset, length) S_map_handle(aTHX_ var, fh, mode, offset, length)
446              
447 8           void S_map_file(pTHX_ SV* var, SV* filename, SV* mode, Off_t offset, SV* length_sv) {
448             STRLEN mode_len;
449 8 50         const char* mode_raw = SvPV(mode, mode_len);
450 8 100         if (memchr(mode_raw, ':', mode_len) == NULL) {
451 7           SV* newmode = sv_2mortal(newSVsv(mode));
452 7           sv_catpvs(newmode, ":raw");
453 7 50         mode_raw = SvPV(newmode, mode_len);
454             }
455 8           GV* gv = MUTABLE_GV(sv_2mortal(newSV_type(SVt_NULL)));
456 8           gv_init_pvn(gv, CopSTASH(PL_curcop), "__ANONIO__", 10, GV_ADDMULTI);
457 8 100         if (!do_openn(gv, mode_raw, mode_len, 0, 0, 0, NULL, &filename, 1))
458 1 50         Perl_croak(aTHX_ "Couldn't open file %s: %s", SvPV_nolen(filename), strerror(errno));
459 7 50         map_handle(var, IoIFP(GvIO(gv)), mode, offset, length_sv);
    50          
    50          
460 6           }
461             #define map_file(var, filename, mode, offset, length) S_map_file(aTHX_ var, filename, mode, offset, length)
462              
463             static const map flags = {
464             { STR_WITH_LEN("shared") , MAP_SHARED },
465             { STR_WITH_LEN("private"), MAP_PRIVATE },
466             };
467              
468 16           void S_map_anonymous(pTHX_ SV* var, size_t length, const char* flag_name) {
469             int flag = map_get(flags, flag_name, -1);
470 8 50         if (flag == -1)
471 0           Perl_croak(aTHX_ "No such flag '%s'", flag_name);
472 8 100         if (length == 0)
473 1           Perl_croak(aTHX_ "Zero length specified for anonymous map");
474 7           mmap_impl(var, length, PROT_READ | PROT_WRITE, flag | MAP_ANONYMOUS, -1, 0, 0);
475 6           }
476             #define map_anonymous(var, length, flag_name) S_map_anonymous(aTHX_ var, length, flag_name)
477              
478 0           void S_sys_map(pTHX_ SV* var, size_t length, int protection, int flags, SV* fh, Off_t offset) {
479 0 0         if (flags & MAP_ANONYMOUS)
480 0           mmap_impl(var, length, protection, flags, -1, offset, 0);
481             else {
482 0           PerlIO* pio = IoIFP(sv_2io(fh)); // XXX error check
483 0           int utf8 = check_layers(pio);
484 0           int fd = PerlIO_fileno(pio);
485 0           mmap_impl(var, length, protection, flags, fd, offset, utf8);
486             }
487 0           }
488             #define sys_map(var, length, protection, flags, fh, offset) S_sys_map(aTHX_ var, length, protection, flags, fh, offset)
489              
490 2           void S_sync(pTHX_ SV* var, bool sync) {
491 2           struct mmap_info* info = get_mmap_magic(var, "sync");
492 1 50         if (EMPTY_MAP(info))
493             return;
494 0 0         if (SvREADONLY(var) && ckWARN(WARN_IO))
    0          
495 0           Perl_warn(aTHX_ "Syncing a readonly map makes no sense");
496 0 0         if (msync(info->real_address, info->real_length, sync ? MS_SYNC : MS_ASYNC ) == -1)
    0          
497 0           die_sys("Could not sync: %s");
498             }
499             #define sync(var, sync) S_sync(aTHX_ var, sync)
500              
501             #ifdef __linux__
502 2           void S_remap(pTHX_ SV* var, size_t new_size) {
503 2           struct mmap_info* info = get_mmap_magic(var, "remap");
504 2           ptrdiff_t correction = info->real_length - info->fake_length;
505             void* new_address;
506             CODE:
507             #ifdef USE_ITHREADS
508             if (info->count != 1)
509             Perl_croak(aTHX_ "Can't remap a shared mapping");
510             #endif
511 2 50         if (EMPTY_MAP(info))
512 0           Perl_croak(aTHX_ "Can't remap empty map"); /* XXX */
513 2 50         if (new_size == 0)
514 0           Perl_croak(aTHX_ "Can't remap to zero");
515 2 50         if ((info->flags & (MAP_ANONYMOUS|MAP_SHARED)) == (MAP_ANONYMOUS|MAP_SHARED))
516 0           Perl_croak(aTHX_ "Can't remap a shared anonymous mapping");
517 2 50         if ((new_address = mremap(info->real_address, info->real_length, new_size + correction, MREMAP_MAYMOVE)) == MAP_FAILED)
518 0           die_sys("Could not remap: %s");
519             set_mmap_info(info, new_address, new_size, correction);
520             reset_var(var, info);
521 2           }
522             #define remap(var, new_size) S_remap(aTHX_ var, new_size)
523             #endif
524              
525 2           void S_unmap(pTHX_ SV* var) {
526 2           get_mmap_magic(var, "unmap");
527 1           sv_unmagicext(var, PERL_MAGIC_ext, (MGVTBL*)&mmap_table);
528 1           }
529             #define unmap(var) S_unmap(aTHX_ var)
530              
531 0           void S_pin(pTHX_ struct mmap_info* info) {
532             #ifndef VMS
533 0 0         if (EMPTY_MAP(info))
534             return;
535 0 0         if (mlock(info->real_address, info->real_length) == -1)
536 0           die_sys("Could not pin: %s");
537             #else
538             Perl_croak(aTHX_ "pin not implemented on VMS");
539             #endif
540             }
541             #define pin(var) S_pin(aTHX_ var)
542              
543 0           void S_unpin(pTHX_ struct mmap_info* info) {
544             #ifndef VMS
545 0 0         if (EMPTY_MAP(info))
546             return;
547 0 0         if (munlock(info->real_address, info->real_length) == -1)
548 0           die_sys("Could not unpin: %s");
549             #else
550             Perl_croak(aTHX_ "unpin not implemented on VMS");
551             #endif
552             }
553             #define unpin(var) S_unpin(aTHX_ var)
554              
555 3           void S_advise(pTHX_ struct mmap_info* info, SV* name) {
556 3           HV* constants = (HV*) *hv_fetch(PL_modglobal, "File::Map::ADVISE_CONSTANTS", 27, 0);
557 3           HE* value = hv_fetch_ent(constants, name, 0, 0);
558              
559 3 50         if (EMPTY_MAP(info))
560             return;
561 3 100         if (!value) {
562 1 50         if (ckWARN(WARN_PORTABLE))
563 1 50         Perl_warn(aTHX_ "Unknown advice '%s'", SvPV_nolen(name));
564             }
565 2 50         else if (madvise(info->real_address, info->real_length, SvUV(HeVAL(value))) == -1)
    50          
566 0           die_sys("Could not advice: %s");
567             }
568             #define advise(var, name) S_advise(aTHX_ var, name)
569              
570 2           void S_protect(pTHX_ SV* var, SV* prot) {
571 2           struct mmap_info* info = get_mmap_magic(var, "protect");
572 2 50         int prot_val = SvIOK(prot) ? SvIV(prot) : protection_sv(prot);
    0          
573 2 50         if (!EMPTY_MAP(info))
574 2           mprotect(info->real_address, info->real_length, prot_val);
575 2 100         if (prot_val & PROT_WRITE)
576 1           SvREADONLY_off(var);
577             else
578 1           SvREADONLY_on(var);
579 2           }
580             #define protect(var, prot) S_protect(aTHX_ var, prot)
581              
582 0           void S_lock_map(pTHX_ struct mmap_info* info) {
583             #ifdef USE_ITHREADS
584             LEAVE;
585             SAVEDESTRUCTOR_X(magic_end, info);
586             MUTEX_LOCK(&info->data_mutex);
587             info->owner = aTHX;
588             ENTER;
589             #endif
590 0           }
591             #define lock_map(var) S_lock_map(aTHX_ var)
592              
593             #ifdef USE_ITHREADS
594             SV* S_wait_until(pTHX_ SV* block, SV* var) {
595             struct mmap_info* info = get_mmap_magic(var, "wait_until");
596             if (info->owner != aTHX)
597             Perl_croak(aTHX_ "Trying to wait on an unlocked map");
598             SAVESPTR(DEFSV);
599             DEFSV = var;
600             dSP;
601             while (1) {
602             PUSHMARK(SP);
603             call_sv(block, G_SCALAR | G_NOARGS);
604             SPAGAIN;
605             SV* result = POPs;
606             if (SvTRUE(result))
607             return SvREFCNT_inc(result);
608             COND_WAIT(&info->cond, &info->data_mutex);
609             }
610             }
611             #define wait_until(block, var) S_wait_until(aTHX_ block, var)
612              
613             void S_notify(pTHX_ struct mmap_info* info) {
614             if (info->owner != aTHX)
615             Perl_croak(aTHX_ "Trying to notify on an unlocked map");
616             COND_SIGNAL(&info->cond);
617             }
618             #define notify(var) S_notify(aTHX_ var)
619              
620             void S_broadcast(pTHX_ struct mmap_info* info) {
621             if (info->owner != aTHX)
622             Perl_croak(aTHX_ "Trying to broadcast on an unlocked map");
623             COND_BROADCAST(&info->cond);
624             }
625             #define broadcast(var) S_broadcast(aTHX_ var)
626             #endif
627              
628             MODULE = File::Map PACKAGE = File::Map
629              
630             PROTOTYPES: DISABLED
631              
632             BOOT:
633 7           boot();
634              
635             void map_file(SV* var, SV* filename, SV* mode = READONLY, Off_t offset = 0, SV* length = undef)
636              
637             void map_handle(SV* var, PerlIO* fh, SV* mode = READONLY, Off_t offset = 0, SV* length = undef)
638              
639             void map_anonymous(SV* var, size_t length, const char* flag_name = "shared")
640              
641             void sys_map(SV* var, size_t length, int protection, int flags, SV* fh = undef, Off_t offset = 0)
642              
643             void sync(SV* var, bool sync = TRUE)
644              
645             #ifdef __linux__
646             void remap(SV* var, size_t new_size)
647              
648             #endif
649              
650             void unmap(SV* var)
651              
652             void pin(struct mmap_info* var)
653              
654             void unpin(struct mmap_info* var)
655              
656             void advise(struct mmap_info* var, SV* name)
657              
658             void protect(SV* var, SV* prot)
659              
660             void lock_map(struct mmap_info* var)
661              
662             #ifdef USE_ITHREADS
663             SV* wait_until(SV* block, SV* var)
664             PROTOTYPE: &@
665              
666             void notify(struct mmap_info* var)
667              
668             void broadcast(struct mmap_info* var)
669              
670             #endif /* USE ITHREADS */