vppinfra: momve clib_sysfs_list_to_bitmap to sysfs.c
[vpp.git] / src / vlib / threads.c
index d5096c8..f3a6643 100644 (file)
@@ -18,6 +18,7 @@
 #include <math.h>
 #include <vppinfra/format.h>
 #include <vppinfra/time_range.h>
+#include <vppinfra/interrupt.h>
 #include <vppinfra/linux/sysfs.h>
 #include <vlib/vlib.h>
 
@@ -47,13 +48,11 @@ barrier_trace_sync (f64 t_entry, f64 t_open, f64 t_closed)
   if (!vlib_worker_threads->barrier_elog_enabled)
     return;
 
-    /* *INDENT-OFF* */
-    ELOG_TYPE_DECLARE (e) =
-      {
-        .format = "bar-trace-%s-#%d",
-        .format_args = "T4i4",
-      };
-    /* *INDENT-ON* */
+  ELOG_TYPE_DECLARE (e) = {
+    .format = "bar-trace-%s-#%d",
+    .format_args = "T4i4",
+  };
+
   struct
   {
     u32 caller, count, t_entry, t_open, t_closed;
@@ -74,13 +73,11 @@ barrier_trace_sync_rec (f64 t_entry)
   if (!vlib_worker_threads->barrier_elog_enabled)
     return;
 
-    /* *INDENT-OFF* */
-    ELOG_TYPE_DECLARE (e) =
-      {
-        .format = "bar-syncrec-%s-#%d",
-        .format_args = "T4i4",
-      };
-    /* *INDENT-ON* */
+  ELOG_TYPE_DECLARE (e) = {
+    .format = "bar-syncrec-%s-#%d",
+    .format_args = "T4i4",
+  };
+
   struct
   {
     u32 caller, depth;
@@ -98,13 +95,11 @@ barrier_trace_release_rec (f64 t_entry)
   if (!vlib_worker_threads->barrier_elog_enabled)
     return;
 
-    /* *INDENT-OFF* */
-    ELOG_TYPE_DECLARE (e) =
-      {
-        .format = "bar-relrrec-#%d",
-        .format_args = "i4",
-      };
-    /* *INDENT-ON* */
+  ELOG_TYPE_DECLARE (e) = {
+    .format = "bar-relrrec-#%d",
+    .format_args = "i4",
+  };
+
   struct
   {
     u32 depth;
@@ -120,13 +115,11 @@ barrier_trace_release (f64 t_entry, f64 t_closed_total, f64 t_update_main)
   if (!vlib_worker_threads->barrier_elog_enabled)
     return;
 
-    /* *INDENT-OFF* */
-    ELOG_TYPE_DECLARE (e) =
-      {
-        .format = "bar-rel-#%d-e%d-u%d-t%d",
-        .format_args = "i4i4i4i4",
-      };
-    /* *INDENT-ON* */
+  ELOG_TYPE_DECLARE (e) = {
+    .format = "bar-rel-#%d-e%d-u%d-t%d",
+    .format_args = "i4i4i4i4",
+  };
+
   struct
   {
     u32 count, t_entry, t_update_main, t_closed_total;
@@ -173,33 +166,6 @@ sort_registrations_by_no_clone (void *a0, void *a1)
          - ((i32) ((*tr1)->no_data_structure_clone)));
 }
 
-static uword *
-clib_sysfs_list_to_bitmap (char *filename)
-{
-  FILE *fp;
-  uword *r = 0;
-
-  fp = fopen (filename, "r");
-
-  if (fp != NULL)
-    {
-      u8 *buffer = 0;
-      vec_validate (buffer, 256 - 1);
-      if (fgets ((char *) buffer, 256, fp))
-       {
-         unformat_input_t in;
-         unformat_init_string (&in, (char *) buffer,
-                               strlen ((char *) buffer));
-         if (unformat (&in, "%U", unformat_bitmap_list, &r) != 1)
-           clib_warning ("unformat_bitmap_list failed");
-         unformat_free (&in);
-       }
-      vec_free (buffer);
-      fclose (fp);
-    }
-  return r;
-}
-
 
 /* Called early in the init sequence */
 
@@ -320,13 +286,13 @@ vlib_thread_init (vlib_main_t * vm)
        {
          uword c;
           /* *INDENT-OFF* */
-          clib_bitmap_foreach (c, tr->coremask, ({
+          clib_bitmap_foreach (c, tr->coremask)  {
             if (clib_bitmap_get(avail_cpu, c) == 0)
               return clib_error_return (0, "cpu %u is not available to be used"
                                         " for the '%s' thread",c, tr->name);
 
             avail_cpu = clib_bitmap_set(avail_cpu, c, 0);
-          }));
+          }
           /* *INDENT-ON* */
        }
       else
@@ -581,7 +547,8 @@ vlib_worker_thread_bootstrap_fn (void *arg)
 
   __os_thread_index = w - vlib_worker_threads;
 
-  vlib_process_start_switch_stack (vlib_mains[__os_thread_index], 0);
+  vlib_process_start_switch_stack (vlib_get_main_by_index (__os_thread_index),
+                                  0);
   rv = (void *) clib_calljmp
     ((uword (*)(uword)) w->thread_function,
      (uword) arg, w->thread_stack + VLIB_THREAD_STACK_SIZE);
@@ -606,14 +573,14 @@ vlib_get_thread_core_numa (vlib_worker_thread_t * w, unsigned cpu_id)
   /* *INDENT-OFF* */
   clib_sysfs_read ("/sys/devices/system/node/online", "%U",
         unformat_bitmap_list, &nbmp);
-  clib_bitmap_foreach (node, nbmp, ({
+  clib_bitmap_foreach (node, nbmp)  {
     p = format (p, "%s%u/cpulist%c", sys_node_path, node, 0);
     clib_sysfs_read ((char *) p, "%U", unformat_bitmap_list, &cbmp);
     if (clib_bitmap_get (cbmp, cpu_id))
       numa_id = node;
     vec_reset_length (cbmp);
     vec_reset_length (p);
-  }));
+  }
   /* *INDENT-ON* */
   vec_free (nbmp);
   vec_free (cbmp);
@@ -626,6 +593,7 @@ vlib_get_thread_core_numa (vlib_worker_thread_t * w, unsigned cpu_id)
 static clib_error_t *
 vlib_launch_thread_int (void *fp, vlib_worker_thread_t * w, unsigned cpu_id)
 {
+  clib_mem_main_t *mm = &clib_mem_main;
   vlib_thread_main_t *tm = &vlib_thread_main;
   void *(*fp_arg) (void *) = fp;
   void *numa_heap;
@@ -634,19 +602,22 @@ vlib_launch_thread_int (void *fp, vlib_worker_thread_t * w, unsigned cpu_id)
   vlib_get_thread_core_numa (w, cpu_id);
 
   /* Set up NUMA-bound heap if indicated */
-  if (clib_per_numa_mheaps[w->numa_id] == 0)
+  if (mm->per_numa_mheaps[w->numa_id] == 0)
     {
       /* If the user requested a NUMA heap, create it... */
       if (tm->numa_heap_size)
        {
-         numa_heap = clib_mem_init_thread_safe_numa
-           (0 /* DIY */ , tm->numa_heap_size, w->numa_id);
-         clib_per_numa_mheaps[w->numa_id] = numa_heap;
+         clib_mem_set_numa_affinity (w->numa_id, 1 /* force */ );
+         numa_heap = clib_mem_create_heap (0 /* DIY */ , tm->numa_heap_size,
+                                           1 /* is_locked */ ,
+                                           "numa %u heap", w->numa_id);
+         clib_mem_set_default_numa_affinity ();
+         mm->per_numa_mheaps[w->numa_id] = numa_heap;
        }
       else
        {
          /* Or, use the main heap */
-         clib_per_numa_mheaps[w->numa_id] = w->thread_mheap;
+         mm->per_numa_mheaps[w->numa_id] = w->thread_mheap;
        }
     }
 
@@ -672,6 +643,7 @@ vlib_launch_thread_int (void *fp, vlib_worker_thread_t * w, unsigned cpu_id)
 static clib_error_t *
 start_workers (vlib_main_t * vm)
 {
+  vlib_global_main_t *vgm = vlib_get_global_main ();
   int i, j;
   vlib_worker_thread_t *w;
   vlib_main_t *vm_clone;
@@ -681,14 +653,14 @@ start_workers (vlib_main_t * vm)
   vlib_node_runtime_t *rt;
   u32 n_vlib_mains = tm->n_vlib_mains;
   u32 worker_thread_index;
-  u8 *main_heap = clib_mem_get_per_cpu_heap ();
+  clib_mem_heap_t *main_heap = clib_mem_get_per_cpu_heap ();
 
   vec_reset_length (vlib_worker_threads);
 
   /* Set up the main thread */
   vec_add2_aligned (vlib_worker_threads, w, 1, CLIB_CACHE_LINE_BYTES);
   w->elog_track.name = "main thread";
-  elog_track_register (&vm->elog_main, &w->elog_track);
+  elog_track_register (vlib_get_elog_main (), &w->elog_track);
 
   if (vec_len (tm->thread_prefix))
     {
@@ -696,23 +668,20 @@ start_workers (vlib_main_t * vm)
       vlib_set_thread_name ((char *) w->name);
     }
 
-  vm->elog_main.lock =
+  vgm->elog_main.lock =
     clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
-  vm->elog_main.lock[0] = 0;
+  vgm->elog_main.lock[0] = 0;
 
   clib_callback_data_init (&vm->vlib_node_runtime_perf_callbacks,
                           &vm->worker_thread_main_loop_callback_lock);
 
+  vec_validate_aligned (vgm->vlib_mains, n_vlib_mains - 1,
+                       CLIB_CACHE_LINE_BYTES);
+  _vec_len (vgm->vlib_mains) = 0;
+  vec_add1_aligned (vgm->vlib_mains, vm, CLIB_CACHE_LINE_BYTES);
+
   if (n_vlib_mains > 1)
     {
-      /* Replace hand-crafted length-1 vector with a real vector */
-      vlib_mains = 0;
-
-      vec_validate_aligned (vlib_mains, tm->n_vlib_mains - 1,
-                           CLIB_CACHE_LINE_BYTES);
-      _vec_len (vlib_mains) = 0;
-      vec_add1_aligned (vlib_mains, vm, CLIB_CACHE_LINE_BYTES);
-
       vlib_worker_threads->wait_at_barrier =
        clib_mem_alloc_aligned (sizeof (u32), CLIB_CACHE_LINE_BYTES);
       vlib_worker_threads->workers_at_barrier =
@@ -730,7 +699,7 @@ start_workers (vlib_main_t * vm)
 
       /* Without update or refork */
       *vlib_worker_threads->node_reforks_required = 0;
-      vm->need_vlib_worker_thread_node_runtime_update = 0;
+      vgm->need_vlib_worker_thread_node_runtime_update = 0;
 
       /* init timing */
       vm->barrier_epoch = 0;
@@ -756,8 +725,10 @@ start_workers (vlib_main_t * vm)
              vec_add2 (vlib_worker_threads, w, 1);
              /* Currently unused, may not really work */
              if (tr->mheap_size)
-               w->thread_mheap = create_mspace (tr->mheap_size,
-                                                0 /* unlocked */ );
+               w->thread_mheap = clib_mem_create_heap (0, tr->mheap_size,
+                                                       /* unlocked */ 0,
+                                                       "%s%d heap",
+                                                       tr->name, k);
              else
                w->thread_mheap = main_heap;
 
@@ -771,7 +742,7 @@ start_workers (vlib_main_t * vm)
              w->elog_track.name =
                (char *) format (0, "%s %d", tr->name, k + 1);
              vec_add1 (w->elog_track.name, 0);
-             elog_track_register (&vm->elog_main, &w->elog_track);
+             elog_track_register (vlib_get_elog_main (), &w->elog_track);
 
              if (tr->no_data_structure_clone)
                continue;
@@ -781,14 +752,13 @@ start_workers (vlib_main_t * vm)
 
              vm_clone = clib_mem_alloc_aligned (sizeof (*vm_clone),
                                                 CLIB_CACHE_LINE_BYTES);
-             clib_memcpy (vm_clone, vlib_mains[0], sizeof (*vm_clone));
+             clib_memcpy (vm_clone, vlib_get_first_main (),
+                          sizeof (*vm_clone));
 
              vm_clone->thread_index = worker_thread_index;
              vm_clone->heap_base = w->thread_mheap;
              vm_clone->heap_aligned_base = (void *)
                (((uword) w->thread_mheap) & ~(VLIB_FRAME_ALIGN - 1));
-             vm_clone->init_functions_called =
-               hash_create (0, /* value bytes */ 0);
              vm_clone->pending_rpc_requests = 0;
              vec_validate (vm_clone->pending_rpc_requests, 0);
              _vec_len (vm_clone->pending_rpc_requests) = 0;
@@ -800,7 +770,7 @@ start_workers (vlib_main_t * vm)
                (&vm_clone->vlib_node_runtime_perf_callbacks,
                 &vm_clone->worker_thread_main_loop_callback_lock);
 
-             nm = &vlib_mains[0]->node_main;
+             nm = &vlib_get_first_main ()->node_main;
              nm_clone = &vm_clone->node_main;
              /* fork next frames array, preserving node runtime indices */
              nm_clone->next_frames = vec_dup_aligned (nm->next_frames,
@@ -858,6 +828,9 @@ start_workers (vlib_main_t * vm)
              nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT] =
                vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_INPUT],
                                 CLIB_CACHE_LINE_BYTES);
+             clib_interrupt_init (
+               &nm_clone->interrupts,
+               vec_len (nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]));
              vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT])
              {
                vlib_node_t *n = vlib_get_node (vm, rt->node_index);
@@ -897,18 +870,20 @@ start_workers (vlib_main_t * vm)
              /* Packet trace buffers are guaranteed to be empty, nothing to do here */
 
              clib_mem_set_heap (oldheap);
-             vec_add1_aligned (vlib_mains, vm_clone, CLIB_CACHE_LINE_BYTES);
+             vec_add1_aligned (vgm->vlib_mains, vm_clone,
+                               CLIB_CACHE_LINE_BYTES);
 
              /* Switch to the stats segment ... */
              void *oldheap = vlib_stats_push_heap (0);
-             vm_clone->error_main.counters = vec_dup_aligned
-               (vlib_mains[0]->error_main.counters, CLIB_CACHE_LINE_BYTES);
+             vm_clone->error_main.counters =
+               vec_dup_aligned (vlib_get_first_main ()->error_main.counters,
+                                CLIB_CACHE_LINE_BYTES);
              vlib_stats_pop_heap2 (vm_clone->error_main.counters,
                                    worker_thread_index, oldheap, 1);
 
-             vm_clone->error_main.counters_last_clear = vec_dup_aligned
-               (vlib_mains[0]->error_main.counters_last_clear,
-                CLIB_CACHE_LINE_BYTES);
+             vm_clone->error_main.counters_last_clear = vec_dup_aligned (
+               vlib_get_first_main ()->error_main.counters_last_clear,
+               CLIB_CACHE_LINE_BYTES);
 
              worker_thread_index++;
            }
