Ruby 1.9.3p327(2012-11-10revision37606)
ext/dl/dl.c
Go to the documentation of this file.
00001 /*
00002  * ext/dl/dl.c
00003  *
00004  * doumentation:
00005  * - Vincent Batts (vbatts@hashbangbash.com)
00006  *
00007  */
00008 #include <ruby/ruby.h>
00009 #include <ruby/io.h>
00010 #include <ctype.h>
00011 #include "dl.h"
00012 
00013 VALUE rb_mDL;
00014 VALUE rb_eDLError;
00015 VALUE rb_eDLTypeError;
00016 
00017 ID rbdl_id_cdecl;
00018 ID rbdl_id_stdcall;
00019 
00020 VALUE
00021 rb_dl_dlopen(int argc, VALUE argv[], VALUE self)
00022 {
00023     return rb_class_new_instance(argc, argv, rb_cDLHandle);
00024 }
00025 
00026 /*
00027  * call-seq: DL.malloc
00028  *
00029  * Allocate +size+ bytes of memory and return the integer memory address
00030  * for the allocated memory.
00031  */
00032 VALUE
00033 rb_dl_malloc(VALUE self, VALUE size)
00034 {
00035     void *ptr;
00036 
00037     rb_secure(4);
00038     ptr = (void*)ruby_xmalloc(NUM2INT(size));
00039     return PTR2NUM(ptr);
00040 }
00041 
00042 /*
00043  * call-seq: DL.realloc(addr, size)
00044  *
00045  * Change the size of the memory allocated at the memory location +addr+ to
00046  * +size+ bytes.  Returns the memory address of the reallocated memory, which
00047  * may be different than the address passed in.
00048  */
00049 VALUE
00050 rb_dl_realloc(VALUE self, VALUE addr, VALUE size)
00051 {
00052     void *ptr = NUM2PTR(addr);
00053 
00054     rb_secure(4);
00055     ptr = (void*)ruby_xrealloc(ptr, NUM2INT(size));
00056     return PTR2NUM(ptr);
00057 }
00058 
00059 /*
00060  * call-seq: DL.free(addr)
00061  *
00062  * Free the memory at address +addr+
00063  */
00064 VALUE
00065 rb_dl_free(VALUE self, VALUE addr)
00066 {
00067     void *ptr = NUM2PTR(addr);
00068 
00069     rb_secure(4);
00070     ruby_xfree(ptr);
00071     return Qnil;
00072 }
00073 
00074 VALUE
00075 rb_dl_ptr2value(VALUE self, VALUE addr)
00076 {
00077     rb_secure(4);
00078     return (VALUE)NUM2PTR(addr);
00079 }
00080 
00081 VALUE
00082 rb_dl_value2ptr(VALUE self, VALUE val)
00083 {
00084     return PTR2NUM((void*)val);
00085 }
00086 
00087 static void
00088 rb_dl_init_callbacks(VALUE dl)
00089 {
00090     static const char cb[] = "dl/callback.so";
00091 
00092     rb_autoload(dl, rb_intern_const("CdeclCallbackAddrs"), cb);
00093     rb_autoload(dl, rb_intern_const("CdeclCallbackProcs"), cb);
00094 #ifdef FUNC_STDCALL
00095     rb_autoload(dl, rb_intern_const("StdcallCallbackAddrs"), cb);
00096     rb_autoload(dl, rb_intern_const("StdcallCallbackProcs"), cb);
00097 #endif
00098 }
00099 
00100 void
00101 Init_dl(void)
00102 {
00103     void Init_dlhandle(void);
00104     void Init_dlcfunc(void);
00105     void Init_dlptr(void);
00106 
00107     rbdl_id_cdecl = rb_intern_const("cdecl");
00108     rbdl_id_stdcall = rb_intern_const("stdcall");
00109 
00110     /* Document-module: DL
00111      *
00112      * A bridge to the dlopen() or dynamic library linker function.
00113      *
00114      * == Example
00115      *
00116      *   bash $> cat > sum.c <<EOF
00117      *   double sum(double *arry, int len)
00118      *   {
00119      *           double ret = 0;
00120      *           int i;
00121      *           for(i = 0; i < len; i++){
00122      *                   ret = ret + arry[i];
00123      *           }
00124      *           return ret;
00125      *   }
00126      *
00127      *   double split(double num)
00128      *   {
00129      *           double ret = 0;
00130      *           ret = num / 2;
00131      *           return ret;
00132      *   }
00133      *   EOF
00134      *   bash $> gcc -o libsum.so -shared sum.c
00135      *   bash $> cat > sum.rb <<EOF
00136      *   require 'dl'
00137      *   require 'dl/import'
00138      *
00139      *   module LibSum
00140      *           extend DL::Importer
00141      *           dlload './libsum.so'
00142      *           extern 'double sum(double*, int)'
00143      *           extern 'double split(double)'
00144      *   end
00145      *
00146      *   a = [2.0, 3.0, 4.0]
00147      *
00148      *   sum = LibSum.sum(a.pack("d*"), a.count)
00149      *   p LibSum.split(sum)
00150      *   EOF
00151      *   bash $> ruby sum.rb
00152      *   4.5
00153      *
00154      * WIN! :-)
00155      */
00156     rb_mDL = rb_define_module("DL");
00157 
00158     /*
00159      * Document-class: DL::DLError
00160      *
00161      * standard dynamic load exception
00162      */
00163     rb_eDLError = rb_define_class_under(rb_mDL, "DLError", rb_eStandardError);
00164 
00165     /*
00166      * Document-class: DL::DLTypeError
00167      *
00168      * dynamic load incorrect type exception
00169      */
00170     rb_eDLTypeError = rb_define_class_under(rb_mDL, "DLTypeError", rb_eDLError);
00171 
00172     /* Document-const: MAX_CALLBACK
00173      *
00174      * Maximum number of callbacks
00175      */
00176     rb_define_const(rb_mDL, "MAX_CALLBACK", INT2NUM(MAX_CALLBACK));
00177 
00178     /* Document-const: DLSTACK_SIZE
00179      *
00180      * Dynamic linker stack size
00181      */
00182     rb_define_const(rb_mDL, "DLSTACK_SIZE", INT2NUM(DLSTACK_SIZE));
00183 
00184     rb_dl_init_callbacks(rb_mDL);
00185 
00186     /* Document-const: RTLD_GLOBAL
00187      *
00188      * rtld DL::Handle flag.
00189      *
00190      * The symbols defined by this library will be made available for symbol
00191      * resolution of subsequently loaded libraries.
00192      */
00193     rb_define_const(rb_mDL, "RTLD_GLOBAL", INT2NUM(RTLD_GLOBAL));
00194 
00195     /* Document-const: RTLD_LAZY
00196      *
00197      * rtld DL::Handle flag.
00198      *
00199      * Perform lazy binding.  Only resolve symbols as the code that references
00200      * them is executed.  If the  symbol is never referenced, then it is never
00201      * resolved.  (Lazy binding is only performed for function references;
00202      * references to variables are always immediately bound when the library
00203      * is loaded.)
00204      */
00205     rb_define_const(rb_mDL, "RTLD_LAZY",   INT2NUM(RTLD_LAZY));
00206 
00207     /* Document-const: RTLD_NOW
00208      *
00209      * rtld DL::Handle flag.
00210      *
00211      * If this value is specified or the environment variable LD_BIND_NOW is
00212      * set to a nonempty string, all undefined symbols in the library are
00213      * resolved before dlopen() returns.  If this cannot be done an error is
00214      * returned.
00215      */
00216     rb_define_const(rb_mDL, "RTLD_NOW",    INT2NUM(RTLD_NOW));
00217 
00218     /* Document-const: TYPE_VOID
00219      *
00220      * DL::CFunc type - void
00221      */
00222     rb_define_const(rb_mDL, "TYPE_VOID",  INT2NUM(DLTYPE_VOID));
00223 
00224     /* Document-const: TYPE_VOIDP
00225      *
00226      * DL::CFunc type - void*
00227      */
00228     rb_define_const(rb_mDL, "TYPE_VOIDP",  INT2NUM(DLTYPE_VOIDP));
00229 
00230     /* Document-const: TYPE_CHAR
00231      *
00232      * DL::CFunc type - char
00233      */
00234     rb_define_const(rb_mDL, "TYPE_CHAR",  INT2NUM(DLTYPE_CHAR));
00235 
00236     /* Document-const: TYPE_SHORT
00237      *
00238      * DL::CFunc type - short
00239      */
00240     rb_define_const(rb_mDL, "TYPE_SHORT",  INT2NUM(DLTYPE_SHORT));
00241 
00242     /* Document-const: TYPE_INT
00243      *
00244      * DL::CFunc type - int
00245      */
00246     rb_define_const(rb_mDL, "TYPE_INT",  INT2NUM(DLTYPE_INT));
00247 
00248     /* Document-const: TYPE_LONG
00249      *
00250      * DL::CFunc type - long
00251      */
00252     rb_define_const(rb_mDL, "TYPE_LONG",  INT2NUM(DLTYPE_LONG));
00253 
00254 #if HAVE_LONG_LONG
00255     /* Document-const: TYPE_LONG_LONG
00256      *
00257      * DL::CFunc type - long long
00258      */
00259     rb_define_const(rb_mDL, "TYPE_LONG_LONG",  INT2NUM(DLTYPE_LONG_LONG));
00260 #endif
00261 
00262     /* Document-const: TYPE_FLOAT
00263      *
00264      * DL::CFunc type - float
00265      */
00266     rb_define_const(rb_mDL, "TYPE_FLOAT",  INT2NUM(DLTYPE_FLOAT));
00267 
00268     /* Document-const: TYPE_DOUBLE
00269      *
00270      * DL::CFunc type - double
00271      */
00272     rb_define_const(rb_mDL, "TYPE_DOUBLE",  INT2NUM(DLTYPE_DOUBLE));
00273 
00274     /* Document-const: ALIGN_VOIDP
00275      *
00276      * The Offset of a struct void* and a void*
00277      */
00278     rb_define_const(rb_mDL, "ALIGN_VOIDP", INT2NUM(ALIGN_VOIDP));
00279 
00280     /* Document-const: ALIGN_CHAR
00281      *
00282      * The Offset of a struct char and a char
00283      */
00284     rb_define_const(rb_mDL, "ALIGN_CHAR",  INT2NUM(ALIGN_CHAR));
00285 
00286     /* Document-const: ALIGN_SHORT
00287      *
00288      * The Offset of a struct short and a short
00289      */
00290     rb_define_const(rb_mDL, "ALIGN_SHORT", INT2NUM(ALIGN_SHORT));
00291 
00292     /* Document-const: ALIGN_INT
00293      *
00294      * The Offset of a struct int and a int
00295      */
00296     rb_define_const(rb_mDL, "ALIGN_INT",   INT2NUM(ALIGN_INT));
00297 
00298     /* Document-const: ALIGN_LONG
00299      *
00300      * The Offset of a struct long and a long
00301      */
00302     rb_define_const(rb_mDL, "ALIGN_LONG",  INT2NUM(ALIGN_LONG));
00303 
00304 #if HAVE_LONG_LONG
00305     /* Document-const: ALIGN_LONG_LONG
00306      *
00307      * The Offset of a struct long long and a long long
00308      */
00309     rb_define_const(rb_mDL, "ALIGN_LONG_LONG",  INT2NUM(ALIGN_LONG_LONG));
00310 #endif
00311 
00312     /* Document-const: ALIGN_FLOAT
00313      *
00314      * The Offset of a struct float and a float
00315      */
00316     rb_define_const(rb_mDL, "ALIGN_FLOAT", INT2NUM(ALIGN_FLOAT));
00317 
00318     /* Document-const: ALIGN_DOUBLE
00319      *
00320      * The Offset of a struct double and a double
00321      */
00322     rb_define_const(rb_mDL, "ALIGN_DOUBLE",INT2NUM(ALIGN_DOUBLE));
00323 
00324     /* Document-const: SIZEOF_VOIDP
00325      *
00326      * OS Dependent - sizeof(void*)
00327      */
00328     rb_define_const(rb_mDL, "SIZEOF_VOIDP", INT2NUM(sizeof(void*)));
00329 
00330     /* Document-const: SIZEOF_CHAR
00331      *
00332      * OS Dependent - sizeof(char)
00333      */
00334     rb_define_const(rb_mDL, "SIZEOF_CHAR",  INT2NUM(sizeof(char)));
00335 
00336     /* Document-const: SIZEOF_SHORT
00337      *
00338      * OS Dependent - sizeof(short)
00339      */
00340     rb_define_const(rb_mDL, "SIZEOF_SHORT", INT2NUM(sizeof(short)));
00341 
00342     /* Document-const: SIZEOF_INT
00343      *
00344      * OS Dependent - sizeof(int)
00345      */
00346     rb_define_const(rb_mDL, "SIZEOF_INT",   INT2NUM(sizeof(int)));
00347 
00348     /* Document-const: SIZEOF_LONG
00349      *
00350      * OS Dependent - sizeof(long)
00351      */
00352     rb_define_const(rb_mDL, "SIZEOF_LONG",  INT2NUM(sizeof(long)));
00353 
00354 #if HAVE_LONG_LONG
00355     /* Document-const: SIZEOF_LONG_LONG
00356      *
00357      * OS Dependent - sizeof(long long)
00358      */
00359     rb_define_const(rb_mDL, "SIZEOF_LONG_LONG",  INT2NUM(sizeof(LONG_LONG)));
00360 #endif
00361 
00362     /* Document-const: SIZEOF_FLOAT
00363      *
00364      * OS Dependent - sizeof(float)
00365      */
00366     rb_define_const(rb_mDL, "SIZEOF_FLOAT", INT2NUM(sizeof(float)));
00367 
00368     /* Document-const: SIZEOF_DOUBLE
00369      *
00370      * OS Dependent - sizeof(double)
00371      */
00372     rb_define_const(rb_mDL, "SIZEOF_DOUBLE",INT2NUM(sizeof(double)));
00373 
00374     rb_define_module_function(rb_mDL, "dlwrap", rb_dl_value2ptr, 1);
00375     rb_define_module_function(rb_mDL, "dlunwrap", rb_dl_ptr2value, 1);
00376 
00377     rb_define_module_function(rb_mDL, "dlopen", rb_dl_dlopen, -1);
00378     rb_define_module_function(rb_mDL, "malloc", rb_dl_malloc, 1);
00379     rb_define_module_function(rb_mDL, "realloc", rb_dl_realloc, 2);
00380     rb_define_module_function(rb_mDL, "free", rb_dl_free, 1);
00381 
00382     /* Document-const: RUBY_FREE
00383      *
00384      * Address of the ruby_xfree() function
00385      */
00386     rb_define_const(rb_mDL, "RUBY_FREE", PTR2NUM(ruby_xfree));
00387 
00388     /* Document-const: BUILD_RUBY_PLATFORM
00389      *
00390      * Platform built against (i.e. "x86_64-linux", etc.)
00391      *
00392      * See also RUBY_PLATFORM
00393      */
00394     rb_define_const(rb_mDL, "BUILD_RUBY_PLATFORM", rb_str_new2(RUBY_PLATFORM));
00395 
00396     /* Document-const: BUILD_RUBY_VERSION
00397      *
00398      * Ruby Version built. (i.e. "1.9.3")
00399      *
00400      * See also RUBY_VERSION
00401      */
00402     rb_define_const(rb_mDL, "BUILD_RUBY_VERSION",  rb_str_new2(RUBY_VERSION));
00403 
00404     Init_dlhandle();
00405     Init_dlcfunc();
00406     Init_dlptr();
00407 }
00408