Hello,

I am using ruby 1.9.0 (2007-12-25 revision 14709) [i686-linux].

I'm having trouble embedding Ruby inside a pthread because calling
ruby_sysinit() is segfaulting.  I created a small example to reproduce
the problem and illustrate my humble goal.

There are three files in this example:

  $ ls
  extconf.rb  hello.rb  main.c

First, we have a simple Ruby script:

  $ cat hello.rb
  puts "Hello World!"

Second, we have a Makefile generator:

  $ cat extconf.rb
  require 'mkmf'

  have_library('pthread', 'pthread_create')

  have_library('ruby', 'ruby_init') ||
  have_library('ruby-static', 'ruby_init')

  create_makefile('main')

Finally, we have a C program:

  $ cat main.c
  #include <stdio.h>
  #include <pthread.h>
  #include <ruby.h>

  RUBY_GLOBAL_SETUP

  pthread_t gRubyThread;
  pthread_mutex_t gCProgLock;

  void* gRubyThread_body(void* dummy)
  {
      int fake_argc = 0;
      char* fake_argv[1];

      printf("Ruby thread is calling ruby_sysinit()\n");
      ruby_sysinit(&fake_argc, &fake_argv);

      {
          printf("Ruby thread is calling RUBY_INIT_STACK()\n");
          RUBY_INIT_STACK;

          printf("Ruby thread is calling ruby_init()\n");
          ruby_init();

          char* file = "hello.rb"; // the file to run

          printf("Ruby interpreter is loading file: %s\n", file);
          void* node = rb_load_file(file);

          printf("Ruby thread is starting interpreter\n");
          ruby_run_node(node);
      }

      printf("Ruby thread is done, waking up C program...\n");
      pthread_mutex_unlock(&gCProgLock);
      return NULL;
  }

  int main(int argc, char** argv)
  {
      pthread_mutex_init(&gCProgLock, NULL);
      pthread_mutex_lock(&gCProgLock);

      printf("C program is putting Ruby thread in control...\n");

      pthread_create(&gRubyThread, NULL, gRubyThread_body, NULL);
      pthread_mutex_lock(&gCProgLock); // C program blocks here

      printf("C program is back in control, exiting...\n");
      return 0;
  }

This C program is very simple: it creates a new pthread and locks
itself.  (At this point, only the pthread in running.)  The pthread then
proceeds to embed a Ruby 1.9 interpreter inside itself and have the
interpreter run the "hello.rb" file.  Once this is complete, the pthread
unlocks the main C program and dies.  Finally, the main C program exits.

I should clarify that although the main.c in this example has argc and
argv, when I deploy my C extension as a .so file, I do not have any
access to the main() method of the C program.

For this reason, I did not pass the argc and argv from main() to the
body of the gRubyThread (because that is the real-life scenario of this
simple example).  And since ruby_sysinit() requires an argc and argv, I
was forced to fabricate them inside the body of gRubyThread.


Now let's try running this example.

Generate the makefile:

  $ ruby extconf.rb
  checking for pthread_create() in -lpthread... yes
  checking for ruby_init() in -lruby... no
  checking for ruby_init() in -lruby-static... yes
  creating Makefile

Build the C extension:

  $ make
  gcc -I. -I/home/sun/app/ruby19/include/ruby-1.9.0/i686-linux
-I/home/sun/app/ruby19/include/ruby-1.9.0 -I. -D_FILE_OFFSET_BITS=64
-fPIC -g -O2   -o main.o -c main.c
  main.c: In function 'gRubyThread_body':
  main.c:16: warning: passing argument 2 of 'ruby_sysinit' from
incompatible pointer type
  gcc -shared -o main.so main.o -L. -L/home/sun/app/ruby19/lib
-Wl,-R/home/sun/app/ruby19/lib -L.  -rdynamic -Wl,-export-dynamic
-lruby-static -lpthread  -lpthread -lrt -ldl -lcrypt -lm   -lc

Copy and paste the last gcc command from the output above.
Then remove the "-shared" option. And run the new command:

  $ gcc -o main.so main.o -L. -L/home/sun/app/ruby19/lib
-Wl,-R/home/sun/app/ruby19/lib -L.  -rdynamic -Wl,-export-dynamic
-lruby-static -lpthread  -lpthread -lrt -ldl -lcrypt -lm   -lc

Now run the C program:

  $ ./main.so
  C program is putting Ruby thread in control...
  Ruby thread is calling ruby_sysinit()
  Segmentation fault (core dumped)

As you can see, ruby_sysinit() core dumped on us.  Why?

Thanks for your consideration.