创建socket时会创建传输控制块,之后调用初始化函数对控制块进行初始化,其中包括对定时器的初始化,tcp会调用tcp_init_xmit_timers函数来初始化这些定时器,本文将详细分析tcp_init_xmit_timers函数;
下面为这种情况的函数调用关系:
1 /** 2 * inet_create 3 * |-->sk->sk_prot->init 4 * |-->tcp_v4_init_sock 5 * |-->tcp_init_sock 6 * |-->tcp_init_xmit_timers 7 */
tcp_init_xmit_timers函数将三个定时器回调传入到inet_csk_init_xmit_timers函数;
1 void tcp_init_xmit_timers(struct sock *sk) 2 { 3 inet_csk_init_xmit_timers(sk, &tcp_write_timer, &tcp_delack_timer, 4 &tcp_keepalive_timer); 5 }
inet_csk_init_xmit_timers函数将重传定时器icsk_retransmit_timer的回调设置为retransmit_handler,将延迟ack定时器icsk_delack_timer的回调设置为delack_handler,将sk_timer定时器设置wei为keepalive_handler,注: sk_timer为共用定时器,会在连接处于不同状态下设置不同的定时器回调;
1 /* 2 * Using different timers for retransmit, delayed acks and probes 3 * We may wish use just one timer maintaining a list of expire jiffies 4 * to optimize. 5 */ 6 void inet_csk_init_xmit_timers(struct sock *sk, 7 void (*retransmit_handler)(unsigned long), 8 void (*delack_handler)(unsigned long), 9 void (*keepalive_handler)(unsigned long)) 10 { 11 struct inet_connection_sock *icsk = inet_csk(sk); 12 13 setup_timer(&icsk->icsk_retransmit_timer, retransmit_handler, 14 (unsigned long)sk); 15 setup_timer(&icsk->icsk_delack_timer, delack_handler, 16 (unsigned long)sk); 17 setup_timer(&sk->sk_timer, keepalive_handler, (unsigned long)sk); 18 icsk->icsk_pending = icsk->icsk_ack.pending = 0; 19 }
——————–我是分割线——————–
定时器初始化的另外一条调用路径是开启fastopen的情况,本文不做讨论,补充在尾部;
1 /** 2 *tcp_v4_rcv 3 * |-->tcp_v4_do_rcv 4 * |-->tcp_rcv_state_process 5 * |-->tcp_v4_conn_request 6 * |-->tcp_try_fastopen 7 * |-->tcp_fastopen_create_child 8 * |-->tcp_v4_syn_recv_sock 9 * |-->tcp_create_openreq_child 10 * |-->tcp_init_xmit_timers 11 */