vcl: test refactor and improvements
[vpp.git] / src / vcl / vppcom.c
index 195e6cb..bf21f52 100644 (file)
 
 __thread uword __vcl_worker_index = ~0;
 
-static u8 not_ready;
 
-void
-sigsegv_signal (int signum)
+static int
+vcl_wait_for_segment (u64 segment_handle)
 {
-  not_ready = 1;
-}
+  vcl_worker_t *wrk = vcl_worker_get_current ();
+  u32 wait_for_seconds = 10, segment_index;
+  f64 timeout;
 
-static void
-vcl_wait_for_memory (void *mem)
-{
-  u8 __clib_unused test;
-  if (vcm->mounting_segment)
-    {
-      while (vcm->mounting_segment)
-       ;
-      return;
-    }
-  if (1 || vcm->debug)
-    {
-      usleep (1e5);
-      return;
-    }
-  if (signal (SIGSEGV, sigsegv_signal))
-    {
-      perror ("signal()");
-      return;
-    }
-  not_ready = 0;
+  if (segment_handle == VCL_INVALID_SEGMENT_HANDLE)
+    return 1;
 
-again:
-  test = *(u8 *) mem;
-  if (not_ready)
+  timeout = clib_time_now (&wrk->clib_time) + wait_for_seconds;
+  while (clib_time_now (&wrk->clib_time) < timeout)
     {
-      not_ready = 0;
-      usleep (1);
-      goto again;
+      segment_index = vcl_segment_table_lookup (segment_handle);
+      if (segment_index != VCL_INVALID_SEGMENT_INDEX)
+       return 0;
+      usleep (10);
     }
-
-  signal (SIGSEGV, SIG_DFL);
+  return 1;
 }
 
 const char *
@@ -281,7 +261,12 @@ vcl_session_accepted_handler (vcl_worker_t * wrk, session_accepted_msg_t * mp)
                                             svm_msg_q_t *);
       session->our_evt_q = uword_to_pointer (mp->server_event_queue_address,
                                             svm_msg_q_t *);
-      vcl_wait_for_memory (session->vpp_evt_q);
+      if (vcl_wait_for_segment (mp->segment_handle))
+       {
+         clib_warning ("segment for session %u couldn't be mounted!",
+                       session->session_index);
+         return VCL_INVALID_SESSION_INDEX;
+       }
       rx_fifo->master_session_index = session->session_index;
       tx_fifo->master_session_index = session->session_index;
       rx_fifo->master_thread_index = vcl_get_worker_index ();
@@ -360,7 +345,13 @@ vcl_session_connected_handler (vcl_worker_t * wrk,
 
   rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
   tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
-  vcl_wait_for_memory (rx_fifo);
+  if (vcl_wait_for_segment (mp->segment_handle))
+    {
+      clib_warning ("segment for session %u couldn't be mounted!",
+                   session->session_index);
+      return VCL_INVALID_SESSION_INDEX;
+    }
+
   rx_fifo->client_session_index = session_index;
   tx_fifo->client_session_index = session_index;
   rx_fifo->client_thread_index = vcl_get_worker_index ();
@@ -436,8 +427,8 @@ vcl_session_bound_handler (vcl_worker_t * wrk, session_bound_msg_t * mp)
   session = vcl_session_get (wrk, sid);
   if (mp->retval)
     {
-      VDBG (0, "VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: bind failed: %U",
-           getpid (), mp->handle, sid, format_api_error, ntohl (mp->retval));
+      VERR ("vpp handle 0x%llx, sid %u: bind failed: %U", mp->handle, sid,
+           format_api_error, mp->retval);
       if (session)
        {
          session->session_state = STATE_FAILED;
@@ -473,7 +464,7 @@ vcl_session_bound_handler (vcl_worker_t * wrk, session_bound_msg_t * mp)
       session->tx_fifo = tx_fifo;
     }
 
-  VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: bind succeeded!",
+  VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: bind succeeded!",
        getpid (), mp->handle, sid);
   return sid;
 }
@@ -568,7 +559,10 @@ vppcom_wait_for_session_state_change (u32 session_index,
        }
 
       if (svm_msg_q_sub (wrk->app_event_queue, &msg, SVM_Q_NOWAIT, 0))
-       continue;
+       {
+         usleep (100);
+         continue;
+       }
       e = svm_msg_q_msg_data (wrk->app_event_queue, &msg);
       vcl_handle_mq_event (wrk, e);
       svm_msg_q_free_msg (wrk->app_event_queue, &msg);
@@ -709,12 +703,12 @@ vcl_app_fork_child_handler (void)
   u8 *child_name;
   int rv, parent_wrk;
 
-  VDBG (0, "initializing forked child");
+  parent_wrk = vcl_get_worker_index ();
+  VDBG (0, "initializing forked child with parent wrk %u", parent_wrk);
 
   /*
    * Allocate worker
    */
