* @returns 0 on success, otherwise a clib_error_t *.
*/
-static clib_error_t *init_exit_function_sort
+clib_error_t *vlib_sort_init_exit_functions
(_vlib_init_function_list_elt_t ** head)
{
uword *index_by_name;
* A and B - and it leads to hugely annoying debugging exercises.
*/
-clib_error_t *
-vlib_call_init_exit_functions (vlib_main_t * vm,
- _vlib_init_function_list_elt_t ** headp,
- int call_once)
+static inline clib_error_t *
+call_init_exit_functions_internal (vlib_main_t * vm,
+ _vlib_init_function_list_elt_t ** headp,
+ int call_once, int do_sort)
{
clib_error_t *error = 0;
_vlib_init_function_list_elt_t *i;
- if ((error = init_exit_function_sort (headp)))
+ if (do_sort && (error = vlib_sort_init_exit_functions (headp)))
return (error);
i = *headp;
return error;
}
+clib_error_t *
+vlib_call_init_exit_functions (vlib_main_t * vm,
+ _vlib_init_function_list_elt_t ** headp,
+ int call_once)
+{
+ return call_init_exit_functions_internal (vm, headp, call_once,
+ 1 /* do_sort */ );
+}
+
+clib_error_t *
+vlib_call_init_exit_functions_no_sort (vlib_main_t * vm,
+ _vlib_init_function_list_elt_t **
+ headp, int call_once)
+{
+ return call_init_exit_functions_internal (vm, headp, call_once,
+ 0 /* do_sort */ );
+}
+
clib_error_t *
vlib_call_all_init_functions (vlib_main_t * vm)
{
clib_error_t *vlib_call_init_exit_functions (struct vlib_main_t *vm,
_vlib_init_function_list_elt_t **
headp, int call_once);
-
+clib_error_t *vlib_call_init_exit_functions_no_sort (struct vlib_main_t *vm,
+ _vlib_init_function_list_elt_t
+ ** headp, int call_once);
+clib_error_t *vlib_sort_init_exit_functions (_vlib_init_function_list_elt_t
+ **);
#define foreach_vlib_module_reference \
_ (node_cli) \
_ (trace_cli)
if (is_main)
{
uword i;
+
+ /*
+ * Perform an initial barrier sync. Pays no attention to
+ * the barrier sync hold-down timer scheme, which won't work
+ * at this point in time.
+ */
+ vlib_worker_thread_initial_barrier_sync_and_release (vm);
+
nm->current_process_index = ~0;
for (i = 0; i < vec_len (nm->processes); i++)
cpu_time_now = dispatch_process (vm, nm->processes[i], /* frame */ 0,
if ((error = vlib_call_all_config_functions (vm, input, 0 /* is_early */ )))
goto done;
+ /* Sort per-thread init functions before we start threads */
+ vlib_sort_init_exit_functions (&vm->worker_init_function_registrations);
+
/* Call all main loop enter functions. */
{
clib_error_t *sub_error;
#define BARRIER_MINIMUM_OPEN_FACTOR 3
#endif
+void
+vlib_worker_thread_initial_barrier_sync_and_release (vlib_main_t * vm)
+{
+ f64 deadline;
+ f64 now = vlib_time_now (vm);
+ u32 count = vec_len (vlib_mains) - 1;
+
+ /* No worker threads? */
+ if (count == 0)
+ return;
+
+ deadline = now + BARRIER_SYNC_TIMEOUT;
+ *vlib_worker_threads->wait_at_barrier = 1;
+ while (*vlib_worker_threads->workers_at_barrier != count)
+ {
+ if ((now = vlib_time_now (vm)) > deadline)
+ {
+ fformat (stderr, "%s: worker thread deadlock\n", __FUNCTION__);
+ os_panic ();
+ }
+ CLIB_PAUSE ();
+ }
+ *vlib_worker_threads->wait_at_barrier = 0;
+}
+
void
vlib_worker_thread_barrier_sync_int (vlib_main_t * vm, const char *func_name)
{
clib_time_init (&vm->clib_time);
clib_mem_set_heap (w->thread_mheap);
- /* Wait until the dpdk init sequence is complete */
- while (tm->extern_thread_mgmt && tm->worker_thread_release == 0)
- vlib_worker_thread_barrier_check ();
-
- e = vlib_call_init_exit_functions
+ e = vlib_call_init_exit_functions_no_sort
(vm, &vm->worker_init_function_registrations, 1 /* call_once */ );
if (e)
clib_error_report (e);
+ /* Wait until the dpdk init sequence is complete */
+ while (tm->extern_thread_mgmt && tm->worker_thread_release == 0)
+ vlib_worker_thread_barrier_check ();
+
vlib_worker_loop (vm);
}
void vlib_worker_thread_barrier_sync_int (vlib_main_t * vm,
const char *func_name);
void vlib_worker_thread_barrier_release (vlib_main_t * vm);
+void vlib_worker_thread_initial_barrier_sync_and_release (vlib_main_t * vm);
void vlib_worker_thread_node_refork (void);
static_always_inline uword