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

Posted by Graham Menhennitt (Guest)
on 2012-11-21 07:38
(Received via mailing list)
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
Posted by Matthew Kerwin (mattyk)
on 2012-11-21 07:46
(Received via mailing list)
Is this thread related?

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


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

> #include <ruby.h>
>
>     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
Posted by Graham Menhennitt (Guest)
on 2012-11-21 08:25
(Received via mailing list)
On 21/11/2012 17:46, Matthew Kerwin wrote:
>     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).
>
Yes, that was one of the "few other people". But no solution to it.

Thanks for replying,
  Graham
Posted by Graham Menhennitt (Guest)
on 2012-11-22 02:54
(Received via mailing list)
On 21/11/2012 5:38 PM, Graham Menhennitt wrote:
>      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;
    }
Posted by Arlen Cuss (unnali)
on 2012-11-22 03:03
(Received via mailing list)
> 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
Posted by Arlen Cuss (unnali)
on 2012-11-22 03:10
(Received via mailing list)
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
Posted by Graham Menhennitt (Guest)
on 2012-11-22 04:01
(Received via mailing list)
On 22/11/2012 1:09 PM, Arlen Cuss wrote:
>
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
Posted by Arlen Cuss (unnali)
on 2012-11-22 04:07
(Received via mailing list)
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. :(  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. :)

Cheers,

Arlen
Posted by Graham Menhennitt (Guest)
on 2012-11-22 21:23
(Received via mailing list)
On 22/11/2012 2:07 PM, Arlen Cuss wrote:
> It does seem like a less than perfect solution. :( 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 */.
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;
    }
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.