您的位置:首页 > 运维架构 > Linux

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

2011-08-26 22:24 495 查看
之前调试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;

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: