X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvcl%2Fvppcom.c;h=0eaab6cbd6bc5ca87a301a0e00a864184cc171b3;hb=eaec2a6d9ab8b983aaee536be1a95846c07a9d7f;hp=195e6cbc60214ef74ff2fdcb232cf10870ba2412;hpb=47c40e2d944c9a29677d0542103207ba8372b66a;p=vpp.git diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c index 195e6cbc602..0eaab6cbd6b 100644 --- a/src/vcl/vppcom.c +++ b/src/vcl/vppcom.c @@ -22,46 +22,26 @@ __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); @@ -703,18 +697,103 @@ 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; - VDBG (0, "initializing forked child"); + parent_wrk_index = vcl_get_worker_index (); + VDBG (0, "initializing forked child with parent wrk %u", parent_wrk_index); /* * 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"); @@ -738,21 +817,43 @@ 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) ; } +/** + * 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 (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 (1 /* vpp should cleanup */ ); +} + /* * VPPCOM Public API functions */ @@ -764,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; @@ -776,12 +877,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); - pthread_atfork (NULL, vcl_app_fork_parent_handler, + clib_rwlock_init (&vcm->segment_table_lock); + pthread_atfork (vcl_app_pre_fork, vcl_app_fork_parent_handler, vcl_app_fork_child_handler); + atexit (vppcom_app_exit); /* Allocate default worker */ vcl_worker_alloc_and_init (); @@ -824,9 +927,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 +942,17 @@ 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 (vcl_worker_get_current (), 0 /* notify vpp */ ); } else { - vcl_worker_cleanup (); + vcl_worker_cleanup (vcl_worker_get_current (), 1 /* notify vpp */ ); } + vcl_set_worker_index (~0); vcl_elog_stop (vcm); vl_client_disconnect_from_vlib (); - vec_free (vcm->app_name); } int @@ -1163,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)); @@ -1191,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",