EN JA
SYSCTL_CTX_INIT(9)
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 ではじめて登場しました。

作者

Andrzej Bialecki <abial@FreeBSD.org>

バグ

現在の削除アルゴリズムは、多少重いです。最悪の場合、全ての oid が登録抹消され、再登録され、それから登録抹消され、削除される必要があります。しかしながら、削除操作がトランザクションの特質を持つことを、このアルゴリズムは、保証します。

コンテキスト上の全ての操作は、リンクリストを横切ることを必要とします。この理由のため、エントリの作成と削除には、相対的にコストがかかります。

July 15, 2000 FreeBSD