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 コンテキスト

書式
<sys/types.h> <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 を登録している間に、 この番号は 99 よりも大きい最初の利用可能な番号に変更されます。 コンテキスト削除の最初のステップが失敗した場合、 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;
    char *string = "dynamic sysctl";
     ...
    sysctl_ctx_init(&clist);
    oidp = SYSCTL_ADD_NODE( &clist, SYSCTL_STATIC_CHILDREN(/* ツリートップ */),
    	OID_AUTO, newtree, CTFLAG_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, CTFLAG_RW, 0, "new tree under debug");
    oidp = SYSCTL_ADD_STRING( &clist, SYSCTL_CHILDREN(oidp),
    	OID_AUTO, newstring, CTLFLAG_R, 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() の呼び出しを通して、両方のツリーが削除され、 リソースが解放されることに注意してください。 最新のエントリ (葉) を解放することによって始まり、それから 古いエントリ (この場合はノード) の削除を続行します。

関連項目
queue(3), sysctl(8), sysctl_add_oid(9), sysctl_remove_oid(9)

歴史
これらの関数は FreeBSD 4.2 ではじめて登場しました。

作者
Andrzej Bialecki <abial@FreeBSD.org>

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

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