接下来从tapdisk_server_run()入手,看看tapdisk怎么运行的。
327 int
328 tapdisk_server_run()
329 {
330 int err;
331 //资源锁?
332 err = tapdisk_set_resource_limits();
333 if (err)
334 return err;
335 //注册信号处理函数
336 signal(SIGBUS, tapdisk_server_signal_handler);
337 signal(SIGINT, tapdisk_server_signal_handler);
338 signal(SIGUSR1, tapdisk_server_signal_handler);
339 signal(SIGXFSZ, tapdisk_server_signal_handler);
340 //运行server
341 __tapdisk_server_run();
342 tapdisk_server_close();
343
344 return 0;
345 }
245 static void
246 __tapdisk_server_run(void)
247 { //初始化1了
248 while (server.run)
249 tapdisk_server_iterate();
250 }
227 void
228 tapdisk_server_iterate(void)
229 {
230 int ret;
231 //空函数??可能是以后要添加的
232 tapdisk_server_assert_locks();
233 tapdisk_server_set_retry_timeout();
234 tapdisk_server_check_progress();
235
236 ret = scheduler_wait_for_events(&server.scheduler);
237 if (ret < 0)
238 DBG(TLOG_WARN, "server wait returned %d\n", ret);
239
240 tapdisk_server_check_vbds();
241 tapdisk_server_submit_tiocbs();
242 tapdisk_server_kick_responses();
243 }
150 static void
151 tapdisk_server_set_retry_timeout(void)
152 {
153 td_vbd_t *vbd, *tmp;
154
155 tapdisk_server_for_each_vbd(vbd, tmp)
156 if (tapdisk_vbd_retry_needed(vbd)) {
157 tapdisk_server_set_max_timeout(TD_VBD_RETRY_INTERVAL);
158 return;
159 }
160 }
vbd?virtual block device?
56 typedef struct td_vbd_handle td_vbd_t;
//从server.vbds当前保存的list_head开始,遍历所有的vbd
45 #define tapdisk_server_for_each_vbd(vbd, tmp)
46 list_for_each_entry_safe(vbd, tmp, &server.vbds, next)
遍历所有的vbd,找到需要retry的vbd(通过vbd->state)
869 int
870 tapdisk_vbd_retry_needed(td_vbd_t *vbd)
871 {
//&
87: return td_flag_test(vbd->state, TD_VBD_RETRY_NEEDED);
873 }
设置最大超时。
但是server变量只有一个,tapdisk_server_set_max_timeout只有一个常量ian量,为什么要遍历vbd?
162 static void
163 tapdisk_server_check_progress(void)
164 {
165 struct timeval now;
166 td_vbd_t *vbd, *tmp;
167 //获取时间到now里,干嘛用?
168 gettimeofday(&now, NULL);
169
170 tapdisk_server_for_each_vbd(vbd, tmp)
171 tapdisk_vbd_check_progress(vbd);
172 }
1107 void
1108 tapdisk_vbd_check_progress(td_vbd_t *vbd)
1109 {
1110 int diff;
1111 struct timeval now;
1112 //vbd的pending_requests指向自身,说明没有加入队列,即非peding
1113 if (list_empty(&vbd->pending_requests))
1114 return;
1115
1116 gettimeofday(&now, NULL);
1117 diff = now.tv_sec - vbd->ts.tv_sec;
1118 //10,idle超时
1119 if (diff >= TD_VBD_WATCHDOG_TIMEOUT) {
1120 DBG(TLOG_WARN, "%s: watchdog timeout: pending requests "
1121 "idle for %d seconds\n", vbd->name, diff);
1122 tapdisk_vbd_drop_log(vbd);
1123 return;
1124 }
1125//更新剩下的时间
1126 tapdisk_server_set_max_timeout(TD_VBD_WATCHDOG_TIMEOUT - diff);
1127 }
check_progress检查所有的vbd是否超时,根据vbd设置server的max_timeout
接下来终于开始处理event
224 int
225 scheduler_wait_for_events(scheduler_t *s)
226 {
227 int ret;
228 struct timeval tv;
229
230 scheduler_prepare_events(s);
231
232 tv.tv_sec = s->timeout;
233 tv.tv_usec = 0;
234
235 DBG("timeout: %d, max_timeout: %d\n",
236 s->timeout, s->max_timeout);
237
238 ret = select(s->max_fd + 1, &s->read_fds,
239 &s->write_fds, &s->except_fds, &tv);
240
241 s->restart = 0;
242 s->timeout = SCHEDULER_MAX_TIMEOUT;
243 s->max_timeout = SCHEDULER_MAX_TIMEOUT;
244
245 if (ret < 0)
246 return ret;
247
248 scheduler_run_events(s);
249
250 return ret;
251 }
ret = select(s->max_fd + 1, &s->read_fds,&s->write_fds, &s->except_fds, &tv);
设置select函数,监听读写异常文件,如果集合中有文件可读/可写/异常发生则返回大于0的数;如果没有则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值,没有超时则等待。即select程序最多在tv时间内阻塞。
select()
64 static void
65 scheduler_prepare_events(scheduler_t *s)
66 {
67 int diff;
68 struct timeval now;
69 event_t *event, *tmp;
70 //清空文件描述符
71 FD_ZERO(&s->read_fds);
72 FD_ZERO(&s->write_fds);
73 FD_ZERO(&s->except_fds);
74
75 s->max_fd = 0;
//设置超时
76 s->timeout = SCHEDULER_MAX_TIMEOUT;
77
78 gettimeofday(&now, NULL);
79
//47 #define scheduler_for_each_event(s, event, tmp) \
//48 list_for_each_entry_safe(event, tmp, &(s)->events, next)
//通过s->events为list_head找到列表,遍历所有的event
80 scheduler_for_each_event(s, event, tmp) {
81 if (event->mode & SCHEDULER_POLL_READ_FD) {
82 FD_SET(event->fd, &s->read_fds);
83 s->max_fd = MAX(event->fd, s->max_fd);
84 }
85
86 if (event->mode & SCHEDULER_POLL_WRITE_FD) {
87 FD_SET(event->fd, &s->write_fds);
88 s->max_fd = MAX(event->fd, s->max_fd);
89 }
90
91 if (event->mode & SCHEDULER_POLL_EXCEPT_FD) {
92 FD_SET(event->fd, &s->except_fds);
93 s->max_fd = MAX(event->fd, s->max_fd);
94 }
95
96 if (event->mode & SCHEDULER_POLL_TIMEOUT) {
97 diff = event->deadline - now.tv_sec;
98 if (diff > 0)
99 s->timeout = MIN(s->timeout, diff);
100 else
101 s->timeout = 0;
102 }
103 }
104
105 s->timeout = MIN(s->timeout, s->max_timeout);
106 }
scheduler_prepare_events先清空文件描述符,将设置timeout(600)。
遍历event,根据event->mode设置s。比如event是读,把event->fd添加到s的读文件描述符集中,设置s的max_fd。
fd_set是一个unsigned long类型的数组。每一个里面的每一位记录一个fd(位图)。FD_SET就是把对应位变为1
FD_SET(600,master_set_read);=> master_set_read->fds_bits[(600)/32] |= (1<<(600%32));
除了读写还有except,这个是什么情况,先放着。如果event是SCHEDULER_POLL_TIMEOUT(有限制时间的),检查现在是否超时,更新s的timeout(超时为0)
最后s->timeout = MIN(s->timeout, s->max_timeout);