Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/dl/handle.c

Go to the documentation of this file.

    00001 /* -*- C -*-
    00002  * $Id: handle.c 28736 2010-07-24 05:33:17Z yugui $
    00003  */
    00004
    00005 #include <ruby.h>
    00006 #include "dl.h"
    00007
    00008 VALUE rb_cDLHandle;
    00009
    00010 #ifdef HAVE_WINDOWS_H
    00011 # ifndef _WIN32_WCE
    00012 static void *
    00013 w32_coredll(void)
    00014 {
    00015     MEMORY_BASIC_INFORMATION m;
    00016     memset(&m, 0, sizeof(m));
    00017     if( !VirtualQuery(_errno, &m, sizeof(m)) ) return NULL;
    00018     return m.AllocationBase;
    00019 }
    00020 # endif
    00021
    00022 static int
    00023 w32_dlclose(void *ptr)
    00024 {
    00025 # ifndef _WIN32_WCE
    00026     if( ptr == w32_coredll() ) return 0;
    00027 # endif
    00028     if( FreeLibrary((HMODULE)ptr) ) return 0;
    00029     return errno = rb_w32_map_errno(GetLastError());
    00030 }
    00031 #define dlclose(ptr) w32_dlclose(ptr)
    00032 #endif
    00033
    00034 static void
    00035 dlhandle_free(void *ptr)
    00036 {
    00037     struct dl_handle *dlhandle = ptr;
    00038     if( dlhandle->ptr && dlhandle->open && dlhandle->enable_close ){
    00039         dlclose(dlhandle->ptr);
    00040     }
    00041 }
    00042
    00043 static size_t
    00044 dlhandle_memsize(const void *ptr)
    00045 {
    00046     return ptr ? sizeof(struct dl_handle) : 0;
    00047 }
    00048
    00049 static const rb_data_type_t dlhandle_data_type = {
    00050     "dl/handle",
    00051     0, dlhandle_free, dlhandle_memsize,
    00052 };
    00053
    00054 /*
    00055  * call-seq: close
    00056  *
    00057  * Close this DL::Handle.  Calling close more than once will raise a
    00058  * DL::DLError exception.
    00059  */
    00060 VALUE
    00061 rb_dlhandle_close(VALUE self)
    00062 {
    00063     struct dl_handle *dlhandle;
    00064
    00065     TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
    00066     if(dlhandle->open) {
    00067         int ret = dlclose(dlhandle->ptr);
    00068         dlhandle->open = 0;
    00069
    00070         /* Check dlclose for successful return value */
    00071         if(ret) {
    00072 #if defined(HAVE_DLERROR)
    00073             rb_raise(rb_eDLError, "%s", dlerror());
    00074 #else
    00075             rb_raise(rb_eDLError, "could not close handle");
    00076 #endif
    00077         }
    00078         return INT2NUM(ret);
    00079     }
    00080     rb_raise(rb_eDLError, "dlclose() called too many times");
    00081 }
    00082
    00083 VALUE
    00084 rb_dlhandle_s_allocate(VALUE klass)
    00085 {
    00086     VALUE obj;
    00087     struct dl_handle *dlhandle;
    00088
    00089     obj = TypedData_Make_Struct(rb_cDLHandle, struct dl_handle, &dlhandle_data_type, dlhandle);
    00090     dlhandle->ptr  = 0;
    00091     dlhandle->open = 0;
    00092     dlhandle->enable_close = 0;
    00093
    00094     return obj;
    00095 }
    00096
    00097 static VALUE
    00098 predefined_dlhandle(void *handle)
    00099 {
    00100     VALUE obj = rb_dlhandle_s_allocate(rb_cDLHandle);
    00101     struct dl_handle *dlhandle = DATA_PTR(obj);
    00102
    00103     dlhandle->ptr = handle;
    00104     dlhandle->open = 1;
    00105     OBJ_FREEZE(obj);
    00106     return obj;
    00107 }
    00108
    00109 /*
    00110  * call-seq:
    00111  *    initialize(lib = nil, flags = DL::RTLD_LAZY | DL::RTLD_GLOBAL)
    00112  *
    00113  * Create a new handler that opens library named +lib+ with +flags+.  If no
    00114  * library is specified, RTLD_DEFAULT is used.
    00115  */
    00116 VALUE
    00117 rb_dlhandle_initialize(int argc, VALUE argv[], VALUE self)
    00118 {
    00119     void *ptr;
    00120     struct dl_handle *dlhandle;
    00121     VALUE lib, flag;
    00122     char  *clib;
    00123     int   cflag;
    00124     const char *err;
    00125
    00126     switch( rb_scan_args(argc, argv, "02", &lib, &flag) ){
    00127       case 0:
    00128         clib = NULL;
    00129         cflag = RTLD_LAZY | RTLD_GLOBAL;
    00130         break;
    00131       case 1:
    00132         clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
    00133         cflag = RTLD_LAZY | RTLD_GLOBAL;
    00134         break;
    00135       case 2:
    00136         clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
    00137         cflag = NUM2INT(flag);
    00138         break;
    00139       default:
    00140         rb_bug("rb_dlhandle_new");
    00141     }
    00142
    00143     rb_secure(2);
    00144
    00145 #if defined(HAVE_WINDOWS_H)
    00146     if( !clib ){
    00147         HANDLE rb_libruby_handle(void);
    00148         ptr = rb_libruby_handle();
    00149     }
    00150     else if( STRCASECMP(clib, "libc") == 0
    00151 # ifdef RUBY_COREDLL
    00152              || STRCASECMP(clib, RUBY_COREDLL) == 0
    00153              || STRCASECMP(clib, RUBY_COREDLL".dll") == 0
    00154 # endif
    00155         ){
    00156 # ifdef _WIN32_WCE
    00157         ptr = dlopen("coredll.dll", cflag);
    00158 # else
    00159         ptr = w32_coredll();
    00160 # endif
    00161     }
    00162     else
    00163 #endif
    00164         ptr = dlopen(clib, cflag);
    00165 #if defined(HAVE_DLERROR)
    00166     if( !ptr && (err = dlerror()) ){
    00167         rb_raise(rb_eDLError, "%s", err);
    00168     }
    00169 #else
    00170     if( !ptr ){
    00171         err = dlerror();
    00172         rb_raise(rb_eDLError, "%s", err);
    00173     }
    00174 #endif
    00175     TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
    00176     if( dlhandle->ptr && dlhandle->open && dlhandle->enable_close ){
    00177         dlclose(dlhandle->ptr);
    00178     }
    00179     dlhandle->ptr = ptr;
    00180     dlhandle->open = 1;
    00181     dlhandle->enable_close = 0;
    00182
    00183     if( rb_block_given_p() ){
    00184         rb_ensure(rb_yield, self, rb_dlhandle_close, self);
    00185     }
    00186
    00187     return Qnil;
    00188 }
    00189
    00190 /*
    00191  * call-seq: enable_close
    00192  *
    00193  * Enable a call to dlclose() when this DL::Handle is garbage collected.
    00194  */
    00195 VALUE
    00196 rb_dlhandle_enable_close(VALUE self)
    00197 {
    00198     struct dl_handle *dlhandle;
    00199
    00200     TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
    00201     dlhandle->enable_close = 1;
    00202     return Qnil;
    00203 }
    00204
    00205 /*
    00206  * call-seq: disable_close
    00207  *
    00208  * Disable a call to dlclose() when this DL::Handle is garbage collected.
    00209  */
    00210 VALUE
    00211 rb_dlhandle_disable_close(VALUE self)
    00212 {
    00213     struct dl_handle *dlhandle;
    00214
    00215     TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
    00216     dlhandle->enable_close = 0;
    00217     return Qnil;
    00218 }
    00219
    00220 /*
    00221  * call-seq: close_enabled?
    00222  *
    00223  * Returns +true+ if dlclose() will be called when this DL::Handle is
    00224  * garbage collected.
    00225  */
    00226 static VALUE
    00227 rb_dlhandle_close_enabled_p(VALUE self)
    00228 {
    00229     struct dl_handle *dlhandle;
    00230
    00231     TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
    00232
    00233     if(dlhandle->enable_close) return Qtrue;
    00234     return Qfalse;
    00235 }
    00236
    00237 /*
    00238  * call-seq: to_i
    00239  *
    00240  * Returns the memory address for this handle.
    00241  */
    00242 VALUE
    00243 rb_dlhandle_to_i(VALUE self)
    00244 {
    00245     struct dl_handle *dlhandle;
    00246
    00247     TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
    00248     return PTR2NUM(dlhandle);
    00249 }
    00250
    00251 static VALUE dlhandle_sym(void *handle, const char *symbol);
    00252
    00253 /*
    00254  * Document-method: sym
    00255  * Document-method: []
    00256  *
    00257  * call-seq: sym(name)
    00258  *
    00259  * Get the address as an Integer for the function named +name+.
    00260  */
    00261 VALUE
    00262 rb_dlhandle_sym(VALUE self, VALUE sym)
    00263 {
    00264     struct dl_handle *dlhandle;
    00265
    00266     TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
    00267     if( ! dlhandle->open ){
    00268         rb_raise(rb_eDLError, "closed handle");
    00269     }
    00270
    00271     return dlhandle_sym(dlhandle->ptr, StringValueCStr(sym));
    00272 }
    00273
    00274 #ifndef RTLD_NEXT
    00275 #define RTLD_NEXT NULL
    00276 #endif
    00277 #ifndef RTLD_DEFAULT
    00278 #define RTLD_DEFAULT NULL
    00279 #endif
    00280
    00281 /*
    00282  * Document-method: sym
    00283  * Document-method: []
    00284  *
    00285  * call-seq: sym(name)
    00286  *
    00287  * Get the address as an Integer for the function named +name+.  The function
    00288  * is searched via dlsym on RTLD_NEXT.  See man(3) dlsym() for more info.
    00289  */
    00290 VALUE
    00291 rb_dlhandle_s_sym(VALUE self, VALUE sym)
    00292 {
    00293     return dlhandle_sym(RTLD_NEXT, StringValueCStr(sym));
    00294 }
    00295
    00296 static VALUE
    00297 dlhandle_sym(void *handle, const char *name)
    00298 {
    00299 #if defined(HAVE_DLERROR)
    00300     const char *err;
    00301 # define CHECK_DLERROR if( err = dlerror() ){ func = 0; }
    00302 #else
    00303 # define CHECK_DLERROR
    00304 #endif
    00305     void (*func)();
    00306
    00307     rb_secure(2);
    00308     func = (void (*)())(VALUE)dlsym(handle, name);
    00309     CHECK_DLERROR;
    00310 #if defined(FUNC_STDCALL)
    00311     if( !func ){
    00312         int  i;
    00313         int  len = strlen(name);
    00314         char *name_n;
    00315 #if defined(__CYGWIN__) || defined(_WIN32) || defined(__MINGW32__)
    00316         {
    00317             char *name_a = (char*)xmalloc(len+2);
    00318             strcpy(name_a, name);
    00319             name_n = name_a;
    00320             name_a[len]   = 'A';
    00321             name_a[len+1] = '\0';
    00322             func = dlsym(handle, name_a);
    00323             CHECK_DLERROR;
    00324             if( func ) goto found;
    00325             name_n = xrealloc(name_a, len+6);
    00326         }
    00327 #else
    00328         name_n = (char*)xmalloc(len+6);
    00329 #endif
    00330         memcpy(name_n, name, len);
    00331         name_n[len++] = '@';
    00332         for( i = 0; i < 256; i += 4 ){
    00333             sprintf(name_n + len, "%d", i);
    00334             func = dlsym(handle, name_n);
    00335             CHECK_DLERROR;
    00336             if( func ) break;
    00337         }
    00338         if( func ) goto found;
    00339         name_n[len-1] = 'A';
    00340         name_n[len++] = '@';
    00341         for( i = 0; i < 256; i += 4 ){
    00342             sprintf(name_n + len, "%d", i);
    00343             func = dlsym(handle, name_n);
    00344             CHECK_DLERROR;
    00345             if( func ) break;
    00346         }
    00347       found:
    00348         xfree(name_n);
    00349     }
    00350 #endif
    00351     if( !func ){
    00352         rb_raise(rb_eDLError, "unknown symbol \"%s\"", name);
    00353     }
    00354
    00355     return PTR2NUM(func);
    00356 }
    00357
    00358 void
    00359 Init_dlhandle(void)
    00360 {
    00361     rb_cDLHandle = rb_define_class_under(rb_mDL, "Handle", rb_cObject);
    00362     rb_define_alloc_func(rb_cDLHandle, rb_dlhandle_s_allocate);
    00363     rb_define_singleton_method(rb_cDLHandle, "sym", rb_dlhandle_s_sym, 1);
    00364     rb_define_singleton_method(rb_cDLHandle, "[]", rb_dlhandle_s_sym,  1);
    00365     rb_define_const(rb_cDLHandle, "NEXT", predefined_dlhandle(RTLD_NEXT));
    00366     rb_define_const(rb_cDLHandle, "DEFAULT", predefined_dlhandle(RTLD_DEFAULT));
    00367     rb_define_method(rb_cDLHandle, "initialize", rb_dlhandle_initialize, -1);
    00368     rb_define_method(rb_cDLHandle, "to_i", rb_dlhandle_to_i, 0);
    00369     rb_define_method(rb_cDLHandle, "close", rb_dlhandle_close, 0);
    00370     rb_define_method(rb_cDLHandle, "sym",  rb_dlhandle_sym, 1);
    00371     rb_define_method(rb_cDLHandle, "[]",  rb_dlhandle_sym,  1);
    00372     rb_define_method(rb_cDLHandle, "disable_close", rb_dlhandle_disable_close, 0);
    00373     rb_define_method(rb_cDLHandle, "enable_close", rb_dlhandle_enable_close, 0);
    00374     rb_define_method(rb_cDLHandle, "close_enabled?", rb_dlhandle_close_enabled_p, 0);
    00375 }
    00376
    00377 /* mode: c; tab-with=8; sw=4; ts=8; noexpandtab: */
    00378