JuanA1的专栏

金字塔最底层之IT民工的技术点滴

Linux下中断处理程序源码分析

    之前调试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; 

    } 

} 
阅读更多
想对作者说点什么? 我来说一句

<em>linux</em>--<em>中断</em>

2018年05月08日 0B 下载

Linux下网卡驱动程序源码分析.rar

2009年04月22日 306KB 下载

CTorrent程序源码分析

2010年03月20日 78KB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