Module: DL

Included in:
Function, Importer
Defined in:
dl.c,
lib/dl.rb,
lib/dl/pack.rb,
lib/dl/func.rb,
lib/dl/stack.rb,
lib/dl/value.rb,
lib/dl/types.rb,
lib/dl/struct.rb,
lib/dl/import.rb,
lib/dl/cparser.rb,
lib/dl/callback.rb

Overview

A bridge to the dlopen() or dynamic library linker function.

Example

bash $> cat > sum.c <<EOF
double sum(double *arry, int len)
{
        double ret = 0;
        int i;
        for(i = 0; i < len; i++){
                ret = ret + arry[i];
        }
        return ret;
}

double split(double num)
{
        double ret = 0;
        ret = num / 2;
        return ret;
}
EOF
bash $> gcc -o libsum.so -shared sum.c
bash $> cat > sum.rb <<EOF
require 'dl'
require 'dl/import'

module LibSum
        extend DL::Importer
        dlload './libsum.so'
        extern 'double sum(double*, int)'
        extern 'double split(double)'
end

a = [2.0, 3.0, 4.0]

sum = LibSum.sum(a.pack("d*"), a.count)
p LibSum.split(sum)
EOF
bash $> ruby sum.rb
4.5

WIN! :-)

Defined Under Namespace

Modules: BasicTypes, CParser, CStructBuilder, Importer, PackInfo, ValueUtil, Win32Types Classes: CFunc, CPtr, CStruct, CStructEntity, CUnion, CUnionEntity, CarriedFunction, CompositeHandler, DLError, DLTypeError, Function, Handle, Packer, Stack, TempFunction

Constant Summary collapse

MAX_CALLBACK =

Maximum number of callbacks

INT2NUM(MAX_CALLBACK)
DLSTACK_SIZE =

Dynamic linker stack size

INT2NUM(DLSTACK_SIZE)
RTLD_GLOBAL =

:Handle flag.

The symbols defined by this library will be made available for symbol resolution of subsequently loaded libraries.

rtld DL
RTLD_LAZY =

:Handle flag.

Perform lazy binding. Only resolve symbols as the code that references them is executed. If the symbol is never referenced, then it is never resolved. (Lazy binding is only performed for function references; references to variables are always immediately bound when the library is loaded.)

rtld DL
RTLD_NOW =

:Handle flag.

If this value is specified or the environment variable LD_BIND_NOW is set to a nonempty string, all undefined symbols in the library are resolved before dlopen() returns. If this cannot be done an error is returned.

rtld DL
TYPE_VOID =

:CFunc type - void

DL
TYPE_VOIDP =

:CFunc type - void*

DL
TYPE_CHAR =

:CFunc type - char

DL
TYPE_SHORT =

:CFunc type - short

DL
TYPE_INT =

:CFunc type - int

DL
TYPE_LONG =

:CFunc type - long

DL
TYPE_LONG_LONG =

:CFunc type - long long

DL
TYPE_FLOAT =

:CFunc type - float

DL
TYPE_DOUBLE =

:CFunc type - double

DL
ALIGN_VOIDP =

The Offset of a struct void* and a void*

INT2NUM(ALIGN_VOIDP)
ALIGN_CHAR =

The Offset of a struct char and a char

INT2NUM(ALIGN_CHAR)
ALIGN_SHORT =

The Offset of a struct short and a short

INT2NUM(ALIGN_SHORT)
ALIGN_INT =

The Offset of a struct int and a int

INT2NUM(ALIGN_INT)
ALIGN_LONG =

The Offset of a struct long and a long

INT2NUM(ALIGN_LONG)
ALIGN_LONG_LONG =

The Offset of a struct long long and a long long

INT2NUM(ALIGN_LONG_LONG)
ALIGN_FLOAT =

The Offset of a struct float and a float

INT2NUM(ALIGN_FLOAT)
ALIGN_DOUBLE =

The Offset of a struct double and a double

INT2NUM(ALIGN_DOUBLE)
SIZEOF_VOIDP =

OS Dependent - sizeof(void*)

INT2NUM(sizeof(void*))
SIZEOF_CHAR =

OS Dependent - sizeof(char)

INT2NUM(sizeof(char))
SIZEOF_SHORT =

OS Dependent - sizeof(short)

INT2NUM(sizeof(short))
SIZEOF_INT =

OS Dependent - sizeof(int)

INT2NUM(sizeof(int))
SIZEOF_LONG =

OS Dependent - sizeof(long)

INT2NUM(sizeof(long))
SIZEOF_LONG_LONG =

OS Dependent - sizeof(long long)

INT2NUM(sizeof(LONG_LONG))
SIZEOF_FLOAT =

OS Dependent - sizeof(float)

INT2NUM(sizeof(float))
SIZEOF_DOUBLE =

OS Dependent - sizeof(double)

INT2NUM(sizeof(double))
RUBY_FREE =

Address of the ruby_xfree() function

PTR2NUM(ruby_xfree)
BUILD_RUBY_PLATFORM =

Platform built against (i.e. "x86_64-linux", etc.)

See also RUBY_PLATFORM

rb_str_new2(RUBY_PLATFORM)
BUILD_RUBY_VERSION =

Ruby Version built. (i.e. "1.9.3")

See also RUBY_VERSION

rb_str_new2(RUBY_VERSION)
NULL =

A NULL pointer

rb_dlptr_new(0, 0, 0)
SEM =

The mutual exclusion (Mutex) semaphore for the DL module

Mutex.new
CdeclCallbackProcs =

