diff options
Diffstat (limited to 'src/vcl/vppcom.c')
-rw-r--r-- | src/vcl/vppcom.c | 106 |
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 (); } |