diff options
Diffstat (limited to 'ext/ffi_c/Variadic.c')
-rw-r--r-- | ext/ffi_c/Variadic.c | 88 |
1 files changed, 65 insertions, 23 deletions
diff --git a/ext/ffi_c/Variadic.c b/ext/ffi_c/Variadic.c index 8ad38b1..09d7ce8 100644 --- a/ext/ffi_c/Variadic.c +++ b/ext/ffi_c/Variadic.c @@ -36,6 +36,9 @@ #include <stdint.h> #include <stdbool.h> #include <ruby.h> +#if HAVE_RB_EXT_RACTOR_SAFE +#include <ruby/ractor.h> +#endif #include <ffi.h> #include "rbffi.h" @@ -62,35 +65,65 @@ typedef struct VariadicInvoker_ { bool blocking; } VariadicInvoker; - static VALUE variadic_allocate(VALUE klass); static VALUE variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE rbReturnType, VALUE options); -static void variadic_mark(VariadicInvoker *); +static void variadic_mark(void *); +static void variadic_compact(void *); +static size_t variadic_memsize(const void *); static VALUE classVariadicInvoker = Qnil; +static const rb_data_type_t variadic_data_type = { + .wrap_struct_name = "FFI::VariadicInvoker", + .function = { + .dmark = variadic_mark, + .dfree = RUBY_TYPED_DEFAULT_FREE, + .dsize = variadic_memsize, + ffi_compact_callback( variadic_compact ) + }, + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | FFI_RUBY_TYPED_FROZEN_SHAREABLE +}; + static VALUE variadic_allocate(VALUE klass) { VariadicInvoker *invoker; - VALUE obj = Data_Make_Struct(klass, VariadicInvoker, variadic_mark, -1, invoker); + VALUE obj = TypedData_Make_Struct(klass, VariadicInvoker, &variadic_data_type, invoker); - invoker->rbAddress = Qnil; - invoker->rbEnums = Qnil; - invoker->rbReturnType = Qnil; + RB_OBJ_WRITE(obj, &invoker->rbAddress, Qnil); + RB_OBJ_WRITE(obj, &invoker->rbEnums, Qnil); + RB_OBJ_WRITE(obj, &invoker->rbReturnType, Qnil); invoker->blocking = false; return obj; } static void -variadic_mark(VariadicInvoker *invoker) +variadic_mark(void *data) +{ + VariadicInvoker *invoker = (VariadicInvoker *)data; + rb_gc_mark_movable(invoker->rbEnums); + rb_gc_mark_movable(invoker->rbAddress); + rb_gc_mark_movable(invoker->rbReturnType); +} + +static void +variadic_compact(void *data) { - rb_gc_mark(invoker->rbEnums); - rb_gc_mark(invoker->rbAddress); - rb_gc_mark(invoker->rbReturnType); + VariadicInvoker *invoker = (VariadicInvoker *)data; + ffi_gc_location(invoker->rbEnums); + ffi_gc_location(invoker->rbAddress); + ffi_gc_location(invoker->rbReturnType); +} + +static size_t +variadic_memsize(const void *data) +{ + return sizeof(VariadicInvoker); } static VALUE @@ -108,10 +141,10 @@ variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE Check_Type(options, T_HASH); convention = rb_hash_aref(options, ID2SYM(rb_intern("convention"))); - Data_Get_Struct(self, VariadicInvoker, invoker); - invoker->rbEnums = rb_hash_aref(options, ID2SYM(rb_intern("enums"))); - invoker->rbAddress = rbFunction; - invoker->function = rbffi_AbstractMemory_Cast(rbFunction, rbffi_PointerClass)->address; + TypedData_Get_Struct(self, VariadicInvoker, &variadic_data_type, invoker); + RB_OBJ_WRITE(self, &invoker->rbEnums, rb_hash_aref(options, ID2SYM(rb_intern("enums")))); + RB_OBJ_WRITE(self, &invoker->rbAddress, rbFunction); + invoker->function = rbffi_AbstractMemory_Cast(rbFunction, &rbffi_pointer_data_type)->address; invoker->blocking = RTEST(rb_hash_aref(options, ID2SYM(rb_intern("blocking")))); #if defined(X86_WIN32) @@ -122,13 +155,13 @@ variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE invoker->abi = FFI_DEFAULT_ABI; #endif - invoker->rbReturnType = rbffi_Type_Lookup(rbReturnType); + RB_OBJ_WRITE(self, &invoker->rbReturnType, rbffi_Type_Lookup(rbReturnType)); if (!RTEST(invoker->rbReturnType)) { VALUE typeName = rb_funcall2(rbReturnType, rb_intern("inspect"), 0, NULL); rb_raise(rb_eTypeError, "Invalid return type (%s)", RSTRING_PTR(typeName)); } - Data_Get_Struct(rbReturnType, Type, invoker->returnType); + TypedData_Get_Struct(rbReturnType, Type, &rbffi_type_data_type, invoker->returnType); invoker->paramCount = -1; @@ -142,7 +175,7 @@ variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE VALUE typeName = rb_funcall2(entry, rb_intern("inspect"), 0, NULL); rb_raise(rb_eTypeError, "Invalid parameter type (%s)", RSTRING_PTR(typeName)); } - Data_Get_Struct(rbType, Type, type); + TypedData_Get_Struct(rbType, Type, &rbffi_type_data_type, type); if (type->nativeType != NATIVE_VARARGS) { rb_ary_push(fixed, entry); } @@ -150,7 +183,7 @@ variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE /* * @fixed and @type_map are used by the parameter mangling ruby code */ - rb_iv_set(self, "@fixed", fixed); + rb_iv_set(self, "@fixed", rb_obj_freeze(fixed)); rb_iv_set(self, "@type_map", rb_hash_aref(options, ID2SYM(rb_intern("type_map")))); return retval; @@ -176,7 +209,7 @@ variadic_invoke(VALUE self, VALUE parameterTypes, VALUE parameterValues) Check_Type(parameterTypes, T_ARRAY); Check_Type(parameterValues, T_ARRAY); - Data_Get_Struct(self, VariadicInvoker, invoker); + TypedData_Get_Struct(self, VariadicInvoker, &variadic_data_type, invoker); paramCount = (int) RARRAY_LEN(parameterTypes); paramTypes = ALLOCA_N(Type *, paramCount); ffiParamTypes = ALLOCA_N(ffi_type *, paramCount); @@ -192,25 +225,25 @@ variadic_invoke(VALUE self, VALUE parameterTypes, VALUE parameterValues) if (!rb_obj_is_kind_of(rbType, rbffi_TypeClass)) { rb_raise(rb_eTypeError, "wrong type. Expected (FFI::Type)"); } - Data_Get_Struct(rbType, Type, paramTypes[i]); + TypedData_Get_Struct(rbType, Type, &rbffi_type_data_type, paramTypes[i]); switch (paramTypes[i]->nativeType) { case NATIVE_INT8: case NATIVE_INT16: case NATIVE_INT32: rbType = rb_const_get(rbffi_TypeClass, rb_intern("INT32")); - Data_Get_Struct(rbType, Type, paramTypes[i]); + TypedData_Get_Struct(rbType, Type, &rbffi_type_data_type, paramTypes[i]); break; case NATIVE_UINT8: case NATIVE_UINT16: case NATIVE_UINT32: rbType = rb_const_get(rbffi_TypeClass, rb_intern("UINT32")); - Data_Get_Struct(rbType, Type, paramTypes[i]); + TypedData_Get_Struct(rbType, Type, &rbffi_type_data_type, paramTypes[i]); break; case NATIVE_FLOAT32: rbType = rb_const_get(rbffi_TypeClass, rb_intern("DOUBLE")); - Data_Get_Struct(rbType, Type, paramTypes[i]); + TypedData_Get_Struct(rbType, Type, &rbffi_type_data_type, paramTypes[i]); break; case NATIVE_FUNCTION: @@ -288,6 +321,14 @@ variadic_invoke(VALUE self, VALUE parameterTypes, VALUE parameterValues) return rbffi_NativeValue_ToRuby(invoker->returnType, invoker->rbReturnType, retval); } +static VALUE +variadic_return_type(VALUE self) +{ + VariadicInvoker* invoker; + + TypedData_Get_Struct(self, VariadicInvoker, &variadic_data_type, invoker); + return invoker->rbReturnType; +} void rbffi_Variadic_Init(VALUE moduleFFI) @@ -299,5 +340,6 @@ rbffi_Variadic_Init(VALUE moduleFFI) rb_define_method(classVariadicInvoker, "initialize", variadic_initialize, 4); rb_define_method(classVariadicInvoker, "invoke", variadic_invoke, 2); + rb_define_method(classVariadicInvoker, "return_type", variadic_return_type, 0); } |