- static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
-
{
-
int error;
/*
前面的操作都是初始化wait,为将socket加入wait队列作准备,这部分代码牵涉到进程调度。关于进程调度,我 只是知道一些皮毛,留在以后学习。这里只需要将其看作是一些加入wait队列的准备工作即可,并不影响理解代码 。
*/
-
DEFINE_WAIT_FUNC(wait, receiver_wake_function);
-
-
prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
-
/* Socket errors? */
-
error = sock_error(sk);
-
if (error)
-
goto out_err;
/* 一个完备检测。在决定wait和调用wait之间,有数据包到了,那么就不需要wait,所以这里再次检查socket 的队列是否为空 */
-
if (!skb_queue_empty(&sk->sk_receive_queue))
-
goto out;
/* 完备检测。也许socket无数据包读取,因为socket已经被另外的线程关闭了。这样可以保证关闭socket的时 候,不会导致其他的socket的读写操作被阻塞。*/
-
/* Socket shut down? */
-
if (sk->sk_shutdown & RCV_SHUTDOWN)
-
goto out_noerr;
/* 对于面向连接的socket进行检查。如果是面向连接的socket,如果不是已经建立连接或者正在监听状态的so cket是不可能有数据包的。不然即出错*/
-
/* Sequenced packets can come disconnected.
-
* If so we report the problem
-
*/
-
error = -ENOTCONN;
-
if (connection_based(sk) &&
-
!(sk->sk_state == TCP_ESTABLISHED || sk->sk_state == TCP_LISTEN))
-
goto out_err;
/* 检查是否有pending的signal,保证阻塞时,进程可以被signal唤醒 */
-
/* handle signals */
-
if (signal_pending(current))
-
goto interrupted;
-
-
error = 0;
- /* sleep本进程,直至满足唤醒条件或者被信号唤醒——因为前面设置了TASK_INTERRUPTIBLE*/
-
*timeo_p = schedule_timeout(*timeo_p);
-
out:
/* wait队列的清理工作 */
-
finish_wait(sk_sleep(sk), &wait);
-
return error;
-
interrupted:
-
error = sock_intr_errno(*timeo_p);
-
out_err:
-
*err = error;
-
goto out;
-
out_noerr:
-
*err = 0;
-
error = 1;
-
goto out;
-
}