@@ -926,8 +901,10 @@ start_workers (vlib_main_t * vm)
              vec_add2 (vlib_worker_threads, w, 1);
              if (tr->mheap_size)
                {
-                 w->thread_mheap =
-                   create_mspace (tr->mheap_size, 0 /* locked */ );
+                 w->thread_mheap = clib_mem_create_heap (0, tr->mheap_size,
+                                                         /* locked */ 0,
+                                                         "%s%d heap",
+                                                         tr->name, j);
                }
              else
                w->thread_mheap = main_heap;
@@ -940,7 +917,7 @@ start_workers (vlib_main_t * vm)
                (char *) format (0, "%s %d", tr->name, j + 1);
              w->registration = tr;
              vec_add1 (w->elog_track.name, 0);
-             elog_track_register (&vm->elog_main, &w->elog_track);
+             elog_track_register (vlib_get_elog_main (), &w->elog_track);
            }
        }
     }
@@ -969,13 +946,13 @@ start_workers (vlib_main_t * vm)
        {
          uword c;
           /* *INDENT-OFF* */
-          clib_bitmap_foreach (c, tr->coremask, ({
+          clib_bitmap_foreach (c, tr->coremask)  {
             w = vlib_worker_threads + worker_thread_index++;
            err = vlib_launch_thread_int (vlib_worker_thread_bootstrap_fn,
                                          w, c);
            if (err)
              clib_error_report (err);
-          }));
+          }
           /* *INDENT-ON* */
        }
     }
