FreeBSD kernel SOCKET I/F 探検 (23)

recvfrom() システムコール (3)

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

revcfrom() システムコール、三回目です。sys_recvfrom()->recvit()->kern_recvit()->soreceive()->soreceive_dgram()と呼び出されて、soreceive_dgram()のwhileループの最後のところです。

該当部分を以下に掲載します。

/*
 * Loop blocking while waiting for a datagram.
 */
SOCKBUF_LOCK(&so->so_rcv);
while ((m = so->so_rcv.sb_mb) == NULL) {
...snip...
      SBLASTRECORDCHK(&so->so_rcv);
      SBLASTMBUFCHK(&so->so_rcv);
      error = sbwait(&so->so_rcv);
      if (error) {
              SOCKBUF_UNLOCK(&so->so_rcv);
              return (error);
      }
}
SOCKBUF_LOCK_ASSERT(&so->so_rcv);

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

#ifdef SOCKBUF_DEBUG
void    sblastrecordchk(struct sockbuf *, const char *, int);
#define SBLASTRECORDCHK(sb)     sblastrecordchk((sb), __FILE__, __LINE__)

void    sblastmbufchk(struct sockbuf *, const char *, int);
#define SBLASTMBUFCHK(sb)       sblastmbufchk((sb), __FILE__, __LINE__)
#else
#define SBLASTRECORDCHK(sb)      /* nothing */
#define SBLASTMBUFCHK(sb)        /* nothing */
#endif /* SOCKBUF_DEBUG */

#ifdef SOCKBUF_DEBUGで括られていてかつ#elseの時には何もしていないので、詳細は割愛します。

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

/*
 * Wait for data to arrive at/drain from a socket buffer.
 */
int
sbwait(struct sockbuf *sb)
{

        SOCKBUF_LOCK_ASSERT(sb);

        sb->sb_flags |= SB_WAIT;
        return (msleep(&sb->sb_cc, &sb->sb_mtx,
            (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, "sbwait",
            sb->sb_timeo));
}

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

/*
 * Common `proc' functions are declared here so that proc.h can be included
 * less often.
 */
int     _sleep(void *chan, struct lock_object *lock, int pri, const char *wmesg,
            int timo) __nonnull(1);
#define msleep(chan, mtx, pri, wmesg, timo)                             \
        _sleep((chan), &(mtx)->lock_object, (pri), (wmesg), (timo))

sbwait()とmsleep()共に詳細は割愛しますが、なにか事象(この場合はソケットに対するデータの受信)が発生するまで、呼び出したプロセスがsleep状態となると理解てください。

今回はここで終了です。

今回で一旦recvfrom()システムコールの解析は中断するので、recvfrom()システムコールで変更したデータ構造を再掲載します。ただし、今回はsocket()システムコールなどとは異なり、sys_recvfrom()と kern_recvit()のローカル変数のみが変更されています。

sys_recvfrom()からsoreceive_dgram()のsbwait()呼び出しまでの処理で変更した変数を青、変更した値は赤で示して います。

次回から、serverの通信相手となるclientの処理を見ていきます。

記事執筆者: asou
記事公開日:2016年07月20日