Add thread-safe event signaller, use RPC where required

Update ping code to use the new function

Change-Id: Ieb753b23f8402cbe5667c22747896784c8ece937
Signed-off-by: Florin Coras <fcoras@cisco.com>
Signed-off-by: Dave Barach <dave@barachs.net>
diff --git a/src/vlib/node_funcs.h b/src/vlib/node_funcs.h
index 3ae4e54..0734476 100644
--- a/src/vlib/node_funcs.h
+++ b/src/vlib/node_funcs.h
@@ -965,6 +965,29 @@
   d[0] = data;
 }
 
+/**
+ * Signal event to process from any thread.
+ *
+ * When in doubt, use this.
+ */
+always_inline void
+vlib_process_signal_event_mt (vlib_main_t * vm,
+			      uword node_index, uword type_opaque, uword data)
+{
+  if (vlib_get_thread_index () != 0)
+    {
+      vlib_process_signal_event_mt_args_t args = {
+	.node_index = node_index,
+	.type_opaque = type_opaque,
+	.data = data,
+      };
+      vlib_rpc_call_main_thread (vlib_process_signal_event_mt_helper,
+				 (u8 *) & args, sizeof (args));
+    }
+  else
+    vlib_process_signal_event (vm, node_index, type_opaque, data);
+}
+
 always_inline void
 vlib_process_signal_one_time_event (vlib_main_t * vm,
 				    uword node_index,
diff --git a/src/vlib/threads.c b/src/vlib/threads.c
index f9c7043..be8daa6 100644
--- a/src/vlib/threads.c
+++ b/src/vlib/threads.c
@@ -1767,7 +1767,6 @@
   return (fqm - tm->frame_queue_mains);
 }
 
-
 int
 vlib_thread_cb_register (struct vlib_main_t *vm, vlib_thread_callbacks_t * cb)
 {
@@ -1781,6 +1780,29 @@
   return 0;
 }
 
+void
+vlib_process_signal_event_mt_helper (vlib_process_signal_event_mt_args_t *
+				     args)
+{
+  ASSERT (vlib_get_thread_index () == 0);
+  vlib_process_signal_event (vlib_get_main (), args->node_index,
+			     args->type_opaque, args->data);
+}
+
+void *rpc_call_main_thread_cb_fn;
+
+void
+vlib_rpc_call_main_thread (void *callback, u8 * args, u32 arg_size)
+{
+  if (rpc_call_main_thread_cb_fn)
+    {
+      void (*fp) (void *, u8 *, u32) = rpc_call_main_thread_cb_fn;
+      (*fp) (callback, args, arg_size);
+    }
+  else
+    clib_warning ("BUG: rpc_call_main_thread_cb_fn NULL!");
+}
+
 clib_error_t *
 threads_init (vlib_main_t * vm)
 {
diff --git a/src/vlib/threads.h b/src/vlib/threads.h
index 72340ee..8931584 100644
--- a/src/vlib/threads.h
+++ b/src/vlib/threads.h
@@ -171,6 +171,13 @@
   frame_queue_nelt_counter_t *frame_queue_histogram;
 } vlib_frame_queue_main_t;
 
+typedef struct
+{
+  uword node_index;
+  uword type_opaque;
+  uword data;
+} vlib_process_signal_event_mt_args_t;
+
 /* Called early, in thread 0's context */
 clib_error_t *vlib_thread_init (vlib_main_t * vm);
 
@@ -510,9 +517,14 @@
 }
 
 u8 *vlib_thread_stack_init (uword thread_index);
-
 int vlib_thread_cb_register (struct vlib_main_t *vm,
 			     vlib_thread_callbacks_t * cb);
+extern void *rpc_call_main_thread_cb_fn;
+
+void
+vlib_process_signal_event_mt_helper (vlib_process_signal_event_mt_args_t *
+				     args);
+void vlib_rpc_call_main_thread (void *function, u8 * args, u32 size);
 
 #endif /* included_vlib_threads_h */
 
diff --git a/src/vlibmemory/memory_vlib.c b/src/vlibmemory/memory_vlib.c
index 77959e6..d305ea6 100644
--- a/src/vlibmemory/memory_vlib.c
+++ b/src/vlibmemory/memory_vlib.c
@@ -1573,6 +1573,17 @@
 #define foreach_plugin_trace_msg		\
 _(TRACE_PLUGIN_MSG_IDS,trace_plugin_msg_ids)
 
+/*
+ * Set the rpc callback at our earliest possible convenience.
+ * This avoids ordering issues between thread_init() -> start_workers and
+ * an init function which we could define here. If we ever intend to use
+ * vlib all by itself, we can't create a link-time dependency on
+ * an init function here and a typical "call foo_init first"
+ * guitar lick.
+ */
+
+extern void *rpc_call_main_thread_cb_fn;
+
 static clib_error_t *
 rpc_api_hookup (vlib_main_t * vm)
 {
@@ -1599,7 +1610,7 @@
 
   /* No reason to halt the parade to create a trace record... */
   am->is_mp_safe[VL_API_TRACE_PLUGIN_MSG_IDS] = 1;
-
+  rpc_call_main_thread_cb_fn = vl_api_rpc_call_main_thread;
   return 0;
 }
 
diff --git a/src/vnet/ip/ping.c b/src/vnet/ip/ping.c
index c847e69..0fa537f 100755
--- a/src/vnet/ip/ping.c
+++ b/src/vnet/ip/ping.c
@@ -97,7 +97,7 @@
   clib_memcpy (vnet_buffer
 	       (vlib_get_buffer
 		(vm, bi0_copy))->unused, &nowts, sizeof (nowts));
-  vlib_process_signal_event (vm, pr->cli_process_id, event_type, bi0_copy);
+  vlib_process_signal_event_mt (vm, pr->cli_process_id, event_type, bi0_copy);
   return 1;
 }
 
@@ -646,7 +646,7 @@
 	      i = 1 + ping_repeat;
 	      break;
 	    }
-      vec_free(event_data);
+	  vec_free (event_data);
 	}
     }
   vlib_cli_output (vm, "\n");