@@ -995,15 +972,10 @@ worker_thread_node_runtime_update_internal (void)
   vlib_node_main_t *nm, *nm_clone;
   vlib_main_t *vm_clone;
   vlib_node_runtime_t *rt;
-  never_inline void
-    vlib_node_runtime_sync_stats (vlib_main_t * vm,
-                                 vlib_node_runtime_t * r,
-                                 uword n_calls,
-                                 uword n_vectors, uword n_clocks);
 
   ASSERT (vlib_get_thread_index () == 0);
 
-  vm = vlib_mains[0];
+  vm = vlib_get_first_main ();
   nm = &vm->node_main;
 
   ASSERT (*vlib_worker_threads->wait_at_barrier == 1);
@@ -1019,11 +991,11 @@ worker_thread_node_runtime_update_internal (void)
       vlib_node_sync_stats (vm, n);
     }
 
-  for (i = 1; i < vec_len (vlib_mains); i++)
+  for (i = 1; i < vlib_get_n_threads (); i++)
     {
       vlib_node_t *n;
 
-      vm_clone = vlib_mains[i];
+      vm_clone = vlib_get_main_by_index (i);
       nm_clone = &vm_clone->node_main;
 
       for (j = 0; j < vec_len (nm_clone->nodes); j++)
@@ -1051,7 +1023,7 @@ vlib_worker_thread_node_refork (void)
 
   int j;
 
-  vm = vlib_mains[0];
+  vm = vlib_get_first_main ();
   nm = &vm->node_main;
   vm_clone = vlib_get_main ();
   nm_clone = &vm_clone->node_main;
@@ -1171,6 +1143,9 @@ vlib_worker_thread_node_refork (void)
   nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT] =
     vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_INPUT],
                     CLIB_CACHE_LINE_BYTES);
