From: "Suraj N. Kurapati" Date: 2008-03-14T15:04:40+09:00 Subject: Re: embedding Ruby 1.9.0 inside pthread Suraj N. Kurapati wrote: > Below is the revised (and more complex) > example that better shows the Ruby/C interaction of my final program. Whoops, the example had some redundant statements (in the Ruby pthread body) that were never executed. Below is the corrected code. Sorry for the confusion. > One discrepancy I noticed is that this program works correctly with > ruby-1.9.0-0 but crashes with the new ruby-1.9.0-1 release. For > instance, here is the response when running with ruby-1.9.0-0: The new response with ruby-1.9.0-0 is: $ ./main.so C program is calling RUBY_INIT_STACK() C program is calling ruby_init() C program is registering Object#relay_to_c method C program is loading file: hello.rb Ruby thread has been started, but is paused. C program relaying to Ruby thread... 1st time Ruby thread is starting interpreter... rubygems OK! {:$0=>"hello.rb"} {:ARGV=>[]} ------------------------------------------------------------ Hello World! 0 C program relaying to Ruby thread... 2nd time Hello World! 1 C program relaying to Ruby thread... 3rd time Hello World! 2 C program relaying to Ruby thread... last time Ruby thread is done, goodbye C program... C program is back in control, exiting... And with ruby-1.9.0-1 is: $ ./main.so C program is calling RUBY_INIT_STACK() C program is calling ruby_init() C program is registering Object#relay_to_c method C program is loading file: hello.rb Ruby thread has been started, but is paused. C program relaying to Ruby thread... 1st time Ruby thread is starting interpreter... :17: SystemStackError Ruby thread is done, goodbye C program... C program relaying to Ruby thread... 2nd time [Control-C] At this point, the C program is hung waiting for the Ruby thread which has already terminated. So I had to kill it manually. Why does ruby_run_node() cause a SystemStackError in ruby-1.9.0-1? Is embedding ruby-1.9 inside a pthread no longer possible starting from the ruby-1.9.0-1 release? Thanks for your consideration. --- Corrected example code: $ cat hello.rb require 'rubygems' puts "rubygems OK!" p :'$0' => $0 p :ARGV => ARGV puts '-' * 60 3.times do |i| puts "Hello World! #{i}" relay_to_c end $ cat main.c #include #include #include #include pthread_t gRubyThread; pthread_mutex_t gRubyLock; pthread_cond_t gRubyCond; bool gRubyRunning; /// /// Transfers control from the Ruby script /// to the C program and pauses Ruby. /// VALUE relay_to_c(VALUE); /// /// Transfers control from the Ruby thread /// to the C program and pauses Ruby. /// void relay_from_ruby_to_c(); /// /// Transfers control from the C program to /// the Ruby thread and pauses the C program. /// void relay_from_c_to_ruby(); /// /// Makes the C program wait until the Ruby /// thread finishes running (for now). /// void wait_for_ruby(); /// /// Tells the C program that the Ruby /// thread has finished running (for now). /// void ruby_is_done(); /// /// Makes the Ruby thread wait until the /// C program finishes running (for now). /// void wait_for_c(); /// /// Tells the Ruby thread that the C /// program has finished running (for now). /// void c_is_done(); /// /// Body of the pthread which hosts the /// Ruby interpreter's flow of execution. /// /// aRubyProgram:: program node for the interpreter to run /// void* the_ruby_thread(void* aRubyProgram) { printf("Ruby thread has been started, but is paused.\n"); relay_from_ruby_to_c(); printf("Ruby thread is starting interpreter...\n"); ruby_run_node(aRubyProgram); printf("Ruby thread is done, goodbye C program...\n"); ruby_is_done(); pthread_exit(NULL); } RUBY_GLOBAL_SETUP void the_c_program() { char* file = "hello.rb"; // the file to run int fake_argc = 2; char* fake_args[fake_argc]; fake_args[0] = file; // $0 - name of the program fake_args[1] = file; char** fake_argv = fake_args; printf("C program is calling RUBY_INIT_STACK()\n"); RUBY_INIT_STACK; printf("C program is calling ruby_init()\n"); ruby_init(); printf("C program is registering Object#relay_to_c method\n"); rb_define_module_function(rb_cObject, "relay_to_c", relay_to_c, 0); printf("C program is loading file: %s\n", file); void* rubyProgram = ruby_options(fake_argc, fake_argv); pthread_mutex_init(&gRubyLock, NULL); pthread_cond_init(&gRubyCond, NULL); gRubyRunning = true; pthread_create(&gRubyThread, NULL, the_ruby_thread, rubyProgram); wait_for_ruby(); printf("C program relaying to Ruby thread... 1st time\n"); relay_from_c_to_ruby(); // C program blocks here printf("C program relaying to Ruby thread... 2nd time\n"); relay_from_c_to_ruby(); // C program blocks here printf("C program relaying to Ruby thread... 3rd time\n"); relay_from_c_to_ruby(); // C program blocks here printf("C program relaying to Ruby thread... last time\n"); relay_from_c_to_ruby(); // C program blocks here printf("C program is back in control, exiting...\n"); pthread_mutex_destroy(&gRubyLock); pthread_cond_destroy(&gRubyCond); } int main(int argc, char** argv) { the_c_program(); return 0; } VALUE relay_to_c(VALUE self) { relay_from_ruby_to_c(); return self; } void relay_from_ruby_to_c() { ruby_is_done(); wait_for_c(); } void ruby_is_done() { pthread_mutex_lock(&gRubyLock); { gRubyRunning = false; pthread_cond_signal(&gRubyCond); } pthread_mutex_unlock(&gRubyLock); } void wait_for_c() { pthread_mutex_lock(&gRubyLock); { while (!gRubyRunning) { pthread_cond_wait(&gRubyCond, &gRubyLock); } } pthread_mutex_unlock(&gRubyLock); } void relay_from_c_to_ruby() { c_is_done(); wait_for_ruby(); } void c_is_done() { pthread_mutex_lock(&gRubyLock); { gRubyRunning = true; pthread_cond_signal(&gRubyCond); } pthread_mutex_unlock(&gRubyLock); } void wait_for_ruby() { pthread_mutex_lock(&gRubyLock); { while (gRubyRunning) { pthread_cond_wait(&gRubyCond, &gRubyLock); } } pthread_mutex_unlock(&gRubyLock); }