diff options
author | Hiroshi SHIBATA <[email protected]> | 2025-01-24 16:23:16 +0900 |
---|---|---|
committer | Hiroshi SHIBATA <[email protected]> | 2025-02-05 07:36:59 +0900 |
commit | 908529b7e0cf39bb1204588bd7f86c6bd40b8a00 (patch) | |
tree | b1bcb3d15b22f04cbce25f0658935b5c5d218a17 /ext/fiddle/closure.c | |
parent | 91a10c07579f282a94e4b5830feaeca87f9a7dd3 (diff) |
Migrate fiddle as bundled gems
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/12616
Diffstat (limited to 'ext/fiddle/closure.c')
-rw-r--r-- | ext/fiddle/closure.c | 458 |
1 files changed, 0 insertions, 458 deletions
diff --git a/ext/fiddle/closure.c b/ext/fiddle/closure.c deleted file mode 100644 index d526d870e8..0000000000 --- a/ext/fiddle/closure.c +++ /dev/null @@ -1,458 +0,0 @@ -#include <fiddle.h> -#include <stdbool.h> -#include <ruby/thread.h> - -int ruby_thread_has_gvl_p(void); /* from internal.h */ - -VALUE cFiddleClosure; - -typedef struct { - void * code; - ffi_closure *pcl; - ffi_cif cif; - int argc; - ffi_type **argv; -} fiddle_closure; - -#if defined(__OpenBSD__) -# define USE_FFI_CLOSURE_ALLOC 0 -#endif - -#if defined(USE_FFI_CLOSURE_ALLOC) -#elif !defined(HAVE_FFI_CLOSURE_ALLOC) -# define USE_FFI_CLOSURE_ALLOC 0 -#else -# define USE_FFI_CLOSURE_ALLOC 1 -#endif - -static void -dealloc(void * ptr) -{ - fiddle_closure * cls = (fiddle_closure *)ptr; -#if USE_FFI_CLOSURE_ALLOC - ffi_closure_free(cls->pcl); -#else - munmap(cls->pcl, sizeof(*cls->pcl)); -#endif - if (cls->argv) xfree(cls->argv); - xfree(cls); -} - -static size_t -closure_memsize(const void * ptr) -{ - fiddle_closure * cls = (fiddle_closure *)ptr; - size_t size = 0; - - size += sizeof(*cls); -#if !defined(FFI_NO_RAW_API) || !FFI_NO_RAW_API - size += ffi_raw_size(&cls->cif); -#endif - size += sizeof(*cls->argv); - size += sizeof(ffi_closure); - - return size; -} - -const rb_data_type_t closure_data_type = { - .wrap_struct_name = "fiddle/closure", - .function = { - .dmark = 0, - .dfree = dealloc, - .dsize = closure_memsize - }, - .flags = FIDDLE_DEFAULT_TYPED_DATA_FLAGS, -}; - -struct callback_args { - ffi_cif *cif; - void *resp; - void **args; - void *ctx; -}; - -static void * -with_gvl_callback(void *ptr) -{ - struct callback_args *x = ptr; - - VALUE self = (VALUE)x->ctx; - VALUE rbargs = rb_iv_get(self, "@args"); - VALUE ctype = rb_iv_get(self, "@ctype"); - int argc = RARRAY_LENINT(rbargs); - VALUE params = rb_ary_tmp_new(argc); - VALUE ret; - VALUE cPointer; - int i, type; - - cPointer = rb_const_get(mFiddle, rb_intern("Pointer")); - - for (i = 0; i < argc; i++) { - type = NUM2INT(RARRAY_AREF(rbargs, i)); - switch (type) { - case TYPE_VOID: - argc = 0; - break; - case TYPE_INT: - rb_ary_push(params, INT2NUM(*(int *)x->args[i])); - break; - case TYPE_UINT: - rb_ary_push(params, UINT2NUM(*(unsigned int *)x->args[i])); - break; - case TYPE_VOIDP: - rb_ary_push(params, - rb_funcall(cPointer, rb_intern("[]"), 1, - PTR2NUM(*(void **)x->args[i]))); - break; - case TYPE_LONG: - rb_ary_push(params, LONG2NUM(*(long *)x->args[i])); - break; - case TYPE_ULONG: - rb_ary_push(params, ULONG2NUM(*(unsigned long *)x->args[i])); - break; - case TYPE_CHAR: - rb_ary_push(params, INT2NUM(*(signed char *)x->args[i])); - break; - case TYPE_UCHAR: - rb_ary_push(params, UINT2NUM(*(unsigned char *)x->args[i])); - break; - case TYPE_SHORT: - rb_ary_push(params, INT2NUM(*(signed short *)x->args[i])); - break; - case TYPE_USHORT: - rb_ary_push(params, UINT2NUM(*(unsigned short *)x->args[i])); - break; - case TYPE_DOUBLE: - rb_ary_push(params, rb_float_new(*(double *)x->args[i])); - break; - case TYPE_FLOAT: - rb_ary_push(params, rb_float_new(*(float *)x->args[i])); - break; -#if HAVE_LONG_LONG - case TYPE_LONG_LONG: - rb_ary_push(params, LL2NUM(*(LONG_LONG *)x->args[i])); - break; - case TYPE_ULONG_LONG: - rb_ary_push(params, ULL2NUM(*(unsigned LONG_LONG *)x->args[i])); - break; -#endif - case TYPE_CONST_STRING: - rb_ary_push(params, - rb_str_new_cstr(*((const char **)(x->args[i])))); - break; - case TYPE_BOOL: - if (sizeof(bool) == sizeof(char)) { - rb_ary_push(params, CBOOL2RBBOOL(*(unsigned char *)x->args[i])); - } else if (sizeof(bool) == sizeof(short)) { - rb_ary_push(params, CBOOL2RBBOOL(*(unsigned short *)x->args[i])); - } else if (sizeof(bool) == sizeof(int)) { - rb_ary_push(params, CBOOL2RBBOOL(*(unsigned int *)x->args[i])); - } else if (sizeof(bool) == sizeof(long)) { - rb_ary_push(params, CBOOL2RBBOOL(*(unsigned long *)x->args[i])); - } else { - rb_raise(rb_eNotImpError, "bool isn't supported: %u", - (unsigned int)sizeof(bool)); - } - break; - default: - rb_raise(rb_eRuntimeError, "closure args: %d", type); - } - } - - ret = rb_funcall2(self, rb_intern("call"), argc, RARRAY_CONST_PTR(params)); - RB_GC_GUARD(params); - - type = NUM2INT(ctype); - switch (type) { - case TYPE_VOID: - break; - case TYPE_LONG: - *(long *)x->resp = NUM2LONG(ret); - break; - case TYPE_ULONG: - *(unsigned long *)x->resp = NUM2ULONG(ret); - break; - case TYPE_CHAR: - case TYPE_SHORT: - case TYPE_INT: - *(ffi_sarg *)x->resp = NUM2INT(ret); - break; - case TYPE_UCHAR: - case TYPE_USHORT: - case TYPE_UINT: - *(ffi_arg *)x->resp = NUM2UINT(ret); - break; - case TYPE_VOIDP: - *(void **)x->resp = NUM2PTR(ret); - break; - case TYPE_DOUBLE: - *(double *)x->resp = NUM2DBL(ret); - break; - case TYPE_FLOAT: - *(float *)x->resp = (float)NUM2DBL(ret); - break; -#if HAVE_LONG_LONG - case TYPE_LONG_LONG: - *(LONG_LONG *)x->resp = NUM2LL(ret); - break; - case TYPE_ULONG_LONG: - *(unsigned LONG_LONG *)x->resp = NUM2ULL(ret); - break; -#endif - case TYPE_CONST_STRING: - /* Dangerous. Callback must keep reference of the String. */ - *((const char **)(x->resp)) = StringValueCStr(ret); - break; - case TYPE_BOOL: - if (sizeof(bool) == sizeof(long)) { - *(unsigned long *)x->resp = RB_TEST(ret); - } else { - *(ffi_arg *)x->resp = RB_TEST(ret); - } - break; - default: - rb_raise(rb_eRuntimeError, "closure retval: %d", type); - } - return 0; -} - -static void -callback(ffi_cif *cif, void *resp, void **args, void *ctx) -{ - struct callback_args x; - - x.cif = cif; - x.resp = resp; - x.args = args; - x.ctx = ctx; - - if (ruby_thread_has_gvl_p()) { - (void)with_gvl_callback(&x); - } else { - (void)rb_thread_call_with_gvl(with_gvl_callback, &x); - } -} - -static VALUE -allocate(VALUE klass) -{ - fiddle_closure * closure; - - VALUE i = TypedData_Make_Struct(klass, fiddle_closure, - &closure_data_type, closure); - -#if USE_FFI_CLOSURE_ALLOC - 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 - - return i; -} - -static fiddle_closure * -get_raw(VALUE self) -{ - fiddle_closure *closure; - TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, closure); - if (!closure) { - rb_raise(rb_eArgError, "already freed: %+"PRIsVALUE, self); - } - return closure; -} - -typedef struct { - VALUE self; - int argc; - VALUE *argv; -} initialize_data; - -static VALUE -initialize_body(VALUE user_data) -{ - initialize_data *data = (initialize_data *)user_data; - VALUE ret; - VALUE args; - VALUE normalized_args; - VALUE abi; - fiddle_closure * cl; - ffi_cif * cif; - ffi_closure *pcl; - ffi_status result; - int i, argc; - - if (2 == rb_scan_args(data->argc, data->argv, "21", &ret, &args, &abi)) - abi = INT2NUM(FFI_DEFAULT_ABI); - - Check_Type(args, T_ARRAY); - - argc = RARRAY_LENINT(args); - - TypedData_Get_Struct(data->self, fiddle_closure, &closure_data_type, cl); - - cl->argv = (ffi_type **)xcalloc(argc + 1, sizeof(ffi_type *)); - - normalized_args = rb_ary_new_capa(argc); - for (i = 0; i < argc; i++) { - VALUE arg = rb_fiddle_type_ensure(RARRAY_AREF(args, i)); - rb_ary_push(normalized_args, arg); - cl->argv[i] = rb_fiddle_int_to_ffi_type(NUM2INT(arg)); - } - cl->argv[argc] = NULL; - OBJ_FREEZE_RAW(normalized_args); - - ret = rb_fiddle_type_ensure(ret); - rb_iv_set(data->self, "@ctype", ret); - rb_iv_set(data->self, "@args", normalized_args); - - cif = &cl->cif; - pcl = cl->pcl; - - result = ffi_prep_cif(cif, - NUM2INT(abi), - argc, - rb_fiddle_int_to_ffi_type(NUM2INT(ret)), - cl->argv); - - if (FFI_OK != result) { - rb_raise(rb_eRuntimeError, "error prepping CIF %d", result); - } - -#if USE_FFI_CLOSURE_ALLOC - result = ffi_prep_closure_loc(pcl, cif, callback, - (void *)(data->self), cl->code); -#else - result = ffi_prep_closure(pcl, cif, callback, (void *)(data->self)); - cl->code = (void *)pcl; - i = mprotect(pcl, sizeof(*pcl), PROT_READ | PROT_EXEC); - if (i) { - rb_sys_fail("mprotect"); - } -#endif - - if (FFI_OK != result) { - rb_raise(rb_eRuntimeError, "error prepping closure %d", result); - } - - return data->self; -} - -static VALUE -initialize_rescue(VALUE user_data, VALUE exception) -{ - initialize_data *data = (initialize_data *)user_data; - dealloc(RTYPEDDATA_DATA(data->self)); - RTYPEDDATA_DATA(data->self) = NULL; - rb_exc_raise(exception); - return data->self; -} - -static VALUE -initialize(int argc, VALUE *argv, VALUE self) -{ - initialize_data data; - data.self = self; - data.argc = argc; - data.argv = argv; - return rb_rescue(initialize_body, (VALUE)&data, - initialize_rescue, (VALUE)&data); -} - -static VALUE -to_i(VALUE self) -{ - fiddle_closure *closure = get_raw(self); - return PTR2NUM(closure->code); -} - -static VALUE -closure_free(VALUE self) -{ - fiddle_closure *closure; - TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, closure); - if (closure) { - dealloc(closure); - RTYPEDDATA_DATA(self) = NULL; - } - return RUBY_Qnil; -} - -static VALUE -closure_freed_p(VALUE self) -{ - fiddle_closure *closure; - TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, closure); - return closure ? RUBY_Qfalse : RUBY_Qtrue; -} - -void -Init_fiddle_closure(void) -{ -#if 0 - mFiddle = rb_define_module("Fiddle"); /* let rdoc know about mFiddle */ -#endif - - /* - * Document-class: Fiddle::Closure - * - * == Description - * - * An FFI closure wrapper, for handling callbacks. - * - * == Example - * - * closure = Class.new(Fiddle::Closure) { - * def call - * 10 - * end - * }.new(Fiddle::TYPE_INT, []) - * #=> #<#<Class:0x0000000150d308>:0x0000000150d240> - * func = Fiddle::Function.new(closure, [], Fiddle::TYPE_INT) - * #=> #<Fiddle::Function:0x00000001516e58> - * func.call - * #=> 10 - */ - cFiddleClosure = rb_define_class_under(mFiddle, "Closure", rb_cObject); - - rb_define_alloc_func(cFiddleClosure, allocate); - - /* - * Document-method: new - * - * call-seq: new(ret, args, abi = Fiddle::DEFAULT) - * - * Construct a new Closure object. - * - * * +ret+ is the C type to be returned - * * +args+ is an Array of arguments, passed to the callback function - * * +abi+ is the abi of the closure - * - * If there is an error in preparing the ffi_cif or ffi_prep_closure, - * then a RuntimeError will be raised. - */ - rb_define_method(cFiddleClosure, "initialize", initialize, -1); - - /* - * Document-method: to_i - * - * Returns the memory address for this closure. - */ - rb_define_method(cFiddleClosure, "to_i", to_i, 0); - - /* - * Document-method: free - * - * Free this closure explicitly. You can't use this closure anymore. - * - * If this closure is already freed, this does nothing. - */ - rb_define_method(cFiddleClosure, "free", closure_free, 0); - - /* - * Document-method: freed? - * - * Whether this closure was freed explicitly. - */ - rb_define_method(cFiddleClosure, "freed?", closure_freed_p, 0); -} |