More janitorial work
[vpp.git] / vlib / vlib / threads.c
index 73abba8..1808f36 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define _GNU_SOURCE
+#include <sched.h>
+
 #include <signal.h>
 #include <math.h>
 #include <vppinfra/format.h>
 #include <vlib/vlib.h>
 
 #include <vlib/threads.h>
-#include <vlib/unix/physmem.h>
-
 #include <vlib/unix/cj.h>
 
+
 #if DPDK==1
 #include <rte_config.h>
 #include <rte_common.h>
@@ -175,6 +177,16 @@ vlib_thread_init (vlib_main_t * vm)
   if (!tm->cpu_socket_bitmap)
     tm->cpu_socket_bitmap = clib_bitmap_set(0, 0, 1);
 
+  /* pin main thread to main_lcore  */
+#if DPDK==0
+  {
+     cpu_set_t cpuset;
+     CPU_ZERO(&cpuset);
+     CPU_SET(tm->main_lcore, &cpuset);
+     pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
+  }
+#endif
+
   /* as many threads as stacks... */
   vec_validate_aligned (vlib_worker_threads, vec_len(vlib_thread_stacks)-1,
                         CLIB_CACHE_LINE_BYTES);
@@ -486,7 +498,6 @@ void *vlib_worker_thread_bootstrap_fn (void *arg)
 static int
 vlib_launch_thread (void *fp, vlib_worker_thread_t *w, unsigned lcore_id)
 {
-  pthread_t dummy;
   void *(*fp_arg)(void *) = fp;
 
 #if DPDK==1
@@ -497,7 +508,19 @@ vlib_launch_thread (void *fp, vlib_worker_thread_t *w, unsigned lcore_id)
       return -1;
   else
 #endif
-    return pthread_create (&dummy, NULL /* attr */, fp_arg, (void *)w);
+  {
+    int ret;
+    pthread_t worker;
+    cpu_set_t cpuset;
+    CPU_ZERO(&cpuset);
+    CPU_SET(lcore_id, &cpuset);
+
+    ret = pthread_create (&worker, NULL /* attr */, fp_arg, (void *)w);
+    if(ret == 0)
+        return pthread_setaffinity_np(worker, sizeof(cpu_set_t), &cpuset);
+    else
+        return ret;
+  }
 }
 
 static clib_error_t * start_workers (vlib_main_t * vm)
@@ -512,12 +535,14 @@ static clib_error_t * 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();
+  mheap_t * main_heap_header = mheap_header (main_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 = "thread 0";
+  w->elog_track.name = "main thread";
   elog_track_register (&vm->elog_main, &w->elog_track);
 
   if (vec_len(tm->thread_prefix))
@@ -535,21 +560,19 @@ static clib_error_t * start_workers (vlib_main_t * vm)
     }
 #endif
 
+  /* 
+   * Truth of the matter: we always use at least two
+   * threads. So, make the main heap thread-safe 
+   * and make the event log thread-safe.
+   */
+  main_heap_header->flags |= MHEAP_FLAG_THREAD_SAFE;
+  vm->elog_main.lock = 
+    clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, 
+                            CLIB_CACHE_LINE_BYTES);
+  vm->elog_main.lock[0] = 0;
+          
   if (n_vlib_mains > 1)
     {
-      u8 * heap = clib_mem_get_per_cpu_heap();
-      mheap_t * h = mheap_header (heap);
-      
-      /* make the main heap thread-safe */
-      h->flags |= MHEAP_FLAG_THREAD_SAFE;
-      
-      /* Make the event-log MP-safe */
-      vm->elog_main.lock = 
-        clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, 
-                                CLIB_CACHE_LINE_BYTES);
-  
-      vm->elog_main.lock[0] = 0;
-
       vec_validate (vlib_mains, tm->n_vlib_mains - 1);
       _vec_len (vlib_mains) = 0;
       vec_add1 (vlib_mains, vm);
@@ -586,20 +609,18 @@ static clib_error_t * start_workers (vlib_main_t * vm)
           for (k = 0; k < tr->count; k++)
           {
             vec_add2 (vlib_worker_threads, w, 1);
-            /* 
-             * Share the main heap which is now thread-safe.
-             *
-             * To allocate separate heaps, code:
-             * mheap_alloc (0 / * use VM * /, tr->mheap_size);
-             */
-            w->thread_mheap = heap;
+            if (tr->mheap_size)
+              w->thread_mheap = mheap_alloc (0 /* use VM */, tr->mheap_size);
+            else
+              w->thread_mheap = main_heap;
             w->thread_stack = vlib_thread_stacks[w - vlib_worker_threads];
             w->thread_function = tr->function;
             w->thread_function_arg = w;
             w->instance_id = k;
             w->registration = tr; 
             
-            w->elog_track.name = (char *) format (0, "thread %d", i+1);
+            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);
             
