bapi: add options to have vpp cleanup client registration
[vpp.git] / src / vcl / vppcom.c
index 1b619cf..0eaab6c 100644 (file)
@@ -464,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;
 }
@@ -559,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);
@@ -694,14 +697,99 @@ vcl_cleanup_bapi (void)
   vl_client_api_unmap ();
 }
 
-void
+static void
+vcl_cleanup_forked_child (vcl_worker_t * wrk, vcl_worker_t * child_wrk)
+{
+  vcl_worker_t *sub_child;
+  int tries = 0;
+
+  if (child_wrk->forked_child != ~0)
+    {
+      sub_child = vcl_worker_get_if_valid (child_wrk->forked_child);
+      if (sub_child)
+       {
+         /* Wait a bit, maybe the process is going away */
+         while (kill (sub_child->current_pid, 0) >= 0 && tries++ < 50)
+           usleep (1e3);
+         if (kill (sub_child->current_pid, 0) < 0)
+           vcl_cleanup_forked_child (child_wrk, sub_child);
+       }
+    }
+  vcl_worker_cleanup (child_wrk, 1 /* notify vpp */ );
+  VDBG (0, "Cleaned up wrk %u", child_wrk->wrk_index);
+  wrk->forked_child = ~0;
+}
+
+static struct sigaction old_sa;
+
+static void
+vcl_intercept_sigchld_handler (int signum, siginfo_t * si, void *uc)
+{
+  vcl_worker_t *wrk, *child_wrk;
+
+  if (vcl_get_worker_index () == ~0)
+    return;
+
+  sigaction (SIGCHLD, &old_sa, 0);
+
+  wrk = vcl_worker_get_current ();
+  if (wrk->forked_child == ~0)
+    return;
+
+  child_wrk = vcl_worker_get_if_valid (wrk->forked_child);
+  if (!child_wrk)
+    goto done;
+
+  if (si && si->si_pid != child_wrk->current_pid)
+    {
+      VDBG (0, "unexpected child pid %u", si->si_pid);
+      goto done;
+    }
+  vcl_cleanup_forked_child (wrk, child_wrk);
+
+done:
+  if (old_sa.sa_flags & SA_SIGINFO)
+    {
+      void (*fn) (int, siginfo_t *, void *) = old_sa.sa_sigaction;
+      fn (signum, si, uc);
+    }
+  else
+    {
+      void (*fn) (int) = old_sa.sa_handler;
+      if (fn)
+       fn (signum);
+    }
+}
+
+static void
+vcl_incercept_sigchld ()
+{
+  struct sigaction sa;
+  clib_memset (&sa, 0, sizeof (sa));
+  sa.sa_sigaction = vcl_intercept_sigchld_handler;
+  sa.sa_flags = SA_SIGINFO;
+  if (sigaction (SIGCHLD, &sa, &old_sa))
+    {
+      VERR ("couldn't intercept sigchld");
+      exit (-1);
+    }
+}
+
+static void
+vcl_app_pre_fork (void)
+{
+  vcl_incercept_sigchld ();
+}
+
+static void
 vcl_app_fork_child_handler (void)
 {
+  int rv, parent_wrk_index;
+  vcl_worker_t *parent_wrk;
   u8 *child_name;
-  int rv, parent_wrk;
 
-  parent_wrk = vcl_get_worker_index ();
-  VDBG (0, "initializing forked child with parent wrk %u", parent_wrk);
+  parent_wrk_index = vcl_get_worker_index ();
+  VDBG (0, "initializing forked child with parent wrk %u", parent_wrk_index);
 
   /*
    * Allocate worker
@@ -729,17 +817,18 @@ vcl_app_fork_child_handler (void)
    * Register worker with vpp and share sessions
    */
   vcl_worker_register_with_vpp ();
+  parent_wrk = vcl_worker_get (parent_wrk_index);
   vcl_worker_share_sessions (parent_wrk);
+  parent_wrk->forked_child = vcl_get_worker_index ();
 
   VDBG (0, "forked child main worker initialized");
   vcm->forking = 0;
 }
 
-void
+static void
 vcl_app_fork_parent_handler (void)
 {
   vcm->forking = 1;
-
   while (vcm->forking)
     ;
 }
@@ -756,13 +845,13 @@ vppcom_app_exit (void)
 {
   if (!pool_elts (vcm->workers))
     return;
-
-  vcl_worker_cleanup (1 /* notify vpp */ );
+  vcl_worker_cleanup (vcl_worker_get_current (), 1 /* notify vpp */ );
+  vcl_set_worker_index (~0);
   vcl_elog_stop (vcm);
   if (vec_len (vcm->workers) == 1)
     vl_client_disconnect_from_vlib ();
   else
-    vl_client_send_disconnect ();
+    vl_client_send_disconnect (1 /* vpp should cleanup */ );
 }
 
 /*
@@ -776,8 +865,8 @@ vppcom_app_create (char *app_name)
 
   if (vcm->is_init)
     {
-      clib_warning ("already initialized");
-      return -1;
+      VDBG (1, "already initialized");
+      return VPPCOM_EEXIST;
     }
 
   vcm->is_init = 1;
@@ -793,7 +882,7 @@ vppcom_app_create (char *app_name)
   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,
+  pthread_atfork (vcl_app_pre_fork, vcl_app_fork_parent_handler,
                  vcl_app_fork_child_handler);
   atexit (vppcom_app_exit);
 
@@ -854,13 +943,14 @@ vppcom_app_destroy (void)
        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 */ );
+      vcl_worker_cleanup (vcl_worker_get_current (), 0 /* notify vpp */ );
     }
   else
     {
-      vcl_worker_cleanup (1 /* notify vpp */ );
+      vcl_worker_cleanup (vcl_worker_get_current (), 1 /* notify vpp */ );
     }
 
+  vcl_set_worker_index (~0);
   vcl_elog_stop (vcm);
   vl_client_disconnect_from_vlib ();
 }
@@ -1181,9 +1271,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));
@@ -1209,9 +1299,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",