閱讀888 返回首頁    go 阿裏雲 go 技術社區[雲棲]


網絡子係統84_sock事件通知進程

//	socket初始化
//	調用路徑:inet_create->sock_init_data
1.1 void sock_init_data(struct socket *sock, struct sock *sk)
{
	...
	//sock狀態改變的回調函數,當sock的狀態變遷(如從established到close_wait)就會調用這個函數
	sk->sk_state_change	=	sock_def_wakeup;
	//sock有輸入數據的時被調用
	sk->sk_data_ready	=	sock_def_readable;
	//sock有可寫空間時被調用
	sk->sk_write_space	=	sock_def_write_space;
	//sock出錯(如收到一個rst)會被調
	sk->sk_error_report	=	sock_def_error_report;
	sk->sk_destruct		=	sock_def_destruct;
	...
}


//	喚醒sock上阻塞的進程
//	步驟:
//		1.檢查struct sock->sk_wq上是否有阻塞的進程
//			1.2 喚醒struct sock->sk_wq上的進程
2.1 static void sock_def_wakeup(struct sock *sk)
{
	struct socket_wq *wq;

	rcu_read_lock();
	wq = rcu_dereference(sk->sk_wq);
	if (wq_has_sleeper(wq))
		wake_up_interruptible_all(&wq->wait);
	rcu_read_unlock();
}


//	有可用輸入數據
//	調用路徑:raw_local_deliver->sock_def_readable
//	步驟:
//		1.檢查struct sock->sk_wq上是否有阻塞的進程
//			1.1 喚醒struct sock->sk_wq上的進程
//		2.喚醒在用戶空間設置了信號io的進程
2.2 static void sock_def_readable(struct sock *sk, int len)
{
	struct socket_wq *wq;

	rcu_read_lock();
	//sock的wait_queue
	wq = rcu_dereference(sk->sk_wq);
	//喚醒在wait_queue上等待可用數據的進程
	if (wq_has_sleeper(wq))
		wake_up_interruptible_sync_poll(&wq->wait, POLLIN | POLLPRI |
						POLLRDNORM | POLLRDBAND);
	//處理O_ASYNC
	sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
	rcu_read_unlock();
}

//	有可用輸出空間
//	步驟:
//		1.判斷是否有足夠可用內存
//			1.1 空閑內存量 >= 50%
//		2.喚醒在wait_queue上等待可用內存的進程
//		3.處理信號io
2.3 static void sock_def_write_space(struct sock *sk)
{
	struct socket_wq *wq;

	rcu_read_lock();

	//判斷是否有足夠內存
	//	可用內存>=50%
	if ((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf) {
		wq = rcu_dereference(sk->sk_wq);
		//喚醒wait_queue上的進程
		if (wq_has_sleeper(wq))
			wake_up_interruptible_sync_poll(&wq->wait, POLLOUT |
						POLLWRNORM | POLLWRBAND);
		//處理信號io
		if (sock_writeable(sk))
			sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
	}

	rcu_read_unlock();
}

//	sock發生錯誤
//		1. 檢查sock上是否有進程在阻塞
//			1.1 喚醒進程有錯誤發生
//		2. 處理信號io
2.4 static void sock_def_error_report(struct sock *sk)
{
	struct socket_wq *wq;

	rcu_read_lock();
	wq = rcu_dereference(sk->sk_wq);
	if (wq_has_sleeper(wq))
		wake_up_interruptible_poll(&wq->wait, POLLERR);
	sk_wake_async(sk, SOCK_WAKE_IO, POLL_ERR);
	rcu_read_unlock();
}

最後更新:2017-04-03 12:55:18

  上一篇:go 網絡子係統82_inet協議族-SOCK_RAW(三)
  下一篇:go PHP設置session多級路徑並定期自動清理