diff options
-rw-r--r-- | Changes | 7 | ||||
-rw-r--r-- | mmap.c | 217 | ||||
-rw-r--r-- | mmap.rd | 2 | ||||
-rw-r--r-- | tests/mmapt.rb | 17 |
4 files changed, 169 insertions, 74 deletions
@@ -30,3 +30,10 @@ * adapted for 1.7.2 (mm_str) * corrected real for mm_sub_bang * protected against old class + +-- 0.1.7 + +* 1.7.2 (::allocate, #initialize) +* added "a" for ::new +* experimental EXP_INCR_SIZE (4096) ("increment" => 4096) +* tests for RUNIT/Test::Unit @@ -34,12 +34,14 @@ static VALUE mm_cMap; +#define EXP_INCR_SIZE 4096 + typedef struct { MMAP_RETTYPE addr; int smode, pmode, vscope; int advice, frozen, lock; size_t len, real; - size_t size; + size_t size, incr; off_t offset; char *path; } mm_mmap; @@ -164,6 +166,79 @@ mm_to_str(obj) extern char *ruby_strdup(); +static void +mm_expandf(t_mm, len) + mm_mmap *t_mm; + long len; +{ + int fd; + + if (t_mm->vscope == MAP_PRIVATE) { + rb_raise(rb_eTypeError, "expand for a private map"); + } + if (t_mm->frozen & MM_FIXED) { + rb_raise(rb_eTypeError, "expand for a fixed map"); + } + if (munmap(t_mm->addr, t_mm->len)) { + rb_raise(rb_eArgError, "munmap failed"); + } + if ((fd = open(t_mm->path, t_mm->smode)) == -1) { + rb_raise(rb_eArgError, "Can't open %s", t_mm->path); + } + if (len > t_mm->len) { + if (lseek(fd, len - t_mm->len - 1, SEEK_END) == -1) { + rb_raise(rb_eIOError, "Can't lseek %d", len - t_mm->len - 1); + } + if (write(fd, "\000", 1) != 1) { + rb_raise(rb_eIOError, "Can't extend %s", t_mm->path); + } + } + else if (len < t_mm->len && truncate(t_mm->path, len) == -1) { + rb_raise(rb_eIOError, "Can't truncate %s", t_mm->path); + } + t_mm->addr = mmap(0, len, t_mm->pmode, t_mm->vscope, fd, t_mm->offset); + close(fd); + if (t_mm->addr == MAP_FAILED) { + rb_raise(rb_eArgError, "mmap failed"); + } + if (t_mm->advice && madvise(t_mm->addr, len, t_mm->advice) == -1) { + rb_raise(rb_eArgError, "madvise(%d)", errno); + } + if (t_mm->lock && mlock(t_mm->addr, len) == -1) { + rb_raise(rb_eArgError, "mlock(%d)", errno); + } + t_mm->len = len; +} + +static void +mm_realloc(t_mm, len) + mm_mmap *t_mm; + long len; +{ + if (t_mm->frozen & MM_FROZEN) rb_error_frozen("mmap"); + if (len > t_mm->len) { + if ((len - t_mm->len) < t_mm->incr) { + len = t_mm->len + t_mm->incr; + } + mm_expandf(t_mm, len); + } +} + +static VALUE +mm_extend(obj, a) + VALUE obj, a; +{ + mm_mmap *t_mm; + long len; + + GetMmap(obj, t_mm, MM_MODIFY); + len = NUM2LONG(a); + if (len > 0) { + mm_expandf(t_mm, t_mm->len + len); + } + return INT2NUM(t_mm->len); +} + static VALUE mm_i_options(arg, obj) VALUE arg, obj; @@ -194,16 +269,42 @@ mm_i_options(arg, obj) else if (strcmp(options, "advice") == 0) { t_mm->advice = NUM2INT(value); } + else if (strcmp(options, "increment") == 0) { + t_mm->incr = NUM2INT(value); + if (t_mm->incr < 0) { + rb_raise(rb_eArgError, "Invalid value for increment %d", t_mm->incr); + } + } return Qnil; } + +#if RUBY_VERSION_CODE >= 172 +static VALUE +mm_s_alloc(argc, argv, obj) + int argc; + VALUE *argv, obj; +{ + VALUE res; + mm_mmap *t_mm; + + res = Data_Make_Struct(obj, mm_mmap, 0, mm_free, t_mm); + t_mm->incr = EXP_INCR_SIZE; + return res; +} +#endif + static VALUE +#if RUBY_VERSION_CODE >= 172 +mm_init(argc, argv, obj) +#else mm_s_new(argc, argv, obj) +#endif VALUE obj, *argv; int argc; { struct stat st; - int fd, smode, pmode, vscope; + int fd, smode, pmode, vscope, perm, init; MMAP_RETTYPE addr; VALUE res, fname, vmode, scope, options; mm_mmap *t_mm; @@ -237,7 +338,18 @@ mm_s_new(argc, argv, obj) Check_SafeStr(fname); path = RSTRING(fname)->ptr; #endif - mode = NIL_P(vmode) ? "r" : STR2CSTR(vmode); + perm = 0666; + if (NIL_P(vmode)) { + mode = "r"; + } + else if (TYPE(vmode) == T_ARRAY && RARRAY(vmode)->len >= 2) { + VALUE tmp = RARRAY(vmode)->ptr[0]; + mode = STR2CSTR(tmp); + perm = NUM2INT(RARRAY(vmode)->ptr[1]); + } + else { + mode = STR2CSTR(vmode); + } if (strcmp(mode, "r") == 0) { smode = O_RDONLY; pmode = PROT_READ; @@ -250,13 +362,17 @@ mm_s_new(argc, argv, obj) smode = O_RDWR; pmode = PROT_READ | PROT_WRITE; } + else if (strcmp(mode, "a") == 0) { + smode = O_RDWR | O_CREAT; + pmode = PROT_READ | PROT_WRITE; + } else { rb_raise(rb_eArgError, "Invalid mode %s", mode); } vscope |= NIL_P(scope) ? MAP_SHARED : NUM2INT(scope); size = 0; if (path) { - if ((fd = open(path, smode)) == -1) { + if ((fd = open(path, smode, perm)) == -1) { rb_raise(rb_eArgError, "Can't open %s", path); } if (fstat(fd, &st) == -1) { @@ -267,7 +383,13 @@ mm_s_new(argc, argv, obj) else { fd = -1; } +#if RUBY_VERSION_CODE >= 172 + Data_Get_Struct(obj, mm_mmap, t_mm); + res = obj; +#else res = Data_Make_Struct(obj, mm_mmap, 0, mm_free, t_mm); + t_mm->incr = EXP_INCR_SIZE; +#endif offset = 0; if (options != Qnil) { rb_iterate(rb_each, options, mm_i_options, res); @@ -278,6 +400,7 @@ mm_s_new(argc, argv, obj) if (t_mm->size) size = t_mm->size; offset = t_mm->offset; } + init = 0; if (!path) { if (size <= 0) { rb_raise(rb_eArgError, "length not specified for an anonymous map"); @@ -287,6 +410,16 @@ mm_s_new(argc, argv, obj) offset = 0; } } + else if (size == 0 && (smode & O_RDWR)) { + if (lseek(fd, t_mm->incr - 1, SEEK_END) == -1) { + rb_raise(rb_eIOError, "Can't lseek %d", t_mm->incr - 1); + } + if (write(fd, "\000", 1) != 1) { + rb_raise(rb_eIOError, "Can't extend %s", path); + } + init = 1; + size = t_mm->incr; + } addr = mmap(0, size, pmode, vscope, fd, offset); if (fd != -1) close(fd); if (addr == MAP_FAILED || !addr) { @@ -296,7 +429,8 @@ mm_s_new(argc, argv, obj) rb_raise(rb_eArgError, "madvise(%d)", errno); } t_mm->addr = addr; - t_mm->real = t_mm->len = size; + t_mm->len = size; + if (!init) t_mm->real = size; t_mm->pmode = pmode; t_mm->vscope = vscope; t_mm->smode = smode; @@ -308,10 +442,13 @@ mm_s_new(argc, argv, obj) else { OBJ_TAINT(res); } +#if RUBY_VERSION_CODE < 172 rb_obj_call_init(res, argc, argv); +#endif return res; } +#if RUBY_VERSION_CODE < 171 static VALUE mm_init(argc, argv, obj) int argc; @@ -319,70 +456,8 @@ mm_init(argc, argv, obj) { return obj; } +#endif -static void -mm_expandf(t_mm, len) - mm_mmap *t_mm; - long len; -{ - int fd; - - if (t_mm->vscope == MAP_PRIVATE) { - rb_raise(rb_eTypeError, "expand for a private map"); - } - if (t_mm->frozen & MM_FIXED) { - rb_raise(rb_eTypeError, "expand for a fixed map"); - } - if (munmap(t_mm->addr, t_mm->len)) { - rb_raise(rb_eArgError, "munmap failed"); - } - if ((fd = open(t_mm->path, t_mm->smode)) == -1) { - rb_raise(rb_eArgError, "Can't open %s", t_mm->path); - } - if (len > t_mm->len) { - if (lseek(fd, len - t_mm->len - 1, SEEK_END) == -1) { - rb_raise(rb_eIOError, "Can't lseek %d", len - t_mm->len - 1); - } - if (write(fd, "\000", 1) != 1) { - rb_raise(rb_eIOError, "Can't extend %s", t_mm->path); - } - } - else if (len < t_mm->len && truncate(t_mm->path, len) == -1) { - rb_raise(rb_eIOError, "Can't truncate %s", t_mm->path); - } - t_mm->addr = mmap(0, len, t_mm->pmode, t_mm->vscope, fd, t_mm->offset); - close(fd); - if (t_mm->addr == MAP_FAILED) { - rb_raise(rb_eArgError, "mmap failed"); - } - if (t_mm->advice && madvise(t_mm->addr, len, t_mm->advice) == -1) { - rb_raise(rb_eArgError, "madvise(%d)", errno); - } - if (t_mm->lock && mlock(t_mm->addr, len) == -1) { - rb_raise(rb_eArgError, "mlock(%d)", errno); - } - t_mm->len = len; -} - -static void -mm_realloc(t_mm, len) - mm_mmap *t_mm; - long len; -{ - if (t_mm->frozen & MM_FROZEN) rb_error_frozen("mmap"); - if (len > t_mm->len) mm_expandf(t_mm, len); -} - -static VALUE -mm_extend(obj, a) - VALUE obj, a; -{ - mm_mmap *t_mm; - - GetMmap(obj, t_mm, MM_MODIFY); - mm_realloc(t_mm, t_mm->len + NUM2LONG(a)); - return INT2NUM(t_mm->len); -} static VALUE mm_msync(argc, argv, obj) @@ -717,7 +792,7 @@ mm_gsub_bang(argc, argv, obj) if (OBJ_TAINTED(repl)) tainted = 1; plen = END(0); if ((t_mm->real + RSTRING(val)->len - plen) > t_mm->len) { - mm_realloc(t_mm, RSTRING(str)->len + 2 * RSTRING(val)->len); + mm_realloc(t_mm, RSTRING(str)->len + RSTRING(val)->len - plen); RSTRING(str)->ptr = t_mm->addr; } if (RSTRING(val)->len != plen) { @@ -1559,7 +1634,11 @@ Init_mmap() rb_include_module(mm_cMap, rb_mComparable); rb_include_module(mm_cMap, rb_mEnumerable); +#if RUBY_VERSION_CODE >= 172 + rb_define_singleton_method(mm_cMap, "allocate", mm_s_alloc, -1); +#else rb_define_singleton_method(mm_cMap, "new", mm_s_new, -1); +#endif rb_define_singleton_method(mm_cMap, "mlockall", mm_mlockall, 1); rb_define_singleton_method(mm_cMap, "lockall", mm_mlockall, 1); rb_define_singleton_method(mm_cMap, "munlockall", mm_munlockall, 0); @@ -31,7 +31,7 @@ Object is created ((|Mmanp::MAP_ANON|)) : ((|mode|)) - Mode to open the file, it can be "r", "w" or "rw" + Mode to open the file, it can be "r", "w", "rw", "a" : ((|protection|)) specify the nature of the mapping diff --git a/tests/mmapt.rb b/tests/mmapt.rb index 15fe5e4..a7a049c 100644 --- a/tests/mmapt.rb +++ b/tests/mmapt.rb @@ -2,12 +2,18 @@ $LOAD_PATH.unshift *%w{.. . tests} require 'mmap' require 'ftools' -require 'runit/testcase' -require 'runit/cui/testrunner' +begin + require 'test/unit' + Inh = Test::Unit +rescue LoadError + require 'runit/testcase' + require 'runit/cui/testrunner' + Inh = RUNIT +end $mmap, $str = nil, nil -class TestMmap < RUNIT::TestCase +class TestMmap < Inh::TestCase def internal_init $mmap.unmap if $mmap file = "mmap.c" @@ -190,4 +196,7 @@ class TestMmap < RUNIT::TestCase end -RUNIT::CUI::TestRunner.run(TestMmap.suite) +if defined?(RUNIT) + RUNIT::CUI::TestRunner.run(TestMmap.suite) +end + |