diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/log.c | 4 | ||||
-rw-r--r-- | lib/privs.c | 3 | ||||
-rw-r--r-- | lib/privs.h | 2 | ||||
-rw-r--r-- | lib/qpnexus.c | 148 | ||||
-rw-r--r-- | lib/qpnexus.h | 11 | ||||
-rw-r--r-- | lib/thread.c | 4 | ||||
-rw-r--r-- | lib/vty.c | 30 | ||||
-rw-r--r-- | lib/vty.h | 2 |
8 files changed, 156 insertions, 48 deletions
@@ -768,16 +768,12 @@ openzlog (const char *progname, zlog_proto_t protocol, void closezlog (struct zlog *zl) { - LOCK - closelog(); if (zl->fp != NULL) fclose (zl->fp); XFREE (MTYPE_ZLOG, zl); - - UNLOCK } /* Called from command.c. */ diff --git a/lib/privs.c b/lib/privs.c index 68757340..9d8cf79c 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -671,10 +671,9 @@ zprivs_state_null (void) } void -zprivs_init_r(struct zebra_privs_t *zprivs) +zprivs_init_r() { mx = qpt_mutex_init(mx, qpt_mutex_quagga); - zprivs_init(zprivs); } void diff --git a/lib/privs.h b/lib/privs.h index 18d35d8d..9c789d16 100644 --- a/lib/privs.h +++ b/lib/privs.h @@ -81,7 +81,7 @@ struct zprivs_ids_t }; /* initialise zebra privileges */ -extern void zprivs_init_r (struct zebra_privs_t *zprivs); +extern void zprivs_init_r (void); extern void zprivs_init (struct zebra_privs_t *zprivs); extern void zprivs_destroy_r (void); diff --git a/lib/qpnexus.c b/lib/qpnexus.c index 01985d29..1e71dc35 100644 --- a/lib/qpnexus.c +++ b/lib/qpnexus.c @@ -19,18 +19,20 @@ * Boston, MA 02111-1307, USA. */ -/* This MUST come first... otherwise we don't get __USE_UNIX98, which is */ -/* essential if glibc is to allow pthread_mutexattr_settype() to be used. */ -#include "config.h" - -#include <signal.h> -#include <string.h> +#include <zebra.h> #include "qpnexus.h" #include "memory.h" +#include "thread.h" /* prototypes */ +static void qpn_dispatch_queue(qpn_nexus qpn); static void* qpn_start(void* arg); +static void* qpn_start_legacy(void* arg); +static void qpn_thread_prep(qpn_nexus qpn); + +/* Master of the threads. */ +extern struct thread_master *master; /*============================================================================== * Quagga Nexus Interface -- qpt_xxxx @@ -40,59 +42,94 @@ static void* qpn_start(void* arg); /* Initialise a nexus -- allocating it if required. * + * If main_thread is set then no new thread will be created + * when qpn_exec() is called, instead the finite state machine will be + * run in the calling thread. The main thread will only block the + * message queue's signal. Non main threads will block all signals. + * * Returns the qtn_nexus. */ qpn_nexus -qpn_init_new(qpn_nexus qpn) +qpn_init_new(qpn_nexus qpn, int main) { if (qpn == NULL) qpn = XCALLOC(MTYPE_QPN_NEXUS, sizeof(struct qpn_nexus)) ; else memset(qpn, 0, sizeof(struct qpn_nexus)) ; + /* will change if we start new thread */ qpn->selection = qps_selection_init_new(qpn->selection); qpn->pile = qtimer_pile_init_new(qpn->pile); - - /* TODO mqueue initialisation */ + qpn->queue = mqueue_init_new(qpn->queue, mqt_signal_unicast); + qpn->main_thread = main; return qpn; } -void +/* free timers, selection, message queue and nexus */ +static void qpn_free(qpn_nexus qpn) { - /* timers and the pile */ + qps_file qf; qtimer qtr; + + /* timers and the pile */ while ((qtr = qtimer_pile_ream(qpn->pile, 1))) { qtimer_free(qtr); } - /* TODO: free qtn->selection */ + /* files and selection */ + while ((qf = qps_selection_ream(qpn->selection, 1))) + { + qps_file_free(qf); + } /* TODO: free qtn->queue */ XFREE(MTYPE_QPN_NEXUS, qpn) ; } -/* Create and execute the qpthread */ +/* If not main thread create new qpthread. + * Execute the state machine */ void qpn_exec(qpn_nexus qpn) { - qpn->thread_id = qpt_thread_create(qpn_start, qpn, NULL) ; + if (qpn->main_thread) + { + /* Run the state machine in calling thread */ + qpn->thread_id = qpt_thread_self(); + qpn_start(qpn); + } + else + { + /* create a qpthread and run the state machine in it */ + qpn->thread_id = qpt_thread_create(qpn_start, qpn, NULL) ; + } } +/* Prep thread and signals, then run finite state machine + * using qps_selection and qtimer +*/ static void* qpn_start(void* arg) { qpn_nexus qpn = arg; int actions; + qpn_thread_prep(qpn); + while (!qpn->terminate) { - qtime_mono_t now = qt_get_monotonic(); + qtime_mono_t now; + + /* Signals are highest priority. + * only execute on the main thread */ + if (qpn->main_thread) + quagga_sigevent_process (); /* process timers */ + now = qt_get_monotonic(); while (qtimer_pile_dispatch_next(qpn->pile, now)) { } @@ -107,7 +144,8 @@ qpn_start(void* arg) actions = qps_dispatch_next(qpn->selection) ; } - /* TODO process message queue */ + /* process message queue */ + qpn_dispatch_queue(qpn); } qpn_free(qpn); @@ -115,6 +153,84 @@ qpn_start(void* arg) return NULL; } +/* Create new qpthread and execute the thread state machine in it */ +void +qpn_exec_legacy(qpn_nexus qpn) +{ + qpn->thread_id = qpt_thread_create(qpn_start_legacy, qpn, NULL) ; +} + +/* Prep thread and signals, then run finite state machine + * using legacy threads +*/ +static void* +qpn_start_legacy(void* arg) +{ + qpn_nexus qpn = arg; + struct thread thread; + + qpn_thread_prep(qpn); + while (!qpn->terminate) + { + if (thread_fetch (master, &thread)) + thread_call (&thread); + + /* process message queue, if any */ + qpn_dispatch_queue(qpn); + } + + qpn_free(qpn); + + return NULL; +} + +/* dispatch any messages on our message queue */ +static void +qpn_dispatch_queue(qpn_nexus qpn) +{ + mqueue_block mqb; + + for (;;) + { + mqb = mqueue_dequeue(qpn->queue, 1, qpn->mts) ; + if (mqb == NULL) + return; + + mqb_dispatch(mqb); + } +} + +/* Init code to be run within the thread */ +static void +qpn_thread_prep(qpn_nexus qpn) +{ + sigset_t newmask; + + if (qpn->main_thread) + { + /* Main thread, block the message queue's signal */ + sigemptyset (&newmask); + sigaddset (&newmask, SIGMQUEUE); + } + else + { + /* + * Not main thread. Block most signals, but be careful not to + * defer SIGTRAP because doing so breaks gdb, at least on + * NetBSD 2.0. Avoid asking to block SIGKILL, just because + * we shouldn't be able to do so. + */ + sigfillset (&newmask); + sigdelset (&newmask, SIGTRAP); + sigdelset (&newmask, SIGKILL); + } + + qpt_thread_sigmask(SIG_BLOCK, &newmask, NULL); + qps_set_signal(qpn->selection, SIGMQUEUE, newmask); + + /* init mqueue_thread_signal here now we know our thread-id */ + qpn->mts = mqueue_thread_signal_init(qpn->mts, qpn->thread_id, SIGMQUEUE); +} diff --git a/lib/qpnexus.h b/lib/qpnexus.h index ce546edd..339c9bc5 100644 --- a/lib/qpnexus.h +++ b/lib/qpnexus.h @@ -50,6 +50,9 @@ /* maximum time in seconds to sit in a pselect */ #define MAX_PSELECT_TIMOUT 10 +/* signal for message queues */ +#define SIGMQUEUE SIGUSR2 + /*============================================================================== * Data Structures. */ @@ -61,6 +64,9 @@ struct qpn_nexus /* set true to terminate the thread (eventually) */ int terminate; + /* true if this is the main thread */ + int main_thread; + /* thread ID */ qpt_thread_t thread_id; @@ -72,6 +78,7 @@ struct qpn_nexus /* message queue */ mqueue_queue queue; + mqueue_thread_signal mts; }; @@ -79,8 +86,8 @@ struct qpn_nexus * Functions */ -extern qpn_nexus qpn_init_new(qpn_nexus qtn); +extern qpn_nexus qpn_init_new(qpn_nexus qtn, int main); extern void qpn_exec(qpn_nexus qtn); -void qpn_free(qpn_nexus qpn); +extern void qpn_exec_legacy(qpn_nexus qtn); #endif /* _ZEBRA_QPNEXUS_H */ diff --git a/lib/thread.c b/lib/thread.c index e89af541..589443a0 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -29,6 +29,7 @@ #include "hash.h" #include "command.h" #include "sigevent.h" +#include "qpthreads.h" /* Recent absolute time of day */ struct timeval recent_time; @@ -921,7 +922,8 @@ thread_fetch (struct thread_master *m, struct thread *fetch) int num = 0; /* Signals are highest priority */ - quagga_sigevent_process (); + if (!qpthreads_enabled) + quagga_sigevent_process (); /* Normal event are the next highest priority. */ if ((thread = thread_trim_head (&m->event)) != NULL) @@ -138,7 +138,7 @@ char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; /* Master of the threads. */ static struct thread_master *master = NULL; -static qpn_nexus master_nexus = NULL; +static qpn_nexus cli_nexus = NULL; /* VTY standard output function. vty == NULL or VTY_SHELL => stdout */ int @@ -442,11 +442,11 @@ vty_new (int fd) vty->max = VTY_BUFSIZ; vty->fd = fd; - if (master_nexus) + if (cli_nexus) { vty->qf = qps_file_init_new(vty->qf, NULL); - qps_add_file(master_nexus->selection, vty->qf, vty->fd, vty); - vty->qtr = qtimer_init_new(vty->qtr, master_nexus->pile, vty_timeout_r, vty); + qps_add_file(cli_nexus->selection, vty->qf, vty->fd, vty); + vty->qtr = qtimer_init_new(vty->qtr, cli_nexus->pile, vty_timeout_r, vty); } return vty; @@ -2898,7 +2898,7 @@ uty_config_unlock (struct vty *vty) static void vty_event (enum event event, int sock, struct vty *vty) { - if (master_nexus) + if (cli_nexus) vty_event_r(event, sock, vty); else vty_event_t(event, sock, vty); @@ -2976,7 +2976,7 @@ vty_event_r (enum event event, int sock, struct vty *vty) if (accept_file == NULL) { accept_file = qps_file_init_new(accept_file, NULL); - qps_add_file(master_nexus->selection, accept_file, sock, NULL); + qps_add_file(cli_nexus->selection, accept_file, sock, NULL); vector_set_index(Vvty_serv_thread, sock, accept_file); } qps_enable_mode(accept_file, qps_read_mnum, vty_accept_r) ; @@ -3367,7 +3367,7 @@ uty_reset () uty_close (vty); } - if (master_nexus) + if (cli_nexus) { for (i = 0; i < vector_active (Vvty_serv_thread); i++) if ((qf = vector_slot (Vvty_serv_thread, i)) != NULL) @@ -3465,19 +3465,10 @@ vty_init_vtysh () /* qpthreads: Install vty's own commands like `who' command. */ void -vty_init_r (void) +vty_init_r (qpn_nexus qpn) { - master_nexus = qpn_init_new(master_nexus); + cli_nexus = qpn; vty_mutex = qpt_mutex_init(vty_mutex, qpt_mutex_quagga); - vty_init(NULL); -} - -/* create and execute our thread */ -void -vty_exec_r(void) -{ - if (master_nexus) - qpn_exec(master_nexus); } /* threads: Install vty's own commands like `who' command. */ @@ -3536,9 +3527,6 @@ vty_terminate (void) { LOCK - if (master_nexus) - master_nexus->terminate = 1; - if (vty_cwd) XFREE (MTYPE_TMP, vty_cwd); @@ -218,7 +218,7 @@ extern int vty_lock_asserted; #endif /* Prototypes. */ -extern void vty_init_r (void); +extern void vty_init_r (qpn_nexus); extern void vty_exec_r(void); extern void vty_init (struct thread_master *); extern void vty_init_vtysh (void); |