+  clib_interrupt_resize (
+    &nm_clone->interrupts,
+    vec_len (nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]));
 
   vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT])
   {
@@ -1384,9 +1359,10 @@ vnet_main_fixup (vlib_fork_fixup_t which)
 void
 vlib_worker_thread_fork_fixup (vlib_fork_fixup_t which)
 {
+  vlib_global_main_t *vgm = vlib_get_global_main ();
   vlib_main_t *vm = vlib_get_main ();
 
-  if (vlib_mains == 0)
+  if (vgm->vlib_mains == 0)
     return;
 
   ASSERT (vlib_get_thread_index () == 0);
@@ -1424,7 +1400,7 @@ 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;
+  u32 count = vlib_get_n_threads () - 1;
 
   /* No worker threads? */
   if (count == 0)
@@ -1450,7 +1426,7 @@ vlib_worker_thread_initial_barrier_sync_and_release (vlib_main_t * vm)
 u8
 vlib_worker_thread_barrier_held (void)
 {
-  if (vec_len (vlib_mains) < 2)
+  if (vlib_get_n_threads () < 2)
     return (1);
 
   return (*vlib_worker_threads->wait_at_barrier == 1);
@@ -1468,13 +1444,13 @@ vlib_worker_thread_barrier_sync_int (vlib_main_t * vm, const char *func_name)
   u32 count;
   int i;
 
-  if (vec_len (vlib_mains) < 2)
+  if (vlib_get_n_threads () < 2)
     return;
 
   ASSERT (vlib_get_thread_index () == 0);
 
   vlib_worker_threads[0].barrier_caller = func_name;
-  count = vec_len (vlib_mains) - 1;
+  count = vlib_get_n_threads () - 1;
 
   /* Record entry relative to last close */
   now = vlib_time_now (vm);
@@ -1496,10 +1472,12 @@ vlib_worker_thread_barrier_sync_int (vlib_main_t * vm, const char *func_name)
    * the barrier hold-down timer.
    */
   max_vector_rate = 0.0;
-  for (i = 1; i < vec_len (vlib_mains); i++)
-    max_vector_rate =
-      clib_max (max_vector_rate,
-               (f64) vlib_last_vectors_per_main_loop (vlib_mains[i]));
+  for (i = 1; i < vlib_get_n_threads (); i++)
+    {
+      vlib_main_t *ovm = vlib_get_main_by_index (i);
+      max_vector_rate = clib_max (max_vector_rate,
+                                 (f64) vlib_last_vectors_per_main_loop (ovm));
+    }
 
   vlib_worker_threads[0].barrier_sync_count++;
 
@@ -1553,6 +1531,7 @@ vlib_worker_thread_barrier_sync_int (vlib_main_t * vm, const char *func_name)
 void
 vlib_worker_thread_barrier_release (vlib_main_t * vm)
 {
+  vlib_global_main_t *vgm = vlib_get_global_main ();
   f64 deadline;
   f64 now;
   f64 minimum_open;
@@ -1561,7 +1540,7 @@ vlib_worker_thread_barrier_release (vlib_main_t * vm)
   f64 t_update_main = 0.0;
   int refork_needed = 0;
 
-  if (vec_len (vlib_mains) < 2)
+  if (vlib_get_n_threads () < 2)
     return;
 
   ASSERT (vlib_get_thread_index () == 0);
@@ -1577,7 +1556,7 @@ vlib_worker_thread_barrier_release (vlib_main_t * vm)
     }
 
   /* Update (all) node runtimes before releasing the barrier, if needed */
-  if (vm->need_vlib_worker_thread_node_runtime_update)
+  if (vgm->need_vlib_worker_thread_node_runtime_update)
     {
       /*
        * Lock stat segment here, so we's safe when
@@ -1588,12 +1567,12 @@ vlib_worker_thread_barrier_release (vlib_main_t * vm)
 
       /* Do stats elements on main thread */
       worker_thread_node_runtime_update_internal ();
-      vm->need_vlib_worker_thread_node_runtime_update = 0;
+      vgm->need_vlib_worker_thread_node_runtime_update = 0;
 
       /* Do per thread rebuilds in parallel */
       refork_needed = 1;
       clib_atomic_fetch_add (vlib_worker_threads->node_reforks_required,
-                            (vec_len (vlib_mains) - 1));
+                            (vlib_get_n_threads () - 1));
       now = vlib_time_now (vm);
       t_update_main = now - vm->barrier_epoch;
     }
@@ -1665,9 +1644,10 @@ vlib_worker_thread_barrier_release (vlib_main_t * vm)
 void
 vlib_worker_wait_one_loop (void)
 {
+  vlib_global_main_t *vgm = vlib_get_global_main ();
   ASSERT (vlib_get_thread_index () == 0);
 
-  if (vec_len (vlib_mains) < 2)
+  if (vlib_get_n_threads () < 2)
     return;
 
   if (vlib_worker_thread_barrier_held ())
@@ -1676,17 +1656,17 @@ vlib_worker_wait_one_loop (void)
   u32 *counts = 0;
   u32 ii;
 
-  vec_validate (counts, vec_len (vlib_mains) - 1);
+  vec_validate (counts, vlib_get_n_threads () - 1);
 
   /* record the current loop counts */
-  vec_foreach_index (ii, vlib_mains)
-    counts[ii] = vlib_mains[ii]->main_loop_count;
+  vec_foreach_index (ii, vgm->vlib_mains)
+    counts[ii] = vgm->vlib_mains[ii]->main_loop_count;
 
   /* spin until each changes, apart from the main thread, or we'd be
    * a while */
   for (ii = 1; ii < vec_len (counts); ii++)
     {
-      while (counts[ii] == vlib_mains[ii]->main_loop_count)
+      while (counts[ii] == vgm->vlib_mains[ii]->main_loop_count)
        CLIB_PAUSE ();
     }
 
@@ -1713,7 +1693,7 @@ vlib_frame_queue_dequeue (vlib_main_t * vm, vlib_frame_queue_main_t * fqm)
   u32 vectors = 0;
 
   ASSERT (fq);
-  ASSERT (vm == vlib_mains[thread_id]);
+  ASSERT (vm == vlib_global_main.vlib_mains[thread_id]);
 
   if (PREDICT_FALSE (fqm->node_index == ~0))
     return 0;
@@ -1836,6 +1816,7 @@ vlib_frame_queue_dequeue (vlib_main_t * vm, vlib_frame_queue_main_t * fqm)
 void
 vlib_worker_thread_fn (void *arg)
 {
+  vlib_global_main_t *vgm = vlib_get_global_main ();
   vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg;
   vlib_thread_main_t *tm = vlib_get_thread_main ();
   vlib_main_t *vm = vlib_get_main ();
@@ -1849,8 +1830,11 @@ vlib_worker_thread_fn (void *arg)
   clib_time_init (&vm->clib_time);
   clib_mem_set_heap (w->thread_mheap);
 
-  e = vlib_call_init_exit_functions_no_sort
-    (vm, &vm->worker_init_function_registrations, 1 /* call_once */ );
+  vm->worker_init_functions_called = hash_create (0, 0);
+
+  e = vlib_call_init_exit_functions_no_sort (
+    vm, &vgm->worker_init_function_registrations, 1 /* call_once */,
+    0 /* is_global */);
   if (e)
     clib_error_report (e);
 
@@ -1972,24 +1956,24 @@ show_clock_command_fn (vlib_main_t * vm,
                   verbose, format_clib_timebase_time,
                   clib_timebase_now (tb));
 
-  if (vec_len (vlib_mains) == 1)
+  if (vlib_get_n_threads () == 1)
     return 0;
 
   vlib_cli_output (vm, "Time last barrier release %.9f",
                   vm->time_last_barrier_release);
 
-  for (i = 1; i < vec_len (vlib_mains); i++)
+  for (i = 1; i < vlib_get_n_threads (); i++)
     {
-      if (vlib_mains[i] == 0)
+      vlib_main_t *ovm = vlib_get_main_by_index (i);
+      if (ovm == 0)
        continue;
 
-      vlib_cli_output (vm, "%d: %U", i, format_clib_time,
-                      &vlib_mains[i]->clib_time, verbose);
+      vlib_cli_output (vm, "%d: %U", i, format_clib_time, &ovm->clib_time,
+                      verbose);
 
-      vlib_cli_output (vm, "Thread %d offset %.9f error %.9f", i,
-                      vlib_mains[i]->time_offset,
-                      vm->time_last_barrier_release -
-                      vlib_mains[i]->time_last_barrier_release);
+      vlib_cli_output (
+       vm, "Thread %d offset %.9f error %.9f", i, ovm->time_offset,
+       vm->time_last_barrier_release - ovm->time_last_barrier_release);
     }
   return 0;
 }
@@ -2003,6 +1987,12 @@ VLIB_CLI_COMMAND (f_command, static) =
 };
 /* *INDENT-ON* */
 
+vlib_thread_main_t *
+vlib_get_thread_main_not_inline (void)
+{
+  return vlib_get_thread_main ();
+}
+
 /*
  * fd.io coding-style-patch-verification: ON
  *