FreeBSD kernel SOCKET I/F 探検

第8回 socket() システムコール (6)

2014.02.19

必要とする知識など:
  • UNIX (含む Linux) 上での C 言語と SOCKET によるプログラミング経験および TCP/IP に関する知識。

socket() システムコール、六回目です。soalloc() から socreate() に戻ったところです。

TAILQ_INIT(&so->so_incomp);
TAILQ_INIT(&so->so_comp);

TAILQ_INIT() に渡している so_incomp と so_comp は、struct socekt のメンバ変数ですが、以下のように定義されています。

struct socket {
        ...
        TAILQ_HEAD(, socket) so_incomp; /* (e) queue of partial unaccepted connections */
        TAILQ_HEAD(, socket) so_comp;   /* (e) queue of complete unaccepted connections */

コメントから察するところ、ユーザプログラムから ACCEPT(2) の呼び出しを実施されていない接続の待ちキューのようです。TCP などのように、呼を張る [1] インターフェースで使用するものだと思われます。partial/complete の違いは、カーネル内で接続処理が完了して いない/いる の違いではないかと思います。

TAILQ_HEAD() は、前回 (http://www.soum.co.jp/misc/asou/fbsd-kernel-socket/7.html) 解説済みなので詳細は割愛しますが、TAILQ_HEAD() を展開すると、上記の struct socket は以下のようになります。

struct socket {
        ...
        struct {
                struct socket *fqh_first;
                struct socket **fqh_last;
        } so_incomp;

        struct {
                struct socket *fqh_first;
                struct socket **fqh_last;
        } so_comp;

TAILQ_INIT() も、前回 (http://www.soum.co.jp/misc/asou/fbsd-kernel-socket/7.html) 解説済みなので詳細は割愛しますが、ここではキューを管理するポインタの初期化を行なっています。

次の処理は、so->so_type の初期化です。

so->so_type = type;

本関数 (socreate()) の第三引数 int type を so->so_type に代入しています。この type は、server.c から SOCKET(2) を呼び出した際の第二引数 SOCK_DGRAM です。

次は、crhold() の呼び出しです。

so->so_cred = crhold(cred);

crhold() は、本連載の第四回 (http://www.soum.co.jp/misc/asou/fbsd-kernel-socket/4.html) でも解説しているので詳細は割愛しますが、認証情報 (struct ucred *cred) が保持している参照カウンタ (cr_ref) に 1 を加算しています。なお、srhold() は引数で渡した cred を戻り値として返却するので、so->so_cred には cred が代入されます。

次の処理は、so->so_fibnum の初期化です。

if ((prp->pr_domain->dom_family == PF_INET) ||
    (prp->pr_domain->dom_family == PF_INET6) ||
    (prp->pr_domain->dom_family == PF_ROUTE))
        so->so_fibnum = td->td_proc->p_fibnum;
else
        so->so_fibnum = 0;

prp->pr_domain->dom_family の値は AF_INET (== PF_INET) なので、ここでは so->so_fibnum に td->td_proc->p_fibnum を代入します。

次の処理は、so->so_proto の初期化です。

so->so_proto = prp;

本関数 (socreate()) の始めのところで、pffindtype() で取得した struct protosw *prp を代入しています。

次の処理は、knlist_init_mtx() の呼び出しです。

knlist_init_mtx(&so->so_rcv.sb_sel.si_note, SOCKBUF_MTX(&so->so_rcv));
knlist_init_mtx(&so->so_snd.sb_sel.si_note, SOCKBUF_MTX(&so->so_snd));

knlist_init_mtx() は、/usr/src/sys/kern/kern_event.c (http://svnweb.freebsd.org/base/release/9.1.0/sys/kern/kern_event.c?view=markup) で以下のように定義されています。

void
knlist_init_mtx(struct knlist *knl, struct mtx *lock)
{

        knlist_init(knl, lock, NULL, NULL, NULL, NULL);
}

ここで呼び出している knlist_init() は、同じ /usr/src/sys/kern/kern_event.c で以下のように定義されています。

void
knlist_init(struct knlist *knl, void *lock, void (*kl_lock)(void *),
    void (*kl_unlock)(void *),
    void (*kl_assert_locked)(void *), void (*kl_assert_unlocked)(void *))
{

        if (lock == NULL)
                knl->kl_lockarg = &knlist_lock;
        else
                knl->kl_lockarg = lock;
        ...
        ...

        SLIST_INIT(&knl->kl_list);
}

ロックに関する初期化を行なっているようです。kern_event.c というファイル名から、イベントに関する処理を行なっているようですが、knlist_init_mtx() に送受信バッファ (so->snd/so->so_rcv) 内の変数のポインタを渡しているので、NIC (Network Interface Controler) からの送受信割り込みに関するものではないかと推測しています。knlist_init() の詳細は割愛しますが、knlist_init() は第一引数である struct klist の各メンバ変数の初期化を行なっています。

knlist_init_mtx() の呼び出し時に参照している so_rcv/so_snd は、struct socket (/usr/src/sys/sys/socketvar.h (http://svnweb.freebsd.org/base/release/9.1.0/sys/sys/socketvar.h?view=markup) で以下のように定義されています。

struct socket {
        ...
        struct sockbuf so_rcv, so_snd;

struct sockbuf は、/usr/src/sys/sys/sockbuf.h (http://svnweb.freebsd.org/base/release/9.1.0/sys/sys/sockbuf.h?view=markup) で定義されています。

knlist_init_mtx() の呼び出し時に参照している sb_sel は、同じく /usr/src/sys/sys/sockbuf.h で以下のように定義されています。

struct  sockbuf {
        struct  selinfo sb_sel; /* process selecting read/write */

struct selinfo は、/usr/src/sys/sys/selinfo.h (http://svnweb.freebsd.org/base/release/9.1.0/sys/sys/selinfo.h?view=markup) で定義されています。

knlist_init_mtx() の呼び出し時に参照している si_note は、同じく /usr/src/sys/sys/selinfo.h で以下のように定義されています。

struct selinfo {
        ...
        struct knlist           si_note;        /* kernel note list */

struct knlist は、/usr/src/sys/sys/event.h (http://svnweb.freebsd.org/base/release/9.1.0/sys/sys/event.h?view=markup) で定義されています。

knlist_init_mtx() の呼び出し時に使用している SOCKBUF_MTX は、/usr/src/sys/sys/sockbuf.h (http://svnweb.freebsd.org/base/release/9.1.0/sys/sys/sockbuf.h?view=markup) で以下のように定義されています。

#define SOCKBUF_MTX(_sb)                (&(_sb)->sb_mtx)

knlist_init() の最後で使用している SLIST_INIT() は、/usr/src/sys/sys/queue.h (http://svnweb.freebsd.org/base/release/9.1.0/sys/sys/queue.h?view=markup) で以下のように定義されています。

#define SLIST_INIT(head) do {                                           \
        SLIST_FIRST((head)) = NULL;                                     \
} while (0)

SLIST_FIRST() は、同じく /usr/src/sys/sys/queue.h で以下のように定義されています。

#define SLIST_FIRST(head)       ((head)->slh_first)

従って、knlist_init() の SLIST_INIT(&knl->kl_list); は以下のように展開されます。

do {
        ((&knl->kl_list)->slh_first) = NULL;
} while(0);

knl->kl_list は、/usr/src/sys/sys/event.h で以下のように定義されています。

struct knote;
SLIST_HEAD(klist, knote);

struct knlist {
        struct  klist   kl_list;

SLIST_HEAD() は、/usr/src/sys/sys/queue.h で以下のように定義されています。

#define SLIST_HEAD(name, type)                                          \
struct name {                                                           \
        struct type *slh_first; /* first element */                     \
}

この定義を上記の struct knlist に適用したものを以下に示します。

struct knote;

struct klist {
        struct knote *slh_first; /* first element */
}

struct knlist {
        struct  klist   kl_list;

ここでは struct knote の宣言のみを行なっていますが、/usr/src/sys/sys/event.h の後半で struct knote を定義しています。

次の処理は、so->so_count の初期化です。

so->so_count = 1;

ここまでのデータ構造を以下に示します。

今回の処理で変更した変数を青、変更した値は赤で示しています。参照している値も赤線で示してあります。

[1]TCP などのように、事前に仮想的な通信路を作成する仕組みに対して、その通信路を確立する 方法/手順 などのことを「呼を張る」と表現します。

著者プロフィール

asou

好きな OS は、FreeBSD です。が、最近購入した Mac mini がなかなか快適なので、Mac でいいかなと思うようになってきました。

記事一覧Index