diff options
Diffstat (limited to 'lib/qpnexus.c')
-rw-r--r-- | lib/qpnexus.c | 166 |
1 files changed, 96 insertions, 70 deletions
diff --git a/lib/qpnexus.c b/lib/qpnexus.c index 8a78a70b..cb0bd12c 100644 --- a/lib/qpnexus.c +++ b/lib/qpnexus.c @@ -36,7 +36,13 @@ static void qpn_in_thread_init(qpn_nexus qpn); */ -/* Initialise a nexus -- allocating it if required. +/*============================================================================== + * Initialisation, add hook, free etc. + * + */ + +/*------------------------------------------------------------------------------ + * 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 @@ -45,7 +51,7 @@ static void qpn_in_thread_init(qpn_nexus qpn); * * Returns the qpn_nexus. */ -qpn_nexus +extern qpn_nexus qpn_init_new(qpn_nexus qpn, int main_thread) { if (qpn == NULL) @@ -53,16 +59,27 @@ qpn_init_new(qpn_nexus qpn, int main_thread) else memset(qpn, 0, sizeof(struct qpn_nexus)) ; - qpn->selection = qps_selection_init_new(qpn->selection); - qpn->pile = qtimer_pile_init_new(qpn->pile); - qpn->queue = mqueue_init_new(qpn->queue, mqt_signal_unicast); + qpn->selection = qps_selection_init_new(qpn->selection); + qpn->pile = qtimer_pile_init_new(qpn->pile); + qpn->queue = mqueue_init_new(qpn->queue, mqt_signal_unicast); qpn->main_thread = main_thread; - qpn->start = qpn_start; + qpn->start = qpn_start; return qpn; } -/* free timers, selection, message queue and nexus +/*------------------------------------------------------------------------------ + * Add a hook function to the given nexus. + */ +extern void +qpn_add_hook_function(qpn_hook_list list, void* hook) +{ + passert(list->count < qpn_hooks_max) ; + list->hooks[list->count++] = hook ; +} ; + +/*------------------------------------------------------------------------------ + * free timers, selection, message queue and nexus * return NULL */ qpn_nexus @@ -99,24 +116,25 @@ qpn_free(qpn_nexus qpn) return NULL; } -/* If not main thread create new qpthread. - * Execute the state machine */ -void +/*============================================================================== + * Execution of a nexus + */ + +/*------------------------------------------------------------------------------ + * If not main qpthread create new qpthread. + * + * For all qpthreads: start the thread ! + */ +extern void qpn_exec(qpn_nexus qpn) { if (qpn->main_thread) - { - /* Run the state machine in calling thread */ - qpn->start(qpn); - } + qpn->start(qpn); else - { - /* create a qpthread and run the state machine in it */ - qpt_thread_create(qpn->start, qpn, NULL) ; - } -} + qpt_thread_create(qpn->start, qpn, NULL) ; +} ; -/*============================================================================== +/*------------------------------------------------------------------------------ * Pthread routine * * Processes: @@ -145,78 +163,86 @@ qpn_start(void* arg) qpn_nexus qpn = arg; mqueue_block mqb; int actions; - qtime_mono_t now; - qtime_mono_t max_wait; - int i; + qtime_mono_t now ; + qtime_t max_wait ; + unsigned i; + unsigned done ; + unsigned wait ; - /* now in our thread, complete initialisation */ + /* now in our thread, complete initialisation */ qpn_in_thread_init(qpn); + /* Until required to terminate, loop */ + done = 1 ; while (!qpn->terminate) { - now = qt_get_monotonic(); + wait = (done == 0) ; /* may wait this time only if nothing + found to do on the last pass */ - /* Signals are highest priority. - * only execute on the main thread */ + /* Signals are highest priority -- only execute for main thread + * + * Restarts "done" for this pass. + */ if (qpn->main_thread) - quagga_sigevent_process (); + done = quagga_sigevent_process() ; + else + done = 0 ; - /* max time to wait in pselect */ - max_wait = QTIME(MAX_PSELECT_TIMOUT); - - /* event hooks, if any. High priority */ - for (i = 0; i < NUM_EVENT_HOOK; ++i) - { - if (qpn->event_hook[i] != NULL) - { - /* first, second and third priority */ - qtime_mono_t event_wait = qpn->event_hook[i](qpn_pri_third); - if (event_wait > 0 && event_wait < max_wait) - max_wait = event_wait; - } - } + /* Foreground hooks, if any. */ + for (i = 0; i < qpn->foreground.count ; ++i) + done |= ((qpn_hook_function*)(qpn->foreground.hooks[i]))() ; /* drain the message queue, will be in waiting for signal state * when it's empty */ - for (;;) + + if (done != 0) + wait = 0 ; /* turn off wait if found something */ + + while (1) { - mqb = mqueue_dequeue(qpn->queue, 1, qpn->mts) ; + mqb = mqueue_dequeue(qpn->queue, wait, qpn->mts) ; if (mqb == NULL) break; mqb_dispatch(mqb, mqb_action); - } - /* Event hooks, if any. All priorities */ - for (i = 0; i < NUM_EVENT_HOOK; ++i) - { - if (qpn->event_hook[i] != NULL) - { - /* first, second third and fourth priority */ - qtime_mono_t event_wait = qpn->event_hook[i](qpn_pri_fourth); - if (event_wait > 0 && event_wait < max_wait) - max_wait = event_wait; - } - } - - /* block for some input, output, signal or timeout */ - actions = qps_pselect(qpn->selection, - qtimer_pile_top_time(qpn->pile, now + max_wait)); - - /* process I/O actions */ - while (actions) - actions = qps_dispatch_next(qpn->selection) ; + done = 1 ; /* done something */ + wait = 0 ; /* turn off wait */ + } ; - mqueue_done_waiting(qpn->queue, qpn->mts); + /* block for some input, output, signal or timeout + * + * wait will be true iff did nothing the last time round the loop, and + * not found anything to be done up to this point either. + */ + if (wait) + max_wait = qtimer_pile_top_wait(qpn->pile, QTIME(MAX_PSELECT_WAIT)) ; + else + max_wait = 0 ; + + actions = qps_pselect(qpn->selection, max_wait) ; + done |= actions ; + + if (wait) + mqueue_done_waiting(qpn->queue, qpn->mts); + + /* process I/O actions */ + while (actions) + actions = qps_dispatch_next(qpn->selection) ; - /* process timers */ + /* process timers */ + now = qt_get_monotonic() ; while (qtimer_pile_dispatch_next(qpn->pile, now)) - { - } - } + done = 1 ; + + /* If nothing done in this pass, see if anything in the background */ + if (done == 0) + for (i = 0; i < qpn->background.count ; ++i) + done |= ((qpn_hook_function*)(qpn->background.hooks[i]))() ; + } ; /* last bit of code to run in this thread */ - if (qpn->in_thread_final) + if (qpn->in_thread_final != NULL) qpn->in_thread_final(); return NULL; |