A Hash of callback Procs

Uses Fiddle

tmp
CdeclCallbackAddrs =

A Hash of the addresses of callback Proc

Uses Fiddle

tmp
StdcallCallbackProcs =

A Hash of Stdcall callback Procs

Uses Fiddle on win32

tmp
StdcallCallbackAddrs =

A Hash of the addresses of Stdcall callback Procs

Uses Fiddle on win32

tmp

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.dlopenObject



20
21
22
23
24
# File 'dl.c', line 20

VALUE
rb_dl_dlopen(int argc, VALUE argv[], VALUE self)
{
    return rb_class_new_instance(argc, argv, rb_cDLHandle);
}

.dlunwrapObject



74
75
76
77
78
79
# File 'dl.c', line 74

VALUE
rb_dl_ptr2value(VALUE self, VALUE addr)
{
    rb_secure(4);
    return (VALUE)NUM2PTR(addr);
}

.dlwrapObject



81
82
83
84
85
# File 'dl.c', line 81

VALUE
rb_dl_value2ptr(VALUE self, VALUE val)
{
    return PTR2NUM((void*)val);
}

.fiddle?Boolean

Returns:

  • (Boolean)


9
10
11
# File 'lib/dl.rb', line 9

def self.fiddle?
  Object.const_defined?(:Fiddle)
end

.free(addr) ⇒ Object

Free the memory at address addr



64
65
66
67
68
69
70
71
72
# File 'dl.c', line 64

VALUE
rb_dl_free(VALUE self, VALUE addr)
{
    void *ptr = NUM2PTR(addr);

    rb_secure(4);
    ruby_xfree(ptr);
    return Qnil;
}

.mallocObject

Allocate size bytes of memory and return the integer memory address for the allocated memory.



32
33
34
35
36
37
38
39
40
# File 'dl.c', line 32

VALUE
rb_dl_malloc(VALUE self, VALUE size)
{
    void *ptr;

    rb_secure(4);
    ptr = (void*)ruby_xmalloc(NUM2INT(size));
    return PTR2NUM(ptr);
}

.realloc(addr, size) ⇒ Object

Change the size of the memory allocated at the memory location addr to size bytes. Returns the memory address of the reallocated memory, which may be different than the address passed in.



49
50
51
52
53
54
55
56
57
# File 'dl.c', line 49

VALUE
rb_dl_realloc(VALUE self, VALUE addr, VALUE size)
{
    void *ptr = NUM2PTR(addr);

    rb_secure(4);
    ptr = (void*)ruby_xrealloc(ptr, NUM2INT(size));
    return PTR2NUM(ptr);
}

Instance Method Details

#remove_callback_internal(proc_entry, addr_entry, addr, ctype = nil) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/dl/callback.rb', line 70

def remove_callback_internal(proc_entry, addr_entry, addr, ctype = nil)
  if DL.fiddle?
    addr = addr.to_i
    return false unless proc_entry.key?(addr)
    proc_entry.delete(addr)
    true
  else
    index = nil
    if( ctype )
      addr_entry[ctype].each_with_index{|xaddr, idx|
        if( xaddr == addr )
          index = idx
        end
      }
    else
      addr_entry.each{|ty,entry|
        entry.each_with_index{|xaddr, idx|
          if( xaddr == addr )
            index = idx
          end
        }
      }
    end
    if( index and proc_entry[ctype][index] )
      proc_entry[ctype][index] = nil
      return true
    else
      return false
    end
  end
end

#remove_cdecl_callback(addr, ctype = nil) ⇒ Object Also known as: remove_callback



102
103
104
# File 'lib/dl/callback.rb', line 102

def remove_cdecl_callback(addr, ctype = nil)
  remove_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, addr, ctype)
end

#remove_stdcall_callback(addr, ctype = nil) ⇒ Object



106
107
108
# File 'lib/dl/callback.rb', line 106

def remove_stdcall_callback(addr, ctype = nil)
  remove_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, addr, ctype)
end

#set_callback_internal(proc_entry, addr_entry, argc, ty, abi = nil, &cbp) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/dl/callback.rb', line 30

def set_callback_internal(proc_entry, addr_entry, argc, ty, abi = nil, &cbp)
  if( argc < 0 )
    raise(ArgumentError, "arity should not be less than 0.")
  end
  addr = nil

  if DL.fiddle?
    abi ||= Fiddle::Function::DEFAULT
    closure = Fiddle::Closure::BlockCaller.new(ty, [TYPE_VOIDP] * argc, abi, &cbp)
    proc_entry[closure.to_i] = closure
    addr = closure.to_i
  else
    SEM.synchronize{
      ary = proc_entry[ty]
      (0...MAX_CALLBACK).each{|n|
        idx = (n * DLSTACK_SIZE) + argc
        if( ary[idx].nil? )
          ary[idx] = cbp
          addr = addr_entry[ty][idx]
          break
        end
      }
    }
  end

  addr
end

#set_cdecl_callback(ty, argc, &cbp) ⇒ Object Also known as: set_callback



58
59
60
# File 'lib/dl/callback.rb', line 58

def set_cdecl_callback(ty, argc, &cbp)
  set_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, argc, ty, &cbp)
end

#set_stdcall_callback(ty, argc, &cbp) ⇒ Object



62
63
64
65
66
67
68
# File 'lib/dl/callback.rb', line 62

def set_stdcall_callback(ty, argc, &cbp)
  if DL.fiddle?
    set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, Fiddle::Function::STDCALL, &cbp)
  else
    set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, &cbp)
  end
end