diff options
-rw-r--r-- | extconf.rb | 2 | ||||
-rw-r--r-- | mahoro.c | 148 |
2 files changed, 130 insertions, 20 deletions
@@ -2,6 +2,8 @@ require 'mkmf' dir_config('magic') have_library('magic', 'magic_open') +have_func('rb_thread_call_without_gvl') +have_func('rb_thread_blocking_region') create_makefile('mahoro') # arch-tag: extconf @@ -19,6 +19,63 @@ static VALUE cMahoro; static VALUE eMahoroError; +struct nogvl_args { + magic_t cookie; + union { + const char *path; + int fd; + } as; +}; + +/* + * Compatibility layer for various GVL-releasing + * + * rb_thread_call_without_gvl was detectable via have_func in 1.9.3, + * but not usable. So we must check for ruby/thread.h and use + * rb_thread_blocking_region if ruby/thread.h is not available + * + * HAVE_RUBY_THREAD_H is defined by ruby.h in 2.0.0, NOT using + * extconf.rb since that may find ruby/thread.h in a different + * installation + */ +#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) && \ + defined(HAVE_RUBY_THREAD_H) && \ + HAVE_RUBY_THREAD_H +# include <ruby/thread.h> +# define NOGVL(fn,data1,ubf,data2) \ + rb_thread_call_without_gvl((fn),(data1),(ubf),(data2)) +#elif defined(HAVE_RB_THREAD_BLOCKING_REGION) /* Ruby 1.9.x */ +# define COMPAT_FN (VALUE (*)(void *)) +# define NOGVL(fn,data1,ubf,data2) \ + (void *)rb_thread_blocking_region(COMPAT_FN(fn),(data1),(ubf),(data2)) +#else /* Ruby 1.8 */ +/* + * Ruby 1.8 does not have a GVL, we'll just enable signal interrupts + * here in case we make interruptible syscalls + */ +# define RUBY_UBF_IO ((rb_unblock_function_t *)-1) +# include "rubysig.h" +typedef void rb_unblock_function_t(void *); +typedef void *rb_blocking_function_t(void *); + +static void * +fake_nogvl(fn, data1, ubf, data2) + rb_blocking_function_t fn; + void *data1; + rb_unblock_function_t ubf; + void *data2; +{ + void *rv; + + TRAP_BEG; + rv = fn(data1); + TRAP_END; + + return rv; +} +# define NOGVL(fn,data1,ubf,data2) fake_nogvl((fn),(data1),(ubf),(data2)) +#endif + /* :nodoc: called automatically by GC */ static void mahoro_free(ptr) @@ -36,6 +93,15 @@ mahoro_allocate(klass) return Data_Wrap_Struct(klass, 0, mahoro_free, 0); } +static void * +nogvl_load(ptr) + void *ptr; +{ + struct nogvl_args *args = ptr; + + return magic_load(args->cookie, args->as.path) ? ptr : NULL; +} + /* * call-seq: * Mahoro.new(flags = Mahoro::NONE, path = nil) -> mahoro_obj @@ -56,14 +122,15 @@ mahoro_initialize(argc, argv, self) VALUE *argv, self; { int flags = MAGIC_NONE; - char *path = 0; - magic_t cookie; + struct nogvl_args args; VALUE vpath, vflags; + args.as.path = NULL; + switch(rb_scan_args(argc, argv, "02", &vflags, &vpath)) { case 2: if(!NIL_P(vpath)) { - path = StringValueCStr(vpath); + args.as.path = StringValueCStr(vpath); } /* fallthrough */ case 1: @@ -71,20 +138,29 @@ mahoro_initialize(argc, argv, self) break; } - if(!(cookie = magic_open(flags))) { + if(!(args.cookie = magic_open(flags))) { rb_raise(eMahoroError, "failed to initialize magic cookie"); } - if(magic_load(cookie, path)) { + if(NOGVL(nogvl_load, &args, RUBY_UBF_IO, NULL)) { rb_raise(eMahoroError, "failed to load database: %s", - magic_error(cookie)); + magic_error(args.cookie)); } - DATA_PTR(self) = cookie; + DATA_PTR(self) = args.cookie; return self; } +static void * +nogvl_file(ptr) + void *ptr; +{ + struct nogvl_args *args = ptr; + + return (void *)magic_file(args->cookie, args->as.path); +} + /* * call-seq: * mahoro_obj.file(filename) -> String @@ -99,10 +175,14 @@ mahoro_file(self, path) VALUE self, path; { const char *msg; - magic_t cookie = (magic_t)DATA_PTR(self); + struct nogvl_args args; - if(!(msg = magic_file(cookie, StringValueCStr(path)))) { - rb_raise(eMahoroError, "failed lookup: %s", magic_error(cookie)); + args.cookie = (magic_t)DATA_PTR(self); + args.as.path = StringValueCStr(path); + + if(!(msg = NOGVL(nogvl_file, &args, RUBY_UBF_IO, NULL))) { + rb_raise(eMahoroError, "failed lookup: %s", + magic_error(args.cookie)); } return rb_str_new2(msg); @@ -177,6 +257,15 @@ mahoro_set_flags(self, flags) return INT2FIX(magic_setflags(cookie, FIX2INT(flags))); } +static void * +nogvl_check(ptr) + void *ptr; +{ + struct nogvl_args *args = ptr; + + return magic_check(args->cookie, args->as.path) ? ptr : NULL; +} + /* * call-seq: * mahoro_obj.check(path = nil) -> true or false @@ -190,25 +279,36 @@ mahoro_check(argc, argv, self) int argc; VALUE *argv, self; { - char *path = 0; + struct nogvl_args args; VALUE vpath; - magic_t cookie = (magic_t)DATA_PTR(self); + + args.cookie = (magic_t)DATA_PTR(self); + args.as.path = NULL; switch(rb_scan_args(argc, argv, "01", &vpath)) { case 1: if(!NIL_P(vpath)) { - path = StringValueCStr(vpath); + args.as.path = StringValueCStr(vpath); } break; } - if(!magic_check(cookie, path)) { + if(!NOGVL(nogvl_check, &args, RUBY_UBF_IO, 0)) { return Qtrue; } else { return Qfalse; } } +static void * +nogvl_compile(ptr) + void *ptr; +{ + struct nogvl_args *args = ptr; + + return magic_compile(args->cookie, args->as.path) ? ptr : NULL; +} + /* * call-seq: * mahoro_obj.compile(path) -> true @@ -228,10 +328,14 @@ static VALUE mahoro_compile(self, path) VALUE self, path; { - magic_t cookie = (magic_t)DATA_PTR(self); + struct nogvl_args args; + + args.cookie = (magic_t)DATA_PTR(self); + args.as.path = StringValueCStr(path); - if(magic_compile(cookie, StringValueCStr(path))) { - rb_raise(eMahoroError, "failed compile: %s", magic_error(cookie)); + if(NOGVL(nogvl_compile, &args, RUBY_UBF_IO, NULL)) { + rb_raise(eMahoroError, "failed compile: %s", + magic_error(args.cookie)); } return Qtrue; @@ -276,10 +380,14 @@ static VALUE mahoro_load(self, path) VALUE self, path; { - magic_t cookie = (magic_t)DATA_PTR(self); + struct nogvl_args args; + + args.cookie = (magic_t)DATA_PTR(self); + args.as.path = StringValueCStr(path); - if(magic_load(cookie, StringValueCStr(path))) { - rb_raise(eMahoroError, "failed load: %s", magic_error(cookie)); + if(NOGVL(nogvl_load, &args, RUBY_UBF_IO, NULL)) { + rb_raise(eMahoroError, "failed load: %s", + magic_error(args.cookie)); } return self; |