SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our User Agreement and Privacy Policy.
SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our Privacy Policy and User Agreement for details.
Successfully reported this slideshow.
Activate your 30 day free trial to unlock unlimited reading.
Inside Out Ruby: Using MRI as a C library - Artur Pyrogovskyi
Inside Out Ruby: Using MRI as a C library - Artur Pyrogovskyi
1.
Вівторок, 19 березня 13 р.
2.
Inside-Out Ruby: Using
MRI as a C library
Вівторок, 19 березня 13 р.
3.
About me
Arthur Pirogovski
arthur@flyintealeaf.com
Вівторок, 19 березня 13 р.
4.
About me
Coding for , mostly Ruby.
Вівторок, 19 березня 13 р.
5.
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 р.
18.
Native Extensions
• great speedup
•
•
Вівторок, 19 березня 13 р.
19.
Native Extensions
• great speedup
• portability problems #ifdef
•
Вівторок, 19 березня 13 р.
20.
Native Extensions
• great speedup
• portability problems #ifdef
• secret concurrency (don’t tell Ruby)
Вівторок, 19 березня 13 р.
21.
What if we turn it
inside out?
Вівторок, 19 березня 13 р.
22.
Strings
“much”*10 easier in Ruby
than in char ** C
Вівторок, 19 березня 13 р.
23.
DSL
Turing-complete out of the box
Вівторок, 19 березня 13 р.
24.
DSL
Turing-complete out of the box
Pretty like drugs
Вівторок, 19 березня 13 р.
25.
Calling Ruby code
- Hey, I’m C!
(awkward silence)
- Hey, I’m Ruby!
Вівторок, 19 березня 13 р.
26.
Garbage Collector
Very bad one, but still better than none
Вівторок, 19 березня 13 р.
27.
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 р.
28.
MVP
#ifdef __APPLE__
#define HAVE_STRUCT_TIMESPEC 1
#endif
Вівторок, 19 березня 13 р.
29.
MVP
#ifdef __APPLE__
#define HAVE_STRUCT_TIMESPEC 1
#endif
#include <ruby.h>
Вівторок, 19 березня 13 р.
30.
MVP
#ifdef __APPLE__
#define HAVE_STRUCT_TIMESPEC 1
#endif
#include <ruby.h>
int main() {
ruby_init();
return 0;
}
Вівторок, 19 березня 13 р.
31.
MVP
#ifdef __APPLE__
#define HAVE_STRUCT_TIMESPEC 1
#endif
#include <ruby.h>
int main() {
ruby_init();
ruby_init_loadpath();
return 0;
}
Вівторок, 19 березня 13 р.
32.
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 р.
33.
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 р.
34.
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 р.
35.
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 р.
36.
Warning #1
Ruby can only be initialized
from the main thread
Вівторок, 19 березня 13 р.
37.
Warning #2
DO NOT call ruby_run()
It intercepts control flow and never returns.
Вівторок, 19 березня 13 р.
39.
Memory
management
not fun.
Вівторок, 19 березня 13 р.
40.
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 р.
41.
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 р.
42.
Registering vars
int main() {
ruby_init();
...
ruby_objects = rb_hash_new();
rb_global_variable(&ruby_objects);
}
Вівторок, 19 березня 13 р.
43.
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 р.
44.
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 р.
45.
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 р.
46.
GC tips
call rb_gc() to collect
can also be invoked by Ruby itself
Вівторок, 19 березня 13 р.
47.
GC tips
always register variables
rb_gc_register_address() is slow,
so use some data structure
Вівторок, 19 березня 13 р.
48.
GC tips
run rb_gc() often to detect problems early
automatic GC can be disabled (dangerous!)
Вівторок, 19 березня 13 р.
50.
Exceptions
are evil.
Вівторок, 19 березня 13 р.
51.
Exceptions
rb_raise()
rb_rescue()
rb_ensure()
Вівторок, 19 березня 13 р.
52.
Exceptions
rb_raise() is a longjmp()
longjmp() skips your free()’s
Вівторок, 19 березня 13 р.
53.
Exceptions
rb_protect() is a good catch-all wrapper
Вівторок, 19 березня 13 р.
54.
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 р.
55.
Functions:
calling from C
VALUE new_object =
rb_funcall(some_class,
rb_intern("new"), 1, arg1);
Вівторок, 19 березня 13 р.
56.
Functions:
exporting to Ruby
rb_define_singleton_method(
some_class, “method_name”,
method_name_in_c, -1)
Вівторок, 19 березня 13 р.
57.
Functions:
exporting to Ruby
static VALUE
method_name_in_c(int argc,
VALUE * argv, VALUE self)
Вівторок, 19 березня 13 р.
58.
Functions:
exporting to Ruby
rb_scan_args(argc, argv,
“11”, &arg1, &arg2);
Вівторок, 19 березня 13 р.
59.
Speed
For simple tasks,
C-based loader is up to 4x faster
Вівторок, 19 березня 13 р.
60.
Speed
But for complex tasks,
speed gain is only about 15%
Вівторок, 19 березня 13 р.
61.
Speed
Pure C code is up to 15x times faster
Вівторок, 19 березня 13 р.
62.
Docs
README.EXT
Vim’s if_ruby.c
Ruby source code
Вівторок, 19 березня 13 р.
63.
Examples
https://github.com/arp/ruby_from_c
Вівторок, 19 березня 13 р.