ruby-changes:51066
From: nobu <ko1@a...>
Date: Fri, 27 Apr 2018 16:39:06 +0900 (JST)
Subject: [ruby-changes:51066] nobu:r63273 (trunk): mjit.c: clean so file on Windows
nobu 2018-04-27 16:39:00 +0900 (Fri, 27 Apr 2018) New Revision: 63273 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=63273 Log: mjit.c: clean so file on Windows * mjit.c (dlclose): use FreeLibrary to manage the reference count on the loaded module properly. * mjit.c (clean_so_file): clean shared object file after unloaded, in-use files cannot be removed on Windows. Modified files: trunk/mjit.c trunk/test/lib/jit_support.rb trunk/test/ruby/test_jit.rb Index: mjit.c =================================================================== --- mjit.c (revision 63272) +++ mjit.c (revision 63273) @@ -115,7 +115,7 @@ extern int rb_thread_create_mjit_thread( https://github.com/ruby/ruby/blob/trunk/mjit.c#L115 #define dlopen(name,flag) ((void*)LoadLibrary(name)) #define dlerror() strerror(rb_w32_map_errno(GetLastError())) #define dlsym(handle,name) ((void*)GetProcAddress((handle),(name))) -#define dlclose(handle) (CloseHandle(handle)) +#define dlclose(handle) (FreeLibrary(handle)) #define RTLD_NOW -1 #define waitpid(pid,stat_loc,options) (WaitForSingleObject((HANDLE)(pid), INFINITE), GetExitCodeProcess((HANDLE)(pid), (LPDWORD)(stat_loc))) @@ -148,6 +148,10 @@ struct rb_mjit_unit { https://github.com/ruby/ruby/blob/trunk/mjit.c#L148 /* Dlopen handle of the loaded object file. */ void *handle; const rb_iseq_t *iseq; +#ifdef _WIN32 + /* DLL cannot be removed while loaded on Windows */ + char *so_file; +#endif /* Only used by unload_units. Flag to check this unit is currently on stack or not. */ char used_code_p; }; @@ -442,12 +446,30 @@ mjit_free_iseq(const rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/mjit.c#L446 } static void +clean_so_file(struct rb_mjit_unit *unit) +{ +#ifdef _WIN32 +# undef Sleep + char *so_file = unit->so_file; + if (so_file) { + unit->so_file = NULL; + if (remove(so_file)) { + fprintf(stderr, "failed to remove \"%s\": %s\n", + so_file, strerror(errno)); + } + free(so_file); + } +#endif +} + +static void free_unit(struct rb_mjit_unit *unit) { if (unit->iseq) /* ISeq is not GCed */ unit->iseq->body->jit_func = 0; if (unit->handle) /* handle is NULL if it's in queue */ dlclose(unit->handle); + clean_so_file(unit); xfree(unit); } @@ -865,8 +887,13 @@ convert_unit_to_func(struct rb_mjit_unit https://github.com/ruby/ruby/blob/trunk/mjit.c#L887 } func = load_func_from_so(so_file, funcname, unit); - if (!mjit_opts.save_temps) + if (!mjit_opts.save_temps) { +#ifdef _WIN32 + unit->so_file = strdup(so_file); +#else remove(so_file); +#endif + } if ((ptrdiff_t)func > (ptrdiff_t)LAST_JIT_ISEQ_FUNC) { struct rb_mjit_unit_node *node = create_list_node(unit); @@ -1095,6 +1122,7 @@ unload_units(void) https://github.com/ruby/ruby/blob/trunk/mjit.c#L1122 assert(unit->handle != NULL); dlclose(unit->handle); unit->handle = NULL; + clean_so_file(unit); } verbose(1, "Too many JIT code -- %d units unloaded", units_num - active_units.length); } Index: test/lib/jit_support.rb =================================================================== --- test/lib/jit_support.rb (revision 63272) +++ test/lib/jit_support.rb (revision 63273) @@ -7,9 +7,12 @@ module JITSupport https://github.com/ruby/ruby/blob/trunk/test/lib/jit_support.rb#L7 ] module_function - def eval_with_jit(script, verbose: 0, min_calls: 5, timeout: JIT_TIMEOUT) - EnvUtil.invoke_ruby( - ['--disable-gems', '--jit-wait', "--jit-verbose=#{verbose}", "--jit-min-calls=#{min_calls}", '-e', script], + def eval_with_jit(env = nil, script, verbose: 0, min_calls: 5, save_temps: false, timeout: JIT_TIMEOUT) + args = ['--disable-gems', '--jit-wait', "--jit-verbose=#{verbose}", "--jit-min-calls=#{min_calls}"] + args << '--jit-save-temps' if save_temps + args << '-e' << script + args.unshift(env) if env + EnvUtil.invoke_ruby(args, '', true, true, timeout: timeout, ) end Index: test/ruby/test_jit.rb =================================================================== --- test/ruby/test_jit.rb (revision 63272) +++ test/ruby/test_jit.rb (revision 63273) @@ -564,6 +564,16 @@ class TestJIT < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_jit.rb#L564 end; end + def test_clean_so + Dir.mktmpdir("jit_test_clean_so_") do |dir| + code = "x = 0; 10.times {|i|x+=i}" + eval_with_jit({"TMPDIR"=>dir}, code) + assert_send([Dir, :empty?, dir]) + eval_with_jit({"TMPDIR"=>dir}, code, save_temps: true) + assert_not_send([Dir, :empty?, dir]) + end + end + private # The shortest way to test one proc @@ -606,7 +616,7 @@ class TestJIT < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_jit.rb#L616 # Run Ruby script with --jit-wait (Synchronous JIT compilation). # Returns [stdout, stderr] - def eval_with_jit(script, **opts) + def eval_with_jit(env = nil, script, **opts) stdout, stderr, status = super assert_equal(true, status.success?, "Failed to run script with JIT:\n#{code_block(script)}\nstdout:\n#{code_block(stdout)}\nstderr:\n#{code_block(stderr)}") [stdout, stderr] -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/