在rxe_req.c文件:
在int rxe_requester(void *arg)发包函数的最后会调用update_state函数,触发retrans_timer定时器
static void update_state(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
struct rxe_pkt_info *pkt, int payload)
{
qp->req.opcode = pkt->opcode;
if (pkt->mask & RXE_END_MASK)
qp->req.wqe_index = queue_next_index(qp->sq.queue,
qp->req.wqe_index);
qp->need_req_skb = 0;
if (qp->qp_timeout_jiffies && !timer_pending(&qp->retrans_timer))
mod_timer(&qp->retrans_timer,
jiffies + qp->qp_timeout_jiffies);
}
所以,retransmit_timer函数会被执行
void retransmit_timer(struct timer_list *t)
{
struct rxe_qp *qp = from_timer(qp, t, retrans_timer);
if (qp->valid) {
qp->comp.timeout = 1;
rxe_run_task(&qp->comp.task, 1);
}
}
从而,在定时器到期以后会调度到rxe_completer函数,
然后从skb队列里取出skb包,如果超时取出的skb为NULL,说明定时器到期以后,还没有ack过来,
那么state的变化为COMPST_GET_WQE->COMPST_EXIT->COMPST_ERROR_RETRY->COMPST_ERROR_RETRY,
然后设置qp->req.need_retry = 1;并启动rxe_run_task(&qp->req.task, 0);
到了req的调度以后,
该条件成立,最后通过req_retry函数重发数据包。
if (unlikely(qp->req.need_retry)) {
req_retry(qp);
qp->req.need_retry = 0;
}
对于timer_pending做了一个测试,注意看打印。
struct timer_list mytimer;
int i = 0;
//定时器超时处理函数
static void mytimer_handle(struct timer_list *t)
{
printk("The timer has happened %d times!\n", i);
if(timer_pending(&mytimer))
printk("timer_pending true!\n");
//这里需要说明的是,定时器在超时后会自动在系统中删除,也就是说如果定义了一个1s后执行的定时器
//1s后定时器到期后将会在系统中删除,无法完成周期性的定时任务;
//如果想要周期性执行,需要在超时处理函数中再次修改下定时器到期时间;
// mod_timer(&mytimer, jiffies + HZ);
i++;
mod_timer(&mytimer, jiffies+HZ);
if(timer_pending(&mytimer))
printk("timer_pending true! 11\n");
}
static int __init hello_init(void)
{
printk("mytimer init!!\n");
timer_setup(&mytimer, mytimer_handle, 0);//(1)初始化定时器mytimer,并设置超时处理函数
if(timer_pending(&mytimer))
printk("timer_pending false!\n");
//mytimer.expires = jiffies + HZ;//(2)设置超时时间,1s
//add_timer(&mytimer);//(3)将定时器mytimer添加到系统中
mod_timer(&mytimer, jiffies+HZ);
if(timer_pending(&mytimer))
printk("timer_pending false 11!\n");
return 0;
}
static void hello_exit(void)
{
printk("mytimer exit!!\n");
del_timer(&mytimer);//(4)退出时删除定时器
}
MODULE_AUTHOR("Tan xujia");
MODULE_LICENSE("Dual BSD/GPL");
module_init(hello_init);
module_exit(hello_exit);
# SPDX-License-Identifier: GPL-2.0
obj-m += vmax.o
vmax-objs := \
vma.o
all:
make -C /usr/src/linux-headers-$(shell uname -r) M=$(shell pwd) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean