SYSCTL_CTX_INIT(9) | FreeBSD Kernel Developer's Manual | SYSCTL_CTX_INIT(9) |
名称
sysctl_ctx_init, sysctl_ctx_free, sysctl_ctx_entry_add, sysctl_ctx_entry_find, sysctl_ctx_entry_del — 動的に生成された sysctl oid のための sysctl コンテキスト書式
#include < sys/types.h>#include < sys/sysctl.h>
int
sysctl_ctx_init( struct sysctl_ctx_list *clist);
int
sysctl_ctx_free( struct sysctl_ctx_list *clist);
struct sysctl_ctx_entry *
sysctl_ctx_entry_add( struct sysctl_ctx_list *clist, struct sysctl_oid *oidp);
struct sysctl_ctx_entry *
sysctl_ctx_entry_find( struct sysctl_ctx_list *clist, struct sysctl_oid *oidp);
int
sysctl_ctx_entry_del( struct sysctl_ctx_list *clist, struct sysctl_oid *oidp);
解説
これらの関数は、動的に作成された oid の管理のためのインタフェースを提供します。 sysctl コンテキストは、作成された oid の必要な時の厳密な削除はもちろん、 oid を見失わないようにすることに対して責任があります。これは、oid の削除操作に簡単なトランザクション的な側面を追加します。すなわち、途中で削除操作が失敗した場合に、sysctl ツリーを以前の状態にロールバックすることが可能です。sysctl_ctx_init() 関数は、sysctl コンテキストを初期化します。 clist 引数は、既に割り当てられている変数を指していなければなりません。コンテキストは、使用の前に 必ず 初期化されていなければなりません。一度初期化されると、そのコンテキストのポインタは、全ての SYSCTL_ADD_* マクロ ( sysctl_add_oid(9) 参照) の引数として渡されることが可能で、新しく作成される oid を指すエントリを伴って更新されるでしょう。
内部的には、コンテキストは、 queue(3) TAILQ リンクリストとして表現されています。そのリストは、 struct sysctl_ctx_entry
エントリから成っています。
struct sysctl_ctx_entry { struct sysctl_oid *entry; TAILQ_ENTRY(sysctl_ctx_entry) link; }; TAILQ_HEAD(sysctl_ctx_list, sysctl_ctx_entry);
各々のコンテキストエントリは、それが管理する 1 つの動的な oid を指します。新しく作成された oid は、常にリストの最初に挿入されます。
sysctl_ctx_free() 関数は、コンテキストおよびそれが管理する関連付けられた oid を削除します。その関数が成功して完了した場合には、全ての管理されている oid は、登録抹消 (ツリーから削除) され、全てのそれらに割り当てられたメモリと共に解放され、同様にコンテキストのエントリも解放されています。
削除操作は、2 ステップで実行されます。最初に、各々のコンテキストエントリのために、リソースの解放を抑制するパラメータ del を 0 に設定して、関数 sysctl_remove_oid(9) が呼び出されます。このステップでエラーが無い場合には、 sysctl_ctx_free() は、次のステップに移行します。最初のステップが失敗した場合には、そのコンテキストに関連付けられた全ての登録抹消された oid が再登録されます。
注意: ほとんどの場合、プログラマは、oid の作成時に oid 番号として OID_AUTO を明示します。しかしながら、ツリーに oid を登録している間に、この番号は、 CTL_AUTO_START 以上の最初に利用可能な番号に変更されます。コンテキスト削除の最初のステップが失敗した場合、 oid の再登録は、既に割り当てられている oid 番号を変更しません (OID_AUTO とは異なります)。これは、再登録されたエントリがツリーの中の元の位置を維持していることを保証します。
2 番目のステップは、動的な oid の削除を実際に実行します。 sysctl_remove_oid(9) は、最初 (すなわち、最新のエントリ) から始めて、コンテキストリストを通して繰り返します。 重要: この時、この関数は、ツリーから oid を削除するだけではなく、全てのコンテキストのメモリは、もちろん、(oid_refcount == 0 であれば) oid のメモリも解放します。
sysctl_ctx_entry_add() 関数は、既存の動的な oid のコンテキストへの追加を可能にします。
sysctl_ctx_entry_del() 関数は、コンテキストからエントリを取り除きます。 重要: この場合、対応する struct sysctl_ctx_entry
のみが解放されますが、 oidp ポインタは、そのまま残ります。その後は、プログラマにこの oid に割り当てられたリソースの管理の責任があります。
sysctl_ctx_entry_find() 関数は、与えられた oidp をコンテキストリストの中から検索し、見つかった struct sysctl_ctx_entry へのポインタまたは NULL を返します。
使用例
以下は、どのように新しいトップレベルのカテゴリを作成するか、およびどのように既存の静的なノードに別のサブツリーを引っ掛けるかを示す使用例です。この使用例は、oid の追跡を維持するためにコンテキストを使用しています。
#include <sys/sysctl.h> ... struct sysctl_ctx_list clist; struct sysctl_oid *oidp; int a_int; const char *string = "dynamic sysctl"; ... sysctl_ctx_init(&clist); oidp = SYSCTL_ADD_NODE(&clist, SYSCTL_STATIC_CHILDREN(/* ツリートップ */), OID_AUTO, "newtree", CTLFLAG_RW, 0, "new top level tree"); oidp = SYSCTL_ADD_INT(&clist, SYSCTL_CHILDREN(oidp), OID_AUTO, "newint", CTLFLAG_RW, &a_int, 0, "new int leaf"); ... oidp = SYSCTL_ADD_NODE(&clist, SYSCTL_STATIC_CHILDREN(_debug), OID_AUTO, "newtree", CTLFLAG_RW, 0, "new tree under debug"); oidp = SYSCTL_ADD_STRING(&clist, SYSCTL_CHILDREN(oidp), OID_AUTO, "newstring", CTLFLAG_RD, string, 0, "new string leaf"); ... /* ここで oid を解放できます */ if (sysctl_ctx_free(&clist)) { printf("コンテキストを解放出来ません - 他の oid が依存しています"); return (ENOTEMPTY); } else { printf("成功です!\n"); return (0); }
この使用例は、以下のサブツリーを作成します。
debug.newtree.newstring newtree.newint
1 つの sysctl_ctx_free() の呼び出しを通して、両方のツリーが削除され、リソースが解放されることに注意してください。最新のエントリ (葉) を解放することによって始まり、それから古いエントリ (この場合は、ノード) の削除を続行します。
歴史
これらの関数は、 FreeBSD 4.2 ではじめて登場しました。作者
<abial@FreeBSD.org>バグ
現在の削除アルゴリズムは、多少重いです。最悪の場合、全ての oid が登録抹消され、再登録され、それから登録抹消され、削除される必要があります。しかしながら、削除操作がトランザクションの特質を持つことを、このアルゴリズムは、保証します。コンテキスト上の全ての操作は、リンクリストを横切ることを必要とします。この理由のため、エントリの作成と削除には、相対的にコストがかかります。
July 15, 2000 | FreeBSD |