Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Inside-Out Ruby: Using MRI as a C library

Inside-Out Ruby: Using MRI as a C library

Embedding Ruby in C: getting started, tips and tricks.

Arthur Pirogovski

March 19, 2013
Tweet

More Decks by Arthur Pirogovski

Other Decks in Programming

Transcript

  1. About me And C. segfault(87698) malloc: *** error for object

    0x7fff5dbad6c0: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug Abort trap: 6 Вівторок, 19 березня 13 р.
  2. About C concurrency is as good as your programming skills

    are Вівторок, 19 березня 13 р.
  3. About C conc is urrencyaods go amings your program ls

    askilre Вівторок, 19 березня 13 р.
  4. Native Extensions • great speedup • portability problems #ifdef •

    secret concurrency (don’t tell Ruby) Вівторок, 19 березня 13 р.
  5. Strings “much”*10 easier in Ruby than in char ** C

    Вівторок, 19 березня 13 р.
  6. Calling Ruby code - Hey, I’m C! (awkward silence) -

    Hey, I’m Ruby! Вівторок, 19 березня 13 р.
  7. Garbage Collector Very bad one, but still better than none

    Вівторок, 19 березня 13 р.
  8. Well-known APIs VALUE hash = rb_hash_new(); VALUE key = rb_string_new2(“key”);

    VALUE value = INT2FIX(42); rb_hash_aset(hash, key, value); rb_p(hash); Вівторок, 19 березня 13 р.
  9. MVP #ifdef __APPLE__ #define HAVE_STRUCT_TIMESPEC 1 #endif #include <ruby.h> int

    main() { ruby_init(); return 0; } Вівторок, 19 березня 13 р.
  10. MVP #ifdef __APPLE__ #define HAVE_STRUCT_TIMESPEC 1 #endif #include <ruby.h> int

    main() { ruby_init(); ruby_init_loadpath(); return 0; } Вівторок, 19 березня 13 р.
  11. MVP #ifdef __APPLE__ #define HAVE_STRUCT_TIMESPEC 1 #endif #include <ruby.h> int

    main() { ruby_init(); ruby_init_loadpath(); ruby_script("c.rb"); return 0; } Вівторок, 19 березня 13 р.
  12. MVP #ifdef __APPLE__ #define HAVE_STRUCT_TIMESPEC 1 #endif #include <ruby.h> int

    main() { ruby_init(); ruby_init_loadpath(); ruby_script("c.rb"); ruby_finalize(); return 0; } Вівторок, 19 березня 13 р.
  13. MVP #ifdef __APPLE__ #define HAVE_STRUCT_TIMESPEC 1 #endif #include <ruby.h> int

    main() { ruby_init(); ruby_init_loadpath(); ruby_script("c.rb"); VALUE ruby_string = rb_str_new2("Hi,I’m Ruby!"); rb_p(ruby_string); ruby_finalize(); return 0; } Вівторок, 19 березня 13 р.
  14. MVP $ gcc minimal_embedded_ruby.c \ -o meruby -lruby \ -I

    ${MY_RUBY_HOME}/include/ruby-1.9.1 -I ${MY_RUBY_HOME}/include/\ ruby-1.9.1/x86_64-linux \ -L $MY_RUBY_HOME/lib $ ./meruby "Hi from Ruby!" Note: $MY_RUBY_HOME is RVM-specific Вівторок, 19 березня 13 р.
  15. Warning #1 Ruby can only be initialized from the main

    thread Вівторок, 19 березня 13 р.
  16. Warning #2 DO NOT call ruby_run() It intercepts control flow

    and never returns. Вівторок, 19 березня 13 р.
  17. This will SEGFAULT int main() { ruby_init(); ruby_init_loadpath(); ruby_script("c.rb"); VALUE

    ruby_string = rb_str_new2("Hi,I’m Ruby!"); rb_p(ruby_string); rb_gc(); rb_p(ruby_string); /* Right here */ ruby_finalize(); return 0; } Вівторок, 19 березня 13 р.
  18. Registering vars #include <ruby.h> static VALUE ruby_objects; void lo(VALUE ruby_object)

    { rb_hash_aset(ruby_objects, rb_obj_id(ruby_object), ruby_object); } void uo(VALUE ruby_object) { rb_hash_delete(ruby_objects, rb_obj_id(ruby_object)); } Вівторок, 19 березня 13 р.
  19. Registering vars int main() { ruby_init(); ... ruby_objects = rb_hash_new();

    rb_global_variable(&ruby_objects); } Вівторок, 19 березня 13 р.
  20. Registering vars int main() { ruby_init(); ... ruby_objects = rb_hash_new();

    rb_global_variable(&ruby_objects); VALUE ruby_string = rb_str_new2("Hi from Ruby!"); } Вівторок, 19 березня 13 р.
  21. Registering vars int main() { ruby_init(); ... ruby_objects = rb_hash_new();

    rb_global_variable(&ruby_objects); VALUE ruby_string = rb_str_new2("Hi from Ruby!"); lo(ruby_string); rb_p(ruby_string); rb_gc(); } Вівторок, 19 березня 13 р.
  22. Registering vars int main() { ruby_init(); ... ruby_objects = rb_hash_new();

    rb_global_variable(&ruby_objects); VALUE ruby_string = rb_str_new2("Hi from Ruby!"); lo(ruby_string); rb_p(ruby_string); rb_gc(); rb_p(ruby_string); /* No SEGFAULT this time */ uo(ruby_string); ... } Вівторок, 19 березня 13 р.
  23. GC tips call rb_gc() to collect can also be invoked

    by Ruby itself Вівторок, 19 березня 13 р.
  24. GC tips always register variables rb_gc_register_address() is slow, so use

    some data structure Вівторок, 19 березня 13 р.
  25. GC tips run rb_gc() often to detect problems early automatic

    GC can be disabled (dangerous!) Вівторок, 19 березня 13 р.
  26. Exceptions int state = 0; rb_protect( RUBY_METHOD_FUNC(rb_require), (VALUE) “./code.rb”, &state);

    /* We couldn't execute rb_require */ if (state) { rb_p(rb_gv_get("$!")); exit(1); } Вівторок, 19 березня 13 р.
  27. Functions: exporting to Ruby static VALUE method_name_in_c(int argc, VALUE *

    argv, VALUE self) Вівторок, 19 березня 13 р.
  28. Speed For simple tasks, C-based loader is up to 4x

    faster Вівторок, 19 березня 13 р.
  29. Speed But for complex tasks, speed gain is only about

    15% Вівторок, 19 березня 13 р.
  30. Speed Pure C code is up to 15x times faster

    Вівторок, 19 березня 13 р.