ruby picture

RCR 330: A way to export symbols from binary extensions

Submitted by Vince (Mon Apr 10 21:07:41 UTC 2006)

Abstract

It is not easy and really platform-dependent to use C code from one ruby extension into another one. I propose a simple mechanism by which a binary extension can declare exports in a module/class that another binary extension can use.

Problem

It sometimes can be necessary (for speed issues) or simply really convenient to use C functions declared in one C extension from another C extension, without having to go through real Ruby functions.

For instance, a class doing some mathematical computations could rely heavily on few internals of an extension for manipulating vectors of numbers.

It is for now really difficult to do that in a way that is platform dependent: as it is really easy to do that under Linux, and reasonably easy to do that under MacOS (X), it comes much more difficult under Win32, as the dynamic linker doesn't behave at all like in the two others.

Proposal

I propose a simple mechanism to export and import symbols. An extension using a function symbol useful for other extentsions based on it could declare:

  rb_export_symbol(module, "symbol", &symbol);

And another one based on the first could make use of the function with the simple following code:

  symbol = rb_import_symbol(module, "symbol");

These two functions simply provide a C-level access returning the right types to a class/module hash which could be called for instance @@_exported_C_symbols.

This is a transparent change, as only the extensions which will make use of this system will have a special meaning of the variable @@_exported_C_symbols.

Analysis

This can't be done at the level of an extension, as we precisely need C functions to get the symbols with the right type. That's the reason why a language-level implementation should be necessary.

Moreover, the code is really light and shouldn't be a burden on any architecture, while it will definitely provide a great speed improvement for certain extensions.

Implementation

The following code is extracted from :

 #define MV_SYMBOLS "@@_exported_C_symbols"
 /* makes sure that the hash is registered for the given
    module and returns it */ 
 static VALUE get_symbol_hash(VALUE module)
 {
   VALUE hash = rb_iv_get(module, MV_SYMBOLS);
   if(NIL_P(hash))
     {
       /* Then, we create it */
       hash = rb_hash_new();
       rb_iv_set(module, MV_SYMBOLS, hash);
       return hash;
     }
   else 
     {
       Check_Type(hash, T_HASH);
       return hash;
     }
 } 
 /* registers a symbol in the given module.*/
 void rb_export_symbol(VALUE module, 
                       const char * symbol_name,
                       void * symbol)
 {
   VALUE hash = get_symbol_hash(module);
   rb_hash_aset(hash, rb_str_new2(symbol_name),
                INT2NUM((int)  symbol));
 }
 void * rb_import_symbol(VALUE module,
                         const char * symbol_name)
 {
   VALUE hash = rb_iv_get(module, MV_SYMBOLS);
   if(TYPE(hash) != T_HASH) 
     return NULL; /* doesn't fail, but the importing module
                    should definitely check the 
                    return value. Beware of segfaults ! */
   VALUE symbol = rb_hash_aref(hash,
                              rb_str_new2(symbol_name));
   if(TYPE(symbol) == T_FIXNUM || TYPE(symbol) == T_BIGNUM)
     return (void *) NUM2INT(symbol);
   return NULL;
 }

You can also find some (simple) examples of use in that repository.

ruby picture
Comments Current voting
Strongly opposed 0
Opposed 0
Neutral 1
In favor 0
Strongly advocate 0
ruby picture
If you have registered at RCRchive, you may now sign in below. If you have not registered, you may sign up for a username and password. Registering enables you to submit new RCRs, and vote and leave comments on existing RCRs.
Your username:
Your password:

ruby picture

Powered by .