aboutsummaryrefslogtreecommitdiffstats
path: root/src/vcl/vppcom.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vcl/vppcom.c')
-rw-r--r--src/vcl/vppcom.c106
1 files changed, 95 insertions, 11 deletions
diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c
index bf21f5204b4..07136e9c6c8 100644
--- a/src/vcl/vppcom.c
+++ b/src/vcl/vppcom.c
@@ -697,14 +697,96 @@ 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 (si->si_pid != child_wrk->current_pid)
+ {
+ VDBG (0, "unexpected child pid %u", si->si_pid);
+ return;
+ }
+ if (child_wrk)
+ vcl_cleanup_forked_child (wrk, child_wrk);
+
+ 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
@@ -732,17 +814,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)
;
}
@@ -759,8 +842,8 @@ 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 ();
@@ -796,7 +879,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);
@@ -857,13 +940,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 ();
}