下面是最近调试中断时额外研习了一下Linux的内核代码,下面就直接贴代码和注释了,大量借鉴了网上牛人的见解,还望海涵!!
- int main (int argc, char **argv)
- {
- char *p;
- int daemon_mode = 0;
- char *progname;
- struct thread thread;
- /* Set umask before anything for security */
- umask (0027);
- /* Get program name. */
- progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
- /* First of all we need logging init. */
- // 在这里设置 log
- zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_RIP,
- LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
- /* Command line option parse. */
- while (1)
- {
- int opt;
- // 解析参数
- opt = getopt_long (argc, argv, "df:hA:P:rv", longopts, 0);
- if (opt == EOF)
- break;
- switch (opt)
- {
- case 0:
- break;
- case 'd':
- daemon_mode = 1;
- break;
- case 'f':
- config_file = optarg;
- break;
- case 'A':
- vty_addr = optarg;
- break;
- case 'i':
- pid_file = optarg;
- break;
- case 'P':
- vty_port = atoi (optarg);
- break;
- case 'r':
- retain_mode = 1;
- break;
- case 'v':
- print_version (progname);
- exit (0);
- break;
- case 'h':
- usage (progname, 0);
- break;
- default:
- usage (progname, 1);
- break;
- }
- }
- /* Prepare master thread. */
- master = thread_master_create ();
- /* Library initialization. */
- signal_init ();
- cmd_init (1);
- vty_init ();
- memory_init ();
- keychain_init ();
- /* RIP related initialization. */
- rip_init ();
- rip_if_init ();
- rip_zclient_init ();
- rip_peer_init ();
- /* Sort all installed commands. */
- sort_node ();
- /* Get configuration file. */
- vty_read_config (config_file, config_current, config_default);
- /* Change to the daemon program. */
- if (daemon_mode) // 进入后台运行,成为守护进程
- daemon (0, 0);
- /* Pid file create. */
- pid_output (pid_file);
- /* Create VTY's socket */
- vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH);
- /* Execute each thread. */
- while (thread_fetch (master, &thread)) // 真正执行线程在这里
- thread_call (&thread);
- /* Not reached. */
- exit (0);
- }
- /*先看看 thread_call (&thread); 这一行,进入此函数 */
- void
- thread_call (struct thread *thread)
- {
- unsigned long thread_time;
- RUSAGE_T ru;
- GETRUSAGE (&thread->ru);
- (*thread->func) (thread); // 此处调用线程链表的钩子函数,具体钩子函数是什么,待会看
- GETRUSAGE (&ru);
- thread_time = thread_consumed_time (&ru, &thread->ru);
- #ifdef THREAD_CONSUMED_TIME_CHECK
- if (thread_time > 200000L)
- {
- /*
- * We have a CPU Hog on our hands.
- * Whinge about it now, so we're aware this is yet another task
- * to fix.
- */
- zlog_err ("CPU HOG task %lx ran for %ldms",
- /* FIXME: report the name of the function somehow */
- (unsigned long) thread->func,
- thread_time / 1000L);
- }
- #endif /* THREAD_CONSUMED_TIME_CHECK */
- }
- /*在看看 thread_fetch ,贴出代码 */
- struct thread *
- thread_fetch (struct thread_master *m, struct thread *fetch)
- {
- int num;
- int ready;
- struct thread *thread;
- fd_set readfd;
- fd_set writefd;
- fd_set exceptfd;
- struct timeval timer_now;
- struct timeval timer_val;
- struct timeval *timer_wait;
- struct timeval timer_nowait;
- timer_nowait.tv_sec = 0;
- timer_nowait.tv_usec = 0;
- while (1)
- {
- /* Normal event is the highest priority. */
- /*event 事件优先级最高,其实就是触发更新,所谓触发更新,就是路由表一改变,马上调用线程的钩子函数,多播出去 */
- if ((thread = thread_trim_head (&m->event)) != NULL)
- return thread_run (m, thread, fetch);
- /* Execute timer. */
- gettimeofday (&timer_now, NULL);
- /* 在这里看是否超时,也就是一个路由表项在 180S 内没有更新,则将对应的线程从活动链表取出,
- * 放入 master - >unuse 链表。说白了就是把此线程挂起,不再执行 */
- for (thread = m->timer.head; thread; thread = thread->next)
- if (timeval_cmp (timer_now, thread->u.sands) >= 0)
- {
- thread_list_delete (&m->timer, thread);
- return thread_run (m, thread, fetch);
- }
- // 如果接收到新的 RIP 数据包,则读入 , 采用 select 机制
- /* If there are any ready threads, process top of them. */
- if ((thread = thread_trim_head (&m->ready)) != NULL)
- return thread_run (m, thread, fetch);
- /* Structure copy. */
- readfd = m->readfd;
- writefd = m->writefd;
- exceptfd = m->exceptfd;
- /* Calculate select wait timer. */
- timer_wait = thread_timer_wait (m, &timer_val);
- num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
- if (num == 0)
- continue;
- if (num < 0)
- {
- if (errno == EINTR)
- continue;
- zlog_warn ("select() error: %s", strerror (errno));
- return NULL;
- }
- /* Normal priority read thead. */
- ready = thread_process_fd (m, &m->read, &readfd, &m->readfd);
- /* Write thead. */
- ready = thread_process_fd (m, &m->write, &writefd, &m->writefd);
- if ((thread = thread_trim_head (&m->ready)) != NULL)
- return thread_run (m, thread, fetch);
- }
- }
- /* 通过以上分析,发现就是 RIP 经过初始化后,然后进入一个 while 死循环,
- * 在这个死循环中根据不同的优先级去执行不同的线程钩子函数。而这些钩子函数在什么地方注册的呢,
- * 进入 ripd.c 的 void rip_event (enum rip_event event, int sock) 函数。 */
- void
- rip_event (enum rip_event event, int sock)
- {
- int jitter = 0;
- switch (event)
- {
- //read 事件,通过 thread_add_read 注册的钩子函数为 rip_read.
- case RIP_READ:
- rip->t_read = thread_add_read (master, rip_read, NULL, sock);
- break;
- //update 事件,通过 thread_add_read 注册的钩子函数为 rip_update.
- case RIP_UPDATE_EVENT:
- if (rip->t_update)
- {
- thread_cancel (rip->t_update);
- rip->t_update = NULL;
- }
- jitter = rip_update_jitter (rip->update_time);
- rip->t_update = thread_add_timer (master, rip_update, NULL,
- sock ? 2 : rip->update_time + jitter);
- break;
- // 触发更新,通过 thread_add_read 注册的钩子函数为 rip_triggered_update.
- case RIP_TRIGGERED_UPDATE:
- printf("come in RIP_TRIGGERED_UPDATE\n");
- if (rip->t_triggered_interval)
- rip->trigger = 1;
- else if (! rip->t_triggered_update)
- {
- printf("add event rip_triggered_update\n");
- rip->t_triggered_update =
- thread_add_event (master, rip_triggered_update, NULL, 0);
- }
- break;
- default:
- break;
- }
- }