"undefined method `synchronize' for #<Mutex:0xa0f5adc>" from embedded Ruby program

I'm writing a C++ program (on Centos 5 Linux) that embeds a Ruby 1.9.3
p327 interpreter. It mostly works, but I'm getting a strange error from
a script called by the program. When run from the command line (i.e. not
embedded), the script works correctly. The error is:
    undefined method `synchronize' for #<Mutex:0xa0f5adc>
If I search back over this list's archives, I can see a few other people
with the same problem (but no solution).

I've narrowed it down to the following test program:

#include <ruby.h>

int
main(int argc, char *argv[])
{
    RUBY_INIT_STACK;
    ruby_init();
    ruby_init_loadpath();

    rb_eval_string("$mutex = Mutex.new");
    rb_eval_string("$mutex.synchronize(){}");

    return 0;
}

Does anybody have any clues, please?

Thanks, Graham

Is this thread related?

http://www.ruby-forum.com/topic/217934

···

On 21 November 2012 16:38, Graham Menhennitt <graham@menhennitt.com.au>wrote:

I'm writing a C++ program (on Centos 5 Linux) that embeds a Ruby 1.9.3
p327 interpreter. It mostly works, but I'm getting a strange error from
a script called by the program. When run from the command line (i.e. not
embedded), the script works correctly. The error is:
    undefined method `synchronize' for #<Mutex:0xa0f5adc>
If I search back over this list's archives, I can see a few other people
with the same problem (but no solution).

I've narrowed it down to the following test program:

#include <ruby.h>

int
main(int argc, char *argv)
{
    RUBY_INIT_STACK;
    ruby_init();
    ruby_init_loadpath();

    rb_eval_string("$mutex = Mutex.new");
    rb_eval_string("$mutex.synchronize(){}");

    return 0;
}

Does anybody have any clues, please?

Thanks, Graham

--
  Matthew Kerwin, B.Sc (CompSci) (Hons)
  http://matthew.kerwin.net.au/
  ABN: 59-013-727-651

  "You'll never find a programming language that frees
  you from the burden of clarifying your ideas." - xkcd

I've done a bit more investigation and found that it happens in all 1.9 releases of Ruby, but it does NOT happen in 1.8.7.

The test program below produces:

    [:locked?, :try_lock, :lock, :unlock, :sleep, :nil?, :===, :=~, :!~,
    :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup,
    :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint,
    :untrust, :untrusted?, :trust, :freeze, :frozen?, :to_s, :inspect,
    :methods, :singleton_methods, :protected_methods, :private_methods,
    :public_methods, :instance_variables, :instance_variable_get,
    :instance_variable_set, :instance_variable_defined?, :instance_of?,
    :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?,
    :respond_to_missing?, :extend, :display, :method, :public_method,
    :define_singleton_method, :object_id, :to_enum, :enum_for, :==,
    :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]

Whereas running "ruby -e 'p Mutex.new.methods'" produces:

    [:locked?, :try_lock, :lock, :unlock, :sleep, :synchronize, :nil?,
    :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class,
    :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?,
    :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :to_s,
    :inspect, :methods, :singleton_methods, :protected_methods,
    :private_methods, :public_methods, :instance_variables,
    :instance_variable_get, :instance_variable_set,
    :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap,
    :send, :public_send, :respond_to?, :respond_to_missing?, :extend,
    :display, :method, :public_method, :define_singleton_method,
    :object_id, :to_enum, :enum_for, :==, :equal?, :!, :!=,
    :instance_eval, :instance_exec, :__send__, :__id__]

Note that ":synchronize" is missing from the former.

I've tried removing all gems in case one of them was doing something strange. I've searched the Ruby source code, but I can't see anything that might cause this.

Anybody got any ideas? Should I take this to ruby.core?

Thanks,
     Graham

Test program:

    #include <ruby.h>

    int
    main(int argc, char *argv)
    {
         RUBY_INIT_STACK;
         ruby_init();
         ruby_init_loadpath();

         rb_eval_string("p Mutex.new.methods");

         return 0;
    }

···

On 21/11/2012 5:38 PM, Graham Menhennitt wrote:

The error is:
     undefined method `synchronize' for #<Mutex:0xa0f5adc>
If I search back over this list's archives, I can see a few other people
with the same problem (but no solution).

#include <ruby.h>

int
main(int argc, char *argv)
{
     RUBY_INIT_STACK;
     ruby_init();
     ruby_init_loadpath();

     rb_eval_string("$mutex = Mutex.new");
     rb_eval_string("$mutex.synchronize(){}");

     return 0;
}

Yes, that was one of the "few other people". But no solution to it.

Thanks for replying,
  Graham

···

On 21/11/2012 17:46, Matthew Kerwin wrote:

Is this thread related?

http://www.ruby-forum.com/topic/217934

On 21 November 2012 16:38, Graham Menhennitt <graham@menhennitt.com.au > <mailto:graham@menhennitt.com.au>> wrote:

    I'm writing a C++ program (on Centos 5 Linux) that embeds a Ruby 1.9.3
    p327 interpreter. It mostly works, but I'm getting a strange error
    from
    a script called by the program. When run from the command line
    (i.e. not
    embedded), the script works correctly. The error is:
        undefined method `synchronize' for #<Mutex:0xa0f5adc>
    If I search back over this list's archives, I can see a few other
    people
    with the same problem (but no solution).

I've tried removing all gems in case one of them was doing something strange. I've searched the Ruby source code, but I can't see anything that might cause this.

I can't even locate where the Mutex class gets "synchronize" added as a method to it. thread.c defines rb_mutex_synchronize, but Init_Thread therein doesn't appear to add it as a method on rb_cMutex.

