之前调试vxworks下PCIE的中断程序,都封装好了,所以只用了个intConnect,感觉没学到东西,就再看了下Linux的源码。
下面是最近调试中断时额外研习了一下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; } }