I think I may have found a bug in the Ruby interpreter, but I’m not sure.
Anytime I receive a VALUE
type within a C function which is called from Ruby, the extension completely stalls if I try to access its native data.
What happens is that I’ll call a function from the Ruby interpreter, say StringValueCStr(...)
or NUM2INT(...)
: the interpreter then receives it, and a few seconds later, the callstack shows the process waiting within one of Windows’ core OS .DLLs; the top-most level function is the Win32 API’s WaitForSingleObject
(i.e., it’s waiting for a thread or something else), which sounds like some sort of stall.
Once the initial function call is made to parse the input data received, the native function called from Ruby’s interpreter doesn’t finish its path.
In other words, if one sets a breakpoint on the function call, and then a breakpoint somewhere after it within the same function, that second breakpoint is never hit.
So far I’ve tested this with integer parsing as well as strings. I’ve also tested this both in my own extension as well as one of the SDK examples.
I’m not sure if anyone else has experienced this, or if it’s reproducible on anyone else’s machine. However, I would be grateful if someone would be willing to try, with some simple modifications to the licensed_ruby_extension example:
in licensed_ruby_extension.cpp,
// Implementation of SUEX_Licensed.do_work
static VALUE DoWork(VALUE someString) { //<--- parameter is added to the function signature
Sleep(15000); // I use this as it allows me time to attach Visual Studio's debugger to the extension on load
const char* str = StringValueCStr(someString); // Here is the kicker
if (!CheckLicense()) {
// We aren't allowed to run. Raising a ruby error here for demonstration
// purposes but a well-behaved extension would display a user-friendly
// message in this case.
rb_raise(rb_eRuntimeError, "This extension is not licensed.");
return Qnil;
}
// We are good to run. Do the work here.
// ...
return Qtrue;
}
// Entry point of the C extension.
extern "C" CEXT_EXPORT
void Init_licensed_ruby_extension()
{
VALUE mSUEX_HelloWorld = rb_define_module("SUEX_Licensed");
rb_define_module_function(mSUEX_HelloWorld, "do_work",
VALUEFUNC(DoWork), 1); //<--- the '1' (originally 0) is new: it states that the param count of DoWork is '1'
}
In loader.rb:
def self.execute
# Run some code from the C extension
if Sketchup.respond_to?(:is_64bit?) && Sketchup.is_64bit?
# Load 64-bit binary.
require_relative "bin64/licensed_ruby_extension"
else
# Load 32-bit binary.
require_relative "bin/licensed_ruby_extension"
end
if (SUEX_Licensed.do_work("Hello to you!")) <-- added string argument (only change made)
UI.messagebox("Success!")
else
UI.messagebox("FAILED!")
end
end
For the repro, the compiler used was MSVC 2010 with a 32-bit target architecture.
Thoughts? Experiences?