@@ -607,7 +628,12 @@ static clib_error_t * start_workers (vlib_main_t * vm)
               continue;
 
             /* Allocate "to-worker-N" frame queue */
-            fq = vlib_frame_queue_alloc (FRAME_QUEUE_NELTS);
+            if (tr->frame_queue_nelts) {
+                fq = vlib_frame_queue_alloc (tr->frame_queue_nelts);
+            } else {
+                fq = vlib_frame_queue_alloc (FRAME_QUEUE_NELTS);
+            }
+
             vec_validate (vlib_frame_queues, worker_thread_index);
             vlib_frame_queues[worker_thread_index] = fq;
 
@@ -615,7 +641,7 @@ static clib_error_t * start_workers (vlib_main_t * vm)
             oldheap = clib_mem_set_heap (w->thread_mheap);
 
             vm_clone = clib_mem_alloc (sizeof (*vm_clone));
-            memcpy (vm_clone, vlib_mains[0], sizeof (*vm_clone));
+            clib_memcpy (vm_clone, vlib_mains[0], sizeof (*vm_clone));
 
             vm_clone->cpu_index = worker_thread_index;
             vm_clone->heap_base = w->thread_mheap;
@@ -630,10 +656,13 @@ static clib_error_t * start_workers (vlib_main_t * vm)
               {
                 vlib_next_frame_t *nf = &nm_clone->next_frames[j];
                 u32 save_node_runtime_index;
+                u32 save_flags;
 
                 save_node_runtime_index = nf->node_runtime_index;
+                save_flags = nf->flags & VLIB_FRAME_NO_FREE_AFTER_DISPATCH;
                 vlib_next_frame_init (nf);
                 nf->node_runtime_index = save_node_runtime_index;
+                nf->flags = save_flags;
               }
 
             /* fork the frame dispatch queue */