I note that:

Mutex.new.method(:lock).source_location => nil
(2345).method(:to_s).source_location => nil

Yet:

Mutex.new.method(:synchronize).source_location => ["<internal:prelude>", 7]

So it's definitely special-cased in a way that may be affecting your ability to access it.

Arlen

Ah: prelude.rb defines Mutex#synchronize and Thread.exclusive in Ruby.

prelude.rb is called by Init_prelude(), generated by tool/compile_prelude.rb, itself called by ruby_init_prelude() (in ruby.c).

That in turn is called by ruby_process_options() (in ruby.c) which is called by ruby_options() (from eval.c). It's up to you which of the various ones you want to use, but ruby_init() followed by rb_eval_string() will leave you with a probably incomplete environment.

You're already calling ruby_init_loadpath() yourself, for example, which would normally be done for you by ruby_process_options().

(You could try the hacky method of calling ruby_init_prelude() yourself, too.)

Arlen

···

On Thursday, 22 November 2012 at 12:54 PM, Graham Menhennitt wrote:

On 21/11/2012 5:38 PM, Graham Menhennitt wrote:
> The error is: undefined method `synchronize' for #<Mutex:0xa0f5adc> If I search back over this list's archives, I can see a few other people with the same problem (but no solution). #include <ruby.h> int main(int argc, char *argv) { RUBY_INIT_STACK; ruby_init(); ruby_init_loadpath(); rb_eval_string("$mutex = Mutex.new"); rb_eval_string("$mutex.synchronize(){}"); return 0; } I've done a bit more investigation and found that it happens in all 1.9 releases of Ruby, but it does NOT happen in 1.8.7.

The test program below produces:
> [:locked?, :try_lock, :lock, :unlock, :sleep, :nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :to_s, :inspect, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :==, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]

Whereas running "ruby -e 'p Mutex.new.methods'" produces:
> [:locked?, :try_lock, :lock, :unlock, :sleep, :synchronize, :nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :to_s, :inspect, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :==, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]

Note that ":synchronize" is missing from the former.

I've tried removing all gems in case one of them was doing something strange. I've searched the Ruby source code, but I can't see anything that might cause this.

Anybody got any ideas? Should I take this to ruby.core?

Thanks,
Graham

Test program:
> #include <ruby.h>
>
> int
> main(int argc, char *argv)
> {
> RUBY_INIT_STACK;
> ruby_init();
> ruby_init_loadpath();
>
> rb_eval_string("p Mutex.new.methods");
>
> return 0;
> }

Thanks for replying, Arlen.

I added a call to ruby_init_prelude() but it isn't declared in ruby.h so I got a compilation error. I tried declaring it myself, but then it won't link because it's static in ruby.c.

I then tried calling ruby_process_options(int argc, char**argv). The first time I called it as ruby_process_options(0, 0). That causes a SEGV since it dereferences argv[0] even though argc is zero. This is arguably a bug, but anyway...

Next I called it with real argc and argv parameters with argc set to one - it hung reading from standard input (equivalent to just typing "ruby" at a shell prompt).

Finally, I faked the arguments as "ruby /dev/null" and it worked!!! I now get synchronized() defined. It's a bit clumsy having to fake the arguments, but beggars can't be choosers.

I'll go back to my original script and see whether it works.... Yes it does!

Thanks very much for your assistance,
     Graham

···

On 22/11/2012 1:09 PM, Arlen Cuss wrote:

Ah: prelude.rb defines Mutex#synchronize and Thread.exclusive in Ruby.

prelude.rb is called by Init_prelude(), generated by tool/compile_prelude.rb, itself called by ruby_init_prelude() (in ruby.c).

That in turn is called by ruby_process_options() (in ruby.c) which is called by ruby_options() (from eval.c). It's up to you which of the various ones you want to use, but ruby_init() followed by rb_eval_string() will leave you with a probably incomplete environment.

You're already calling ruby_init_loadpath() yourself, for example, which would normally be done for you by ruby_process_options().

(You could try the hacky method of calling ruby_init_prelude() yourself, too.)

Hi Graham,

I added a call to ruby_init_prelude() but it isn't declared in ruby.h so
I got a compilation error. I tried declaring it myself, but then it
won't link because it's static in ruby.c.

My bad—I didn't think to check the linkage; was assuming the ruby_ prefix implied it might be externally called.

Finally, I faked the arguments as "ruby /dev/null" and it worked!!! I
now get synchronized() defined. It's a bit clumsy having to fake the
arguments, but beggars can't be choosers.

It does seem like a less than perfect solution. :frowning: I note (re: your comment that derefing argv when argc==0 is probably a bug) that the offending line does have that somewhat cheeky comment, /* for the time being */.

I'll go back to my original script and see whether it works.... Yes it does!

Great! Super glad this has worked out well. :slight_smile:

Cheers,

Arlen

Yes, I saw that too - I'll file a defect against it. I'll also file one about having to do the fake argc/argv.

Anyway, just for completeness and for anybody else looking for a workaround, here is my working test program.

Graham

    #include <ruby.h>

    int
    main(int argc, char *argv)
    {
         RUBY_INIT_STACK;
         ruby_init();
         static char* args = { "ruby", "/dev/null" };
         ruby_process_options(2, args);

         rb_eval_string("p Mutex.new.methods");

         return 0;
    }

···

On 22/11/2012 2:07 PM, Arlen Cuss wrote:

It does seem like a less than perfect solution. :frowning: I note (re: your comment that derefing argv when argc==0 is probably a bug) that the offending line does have that somewhat cheeky comment, /* for the time being */.