プログラムの構造体をトレースするには、TNF_DECLARE_RECORD マクロと TNF_DEFINE_RECORD_n マクロを使用して新しい型を定義します。これらのマクロは、プローブポイントに渡される型を拡張するためのコンパイル時インタフェースの一部です。
TNF_DECLARE_RECORD(c_type, tnf_type);
TNF_DEFINE_RECORD_1(c_type, tnf_type, tnf_member_type_1, tnf_member_name_1) TNF_DEFINE_RECORD_2(c_type, tnf_type, tnf_member_type_1, tnf_member_name_1, tnf_member_type_2, tnf_member_name_2) TNF_DEFINE_RECORD_3(c_type, tnf_type, tnf_member_type_1, tnf_member_name_1, tnf_member_type_2, tnf_member_name_2, tnf_member_type_3, tnf_member_name_3) TNF_DEFINE_RECORD_4(c_type, tnf_type, tnf_member_type_1, tnf_member_name_1, tnf_member_type_2, tnf_member_name_2, tnf_member_type_3, tnf_member_name_3, tnf_member_type_4, tnf_member_name_4) TNF_DEFINE_RECORD_5(c_type, tnf_type, tnf_member_type_1, tnf_member_name_1, tnf_member_type_2, tnf_member_name_2, tnf_member_type_3, tnf_member_name_3, tnf_member_type_4, tnf_member_name_4, tnf_member_type_5, tnf_member_name_5)
TNF_DECLARE_RECORD と TNF_DEFINE_RECORD は、新しく定義する型ごとに 1 つだけ作成してください。TNF_DECLARE_RECORD は、TNF_DEFINE_RECORD よりも前に置く必要があります。定義されている tnf_type を複数のソースファイルで使用する必要がある場合は、その複数のファイルで共有するヘッダーファイル中に TNF_DECLARE_RECORD を宣言することができます。TNF_DEFINE_RECORD は、いずれか 1 つのソースファイルだけに作成する必要があります。
TNF_DEFINE_RECORD マクロインタフェースは、1 つの関数といくつかのデータ構造体を定義します。したがってこのインタフェースは、関数の内部ではなく、ソースファイル (.c ファイルまたは .cc ファイル) のファイルスコープ (有効範囲) 内で使用してください。
TNF_DEFINE_RECORD 文の後にセミコロンを置かないでください。セミコロンを置くと、コンパイル時に警告が出力されます。
以下、各変数について説明します。
c_type − 新しい tnf_type を作成するためのテンプレートです。C 構造体のすべての要素を、定義する TNF 型で使用する必要はありません。c_type は、C の構造体型にしてください。
tnf_type − 新しく作成した型に与えられる名前です。このインタフェースは、tnf_type を接頭辞とした名前空間を使用します。したがって、ライブラリが xxx_type という新しい型を定義した場合には、そのライブラリは、xxx_type を接頭辞に使用して別のシンボルを定義することはできません。
型の名前空間の管理方法は、ライブラリ内のその他の名前空間の管理方法と同じです。つまり、ライブラリ内の型以外のシンボルが使用している固有の接頭辞を新しい TNF 型の名前の接頭辞としてください。これによって、新しい TNF 型が定義されている複数のライブラリをリンクしても、名前空間が衝突することはなくなります。
たとえば、libpalloc.so というライブラリが名前の接頭辞として pal を使用してシンボルを定義している場合には、この libpalloc.so は、新しく定義する TNF 型の名前にも pal を接頭辞として使用する必要があります。
tnf_member_type_n − C 構造体の n 番目のメンバーの TNF 型です。
tnf_member_name_n − C 構造体の n 番目のメンバーの名前です。
新しい TNF 型の定義方法と、プローブ内でのその TNF 型の使い方を例 1-5 に示します。
この例 1-5 は、すべてのシンボルの接頭辞に pal を使用している架空のライブラリ libpalloc.so の一部であると仮定しています。
#include <tnf/probe.h> typedef struct pal_header { long size; char * descriptor; struct pal_header *next; } pal_header_t; TNF_DECLARE_RECORD(pal_header_t, pal_tnf_header); TNF_DEFINE_RECORD_2(pal_header_t, pal_tnf_header, tnf_long, size, tnf_string, descriptor) /* * 注 : 接頭辞 pal_tnf_header が付いている名前空間は、 * このクライアントではもう使用できない。 */ void pal_free(pal_header_t *header_p) { int state; TNF_PROBE_2(pal_free_start, "palloc pal_free", "sunw%debug entering pal_free", tnf_long, state_var, state, pal_tnf_header, header_var, header_p); . . . }
next フィールドを使用して自分自身を指し示す構造体 (リンクされたリスト) 中などで、tnf_type を再帰的または相互再帰的に定義することができます。
このような構造体が TNF_PROBE に渡されると、リンクされたリストの全体がトレースファイルに記録されます (next フィールドが NULL になるまで続きます)。ただし、そのリストが循環リストの場合には、処理が無限ループに入ります。この無限ループを中断するには、tnf_type から next フィールドを削除するか、または next メンバーの型を tnf_opaque として定義します。