summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--doc/extension.ja.rdoc157
-rw-r--r--doc/extension.rdoc135
3 files changed, 240 insertions, 61 deletions
diff --git a/ChangeLog b/ChangeLog
index 149835062d..a279220b1e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Wed Apr 15 07:51:23 2015 Yuki Yugui Sonoda <yugui@yugui.jp>
+
+ * doc/extension.ja.rdoc: Added description of TypedData_XXX.
+ Deprecated the old DATA_XXX.
+ Reviewed by ko1 and nobu.
+ Fixes [ruby-dev:40881] #3064
+
+ * doc/extension.rdoc: ditto.
+
Wed Apr 15 07:34:49 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* thread_pthread.c (reserve_stack): keep sp safe zone to get rid
diff --git a/doc/extension.ja.rdoc b/doc/extension.ja.rdoc
index f4255ebb69..9fe5edbecb 100644
--- a/doc/extension.ja.rdoc
+++ b/doc/extension.ja.rdoc
@@ -675,61 +675,131 @@ getterとsetterの仕様は以下の通りです.
== CのデータをRubyオブジェクトにする
Cの世界で定義されたデータ(構造体)をRubyのオブジェクトとして
-取り扱いたい場合がありえます.このような場合には,Dataという
-RubyオブジェクトにCの構造体(へのポインタ)をくるむことでRuby
-オブジェクトとして取り扱えるようになります.
-
-Dataオブジェクトを生成して構造体をRubyオブジェクトにカプセル
-化するためには,以下のマクロを使います.
+取り扱いたい場合がありえます.このような場合はTypedData_XXX
+マクロ群を用いて構造体へのポインタとRubyのオブジェクトとを互
+いに変換できます.
+
+# 古い(非Typedな)Data_XXXマクロ群は非推奨になりました.
+# 将来のバージョンのRubyでは古いマクロは動作しなくなる可能性
+# があります.
+
+=== 構造体からオブジェクトへ
+構造体へのポインタsvalをRubyオブジェクトに変換するには次のマ
+クロを使います。
+
+ TypedData_Wrap_Struct(klass, data_type, sval)
+
+このマクロの戻り値は生成されたオブジェクトを表すVALUE値です.
+
+klassはこのオブジェクトのクラスです.data_typeはこの構造体を
+Rubyが管理するための情報を記述したconst rb_data_type_t型への
+ポインタです.
+
+なお, klassは, Objectや他のクラスではなくData (rb_cData)とい
+う特別なクラスから派生することが推奨されます.
+Dataから派生しない場合には, 必ずrb_undef_alloc_func(klass)
+を呼び出してください.
+
+rb_data_type_tは次のように定義されています.
+
+ struct rb_data_type_struct {
+ const char *wrap_struct_name;
+ struct {
+ void (*dmark)(void*);
+ void (*dfree)(void*);
+ size_t (*dsize)(const void *);
+ void *reserved[2];
+ } function;
+ const rb_data_type_t *parent;
+ void *data;
+ VALUE flags;
+ };
- Data_Wrap_Struct(klass, mark, free, sval)
+wrap_struct_nameはこの構造体を識別する名前です.主に統計情報
+の収集と出力に用いられます.プロセス内で一意であれば特にCや
+Rubyの識別子として有効である必要はありません.
-このマクロの戻り値は生成されたDataオブジェクトです.
+dmarkおよびdfree関数はGC実行中に呼び出されます.
+なお, GC実行中はRubyオブジェクトのアロケーションは禁止されま
+す. よって, dmarkおよびdfree関数でRubyオブジェクトのアロケー
+ションは行わないでください.
-klassはこのDataオブジェクトのクラスです.markはこの構造体が
-Rubyのオブジェクトへの参照がある時に使う関数です.そのような
-参照を含まない時には0を指定します.
+dmarkはガーベージコレクタがオブジェクトへの参照をマークする
+ときに用いる関数です.この構造体がRubyのオブジェクトへの参照
+を保持するときには, dmarkではrb_gc_markなどを用いて構造体内
+のすべての参照をマークしなければなりません.
+そのような参照を含まない時には0を指定します.
# そのような参照は勧められません.
-freeはこの構造体がもう不要になった時に呼ばれる関数です.この
-関数がガーベージコレクタから呼ばれます.これが-1の場合は,単
-純に開放されます.
+dfreeはこの構造体がもう不要になった時に呼ばれる関数です.こ
+の関数がガーベージコレクタから呼ばれます.これが-1の場合は,
+単純に構造体が解放されます.
-markおよびfree関数はGC実行中に呼び出されます.
-なお, GC実行中はRubyオブジェクトのアロケーションは禁止されま
-す. よって, markおよびfree関数でRubyオブジェクトのアロケーシ
-ョンは行わないでください.
+dsizeは構造体が消費しているメモリのバイト数を返す関数です.
+引数として構造体へのポインタが渡されます.実装困難であれば0
+を渡しても差し支えありませんが, できるだけ指定するようにして
+ください.
+
+reservedとparentは0で埋めなければなりません.
+
+dataにはユーザー定義の任意の値を指定できます.Rubyはこの値に
+は関知しないので,好きに使ってください.
+
+flagsには次のフラグのうち当てはまるもののビット和を指定しま
+す.いずれもRubyのガーベージコレクタについての深い理解を必要
+としますので,良くわからない場合には0を指定すると良いでしょ
+う.
+
+RUBY_TYPED_FREE_IMMEDIATELY ::
+
+ このフラグを指定すると,ガーベージコレクタはこの構造体が不
+ 要になった場合にはGC中に直ちにdfreeを呼び出します.
+ dfreeがRuby内部のロック(GVL)を解放する可能性がない場合はこ
+ のフラグを指定できます.
+
+ 指定しない場合はdfree呼び出しは遅延され, ファイナライザと
+ 同じタイミングで実行されます.
-Cの構造体の割当とDataオブジェクトの生成を同時に行うマクロと
-して以下のものが提供されています.
+RUBY_TYPED_WB_PROTECTED ::
- Data_Make_Struct(klass, type, mark, free, sval)
+ オブジェクトの実装がライトバリアをサポートしていることを示
+ します.このフラグを指定するとRubyはそのオブジェクトに対し
+ てGCをより効率的に実行できます.
+ ただし,指定する場合はユーザーはそのオブジェクトのすべての
+ メソッドの実装に適切にライトバリアを挿入する責任があります.
+ さもなくばRubyは実行時にクラッシュする可能性があります.
+
+ ライトバリアについてはdoc/extension.rdocのAppendix D
+ "Generational GC"も参照してください.
-このマクロの戻り値は生成されたDataオブジェクトです.このマク
-ロは以下の式のように働きます:
- (sval = ALLOC(type), Data_Wrap_Struct(klass, mark, free, sval))
+Cの構造体の割当と対応するオブジェクトの生成を同時に行うマク
+ロとして以下のものが提供されています.
-klass, mark, freeはData_Wrap_Structと同じ働きをします.type
+ TypedData_Make_Struct(klass, type, data_type, sval)
+
+このマクロの戻り値は生成されたオブジェクトのVALUE値
+です.このマクロは以下の式のように働きます:
+
+ (sval = ZALLOC(type), TypedData_Wrap_Struct(klass, data_type, sval))
+
+klass, data_typeはData_Wrap_Structと同じ働きをします.type
は割り当てるC構造体の型です.割り当てられた構造体は変数sval
に代入されます.この変数の型は (type*) である必要があります.
-Dataオブジェクトからポインタを取り出すのは以下のマクロを用い
-ます.
-
- Data_Get_Struct(obj, type, sval)
+=== オブジェクトから構造体へ
-Cの構造体へのポインタは変数svalに代入されます.
+TypedData_Wrap_StructやTypedData_Make_Structで生成したオブジェ
+クトから構造体へのポインタを復元するには以下のマクロを用いま
+す.
-これらのDataの使い方はちょっと分かりにくいので,後で説明する
-例題を参照してください.
+ TypedData_Get_Struct(obj, type, &data_type, sval)
-= 例題 - dbmパッケージを作る
+Cの構造体へのポインタは変数svalに代入されます.
-ここまでの説明でとりあえず拡張ライブラリは作れるはずです.
-Rubyのextディレクトリにすでに含まれているdbmライブラリを例に
-して段階的に説明します.
+これらのマクロの使い方はちょっと分かりにくいので,後で説明す
+る例題を参照してください.
== ディレクトリを作る
@@ -797,10 +867,16 @@ dbm.cではData_Make_Structを以下のように使っています.
DBM *di_dbm;
};
+ static const rb_data_type_t dbm_type = {
+ "dbm",
+ {0, free_dbm, memsize_dbm,},
+ 0, 0,
+ RUBY_TYPED_FREE_IMMEDIATELY,
+ };
- obj = Data_Make_Struct(klass, struct dbmdata, 0, free_dbm, dbmp);
+ obj = TypedData_Make_Struct(klass, struct dbmdata, &dbm_type, dbmp);
-ここではdbmstruct構造体へのポインタをDataにカプセル化してい
+ここではdbmdata構造体へのポインタをDataにカプセル化してい
ます.DBM*を直接カプセル化しないのはclose()した時の処理を考
えてのことです.
@@ -808,8 +884,9 @@ Dataオブジェクトからdbmstruct構造体のポインタを取り出すた
に以下のマクロを使っています.
#define GetDBM(obj, dbmp) do {\
- Data_Get_Struct(obj, struct dbmdata, dbmp);\
- if (dbmp->di_dbm == 0) closed_dbm();\
+ TypedData_Get_Struct(obj, struct dbmdata, &dbm_type, dbmp);\
+ if ((dbmp) == 0) closed_dbm();\
+ if ((dbmp)->di_dbm == 0) closed_dbm();\
} while (0)
ちょっと複雑なマクロですが,要するにdbmdata構造体のポインタ
diff --git a/doc/extension.rdoc b/doc/extension.rdoc
index f24029c826..eddbf4589b 100644
--- a/doc/extension.rdoc
+++ b/doc/extension.rdoc
@@ -620,39 +620,124 @@ The prototypes of the getter and setter functions are as follows:
== Encapsulate C Data into a Ruby Object
-To wrap and objectify a C pointer as a Ruby object (so called
-DATA), use Data_Wrap_Struct().
-
- Data_Wrap_Struct(klass, mark, free, sval)
+Sometimes you need to expose your struct in the C world as a Ruby
+object.
+In a situation like this, making use of the TypedData_XXX macro
+family, the pointer to the struct and the Ruby object can be mutually
+converted.
+
+# The old (non-Typed) Data_XXX macro family has been deprecated.
+# In the future version of Ruby, it is possible old macros will not
+# work.
+
+=== C struct to Ruby object
+You can convert sval, a pointer to your struct, into a Ruby object
+with the next macro.
+
+ TypedData_Wrap_Struct(klass, data_type, sval)
+
+TypedData_Wrap_Struct() returns a created Ruby object as a VALUE.
+
+The klass argument is the class for the object.
+data_type is a pointer to a const ruby_data_type_t which describes
+how Ruby should manage the struct.
+
+It is recommended that klass derives from a special class called
+Data (rb_cData) but not from Object or other ordinal classes.
+If it doesn't, you have to call rb_undef_alloc_func(klass).
+
+ruby_data_type_t is defined like this. Let's take a look at each
+member of the struct.
+
+ struct rb_data_type_struct {
+ const char *wrap_struct_name;
+ struct {
+ void (*dmark)(void*);
+ void (*dfree)(void*);
+ size_t (*dsize)(const void *);
+ void *reserved[2];
+ } function;
+ const rb_data_type_t *parent;
+ void *data;
+ VALUE flags;
+ };
-Data_Wrap_Struct() returns a created DATA object. The klass argument
-is the class for the DATA object. The mark argument is the function
-to mark Ruby objects pointed by this data. The free argument is the
-function to free the pointer allocation. If this is -1, the pointer
-will be just freed. The functions mark and free will be called from
-garbage collector.
+wrap_struct_name is an identifier of this instance of the struct.
+It is basically used for collecting and emitting statistics.
+So the identifier must be unique in the process, but doesn't need
+to be valid as a C or Ruby identifier.
-These mark / free functions are invoked during GC execution. No
+These dmark / dfree functions are invoked during GC execution. No
object allocations are allowed during it, so do not allocate ruby
objects inside them.
+
+dmark is a function to mark Ruby objects referred from your struct.
+It must mark all references from your struct with rb_gc_mark or
+its family if your struct keeps such references.
+
+# Note that it is recommended to avoid such a reference.
+
+dfree is a function to free the pointer allocation.
+If this is -1, the pointer will be just freed.
+
+dsize calculates memory consumption in bytes by the struct.
+Its parameter is a pointer to your struct.
+You can pass 0 as dsize if it is hard to implement such a function.
+But it is still recommended to avoid 0.
+
+You have to fill reserved and parent with 0.
+
+You can fill "data" with an arbitrary value for your use.
+Ruby does nothing with the member.
+
+flags is a bitwise-OR of the following flag values.
+Since they require deep understanding of garbage collector in Ruby,
+you can just set 0 to flags if you are not sure.
+
+RUBY_TYPED_FREE_IMMEDIATELY ::
+
+ This flag makes the garbage collector immediately invoke dfree()
+ during GC when it need to free your struct.
+ You can specify this flag if the dfree never unlocks Ruby's
+ internal lock (GVL).
+
+ If this flag is not set, Ruby defers invokation of dfree()
+ and invokes dfree() at the same time as finalizers.
+
+RUBY_TYPED_WB_PROTECTED ::
+
+ It shows that implementation of the object supports write barriers.
+ If this flag is set, Ruby is better able to do garbage collection
+ of the object.
+
+ When it is set, however, you are responsible for putting write
+ 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.
+
You can allocate and wrap the structure in one step.
- Data_Make_Struct(klass, type, mark, free, sval)
+ TypedData_Make_Struct(klass, type, data_type, sval)
This macro returns an allocated Data object, wrapping the pointer to
the structure, which is also allocated. This macro works like:
- (sval = ALLOC(type), Data_Wrap_Struct(klass, mark, free, sval))
+ (sval = ZALLOC(type), TypedData_Wrap_Struct(klass, data_type, sval))
-Arguments klass, mark, and free work like their counterparts in
-Data_Wrap_Struct(). A pointer to the allocated structure will be
-assigned to sval, which should be a pointer of the type specified.
+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.
+
+
+=== Ruby object to C struct
To retrieve the C pointer from the Data object, use the macro
Data_Get_Struct().
- Data_Get_Struct(obj, type, sval)
+ TypedData_Get_Struct(obj, type, &data_type, sval)
A pointer to the structure will be assigned to the variable sval.
@@ -721,7 +806,14 @@ Data_Make_Struct.
DBM *di_dbm;
};
- obj = Data_Make_Struct(klass, struct dbmdata, 0, free_dbm, dbmp);
+ static const rb_data_type_t dbm_type = {
+ "dbm",
+ {0, free_dbm, memsize_dbm,},
+ 0, 0,
+ RUBY_TYPED_FREE_IMMEDIATELY,
+ };
+
+ obj = TypedData_Make_Struct(klass, struct dbmdata, &dbm_type, dbmp);
This code wraps the dbmdata structure into a Ruby object. We avoid
wrapping DBM* directly, because we want to cache size information.
@@ -730,12 +822,13 @@ To retrieve the dbmdata structure from a Ruby object, we define the
following macro:
#define GetDBM(obj, dbmp) do {\
- Data_Get_Struct(obj, struct dbmdata, dbmp);\
+ TypedData_Get_Struct(obj, struct dbmdata, &dbm_type, dbmp);\
+ if ((dbmp) == 0) closed_dbm();\
if (dbmp->di_dbm == 0) closed_dbm();\
} while (0)
-This sort of complicated macro does the retrieving and close checking for
-the DBM.
+This sort of complicated macro does the retrieving and close checking
+for the DBM.
There are three kinds of way to receive method arguments. First,
methods with a fixed number of arguments receive arguments like this: