diff options
-rw-r--r-- | bgpd/bgp_main.c | 32 | ||||
-rw-r--r-- | lib/memory.c | 7 | ||||
-rw-r--r-- | lib/privs.c | 5 | ||||
-rw-r--r-- | lib/privs.h | 2 | ||||
-rw-r--r-- | lib/qlib_init.c | 6 | ||||
-rw-r--r-- | lib/qpnexus.c | 26 | ||||
-rw-r--r-- | lib/qpnexus.h | 2 | ||||
-rw-r--r-- | lib/thread.c | 33 | ||||
-rw-r--r-- | lib/thread.h | 4 |
9 files changed, 96 insertions, 21 deletions
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 69767a9f..cb2eef29 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -207,7 +207,19 @@ sigint (void) if (! retain_mode) bgp_terminate (); - bgp_exit (0); + if (qpthreads_enabled) + { + /* ask all threads to terminate */ + if (bgp_nexus) + qpn_terminate(bgp_nexus); + + if (cli_nexus) + qpn_terminate(cli_nexus); + } + else + { + bgp_exit (0); + } } /* SIGUSR1 handler. */ @@ -319,13 +331,8 @@ bgp_exit (int status) if (CONF_BGP_DEBUG (normal, NORMAL)) log_memstats_stderr ("bgpd"); - if (bgp_nexus) - bgp_nexus->terminate = 1; - - if (cli_nexus) - cli_nexus->terminate = 1; /* waste of time, its the main thread */ - - /* TODO: join threads ? */ + bgp_nexus = qpn_free(bgp_nexus); + cli_nexus = qpn_free(cli_nexus); qexit (status); } @@ -477,7 +484,6 @@ main (int argc, char **argv) cli_nexus = qpn_init_main(cli_nexus); /* main thread */ bgp_nexus = qpn_init_bgp(bgp_nexus); - zprivs_init_r (); vty_init_r(cli_nexus, bgp_nexus); } @@ -493,8 +499,16 @@ main (int argc, char **argv) /* Launch finite state machines */ if (qpthreads_enabled) { + void * thread_result = NULL; + int result = 0; + qpn_exec(bgp_nexus); qpn_exec(cli_nexus); /* must be last to start - on main thread */ + + /* terminating, wait for all threads to finish */ + /* TODO need qpt_ version */ + result = pthread_join(bgp_nexus->thread_id, &thread_result); + bgp_exit(result); } else { diff --git a/lib/memory.c b/lib/memory.c index 36599f18..9bb49d18 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -524,7 +524,12 @@ void memory_finish (void) { if (memory_mutex) - memory_mutex = qpt_mutex_destroy(memory_mutex, 1); + { + /* avoid re-entrancy with memory disposal */ + qpt_mutex_t* mx = memory_mutex; + memory_mutex = NULL; + qpt_mutex_destroy(mx, 1); + } } void diff --git a/lib/privs.c b/lib/privs.c index 9d8cf79c..cd0f94ec 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -677,9 +677,10 @@ zprivs_init_r() } void -zprivs_destroy_r(void) +zprivs_finish(void) { - mx = qpt_mutex_destroy(mx, 1); + if (mx) + mx = qpt_mutex_destroy(mx, 1); } void diff --git a/lib/privs.h b/lib/privs.h index 9c789d16..45c5f49a 100644 --- a/lib/privs.h +++ b/lib/privs.h @@ -83,7 +83,7 @@ struct zprivs_ids_t /* initialise zebra privileges */ extern void zprivs_init_r (void); extern void zprivs_init (struct zebra_privs_t *zprivs); -extern void zprivs_destroy_r (void); +extern void zprivs_finish (void); /* drop all and terminate privileges */ extern void zprivs_terminate (struct zebra_privs_t *); diff --git a/lib/qlib_init.c b/lib/qlib_init.c index 8f46c610..e6bce633 100644 --- a/lib/qlib_init.c +++ b/lib/qlib_init.c @@ -23,6 +23,8 @@ #include "zassert.h" #include "memory.h" #include "qpthreads.h" +#include "thread.h" +#include "privs.h" /*============================================================================== * Quagga Library Initialise/Closedown @@ -71,12 +73,16 @@ qlib_init_second_stage(int pthreads) { qpt_set_qpthreads_enabled(pthreads); memory_init_r(); + thread_init_r(); + zprivs_init_r(); } void qexit(int exit_code) { + zprivs_finish(); + thread_finish(); memory_finish(); exit (exit_code); } diff --git a/lib/qpnexus.c b/lib/qpnexus.c index 5a5c5417..fa500e36 100644 --- a/lib/qpnexus.c +++ b/lib/qpnexus.c @@ -84,13 +84,18 @@ qpn_init_bgp(qpn_nexus qpn) return qpn; } -/* free timers, selection, message queue and nexus */ -static void +/* free timers, selection, message queue and nexus + * return NULL + */ +qpn_nexus qpn_free(qpn_nexus qpn) { qps_file qf; qtimer qtr; + if (qpn == NULL) + return NULL; + /* timers and the pile */ if (qpn->pile != NULL) { @@ -112,6 +117,8 @@ qpn_free(qpn_nexus qpn) /* TODO: free qtn->queue */ XFREE(MTYPE_QPN_NEXUS, qpn) ; + + return NULL; } /* If not main thread create new qpthread. @@ -127,7 +134,7 @@ qpn_exec(qpn_nexus qpn) else { /* create a qpthread and run the state machine in it */ - qpn->thread_id = qpt_thread_create(qpn->start, qpn, NULL) ; + qpt_thread_create(qpn->start, qpn, NULL) ; } } @@ -173,8 +180,6 @@ qpn_start_main(void* arg) } } - qpn_free(qpn); - return NULL; } @@ -224,7 +229,14 @@ qpn_start_bgp(void* arg) mqueue_done_waiting(qpn->queue, qpn->mts); } - qpn_free(qpn); - return NULL; } + +/* Ask the thread to terminate itself quickly and cleanly */ +void +qpn_terminate(qpn_nexus qpn) +{ + qpn->terminate = 1; + /* wake up any pselect */ + qpt_thread_signal(qpn->thread_id, SIGMQUEUE); +} diff --git a/lib/qpnexus.h b/lib/qpnexus.h index bda5234f..7436c55d 100644 --- a/lib/qpnexus.h +++ b/lib/qpnexus.h @@ -93,5 +93,7 @@ extern qpn_nexus qpn_init_new(qpn_nexus qtn); extern qpn_nexus qpn_init_main(qpn_nexus qtn); extern qpn_nexus qpn_init_bgp(qpn_nexus qtn); extern void qpn_exec(qpn_nexus qtn); +extern void qpn_terminate(qpn_nexus qpn); +extern qpn_nexus qpn_free(qpn_nexus qpn); #endif /* _ZEBRA_QPNEXUS_H */ diff --git a/lib/thread.c b/lib/thread.c index 9fa1fd9f..b58a2c73 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -40,6 +40,10 @@ static struct timeval relative_time_base; /* init flag */ static unsigned short timers_inited; +/* cpu stats needs to be qpthread safe. */ +static qpt_mutex_t* thread_mutex = NULL; +#define LOCK qpt_mutex_lock(thread_mutex); +#define UNLOCK qpt_mutex_unlock(thread_mutex); static struct hash *cpu_record = NULL; /* TODO: remove this */ @@ -323,15 +327,19 @@ cpu_record_print(struct vty *vty, thread_type filter) vty_out(vty, " Avg uSec Max uSecs"); #endif vty_out(vty, " Type Thread%s", VTY_NEWLINE); + + LOCK hash_iterate(cpu_record, (void(*)(struct hash_backet*,void*))cpu_record_hash_print, args); if (tmp.total_calls > 0) vty_out_cpu_thread_history(vty, &tmp); + + UNLOCK } -DEFUN(show_thread_cpu, +DEFUN_CALL(show_thread_cpu, show_thread_cpu_cmd, "show thread cpu [FILTER]", SHOW_STR @@ -529,12 +537,14 @@ thread_master_free (struct thread_master *m) XFREE (MTYPE_THREAD_MASTER, m); + LOCK if (cpu_record) { hash_clean (cpu_record, cpu_record_hash_free); hash_free (cpu_record); cpu_record = NULL; } + UNLOCK } /* Thread list is empty or not. */ @@ -1088,8 +1098,10 @@ thread_call (struct thread *thread) tmp.func = thread->func; tmp.funcname = thread->funcname; + LOCK thread->hist = hash_get (cpu_record, &tmp, (void * (*) (void *))cpu_record_hash_alloc); + UNLOCK } GETRUSAGE (&thread->ru); @@ -1099,6 +1111,8 @@ thread_call (struct thread *thread) GETRUSAGE (&ru); realtime = thread_consumed_time (&ru, &thread->ru, &cputime); + + LOCK thread->hist->real.total += realtime; if (thread->hist->real.max < realtime) thread->hist->real.max = realtime; @@ -1110,6 +1124,7 @@ thread_call (struct thread *thread) ++(thread->hist->total_calls); thread->hist->types |= (1 << thread->add_type); + UNLOCK #ifdef CONSUMED_TIME_CHECK if (realtime > CONSUMED_TIME_CHECK) @@ -1154,4 +1169,20 @@ funcname_thread_execute (struct thread_master *m, return NULL; } + +/* Second state initialisation if qpthreaded */ +void +thread_init_r (void) +{ + thread_mutex = qpt_mutex_init(thread_mutex, qpt_mutex_quagga); +} + +/* Finished with module */ +void +thread_finish (void) +{ + if (thread_mutex) + thread_mutex = qpt_mutex_destroy(thread_mutex, 1); +} + #undef USE_MQUEUE diff --git a/lib/thread.h b/lib/thread.h index b52bc541..43d4d12f 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -22,6 +22,8 @@ #ifndef _ZEBRA_THREAD_H #define _ZEBRA_THREAD_H +#include <sys/resource.h> + struct rusage_t { #ifdef HAVE_RUSAGE @@ -163,6 +165,8 @@ enum quagga_clkid { /* Prototypes. */ extern struct thread_master *thread_master_create (void); extern void thread_master_free (struct thread_master *); +extern void thread_init_r (void); +extern void thread_finish (void); extern struct thread *funcname_thread_add_read (struct thread_master *, int (*)(struct thread *), |