mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* ext/dl: revert dl with libffi because it can't run on mswin now.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@26764 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
9d818a221e
commit
59e4e93ef7
19 changed files with 394 additions and 662 deletions
|
@ -1,3 +1,7 @@
|
|||
Fri Feb 26 07:44:51 2010 NARUSE, Yui <naruse@ruby-lang.org>
|
||||
|
||||
* ext/dl: revert dl with libffi because it can't run on mswin now.
|
||||
|
||||
Thu Feb 25 22:59:46 2010 Tanaka Akira <akr@fsij.org>
|
||||
|
||||
* pack.c: consider DYNAMIC_ENDIAN. refactored.
|
||||
|
|
15
ext/dl/callback/depend
Normal file
15
ext/dl/callback/depend
Normal file
|
@ -0,0 +1,15 @@
|
|||
src: callback.c \
|
||||
callback-0.c callback-1.c callback-2.c \
|
||||
callback-3.c callback-4.c callback-5.c \
|
||||
callback-6.c callback-7.c callback-8.c
|
||||
|
||||
$(OBJS): $(hdrdir)/ruby.h
|
||||
|
||||
callback-0.c callback-1.c callback-2.c \
|
||||
callback-3.c callback-4.c callback-5.c \
|
||||
callback-6.c callback-7.c callback-8.c \
|
||||
: callback.c
|
||||
|
||||
callback.c: $(srcdir)/mkcallback.rb $(srcdir)/../dl.h
|
||||
@echo "generating callback.c"
|
||||
@$(RUBY) $(srcdir)/mkcallback.rb -output=callback $(srcdir)/../dl.h
|
14
ext/dl/callback/extconf.rb
Normal file
14
ext/dl/callback/extconf.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
require 'mkmf'
|
||||
|
||||
if compiled?("dl")
|
||||
callbacks = (0..8).map{|i| "callback-#{i}"}.unshift("callback")
|
||||
callback_srcs = callbacks.map{|basename| "#{basename}.c"}
|
||||
callback_objs = callbacks.map{|basename| "#{basename}.o"}
|
||||
|
||||
$distcleanfiles << '$(SRCS)'
|
||||
$srcs = callback_srcs
|
||||
$objs = callback_objs
|
||||
$INCFLAGS << " -I$(srcdir)/.."
|
||||
|
||||
create_makefile("dl/callback")
|
||||
end
|
238
ext/dl/callback/mkcallback.rb
Normal file
238
ext/dl/callback/mkcallback.rb
Normal file
|
@ -0,0 +1,238 @@
|
|||
#!ruby -s
|
||||
$output ||= "callback"
|
||||
$out = open("#{$output}.c", "w")
|
||||
|
||||
$dl_h = ARGV[0] || "dl.h"
|
||||
|
||||
# import DLSTACK_SIZE, DLSTACK_ARGS and so on
|
||||
File.open($dl_h){|f|
|
||||
pre = ""
|
||||
f.each{|line|
|
||||
line.chop!
|
||||
if( line[-1] == ?\\ )
|
||||
line.chop!
|
||||
line.concat(" ")
|
||||
pre += line
|
||||
next
|
||||
end
|
||||
if( pre.size > 0 )
|
||||
line = pre + line
|
||||
pre = ""
|
||||
end
|
||||
case line
|
||||
when /#define\s+DLSTACK_SIZE\s+\(?(\d+)\)?/
|
||||
DLSTACK_SIZE = $1.to_i
|
||||
when /#define\s+DLSTACK_ARGS\s+(.+)/
|
||||
DLSTACK_ARGS = $1.to_i
|
||||
when /#define\s+DLTYPE_([A-Z_]+)\s+\(?(\d+)\)?/
|
||||
eval("#{$1} = #{$2}")
|
||||
when /#define\s+MAX_DLTYPE\s+\(?(\d+)\)?/
|
||||
MAX_DLTYPE = $1.to_i
|
||||
when /#define\s+MAX_CALLBACK\s+\(?(\d+)\)?/
|
||||
MAX_CALLBACK = $1.to_i
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
CDECL = "cdecl"
|
||||
STDCALL = "stdcall"
|
||||
|
||||
CALLTYPES = [CDECL, STDCALL]
|
||||
|
||||
DLTYPE = {
|
||||
VOID => {
|
||||
:name => 'void',
|
||||
:type => 'void',
|
||||
:conv => nil,
|
||||
},
|
||||
CHAR => {
|
||||
:name => 'char',
|
||||
:type => 'char',
|
||||
:conv => 'NUM2CHR(%s)'
|
||||
},
|
||||
SHORT => {
|
||||
:name => 'short',
|
||||
:type => 'short',
|
||||
:conv => 'NUM2INT(%s)',
|
||||
},
|
||||
INT => {
|
||||
:name => 'int',
|
||||
:type => 'int',
|
||||
:conv => 'NUM2INT(%s)',
|
||||
},
|
||||
LONG => {
|
||||
:name => 'long',
|
||||
:type => 'long',
|
||||
:conv => 'NUM2LONG(%s)',
|
||||
},
|
||||
LONG_LONG => {
|
||||
:name => 'long_long',
|
||||
:type => 'LONG_LONG',
|
||||
:conv => 'NUM2LL(%s)',
|
||||
},
|
||||
FLOAT => {
|
||||
:name => 'float',
|
||||
:type => 'float',
|
||||
:conv => '(float)RFLOAT_VALUE(%s)',
|
||||
},
|
||||
DOUBLE => {
|
||||
:name => 'double',
|
||||
:type => 'double',
|
||||
:conv => 'RFLOAT_VALUE(%s)',
|
||||
},
|
||||
VOIDP => {
|
||||
:name => 'ptr',
|
||||
:type => 'void *',
|
||||
:conv => 'NUM2PTR(%s)',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def func_name(ty, argc, n, calltype)
|
||||
"rb_dl_callback_#{DLTYPE[ty][:name]}_#{argc}_#{n}_#{calltype}"
|
||||
end
|
||||
|
||||
$out << (<<EOS)
|
||||
#include "ruby.h"
|
||||
|
||||
VALUE rb_DLCdeclCallbackAddrs, rb_DLCdeclCallbackProcs;
|
||||
#ifdef FUNC_STDCALL
|
||||
VALUE rb_DLStdcallCallbackAddrs, rb_DLStdcallCallbackProcs;
|
||||
#endif
|
||||
/*static void *cdecl_callbacks[MAX_DLTYPE][MAX_CALLBACK];*/
|
||||
#ifdef FUNC_STDCALL
|
||||
/*static void *stdcall_callbacks[MAX_DLTYPE][MAX_CALLBACK];*/
|
||||
#endif
|
||||
ID rb_dl_cb_call;
|
||||
EOS
|
||||
|
||||
def foreach_proc_entry
|
||||
for calltype in CALLTYPES
|
||||
case calltype
|
||||
when CDECL
|
||||
proc_entry = "rb_DLCdeclCallbackProcs"
|
||||
when STDCALL
|
||||
proc_entry = "rb_DLStdcallCallbackProcs"
|
||||
else
|
||||
raise "unknown calltype: #{calltype}"
|
||||
end
|
||||
yield calltype, proc_entry
|
||||
end
|
||||
end
|
||||
|
||||
def gencallback(ty, calltype, proc_entry, argc, n)
|
||||
<<-EOS
|
||||
#{calltype == STDCALL ? "\n#ifdef FUNC_STDCALL" : ""}
|
||||
static #{DLTYPE[ty][:type]}
|
||||
FUNC_#{calltype.upcase}(#{func_name(ty,argc,n,calltype)})(#{(0...argc).collect{|i| "DLSTACK_TYPE stack" + i.to_s}.join(", ")})
|
||||
{
|
||||
VALUE ret, cb#{argc > 0 ? ", args[#{argc}]" : ""};
|
||||
#{
|
||||
(0...argc).collect{|i|
|
||||
" args[%d] = LONG2NUM(stack%d);" % [i,i]
|
||||
}.join("\n")
|
||||
}
|
||||
cb = rb_ary_entry(rb_ary_entry(#{proc_entry}, #{ty}), #{(n * DLSTACK_SIZE) + argc});
|
||||
ret = rb_funcall2(cb, rb_dl_cb_call, #{argc}, #{argc > 0 ? 'args' : 'NULL'});
|
||||
return #{DLTYPE[ty][:conv] ? DLTYPE[ty][:conv] % "ret" : ""};
|
||||
}
|
||||
#{calltype == STDCALL ? "#endif\n" : ""}
|
||||
EOS
|
||||
end
|
||||
|
||||
def gen_push_proc_ary(ty, aryname)
|
||||
sprintf(" rb_ary_push(#{aryname}, rb_ary_new3(%d,%s));",
|
||||
MAX_CALLBACK * DLSTACK_SIZE,
|
||||
(0...MAX_CALLBACK).collect{
|
||||
(0...DLSTACK_SIZE).collect{ "Qnil" }.join(",")
|
||||
}.join(","))
|
||||
end
|
||||
|
||||
def gen_push_addr_ary(ty, aryname, calltype)
|
||||
sprintf(" rb_ary_push(#{aryname}, rb_ary_new3(%d,%s));",
|
||||
MAX_CALLBACK * DLSTACK_SIZE,
|
||||
(0...MAX_CALLBACK).collect{|i|
|
||||
(0...DLSTACK_SIZE).collect{|argc|
|
||||
"PTR2NUM(%s)" % func_name(ty,argc,i,calltype)
|
||||
}.join(",")
|
||||
}.join(","))
|
||||
end
|
||||
|
||||
def gen_callback_file(ty)
|
||||
filename = "#{$output}-#{ty}.c"
|
||||
initname = "rb_dl_init_callbacks_#{ty}"
|
||||
body = <<-EOS
|
||||
#include "dl.h"
|
||||
|
||||
extern VALUE rb_DLCdeclCallbackAddrs, rb_DLCdeclCallbackProcs;
|
||||
#ifdef FUNC_STDCALL
|
||||
extern VALUE rb_DLStdcallCallbackAddrs, rb_DLStdcallCallbackProcs;
|
||||
#endif
|
||||
extern ID rb_dl_cb_call;
|
||||
EOS
|
||||
yield body
|
||||
body << <<-EOS
|
||||
void
|
||||
#{initname}()
|
||||
{
|
||||
#{gen_push_proc_ary(ty, "rb_DLCdeclCallbackProcs")}
|
||||
#{gen_push_addr_ary(ty, "rb_DLCdeclCallbackAddrs", CDECL)}
|
||||
#ifdef FUNC_STDCALL
|
||||
#{gen_push_proc_ary(ty, "rb_DLStdcallCallbackProcs")}
|
||||
#{gen_push_addr_ary(ty, "rb_DLStdcallCallbackAddrs", STDCALL)}
|
||||
#endif
|
||||
}
|
||||
EOS
|
||||
[filename, initname, body]
|
||||
end
|
||||
|
||||
callbacks = []
|
||||
for ty in 0...MAX_DLTYPE
|
||||
filename, initname, body = gen_callback_file(ty) {|f|
|
||||
foreach_proc_entry do |calltype, proc_entry|
|
||||
for argc in 0...DLSTACK_SIZE
|
||||
for n in 0...MAX_CALLBACK
|
||||
f << gencallback(ty, calltype, proc_entry, argc, n)
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
$out << "void #{initname}();\n"
|
||||
callbacks << [filename, body]
|
||||
end
|
||||
|
||||
$out << (<<EOS)
|
||||
void
|
||||
Init_callback(void)
|
||||
{
|
||||
VALUE tmp;
|
||||
VALUE rb_mDL = rb_path2class("DL");
|
||||
|
||||
rb_dl_cb_call = rb_intern("call");
|
||||
|
||||
tmp = rb_DLCdeclCallbackProcs = rb_ary_new();
|
||||
rb_define_const(rb_mDL, "CdeclCallbackProcs", tmp);
|
||||
|
||||
tmp = rb_DLCdeclCallbackAddrs = rb_ary_new();
|
||||
rb_define_const(rb_mDL, "CdeclCallbackAddrs", tmp);
|
||||
|
||||
#ifdef FUNC_STDCALL
|
||||
tmp = rb_DLStdcallCallbackProcs = rb_ary_new();
|
||||
rb_define_const(rb_mDL, "StdcallCallbackProcs", tmp);
|
||||
|
||||
tmp = rb_DLStdcallCallbackAddrs = rb_ary_new();
|
||||
rb_define_const(rb_mDL, "StdcallCallbackAddrs", tmp);
|
||||
#endif
|
||||
|
||||
#{
|
||||
(0...MAX_DLTYPE).collect{|ty|
|
||||
" rb_dl_init_callbacks_#{ty}();"
|
||||
}.join("\n")
|
||||
}
|
||||
}
|
||||
EOS
|
||||
$out.close
|
||||
|
||||
for filename, body in callbacks
|
||||
open(filename, "wb") {|f| f.puts body}
|
||||
end
|
|
@ -16,7 +16,7 @@ rb_dl_get_last_error(VALUE self)
|
|||
return rb_thread_local_aref(rb_thread_current(), id_last_error);
|
||||
}
|
||||
|
||||
VALUE
|
||||
static VALUE
|
||||
rb_dl_set_last_error(VALUE self, VALUE val)
|
||||
{
|
||||
rb_thread_local_aset(rb_thread_current(), id_last_error, val);
|
||||
|
@ -33,7 +33,7 @@ rb_dl_get_win32_last_error(VALUE self)
|
|||
return rb_thread_local_aref(rb_thread_current(), id_win32_last_error);
|
||||
}
|
||||
|
||||
VALUE
|
||||
static VALUE
|
||||
rb_dl_set_win32_last_error(VALUE self, VALUE val)
|
||||
{
|
||||
rb_thread_local_aset(rb_thread_current(), id_win32_last_error, val);
|
||||
|
@ -147,12 +147,12 @@ rb_dlcfunc_initialize(int argc, VALUE argv[], VALUE self)
|
|||
struct cfunc_data *data;
|
||||
void *saddr;
|
||||
const char *sname;
|
||||
|
||||
|
||||
rb_scan_args(argc, argv, "13", &addr, &type, &name, &calltype);
|
||||
|
||||
|
||||
saddr = (void*)(NUM2PTR(rb_Integer(addr)));
|
||||
sname = NIL_P(name) ? NULL : StringValuePtr(name);
|
||||
|
||||
|
||||
TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, data);
|
||||
if( data->name ) xfree(data->name);
|
||||
data->ptr = saddr;
|
||||
|
@ -284,11 +284,11 @@ rb_dlcfunc_inspect(VALUE self)
|
|||
{
|
||||
VALUE val;
|
||||
char *str;
|
||||
size_t str_size;
|
||||
int str_size;
|
||||
struct cfunc_data *cfunc;
|
||||
|
||||
|
||||
TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
|
||||
|
||||
|
||||
str_size = (cfunc->name ? strlen(cfunc->name) : 0) + 100;
|
||||
str = ruby_xmalloc(str_size);
|
||||
snprintf(str, str_size - 1,
|
||||
|
@ -339,31 +339,22 @@ rb_dlcfunc_call(VALUE self, VALUE ary)
|
|||
|
||||
memset(stack, 0, sizeof(DLSTACK_TYPE) * DLSTACK_SIZE);
|
||||
Check_Type(ary, T_ARRAY);
|
||||
|
||||
|
||||
TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
|
||||
|
||||
if( cfunc->ptr == 0 ){
|
||||
rb_raise(rb_eDLError, "can't call null-function");
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
if( RARRAY_LEN(ary) >= DLSTACK_SIZE ){
|
||||
rb_raise(rb_eDLError, "too many arguments (stack overflow)");
|
||||
}
|
||||
|
||||
for( i = 0; i < RARRAY_LEN(ary); i++ ){
|
||||
unsigned long rb_big2ulong_pack(VALUE x);
|
||||
VALUE arg = RARRAY_PTR(ary)[i];
|
||||
|
||||
rb_check_safe_obj(arg);
|
||||
if (FIXNUM_P(arg)) {
|
||||
stack[i] = FIX2LONG(arg);
|
||||
}
|
||||
else {
|
||||
Check_Type(arg, T_BIGNUM);
|
||||
stack[i] = rb_big2ulong_pack(arg);
|
||||
if( i >= DLSTACK_SIZE ){
|
||||
rb_raise(rb_eDLError, "too many arguments (stack overflow)");
|
||||
}
|
||||
rb_check_safe_obj(RARRAY_PTR(ary)[i]);
|
||||
stack[i] = NUM2LONG(RARRAY_PTR(ary)[i]);
|
||||
}
|
||||
|
||||
|
||||
/* calltype == CFUNC_CDECL */
|
||||
if( cfunc->calltype == CFUNC_CDECL
|
||||
#ifndef FUNC_STDCALL
|
||||
|
|
230
ext/dl/closure.c
230
ext/dl/closure.c
|
@ -1,230 +0,0 @@
|
|||
/* -*- C -*-
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <ruby.h>
|
||||
#include "dl.h"
|
||||
#include <sys/mman.h>
|
||||
#include <dl_conversions.h>
|
||||
|
||||
VALUE rb_cDLClosure;
|
||||
|
||||
typedef struct {
|
||||
void * code;
|
||||
ffi_closure *pcl;
|
||||
ffi_cif * cif;
|
||||
int argc;
|
||||
ffi_type **argv;
|
||||
} dl_closure;
|
||||
|
||||
static void
|
||||
dlclosure_free(void * ptr)
|
||||
{
|
||||
dl_closure * cls = (dl_closure *)ptr;
|
||||
#ifdef USE_NEW_CLOSURE_API
|
||||
ffi_closure_free(cls->pcl);
|
||||
#else
|
||||
munmap(cls->pcl, sizeof(cls->pcl));
|
||||
#endif
|
||||
xfree(cls->cif);
|
||||
if (cls->argv) xfree(cls->argv);
|
||||
xfree(cls);
|
||||
}
|
||||
|
||||
static size_t
|
||||
dlclosure_memsize(const void * ptr)
|
||||
{
|
||||
dl_closure * cls = (dl_closure *)ptr;
|
||||
size_t size = 0;
|
||||
|
||||
if (ptr) {
|
||||
size += sizeof(*cls);
|
||||
size += ffi_raw_size(cls->cif);
|
||||
size += sizeof(*cls->argv);
|
||||
size += sizeof(ffi_closure);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
const rb_data_type_t dlclosure_data_type = {
|
||||
"dl/closure",
|
||||
0, dlclosure_free, dlclosure_memsize,
|
||||
};
|
||||
|
||||
void
|
||||
dlc_callback(ffi_cif *cif, void *resp, void **args, void *ctx)
|
||||
{
|
||||
VALUE self = (VALUE)ctx;
|
||||
VALUE rbargs = rb_iv_get(self, "@args");
|
||||
VALUE ctype = rb_iv_get(self, "@ctype");
|
||||
int argc = RARRAY_LENINT(rbargs);
|
||||
VALUE *params = xcalloc(argc, sizeof(VALUE *));
|
||||
VALUE ret;
|
||||
int i, dl_type;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
dl_type = NUM2INT(RARRAY_PTR(rbargs)[i]);
|
||||
switch (dl_type) {
|
||||
case DLTYPE_VOID:
|
||||
argc = 0;
|
||||
break;
|
||||
case DLTYPE_INT:
|
||||
params[i] = INT2NUM(*(int *)args[i]);
|
||||
break;
|
||||
case DLTYPE_VOIDP:
|
||||
params[i] = rb_dlptr_new(*(void **)args[i], 0, NULL);
|
||||
break;
|
||||
case DLTYPE_LONG:
|
||||
params[i] = LONG2NUM(*(long *)args[i]);
|
||||
break;
|
||||
case DLTYPE_CHAR:
|
||||
params[i] = INT2NUM(*(char *)args[i]);
|
||||
break;
|
||||
case DLTYPE_DOUBLE:
|
||||
params[i] = rb_float_new(*(double *)args[i]);
|
||||
break;
|
||||
case DLTYPE_FLOAT:
|
||||
params[i] = rb_float_new(*(float *)args[i]);
|
||||
break;
|
||||
#if HAVE_LONG_LONG
|
||||
case DLTYPE_LONG_LONG:
|
||||
params[i] = rb_ull2inum(*(unsigned LONG_LONG *)args[i]);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
rb_raise(rb_eRuntimeError, "closure args: %d", dl_type);
|
||||
}
|
||||
}
|
||||
|
||||
ret = rb_funcall2(self, rb_intern("call"), argc, params);
|
||||
|
||||
dl_type = NUM2INT(ctype);
|
||||
switch (dl_type) {
|
||||
case DLTYPE_VOID:
|
||||
break;
|
||||
case DLTYPE_LONG:
|
||||
*(long *)resp = NUM2LONG(ret);
|
||||
break;
|
||||
case DLTYPE_CHAR:
|
||||
*(char *)resp = NUM2INT(ret);
|
||||
break;
|
||||
case DLTYPE_VOIDP:
|
||||
*(void **)resp = NUM2PTR(ret);
|
||||
break;
|
||||
case DLTYPE_INT:
|
||||
*(int *)resp = NUM2INT(ret);
|
||||
break;
|
||||
case DLTYPE_DOUBLE:
|
||||
*(double *)resp = NUM2DBL(ret);
|
||||
break;
|
||||
case DLTYPE_FLOAT:
|
||||
*(float *)resp = (float)NUM2DBL(ret);
|
||||
break;
|
||||
#if HAVE_LONG_LONG
|
||||
case DLTYPE_LONG_LONG:
|
||||
*(unsigned LONG_LONG *)resp = rb_big2ull(ret);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
rb_raise(rb_eRuntimeError, "closure retval: %d", dl_type);
|
||||
}
|
||||
xfree(params);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_dlclosure_allocate(VALUE klass)
|
||||
{
|
||||
dl_closure * closure;
|
||||
|
||||
VALUE i = TypedData_Make_Struct(klass, dl_closure,
|
||||
&dlclosure_data_type, closure);
|
||||
|
||||
#ifdef USE_NEW_CLOSURE_API
|
||||
closure->pcl = ffi_closure_alloc(sizeof(ffi_closure), &closure->code);
|
||||
#else
|
||||
closure->pcl = mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE,
|
||||
MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
#endif
|
||||
closure->cif = xmalloc(sizeof(ffi_cif));
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_dlclosure_init(int rbargc, VALUE argv[], VALUE self)
|
||||
{
|
||||
VALUE ret;
|
||||
VALUE args;
|
||||
VALUE abi;
|
||||
dl_closure * cl;
|
||||
ffi_cif * cif;
|
||||
ffi_closure *pcl;
|
||||
ffi_status result;
|
||||
int i, argc;
|
||||
|
||||
if (2 == rb_scan_args(rbargc, argv, "21", &ret, &args, &abi))
|
||||
abi = INT2NUM(FFI_DEFAULT_ABI);
|
||||
|
||||
argc = RARRAY_LENINT(args);
|
||||
|
||||
TypedData_Get_Struct(self, dl_closure, &dlclosure_data_type, cl);
|
||||
|
||||
cl->argv = (ffi_type **)xcalloc(argc + 1, sizeof(ffi_type *));
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
int dltype = NUM2INT(RARRAY_PTR(args)[i]);
|
||||
cl->argv[i] = DL2FFI_TYPE(dltype);
|
||||
}
|
||||
cl->argv[argc] = NULL;
|
||||
|
||||
rb_iv_set(self, "@ctype", ret);
|
||||
rb_iv_set(self, "@args", args);
|
||||
|
||||
cif = cl->cif;
|
||||
pcl = cl->pcl;
|
||||
|
||||
result = ffi_prep_cif(cif, NUM2INT(abi), argc,
|
||||
DL2FFI_TYPE(NUM2INT(ret)),
|
||||
cl->argv);
|
||||
|
||||
if (FFI_OK != result)
|
||||
rb_raise(rb_eRuntimeError, "error prepping CIF %d", result);
|
||||
|
||||
#ifdef USE_NEW_CLOSURE_API
|
||||
result = ffi_prep_closure_loc(pcl, cif, dlc_callback,
|
||||
(void *)self, cl->code);
|
||||
#else
|
||||
result = ffi_prep_closure(pcl, cif, dlc_callback, (void *)self);
|
||||
cl->code = (void *)pcl;
|
||||
mprotect(pcl, sizeof(pcl), PROT_READ | PROT_EXEC);
|
||||
#endif
|
||||
|
||||
if (FFI_OK != result)
|
||||
rb_raise(rb_eRuntimeError, "error prepping closure %d", result);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_dlclosure_to_i(VALUE self)
|
||||
{
|
||||
dl_closure * cl;
|
||||
void *code;
|
||||
|
||||
TypedData_Get_Struct(self, dl_closure, &dlclosure_data_type, cl);
|
||||
|
||||
code = cl->code;
|
||||
|
||||
return PTR2NUM(code);
|
||||
}
|
||||
|
||||
void
|
||||
Init_dlclosure(void)
|
||||
{
|
||||
rb_cDLClosure = rb_define_class_under(rb_mDL, "Closure", rb_cObject);
|
||||
rb_define_alloc_func(rb_cDLClosure, rb_dlclosure_allocate);
|
||||
|
||||
rb_define_method(rb_cDLClosure, "initialize", rb_dlclosure_init, -1);
|
||||
rb_define_method(rb_cDLClosure, "to_i", rb_dlclosure_to_i, 0);
|
||||
}
|
||||
/* vim: set noet sw=4 sts=4 */
|
|
@ -104,7 +104,7 @@ rb_dlptr2cptr(VALUE val)
|
|||
else{
|
||||
rb_raise(rb_eTypeError, "DL::PtrData was expected");
|
||||
}
|
||||
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
@ -186,7 +186,7 @@ static VALUE
|
|||
rb_dlptr_s_malloc(int argc, VALUE argv[], VALUE klass)
|
||||
{
|
||||
VALUE size, sym, obj;
|
||||
long s;
|
||||
int s;
|
||||
freefunc_t f;
|
||||
|
||||
switch (rb_scan_args(argc, argv, "11", &size, &sym)) {
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
cfunc.o: cfunc.c dl.h $(hdrdir)/ruby.h
|
||||
|
||||
closure.o: closure.c dl.h dl_conversions.h $(hdrdir)/ruby.h
|
||||
|
||||
cptr.o: cptr.c dl.h $(hdrdir)/ruby.h $(hdrdir)/io.h
|
||||
|
||||
handle.o: handle.c dl.h $(hdrdir)/ruby.h
|
||||
|
||||
method.o: method.c dl.h dl_conversions.h $(hdrdir)/ruby.h
|
||||
|
||||
dl.o: dl.c dl.h $(hdrdir)/ruby.h $(hdrdir)/io.h
|
||||
|
||||
dl_conversions.o: dl_conversions.c dl_conversions.h
|
||||
|
|
17
ext/dl/dl.c
17
ext/dl/dl.c
|
@ -77,6 +77,19 @@ rb_dl_value2ptr(VALUE self, VALUE val)
|
|||
return PTR2NUM((void*)val);
|
||||
}
|
||||
|
||||
static void
|
||||
rb_dl_init_callbacks(VALUE dl)
|
||||
{
|
||||
static const char cb[] = "dl/callback.so";
|
||||
|
||||
rb_autoload(dl, rb_intern_const("CdeclCallbackAddrs"), cb);
|
||||
rb_autoload(dl, rb_intern_const("CdeclCallbackProcs"), cb);
|
||||
#ifdef FUNC_STDCALL
|
||||
rb_autoload(dl, rb_intern_const("StdcallCallbackAddrs"), cb);
|
||||
rb_autoload(dl, rb_intern_const("StdcallCallbackProcs"), cb);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
Init_dl(void)
|
||||
{
|
||||
|
@ -94,6 +107,8 @@ Init_dl(void)
|
|||
rb_define_const(rb_mDL, "MAX_CALLBACK", INT2NUM(MAX_CALLBACK));
|
||||
rb_define_const(rb_mDL, "DLSTACK_SIZE", INT2NUM(DLSTACK_SIZE));
|
||||
|
||||
rb_dl_init_callbacks(rb_mDL);
|
||||
|
||||
rb_define_const(rb_mDL, "RTLD_GLOBAL", INT2NUM(RTLD_GLOBAL));
|
||||
rb_define_const(rb_mDL, "RTLD_LAZY", INT2NUM(RTLD_LAZY));
|
||||
rb_define_const(rb_mDL, "RTLD_NOW", INT2NUM(RTLD_NOW));
|
||||
|
@ -147,6 +162,4 @@ Init_dl(void)
|
|||
Init_dlhandle();
|
||||
Init_dlcfunc();
|
||||
Init_dlptr();
|
||||
Init_dlfunction();
|
||||
Init_dlclosure();
|
||||
}
|
||||
|
|
12
ext/dl/dl.h
12
ext/dl/dl.h
|
@ -3,12 +3,6 @@
|
|||
|
||||
#include <ruby.h>
|
||||
|
||||
#ifdef USE_HEADER_HACKS
|
||||
#include <ffi/ffi.h>
|
||||
#else
|
||||
#include <ffi.h>
|
||||
#endif
|
||||
|
||||
#if !defined(FUNC_CDECL)
|
||||
# define FUNC_CDECL(x) x
|
||||
#endif
|
||||
|
@ -136,7 +130,6 @@
|
|||
|
||||
extern VALUE rb_mDL;
|
||||
extern VALUE rb_cDLHandle;
|
||||
extern VALUE rb_cDLCPtr;
|
||||
extern VALUE rb_cDLSymbol;
|
||||
extern VALUE rb_eDLError;
|
||||
extern VALUE rb_eDLTypeError;
|
||||
|
@ -228,9 +221,4 @@ VALUE rb_dlptr_new(void *ptr, long size, freefunc_t func);
|
|||
VALUE rb_dlptr_new2(VALUE klass, void *ptr, long size, freefunc_t func);
|
||||
VALUE rb_dlptr_malloc(long size, freefunc_t func);
|
||||
|
||||
VALUE rb_dl_set_last_error(VALUE self, VALUE val);
|
||||
#if defined(HAVE_WINDOWS_H)
|
||||
VALUE rb_dl_set_win32_last_error(VALUE self, VALUE val);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
#include <dl_conversions.h>
|
||||
|
||||
ffi_type *
|
||||
rb_dl_type_to_ffi_type(int dl_type)
|
||||
{
|
||||
int signed_p = 1;
|
||||
|
||||
if (dl_type < 0) {
|
||||
dl_type = -1 * dl_type;
|
||||
signed_p = 0;
|
||||
}
|
||||
|
||||
#define rb_ffi_type_of(t) (signed_p ? &ffi_type_s##t : &ffi_type_u##t)
|
||||
|
||||
switch (dl_type) {
|
||||
case DLTYPE_VOID:
|
||||
return &ffi_type_void;
|
||||
case DLTYPE_VOIDP:
|
||||
return &ffi_type_pointer;
|
||||
case DLTYPE_CHAR:
|
||||
return rb_ffi_type_of(char);
|
||||
case DLTYPE_SHORT:
|
||||
return rb_ffi_type_of(short);
|
||||
case DLTYPE_INT:
|
||||
return rb_ffi_type_of(int);
|
||||
case DLTYPE_LONG:
|
||||
return rb_ffi_type_of(long);
|
||||
#if HAVE_LONG_LONG
|
||||
case DLTYPE_LONG_LONG:
|
||||
return rb_ffi_type_of(int64);
|
||||
#endif
|
||||
case DLTYPE_FLOAT:
|
||||
return &ffi_type_float;
|
||||
case DLTYPE_DOUBLE:
|
||||
return &ffi_type_double;
|
||||
default:
|
||||
rb_raise(rb_eRuntimeError, "unknown type %d", dl_type);
|
||||
}
|
||||
return &ffi_type_pointer;
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef DL_CONVERSIONS
|
||||
#define DL_CONVERSIONS
|
||||
|
||||
#include <dl.h>
|
||||
|
||||
#define DL2FFI_TYPE(a) rb_dl_type_to_ffi_type(a)
|
||||
|
||||
ffi_type * rb_dl_type_to_ffi_type(int dl_type);
|
||||
|
||||
#endif
|
|
@ -8,30 +8,8 @@ $INSTALLFILES = [
|
|||
["dl.h", "$(HDRDIR)"],
|
||||
]
|
||||
|
||||
if pkg_config("libffi")
|
||||
# libffi closure api must be switched depending on the version
|
||||
if system("pkg-config --atleast-version=3.0.9 libffi")
|
||||
$defs.push(format('-DUSE_NEW_CLOSURE_API'))
|
||||
end
|
||||
else
|
||||
dir_config('ffi', '/usr/include', '/usr/lib')
|
||||
end
|
||||
|
||||
unless have_header('ffi.h')
|
||||
if have_header('ffi/ffi.h')
|
||||
$defs.push(format('-DUSE_HEADER_HACKS'))
|
||||
else
|
||||
abort "ffi is missing"
|
||||
end
|
||||
end
|
||||
|
||||
unless have_library('ffi')
|
||||
abort "ffi is missing"
|
||||
end
|
||||
|
||||
check = true
|
||||
if( have_header("dlfcn.h") )
|
||||
|
||||
have_library("dl")
|
||||
check &&= have_func("dlopen")
|
||||
check &&= have_func("dlclose")
|
||||
|
|
|
@ -1,21 +1,26 @@
|
|||
require 'dl'
|
||||
require 'dl/closure'
|
||||
require 'thread'
|
||||
|
||||
module DL
|
||||
SEM = Mutex.new
|
||||
|
||||
CdeclCallbackProcs = {}
|
||||
CdeclCallbackAddrs = {}
|
||||
|
||||
def set_callback_internal(proc_entry, addr_entry, argc, ty, abi = DL::Function::DEFAULT, &cbp)
|
||||
def set_callback_internal(proc_entry, addr_entry, argc, ty, &cbp)
|
||||
if( argc < 0 )
|
||||
raise(ArgumentError, "arity should not be less than 0.")
|
||||
end
|
||||
|
||||
closure = DL::Closure::BlockCaller.new(ty, [TYPE_VOIDP] * argc, abi, &cbp)
|
||||
proc_entry[closure.to_i] = closure
|
||||
closure.to_i
|
||||
addr = nil
|
||||
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
|
||||
}
|
||||
}
|
||||
addr
|
||||
end
|
||||
|
||||
def set_cdecl_callback(ty, argc, &cbp)
|
||||
|
@ -23,14 +28,32 @@ module DL
|
|||
end
|
||||
|
||||
def set_stdcall_callback(ty, argc, &cbp)
|
||||
set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, DL::Function::STDCALL, &cbp)
|
||||
set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, &cbp)
|
||||
end
|
||||
|
||||
def remove_callback_internal(proc_entry, addr_entry, addr, ctype = nil)
|
||||
addr = addr.to_i
|
||||
return false unless proc_entry.key?(addr)
|
||||
proc_entry.delete(addr)
|
||||
true
|
||||
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
|
||||
|
||||
def remove_cdecl_callback(addr, ctype = nil)
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
require 'dl'
|
||||
|
||||
module DL
|
||||
class Closure
|
||||
attr_reader :ctype
|
||||
attr_reader :args
|
||||
|
||||
class BlockCaller < DL::Closure
|
||||
def initialize ctype, args, abi = DL::Function::DEFAULT, &block
|
||||
super(ctype, args, abi)
|
||||
@block = block
|
||||
end
|
||||
|
||||
def call *args
|
||||
@block.call(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,26 +1,26 @@
|
|||
require 'dl'
|
||||
require 'dl/closure'
|
||||
require 'dl/callback'
|
||||
require 'dl/stack'
|
||||
require 'dl/value'
|
||||
require 'thread'
|
||||
|
||||
module DL
|
||||
class Function < DL::Method
|
||||
class Function
|
||||
include DL
|
||||
include ValueUtil
|
||||
|
||||
def initialize cfunc, argtypes, abi = DEFAULT, &block
|
||||
if block_given?
|
||||
@cfunc = Class.new(DL::Closure) {
|
||||
define_method(:call, block)
|
||||
}.new(cfunc.ctype, argtypes)
|
||||
def initialize(cfunc, argtypes, &proc)
|
||||
@cfunc = cfunc
|
||||
@stack = Stack.new(argtypes.collect{|ty| ty.abs})
|
||||
if( @cfunc.ctype < 0 )
|
||||
@cfunc.ctype = @cfunc.ctype.abs
|
||||
@unsigned = true
|
||||
else
|
||||
@cfunc = cfunc
|
||||
@unsigned = false
|
||||
end
|
||||
if( proc )
|
||||
bind(&proc)
|
||||
end
|
||||
|
||||
@args = argtypes
|
||||
super(@cfunc, @args.reject { |x| x == TYPE_VOID }, cfunc.ctype, abi)
|
||||
end
|
||||
|
||||
def to_i()
|
||||
|
@ -32,10 +32,11 @@ module DL
|
|||
end
|
||||
|
||||
def call(*args, &block)
|
||||
if block_given?
|
||||
args.find { |a| DL::Function === a }.bind_at_call(&block)
|
||||
end
|
||||
super
|
||||
funcs = []
|
||||
args = wrap_args(args, @stack.types, funcs, &block)
|
||||
r = @cfunc.call(@stack.pack(args))
|
||||
funcs.each{|f| f.unbind_at_call()}
|
||||
return wrap_result(r)
|
||||
end
|
||||
|
||||
def wrap_result(r)
|
||||
|
@ -51,16 +52,33 @@ module DL
|
|||
end
|
||||
|
||||
def bind(&block)
|
||||
@cfunc = Class.new(DL::Closure) {
|
||||
def initialize ctype, args, block
|
||||
super(ctype, args)
|
||||
@block = block
|
||||
if( !block )
|
||||
raise(RuntimeError, "block must be given.")
|
||||
end
|
||||
if( @cfunc.ptr == 0 )
|
||||
cb = Proc.new{|*args|
|
||||
ary = @stack.unpack(args)
|
||||
@stack.types.each_with_index{|ty, idx|
|
||||
case ty
|
||||
when TYPE_VOIDP
|
||||
ary[idx] = CPtr.new(ary[idx])
|
||||
end
|
||||
}
|
||||
r = block.call(*ary)
|
||||
wrap_arg(r, @cfunc.ctype, [])
|
||||
}
|
||||
case @cfunc.calltype
|
||||
when :cdecl
|
||||
@cfunc.ptr = set_cdecl_callback(@cfunc.ctype, @stack.size, &cb)
|
||||
when :stdcall
|
||||
@cfunc.ptr = set_stdcall_callback(@cfunc.ctype, @stack.size, &cb)
|
||||
else
|
||||
raise(RuntimeError, "unsupported calltype: #{@cfunc.calltype}")
|
||||
end
|
||||
|
||||
def call *args
|
||||
@block.call(*args)
|
||||
if( @cfunc.ptr == 0 )
|
||||
raise(RuntimeException, "can't bind C function.")
|
||||
end
|
||||
}.new(@cfunc.ctype, @args, block)
|
||||
end
|
||||
end
|
||||
|
||||
def unbind()
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
require 'dl'
|
||||
require 'dl/closure'
|
||||
require 'dl/func.rb'
|
||||
require 'dl/struct.rb'
|
||||
require 'dl/cparser.rb'
|
||||
|
@ -212,11 +211,9 @@ module DL
|
|||
end
|
||||
|
||||
def bind_function(name, ctype, argtype, call_type = nil, &block)
|
||||
closure = Class.new(DL::Closure) {
|
||||
define_method(:call, block)
|
||||
}.new(ctype, argtype)
|
||||
|
||||
Function.new(closure, argtype)
|
||||
f = Function.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype)
|
||||
f.bind(&block)
|
||||
f
|
||||
end
|
||||
|
||||
def create_temp_function(name, ctype, argtype, call_type = nil)
|
||||
|
|
|
@ -36,7 +36,16 @@ module DL
|
|||
end
|
||||
end
|
||||
|
||||
def wrap_arg(arg, ty, funcs = [], &block)
|
||||
def wrap_args(args, tys, funcs, &block)
|
||||
result = []
|
||||
tys ||= []
|
||||
args.each_with_index{|arg, idx|
|
||||
result.push(wrap_arg(arg, tys[idx], funcs, &block))
|
||||
}
|
||||
result
|
||||
end
|
||||
|
||||
def wrap_arg(arg, ty, funcs, &block)
|
||||
funcs ||= []
|
||||
case arg
|
||||
when nil
|
||||
|
|
251
ext/dl/method.c
251
ext/dl/method.c
|
@ -1,251 +0,0 @@
|
|||
/* -*- C -*-
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <ruby.h>
|
||||
#include <errno.h>
|
||||
#include "dl.h"
|
||||
#include <dl_conversions.h>
|
||||
|
||||
VALUE rb_cDLMethod;
|
||||
|
||||
typedef union
|
||||
{
|
||||
unsigned char uchar; /* ffi_type_uchar */
|
||||
signed char schar; /* ffi_type_schar */
|
||||
unsigned short ushort; /* ffi_type_sshort */
|
||||
signed short sshort; /* ffi_type_ushort */
|
||||
unsigned int uint; /* ffi_type_uint */
|
||||
signed int sint; /* ffi_type_sint */
|
||||
unsigned long ulong; /* ffi_type_ulong */
|
||||
signed long slong; /* ffi_type_slong */
|
||||
float ffloat; /* ffi_type_float */
|
||||
double ddouble; /* ffi_type_double */
|
||||
#if HAVE_LONG_LONG
|
||||
unsigned LONG_LONG long_long; /* ffi_type_uint64 */
|
||||
#endif
|
||||
void * pointer; /* ffi_type_pointer */
|
||||
} dl_generic;
|
||||
|
||||
static void
|
||||
dlfunction_free(void *p)
|
||||
{
|
||||
ffi_cif *ptr = p;
|
||||
if (ptr->arg_types) xfree(ptr->arg_types);
|
||||
xfree(ptr);
|
||||
}
|
||||
|
||||
static size_t
|
||||
dlfunction_memsize(const void *p)
|
||||
{
|
||||
/* const */ffi_cif *ptr = (ffi_cif *)p;
|
||||
size_t size = 0;
|
||||
|
||||
if (ptr) {
|
||||
size += sizeof(*ptr);
|
||||
size += ffi_raw_size(ptr);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
const rb_data_type_t dlfunction_data_type = {
|
||||
"dl/method",
|
||||
0, dlfunction_free, dlfunction_memsize,
|
||||
};
|
||||
|
||||
static VALUE
|
||||
rb_dlfunc_allocate(VALUE klass)
|
||||
{
|
||||
ffi_cif * cif;
|
||||
|
||||
return TypedData_Make_Struct(klass, ffi_cif, &dlfunction_data_type, cif);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_dlfunction_initialize(int argc, VALUE argv[], VALUE self)
|
||||
{
|
||||
ffi_cif * cif;
|
||||
ffi_type **arg_types;
|
||||
ffi_status result;
|
||||
VALUE ptr, args, ret_type, abi;
|
||||
int i;
|
||||
|
||||
rb_scan_args(argc, argv, "31", &ptr, &args, &ret_type, &abi);
|
||||
if(NIL_P(abi)) abi = INT2NUM(FFI_DEFAULT_ABI);
|
||||
|
||||
rb_iv_set(self, "@ptr", ptr);
|
||||
rb_iv_set(self, "@args", args);
|
||||
rb_iv_set(self, "@return_type", ret_type);
|
||||
rb_iv_set(self, "@abi", abi);
|
||||
|
||||
TypedData_Get_Struct(self, ffi_cif, &dlfunction_data_type, cif);
|
||||
|
||||
arg_types = xcalloc(RARRAY_LEN(args) + 1, sizeof(ffi_type *));
|
||||
|
||||
for (i = 0; i < RARRAY_LEN(args); i++) {
|
||||
int type = NUM2INT(RARRAY_PTR(args)[i]);
|
||||
arg_types[i] = DL2FFI_TYPE(type);
|
||||
}
|
||||
arg_types[RARRAY_LEN(args)] = NULL;
|
||||
|
||||
result = ffi_prep_cif (
|
||||
cif,
|
||||
NUM2INT(abi),
|
||||
RARRAY_LENINT(args),
|
||||
DL2FFI_TYPE(NUM2INT(ret_type)),
|
||||
arg_types);
|
||||
|
||||
if (result)
|
||||
rb_raise(rb_eRuntimeError, "error creating CIF %d", result);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static void
|
||||
dl2generic(int dl_type, VALUE src, dl_generic * dst)
|
||||
{
|
||||
int signed_p = 1;
|
||||
|
||||
if (dl_type < 0) {
|
||||
dl_type = -1 * dl_type;
|
||||
signed_p = 0;
|
||||
}
|
||||
|
||||
switch (dl_type) {
|
||||
case DLTYPE_VOID:
|
||||
break;
|
||||
case DLTYPE_VOIDP:
|
||||
dst->pointer = NUM2PTR(rb_Integer(src));
|
||||
break;
|
||||
case DLTYPE_CHAR:
|
||||
case DLTYPE_SHORT:
|
||||
case DLTYPE_INT:
|
||||
dst->sint = NUM2INT(src);
|
||||
break;
|
||||
case DLTYPE_LONG:
|
||||
if (signed_p)
|
||||
dst->slong = NUM2LONG(src);
|
||||
else
|
||||
dst->ulong = NUM2LONG(src);
|
||||
break;
|
||||
#if HAVE_LONG_LONG
|
||||
case DLTYPE_LONG_LONG:
|
||||
dst->long_long = rb_big2ull(src);
|
||||
break;
|
||||
#endif
|
||||
case DLTYPE_FLOAT:
|
||||
dst->ffloat = (float)NUM2DBL(src);
|
||||
break;
|
||||
case DLTYPE_DOUBLE:
|
||||
dst->ddouble = NUM2DBL(src);
|
||||
break;
|
||||
default:
|
||||
rb_raise(rb_eRuntimeError, "unknown type %d", dl_type);
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
unwrap_ffi(VALUE rettype, dl_generic retval)
|
||||
{
|
||||
int signed_p = 1;
|
||||
int dl_type = NUM2INT(rettype);
|
||||
|
||||
if (dl_type < 0) {
|
||||
dl_type = -1 * dl_type;
|
||||
signed_p = 0;
|
||||
}
|
||||
|
||||
switch (dl_type) {
|
||||
case DLTYPE_VOID:
|
||||
return Qnil;
|
||||
case DLTYPE_VOIDP:
|
||||
return rb_dlptr_new((void *)retval.pointer, 0, NULL);
|
||||
case DLTYPE_CHAR:
|
||||
case DLTYPE_SHORT:
|
||||
case DLTYPE_INT:
|
||||
return INT2NUM(retval.sint);
|
||||
case DLTYPE_LONG:
|
||||
if (signed_p) return LONG2NUM(retval.slong);
|
||||
return ULONG2NUM(retval.ulong);
|
||||
#if HAVE_LONG_LONG
|
||||
case DLTYPE_LONG_LONG:
|
||||
return rb_ll2inum(retval.long_long);
|
||||
break;
|
||||
#endif
|
||||
case DLTYPE_FLOAT:
|
||||
return rb_float_new(retval.ffloat);
|
||||
case DLTYPE_DOUBLE:
|
||||
return rb_float_new(retval.ddouble);
|
||||
default:
|
||||
rb_raise(rb_eRuntimeError, "unknown type %d", dl_type);
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_dlfunction_call(int argc, VALUE argv[], VALUE self)
|
||||
{
|
||||
ffi_cif * cif;
|
||||
dl_generic retval;
|
||||
dl_generic *generic_args;
|
||||
void **values;
|
||||
void * fun_ptr;
|
||||
VALUE cfunc, types;
|
||||
int i;
|
||||
|
||||
TypedData_Get_Struct(self, ffi_cif, &dlfunction_data_type, cif);
|
||||
|
||||
values = xcalloc((size_t)argc + 1, (size_t)sizeof(void *));
|
||||
generic_args = xcalloc((size_t)argc, (size_t)sizeof(dl_generic));
|
||||
|
||||
cfunc = rb_iv_get(self, "@ptr");
|
||||
types = rb_iv_get(self, "@args");
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
VALUE dl_type = RARRAY_PTR(types)[i];
|
||||
VALUE src = argv[i];
|
||||
|
||||
if(NUM2INT(dl_type) == DLTYPE_VOIDP) {
|
||||
if(NIL_P(src)) {
|
||||
src = INT2NUM(0);
|
||||
} else if(rb_cDLCPtr != CLASS_OF(src)) {
|
||||
src = rb_funcall(rb_cDLCPtr, rb_intern("[]"), 1, src);
|
||||
}
|
||||
src = rb_Integer(src);
|
||||
}
|
||||
|
||||
dl2generic(NUM2INT(dl_type), src, &generic_args[i]);
|
||||
values[i] = (void *)&generic_args[i];
|
||||
}
|
||||
values[argc] = NULL;
|
||||
|
||||
ffi_call(cif, NUM2PTR(rb_Integer(cfunc)), &retval, values);
|
||||
|
||||
rb_dl_set_last_error(self, INT2NUM(errno));
|
||||
#if defined(HAVE_WINDOWS_H)
|
||||
rb_dl_set_win32_last_error(self, INT2NUM(GetLastError()));
|
||||
#endif
|
||||
|
||||
xfree(values);
|
||||
xfree(generic_args);
|
||||
|
||||
return unwrap_ffi(rb_iv_get(self, "@return_type"), retval);
|
||||
}
|
||||
|
||||
void
|
||||
Init_dlfunction(void)
|
||||
{
|
||||
rb_cDLMethod = rb_define_class_under(rb_mDL, "Method", rb_cObject);
|
||||
|
||||
rb_define_const(rb_cDLMethod, "DEFAULT", INT2NUM(FFI_DEFAULT_ABI));
|
||||
|
||||
#ifdef FFI_STDCALL
|
||||
rb_define_const(rb_cDLMethod, "STDCALL", INT2NUM(FFI_STDCALL));
|
||||
#endif
|
||||
|
||||
rb_define_alloc_func(rb_cDLMethod, rb_dlfunc_allocate);
|
||||
|
||||
rb_define_method(rb_cDLMethod, "call", rb_dlfunction_call, -1);
|
||||
|
||||
rb_define_method(rb_cDLMethod, "initialize", rb_dlfunction_initialize, -1);
|
||||
}
|
||||
/* vim: set noet sw=4 sts=4 */
|
Loading…
Reference in a new issue