@@ -647,7 +676,7 @@ static clib_error_t * start_workers (vlib_main_t * vm)
               {
                 vlib_node_t *n;
                 n = clib_mem_alloc_no_fail (sizeof(*n));
-                memcpy (n, nm->nodes[j], sizeof (*n));
+                clib_memcpy (n, nm->nodes[j], sizeof (*n));
                 /* none of the copied nodes have enqueue rights given out */
                 n->owner_node_index = VLIB_INVALID_NODE_INDEX;
                 memset (&n->stats_total, 0, sizeof (n->stats_total));
@@ -673,8 +702,6 @@ static clib_error_t * start_workers (vlib_main_t * vm)
             clib_mem_set_heap (oldheap);
             vec_add1 (vlib_mains, vm_clone);
 
-            unix_physmem_init (vm_clone, 0 /* physmem not required */);
-
            vm_clone->error_main.counters =
              vec_dup(vlib_mains[0]->error_main.counters);
            vm_clone->error_main.counters_last_clear =
@@ -714,12 +741,16 @@ static clib_error_t * start_workers (vlib_main_t * vm)
           for (j = 0; j < tr->count; j++)
             {
               vec_add2 (vlib_worker_threads, w, 1);
-              w->thread_mheap = mheap_alloc (0 /* use VM */, tr->mheap_size);
+              if (tr->mheap_size)
+                w->thread_mheap = mheap_alloc (0 /* use VM */, tr->mheap_size);
+              else
+                w->thread_mheap = main_heap;
               w->thread_stack = vlib_thread_stacks[w - vlib_worker_threads];
               w->thread_function = tr->function;
               w->thread_function_arg = w;
               w->instance_id = j;
-              w->elog_track.name = (char *) format (0, "thread %d", i+1);
+              w->elog_track.name = 
+                  (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);
@@ -828,7 +859,7 @@ void vlib_worker_thread_node_runtime_update(void)
       /* Re-clone error heap */
       u64 * old_counters = vm_clone->error_main.counters;
       u64 * old_counters_all_clear = vm_clone->error_main.counters_last_clear;
-      memcpy (&vm_clone->error_main, &vm->error_main, sizeof (vm->error_main));
+      clib_memcpy (&vm_clone->error_main, &vm->error_main, sizeof (vm->error_main));
       j = vec_len(vm->error_main.counters) - 1;
       vec_validate_aligned(old_counters, j, CLIB_CACHE_LINE_BYTES);
       vec_validate_aligned(old_counters_all_clear, j, CLIB_CACHE_LINE_BYTES);
@@ -843,10 +874,13 @@ void vlib_worker_thread_node_runtime_update(void)
         {
           vlib_next_frame_t *nf = &nm_clone->next_frames[j];
           u32 save_node_runtime_index;
+          u32 save_flags;
 
           save_node_runtime_index = nf->node_runtime_index;
+          save_flags = nf->flags & VLIB_FRAME_NO_FREE_AFTER_DISPATCH;
           vlib_next_frame_init (nf);
           nf->node_runtime_index = save_node_runtime_index;
+          nf->flags = save_flags;
         }
 
       old_nodes_clone = nm_clone->nodes;
@@ -861,7 +895,7 @@ void vlib_worker_thread_node_runtime_update(void)
         old_n_clone = old_nodes_clone[j];
 
         new_n_clone = clib_mem_alloc_no_fail (sizeof(*new_n_clone));
-        memcpy (new_n_clone, new_n, sizeof (*new_n));
+        clib_memcpy (new_n_clone, new_n, sizeof (*new_n));
         /* none of the copied nodes have enqueue rights given out */
         new_n_clone->owner_node_index = VLIB_INVALID_NODE_INDEX;
 
@@ -876,10 +910,10 @@ void vlib_worker_thread_node_runtime_update(void)
         else
           {
             /* Copy stats if the old data is valid */
-            memcpy (&new_n_clone->stats_total, 
+            clib_memcpy (&new_n_clone->stats_total, 
                     &old_n_clone->stats_total,
                     sizeof (new_n_clone->stats_total));
-            memcpy (&new_n_clone->stats_last_clear, 
+            clib_memcpy (&new_n_clone->stats_last_clear, 
                     &old_n_clone->stats_last_clear,
                     sizeof (new_n_clone->stats_last_clear));
 
@@ -949,9 +983,7 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input)
 
   while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat (input, "main-thread-io"))
-        tm->main_thread_is_io_node = 1;
-      else if (unformat (input, "use-pthreads"))
+      if (unformat (input, "use-pthreads"))
         tm->use_pthreads = 1;
       else if (unformat (input, "thread-prefix %v", &tm->thread_prefix))
           ;
@@ -1025,7 +1057,7 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input)
 
 VLIB_EARLY_CONFIG_FUNCTION (cpu_config, "cpu");
 
-#if !defined (__x86_64__)
+#if !defined (__x86_64__) && !defined (__aarch64__) && !defined (__powerpc64__) && !defined(__arm__)
 void __sync_fetch_and_add_8 (void)
 {
   fformat(stderr, "%s called\n", __FUNCTION__);
@@ -1077,6 +1109,8 @@ void vlib_worker_thread_barrier_sync(vlib_main_t *vm)
   if (++vlib_worker_threads[0].recursion_level > 1)
       return;
 
+  vlib_worker_threads[0].barrier_sync_count++;
+
   ASSERT (os_get_cpu_number() == 0);
 
   deadline = vlib_time_now (vm) + BARRIER_SYNC_TIMEOUT;
@@ -1128,6 +1162,7 @@ show_threads_fn (vlib_main_t * vm,
                    "ID", "Name", "Type", "LWP",
                    "lcore", "Core", "Socket", "State");
 
+#if !defined(__powerpc64__)
   for (i = 0; i < vec_len(vlib_worker_threads); i++)
     {
       w = vlib_worker_threads + i;
@@ -1139,6 +1174,7 @@ show_threads_fn (vlib_main_t * vm,
                     w->registration ? w->registration->name : "",
                     w->lwp);
 
+#if DPDK==1
       int lcore = w->dpdk_lcore_id;
       if (lcore > -1)
         {
@@ -1162,10 +1198,11 @@ show_threads_fn (vlib_main_t * vm,
                 line = format(line, "unknown");
             }
         }
-
+#endif
       vlib_cli_output(vm, "%v", line);
       vec_free(line);
     }
+#endif
 
   return 0;
 }