- 必要とする知識など:
- 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の処理を見ていきます。