diff options
Diffstat (limited to 'doc/extension.rdoc')
-rw-r--r-- | doc/extension.rdoc | 175 |
1 files changed, 122 insertions, 53 deletions
diff --git a/doc/extension.rdoc b/doc/extension.rdoc index c0360ae625..ba59d107ab 100644 --- a/doc/extension.rdoc +++ b/doc/extension.rdoc @@ -747,18 +747,24 @@ RUBY_TYPED_WB_PROTECTED :: barriers in all implementations of methods of that object as appropriate. Otherwise Ruby might crash while running. - More about write barriers can be found in "Generational GC" in - Appendix D. + More about write barriers can be found in {Generational + GC}[rdoc-ref:@Appendix+D.+Generational+GC]. RUBY_TYPED_FROZEN_SHAREABLE :: - This flag indicates that the object is shareable object - if the object is frozen. See Appendix F more details. + This flag indicates that the object is shareable object if the object + is frozen. See {Ractor support}[rdoc-ref:@Appendix+F.+Ractor+support] + more details. If this flag is not set, the object can not become a shareable object by Ractor.make_shareable() method. -You can allocate and wrap the structure in one step. +Note that this macro can raise an exception. If sval to be wrapped +holds a resource needs to be released (e.g., allocated memory, handle +from an external library, and etc), you will have to use rb_protect. + +You can allocate and wrap the structure in one step, in more +preferable manner. TypedData_Make_Struct(klass, type, data_type, sval) @@ -767,10 +773,71 @@ the structure, which is also allocated. This macro works like: (sval = ZALLOC(type), TypedData_Wrap_Struct(klass, data_type, sval)) +However, you should use this macro instead of "allocation then wrap" +like the above code if it is simply allocated, because the latter can +raise a NoMemoryError and sval will be memory leaked in that case. + Arguments klass and data_type work like their counterparts in TypedData_Wrap_Struct(). A pointer to the allocated structure will be assigned to sval, which should be a pointer of the type specified. +==== Declaratively marking/compacting struct references + +In the case where your struct refers to Ruby objects that are simple values, +not wrapped in conditional logic or complex data structures an alternative +approach to marking and reference updating is provided, by declaring offset +references to the VALUES in your struct. + +Doing this allows the Ruby GC to support marking these references and GC +compaction without the need to define the +dmark+ and +dcompact+ callbacks. + +You must define a static list of VALUE pointers to the offsets within your +struct where the references are located, and set the "data" member to point to +this reference list. The reference list must end with +RUBY_END_REFS+. + +Some Macros have been provided to make edge referencing easier: + +* <code>RUBY_TYPED_DECL_MARKING</code> =A flag that can be set on the +ruby_data_type_t+ to indicate that references are being declared as edges. + +* <code>RUBY_REFERENCES(ref_list_name)</code> - Define _ref_list_name_ as a list of references + +* <code>RUBY_REF_END</code> - The end mark of the references list. + +* <code>RUBY_REF_EDGE(struct, member)</code> - Declare _member_ as a VALUE edge from _struct_. Use this after +RUBY_REFERENCES_START+ + +* +RUBY_REFS_LIST_PTR+ - Coerce the reference list into a format that can be + accepted by the existing +dmark+ interface. + +The example below is from Dir (defined in +dir.c+) + + // The struct being wrapped. Notice this contains 3 members of which the second + // is a VALUE reference to another ruby object. + struct dir_data { + DIR *dir; + const VALUE path; + rb_encoding *enc; + } + + // Define a reference list `dir_refs` containing a single entry to `path`. + // Needs terminating with RUBY_REF_END + RUBY_REFERENCES(dir_refs) = { + RUBY_REF_EDGE(dir_data, path), + RUBY_REF_END + }; + + // Override the "dmark" field with the defined reference list now that we + // no longer need a marking callback and add RUBY_TYPED_DECL_MARKING to the + // flags field + static const rb_data_type_t dir_data_type = { + "dir", + {RUBY_REFS_LIST_PTR(dir_refs), dir_free, dir_memsize,}, + 0, NULL, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_DECL_MARKING + }; + +Declaring simple references declaratively in this manner allows the GC to both +mark, and move the underlying object, and automatically update the reference to +it during compaction. + ==== Ruby object to C struct To retrieve the C pointer from the T_DATA object, use the macro @@ -2152,70 +2219,72 @@ Ractor safety around C extensions has the following properties: To make a "Ractor-safe" C extension, we need to check the following points: -(1) Do not share unshareable objects between ractors +1. Do not share unshareable objects between ractors -For example, C's global variable can lead sharing an unshareable objects -between ractors. + For example, C's global variable can lead sharing an unshareable objects + between ractors. - VALUE g_var; - VALUE set(VALUE self, VALUE v){ return g_var = v; } - VALUE get(VALUE self){ return g_var; } + VALUE g_var; + VALUE set(VALUE self, VALUE v){ return g_var = v; } + VALUE get(VALUE self){ return g_var; } -set() and get() pair can share an unshareable objects using g_var, and -it is Ractor-unsafe. + set() and get() pair can share an unshareable objects using g_var, and + it is Ractor-unsafe. -Not only using global variables directly, some indirect data structure -such as global st_table can share the objects, so please take care. + Not only using global variables directly, some indirect data structure + such as global st_table can share the objects, so please take care. -Note that class and module objects are shareable objects, so you can -keep the code "cFoo = rb_define_class(...)" with C's global variables. + Note that class and module objects are shareable objects, so you can + keep the code "cFoo = rb_define_class(...)" with C's global variables. -(2) Check the thread-safety of the extension +2. Check the thread-safety of the extension -An extension should be thread-safe. For example, the following code is -not thread-safe: + An extension should be thread-safe. For example, the following code is + not thread-safe: - bool g_called = false; - VALUE call(VALUE self) { - if (g_called) rb_raise("recursive call is not allowed."); - g_called = true; - VALUE ret = do_something(); - g_called = false; - return ret; - } + bool g_called = false; + VALUE call(VALUE self) { + if (g_called) rb_raise("recursive call is not allowed."); + g_called = true; + VALUE ret = do_something(); + g_called = false; + return ret; + } -because g_called global variable should be synchronized by other -ractor's threads. To avoid such data-race, some synchronization should -be used. Check include/ruby/thread_native.h and include/ruby/atomic.h. + because g_called global variable should be synchronized by other + ractor's threads. To avoid such data-race, some synchronization should + be used. Check include/ruby/thread_native.h and include/ruby/atomic.h. -With Ractors, all objects given as method parameters and the receiver (self) -are guaranteed to be from the current Ractor or to be shareable. As a -consequence, it is easier to make code ractor-safe than to make code generally -thread-safe. For example, we don't need to lock an array object to access the -element of it. + With Ractors, all objects given as method parameters and the receiver (self) + are guaranteed to be from the current Ractor or to be shareable. As a + consequence, it is easier to make code ractor-safe than to make code generally + thread-safe. For example, we don't need to lock an array object to access the + element of it. -(3) Check the thread-safety of any used library +3. Check the thread-safety of any used library -If the extension relies on an external library, such as a function foo() from -a library libfoo, the function libfoo foo() should be thread safe. + If the extension relies on an external library, such as a function foo() from + a library libfoo, the function libfoo foo() should be thread safe. -(4) Make an object shareable +4. Make an object shareable -This is not required to make an extension Ractor-safe. + This is not required to make an extension Ractor-safe. -If an extension provides special objects defined by rb_data_type_t, -consider these objects can become shareable or not. + If an extension provides special objects defined by rb_data_type_t, + consider these objects can become shareable or not. -RUBY_TYPED_FROZEN_SHAREABLE flag indicates that these objects can be -shareable objects if the object is frozen. This means that if the object -is frozen, the mutation of wrapped data is not allowed. + RUBY_TYPED_FROZEN_SHAREABLE flag indicates that these objects can be + shareable objects if the object is frozen. This means that if the object + is frozen, the mutation of wrapped data is not allowed. -(5) Others +5. Others -There are possibly other points or requirements which must be considered in the -making of a Ractor-safe extension. This document will be extended as they are -discovered. + There are possibly other points or requirements which must be considered in the + making of a Ractor-safe extension. This document will be extended as they are + discovered. -:enddoc: Local variables: -:enddoc: fill-column: 70 -:enddoc: end: +-- +Local variables: +fill-column: 70 +end: +++ |