Int main (INT argc, char ** argv)
{
Char * P;
Int daemon_mode = 0;
Char * progname;
Struct 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 .*/
// Set log here
Zlog_default = openzlog (progname, zlog_nolog, zlog_rip,
Log_cons | log_ndelay | log_pid, log_daemon );
/* Command line option parse .*/
While (1)
{
Int OPT;
// Parse parameters
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 ();
Pai_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) // enter the background to run and become a 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) // The real execution thread is here
Thread_call (& Thread );
/* Not reached .*/
Exit (0 );
}
First look at the thread_call (& Thread); line, enter this function
Void
Thread_call (struct thread * thread)
{
Unsigned long thread_time;
Rusage_t Ru;
Getrusage (& Thread-> Ru );
(* Thread-> func) (thread); // call the hook function of the thread linked list. For details about the hook function, see
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 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 */
}
Check thread_fetch and paste the code
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 limit TFD;
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. */The Event event has the highest priority. In fact, it triggers an update. The so-called trigger update means that when the route table changes, it immediately calls the hook function of the thread and broadcasts more messages.
If (thread = thread_trim_head (& M-> event ))! = NULL)
Return thread_run (M, thread, fetch );
/* Execute timer .*/
Gettimeofday (& timer_now, null );
// Check whether timeout occurs here, that is, if a route table item is not updated within 180 s, the corresponding thread is taken from the active linked list and put into the master-> unuse linked list. To put it bluntly, this thread is suspended and no longer executed.
For (thread = m-> timer. Head; thread = thread-> next)
If (timeval_cmp (timer_now, thread-> U. Sands)> = 0)
{
Thread_list_delete (& M-> timer, thread );
Return thread_run (M, thread, fetch );
}
// If a new Rip packet is received, it is read and the select mechanism is used.
/* 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;
Required TFD = m-> required TFD;
/* Calculate select wait timer .*/
Timer_wait = thread_timer_wait (M, & timer_val );
Num = select (fd_setsize, & readfd, & writefd, & 1_tfd, 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 );
}
}
Through the above analysis, it is found that the RIP is initialized and then enters a while endless loop, in which different thread hook functions are executed according to different priorities. Where are these hook functions registered? Go to the void rip_event (Enum rip_event event, int sock) function of ripd. C.
Void
Rip_event (Enum rip_event event, int sock)
{
Int jitter = 0;
Switch (Event)
{
// Read event. The hook function registered through thread_add_read is rip_read.
Case rip_read:
Rip-> t_read = thread_add_read (master, rip_read, null, sock );
Break;
// Update event. The hook function registered through thread_add_read is 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;
// Trigger the update. The hook function registered through thread_add_read is rip_triggered_update.
Case rip_triggered_update:
Printf ("come in rip_triggered_update \ n"); // Jimmy
If (rip-> t_triggered_interval)
Rip-> trigger = 1;
Else if (! Rip-> t_triggered_update)
{
Printf ("add event rip_triggered_update \ n"); // Jimmy
Rip-> t_triggered_update =
Thread_add_event (master, rip_triggered_update, null, 0 );
}
Break;
Default:
Break;
}
}