зеркало из https://github.com/github/ruby.git
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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63273 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
ea631cc184
Коммит
fa7fa92870
32
mjit.c
32
mjit.c
|
@ -115,7 +115,7 @@ extern int rb_thread_create_mjit_thread(void (*child_hook)(void), void (*worker_
|
||||||
#define dlopen(name,flag) ((void*)LoadLibrary(name))
|
#define dlopen(name,flag) ((void*)LoadLibrary(name))
|
||||||
#define dlerror() strerror(rb_w32_map_errno(GetLastError()))
|
#define dlerror() strerror(rb_w32_map_errno(GetLastError()))
|
||||||
#define dlsym(handle,name) ((void*)GetProcAddress((handle),(name)))
|
#define dlsym(handle,name) ((void*)GetProcAddress((handle),(name)))
|
||||||
#define dlclose(handle) (CloseHandle(handle))
|
#define dlclose(handle) (FreeLibrary(handle))
|
||||||
#define RTLD_NOW -1
|
#define RTLD_NOW -1
|
||||||
|
|
||||||
#define waitpid(pid,stat_loc,options) (WaitForSingleObject((HANDLE)(pid), INFINITE), GetExitCodeProcess((HANDLE)(pid), (LPDWORD)(stat_loc)))
|
#define waitpid(pid,stat_loc,options) (WaitForSingleObject((HANDLE)(pid), INFINITE), GetExitCodeProcess((HANDLE)(pid), (LPDWORD)(stat_loc)))
|
||||||
|
@ -148,6 +148,10 @@ struct rb_mjit_unit {
|
||||||
/* Dlopen handle of the loaded object file. */
|
/* Dlopen handle of the loaded object file. */
|
||||||
void *handle;
|
void *handle;
|
||||||
const rb_iseq_t *iseq;
|
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. */
|
/* Only used by unload_units. Flag to check this unit is currently on stack or not. */
|
||||||
char used_code_p;
|
char used_code_p;
|
||||||
};
|
};
|
||||||
|
@ -441,6 +445,23 @@ mjit_free_iseq(const rb_iseq_t *iseq)
|
||||||
CRITICAL_SECTION_FINISH(4, "mjit_free_iseq");
|
CRITICAL_SECTION_FINISH(4, "mjit_free_iseq");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static void
|
||||||
free_unit(struct rb_mjit_unit *unit)
|
free_unit(struct rb_mjit_unit *unit)
|
||||||
{
|
{
|
||||||
|
@ -448,6 +469,7 @@ free_unit(struct rb_mjit_unit *unit)
|
||||||
unit->iseq->body->jit_func = 0;
|
unit->iseq->body->jit_func = 0;
|
||||||
if (unit->handle) /* handle is NULL if it's in queue */
|
if (unit->handle) /* handle is NULL if it's in queue */
|
||||||
dlclose(unit->handle);
|
dlclose(unit->handle);
|
||||||
|
clean_so_file(unit);
|
||||||
xfree(unit);
|
xfree(unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -865,8 +887,13 @@ convert_unit_to_func(struct rb_mjit_unit *unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func = load_func_from_so(so_file, funcname, unit);
|
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);
|
remove(so_file);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if ((ptrdiff_t)func > (ptrdiff_t)LAST_JIT_ISEQ_FUNC) {
|
if ((ptrdiff_t)func > (ptrdiff_t)LAST_JIT_ISEQ_FUNC) {
|
||||||
struct rb_mjit_unit_node *node = create_list_node(unit);
|
struct rb_mjit_unit_node *node = create_list_node(unit);
|
||||||
|
@ -1095,6 +1122,7 @@ unload_units(void)
|
||||||
assert(unit->handle != NULL);
|
assert(unit->handle != NULL);
|
||||||
dlclose(unit->handle);
|
dlclose(unit->handle);
|
||||||
unit->handle = NULL;
|
unit->handle = NULL;
|
||||||
|
clean_so_file(unit);
|
||||||
}
|
}
|
||||||
verbose(1, "Too many JIT code -- %d units unloaded", units_num - active_units.length);
|
verbose(1, "Too many JIT code -- %d units unloaded", units_num - active_units.length);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,12 @@ module JITSupport
|
||||||
]
|
]
|
||||||
|
|
||||||
module_function
|
module_function
|
||||||
def eval_with_jit(script, verbose: 0, min_calls: 5, timeout: JIT_TIMEOUT)
|
def eval_with_jit(env = nil, script, verbose: 0, min_calls: 5, save_temps: false, timeout: JIT_TIMEOUT)
|
||||||
EnvUtil.invoke_ruby(
|
args = ['--disable-gems', '--jit-wait', "--jit-verbose=#{verbose}", "--jit-min-calls=#{min_calls}"]
|
||||||
['--disable-gems', '--jit-wait', "--jit-verbose=#{verbose}", "--jit-min-calls=#{min_calls}", '-e', script],
|
args << '--jit-save-temps' if save_temps
|
||||||
|
args << '-e' << script
|
||||||
|
args.unshift(env) if env
|
||||||
|
EnvUtil.invoke_ruby(args,
|
||||||
'', true, true, timeout: timeout,
|
'', true, true, timeout: timeout,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -564,6 +564,16 @@ class TestJIT < Test::Unit::TestCase
|
||||||
end;
|
end;
|
||||||
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
|
private
|
||||||
|
|
||||||
# The shortest way to test one proc
|
# The shortest way to test one proc
|
||||||
|
@ -606,7 +616,7 @@ class TestJIT < Test::Unit::TestCase
|
||||||
|
|
||||||
# Run Ruby script with --jit-wait (Synchronous JIT compilation).
|
# Run Ruby script with --jit-wait (Synchronous JIT compilation).
|
||||||
# Returns [stdout, stderr]
|
# Returns [stdout, stderr]
|
||||||
def eval_with_jit(script, **opts)
|
def eval_with_jit(env = nil, script, **opts)
|
||||||
stdout, stderr, status = super
|
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)}")
|
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]
|
[stdout, stderr]
|
||||||
|
|
Загрузка…
Ссылка в новой задаче