diff options
author | Eric Wong <normalperson@yhbt.net> | 2013-04-05 02:47:04 +0000 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2013-04-05 02:47:04 +0000 |
commit | f5774348b6fe5bb7e86717629fdb8c4d8c30731f (patch) | |
tree | f1c57b2a836fced43d6761971de665c9e1d745dd | |
parent | 92e549dfb5f19125f4b6131937b738eee5b046c7 (diff) | |
download | mahoro-f5774348b6fe5bb7e86717629fdb8c4d8c30731f.tar.gz |
release GVL if filesystem I/O is required
Filesystem I/O has unpredictable latency, release the GVL in these cases since we will never know how long it lasts. We enable interrupt processing since we may be operating on FIFOs. (Matz) Ruby 1.9 and 2.0 releases GVL for all file system operations, too.
-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; |