tcp receive data 的三個佇列
阿新 • • 發佈:2018-11-28
Prequeue queue:
struct tcp_sock {
/* Data for direct copy to user */
struct {
struct sk_buff_head prequeue;
struct task_struct *task;
struct msghdr *msg;
int memory;
int len;
} ucopy;
}
Receive queue and backlog queue:
struct sock { struct sk_buff_head sk_receive_queue; /* * The backlog queue is special, it is always used with * the per-socket spinlock held and requires low latency * access. Therefore we special case it's implementation. * Note : rmem_alloc is in this structure to fill a hole * on 64bit arches, not because its logically part of * backlog. */ struct { atomic_t rmem_alloc; int len; struct sk_buff *head; struct sk_buff *tail; } sk_backlog; #define sk_rmem_alloc sk_backlog.rmem_alloc int sk_forward_alloc; }
對prequeue的處理
bool tcp_prequeue(struct sock *sk, struct sk_buff *skb) { // 這裡只是把skb連線到prequeue佇列裡來,並沒有複製資料 __skb_queue_tail(&tp->ucopy.prequeue, skb); // 增加統計資訊 tp->ucopy.memory += skb->truesize; // prequeue滿了,或者user memory達到了上限,則清空prequeue if (skb_queue_len(&tp->ucopy.prequeue) >= 32 || tp->ucopy.memory + atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf) { struct sk_buff *skb1; while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) sk_backlog_rcv(sk, skb1); tp->ucopy.memory = 0; } else if (skb_queue_len(&tp->ucopy.prequeue) == 1) { wake_up_interruptible_sync_poll(sk_sleep(sk), POLLIN | POLLRDNORM | POLLRDBAND); if (!inet_csk_ack_scheduled(sk)) inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, (3 * tcp_rto_min(sk)) / 4, TCP_RTO_MAX); } } // 把資料寫到user_space static inline int sk_backlog_rcv(struct sock *sk, struct sk_buff *skb) { if (sk_memalloc_socks() && skb_pfmemalloc(skb)) return __sk_backlog_rcv(sk, skb); return sk->sk_backlog_rcv(sk, skb); //.backlog_rcv = tcp_v4_do_rcv, }