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/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 의 삭제 조작에 간단한 트랜잭션(transaction)적인 측면을 추가합니다. 즉, 도중에 삭제 조작이 실패했을 경우에, sysctl 트리를 이전 상태에 롤백(rollback) 하는 것이 가능합니다.

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 가 등록 말소되어 재등록되어 그리고 등록 말소되어 삭제될 필요가 있습니다. 그렇지만, 삭제 조작이 트랜잭션(transaction)의 특징을 가지는 것을, 이 알고리즘은 프로텍션합니다.

문맥상의 모든 조작은 링크 리스트를 횡단하는 것을 필요로 합니다. 이 이유이기 때문에, 엔트리의 작성과 삭제에는 상대적으로 코스트가 듭니다.