-  parent_wrk = vcl_get_worker_index ();
   vcl_set_worker_index (~0);
   if (!vcl_worker_alloc_and_init ())
     VERR ("couldn't allocate new worker");
@@ -753,6 +747,27 @@ vcl_app_fork_parent_handler (void)
     ;
 }
 
+/**
+ * Handle app exit
+ *
+ * Notify vpp of the disconnect and mark the worker as free. If we're the
+ * last worker, do a full cleanup otherwise, since we're probably a forked
+ * child, avoid syscalls as much as possible. We might've lost privileges.
+ */
+void
+vppcom_app_exit (void)
+{
+  if (!pool_elts (vcm->workers))
+    return;
+
+  vcl_worker_cleanup (1 /* notify vpp */ );
+  vcl_elog_stop (vcm);
+  if (vec_len (vcm->workers) == 1)
+    vl_client_disconnect_from_vlib ();
+  else
+    vl_client_send_disconnect ();
+}
+
 /*
  * VPPCOM Public API functions
  */
@@ -764,7 +779,7 @@ vppcom_app_create (char *app_name)
 
   if (vcm->is_init)
     {
-      clib_warning ("already initialized");
+      clib_warning ("vcl<%u> already initialized", getpid ());
       return -1;
     }
 
@@ -776,12 +791,14 @@ vppcom_app_create (char *app_name)
   vcm->main_pid = getpid ();
   vcm->app_name = format (0, "%s", app_name);
   vppcom_init_error_string_table ();
-  svm_fifo_segment_main_init (vcl_cfg->segment_baseva,
+  svm_fifo_segment_main_init (&vcm->segment_main, vcl_cfg->segment_baseva,
                              20 /* timeout in secs */ );
   pool_alloc (vcm->workers, vcl_cfg->max_workers);
   clib_spinlock_init (&vcm->workers_lock);
+  clib_rwlock_init (&vcm->segment_table_lock);
   pthread_atfork (NULL, vcl_app_fork_parent_handler,
                  vcl_app_fork_child_handler);
+  atexit (vppcom_app_exit);
 
   /* Allocate default worker */
   vcl_worker_alloc_and_init ();
@@ -824,9 +841,12 @@ vppcom_app_destroy (void)
   int rv;
   f64 orig_app_timeout;
 
+  if (!pool_elts (vcm->workers))
+    return;
+
   vcl_evt (VCL_EVT_DETACH, vcm);
 
-  if (vec_len (vcm->workers) == 1)
+  if (pool_elts (vcm->workers) == 1)
     {
       vppcom_app_send_detach ();
       orig_app_timeout = vcm->cfg.app_timeout;
@@ -836,15 +856,16 @@ vppcom_app_destroy (void)
       if (PREDICT_FALSE (rv))
        VDBG (0, "application detach timed out! returning %d (%s)", rv,
              vppcom_retval_str (rv));
+      vec_free (vcm->app_name);
+      vcl_worker_cleanup (0 /* notify vpp */ );
     }
   else
     {
-      vcl_worker_cleanup ();
+      vcl_worker_cleanup (1 /* notify vpp */ );
     }
 
   vcl_elog_stop (vcm);
   vl_client_disconnect_from_vlib ();
-  vec_free (vcm->app_name);
 }
 
 int
@@ -1163,9 +1184,9 @@ handle:
     VCL_SESS_ATTR_SET (client_session->attr, VCL_SESS_ATTR_NONBLOCK);
 
   listen_vpp_handle = listen_session->vpp_handle;
-  VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: Got a client request! "
+  VDBG (0, "vpp handle 0x%llx, sid %u: Got a client request! "
        "vpp handle 0x%llx, sid %u, flags %d, is_nonblocking %u",
-       getpid (), listen_vpp_handle, listen_session_handle,
+       listen_vpp_handle, listen_session_handle,
        client_session->vpp_handle, client_session_index,
        flags, VCL_SESS_ATTR_TEST (client_session->attr,
                                   VCL_SESS_ATTR_NONBLOCK));
@@ -1191,9 +1212,9 @@ handle:
   vcl_send_session_accepted_reply (vpp_evt_q, client_session->client_context,
                                   client_session->vpp_handle, 0);
 
-  VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: accepted vpp handle 0x%llx, "
+  VDBG (0, "vpp handle 0x%llx, sid %u: accepted vpp handle 0x%llx, "
        "sid %u connection from peer %s address %U port %u to local %s "
-       "address %U port %u", getpid (), listen_vpp_handle,
+       "address %U port %u", listen_vpp_handle,
        listen_session_handle, client_session->vpp_handle,
        client_session_index,
        client_session->transport.is_ip4 ? "IPv4" : "IPv6",