+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;
+
+ parent_wrk_index = vcl_get_worker_index ();
+ VDBG (0, "initializing forked child with parent wrk %u", parent_wrk_index);
+
+ /*
+ * Allocate worker
+ */
+ vcl_set_worker_index (~0);
+ if (!vcl_worker_alloc_and_init ())
+ VERR ("couldn't allocate new worker");
+
+ /*
+ * Attach to binary api
+ */
+ child_name = format (0, "%v-child-%u%c", vcm->app_name, getpid (), 0);
+ vcl_cleanup_bapi ();
+ vppcom_api_hookup ();
+ vcm->app_state = STATE_APP_START;
+ rv = vppcom_connect_to_vpp ((char *) child_name);
+ vec_free (child_name);
+ if (rv)
+ {
+ VERR ("couldn't connect to VPP!");
+ return;
+ }
+
+ /*
+ * 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;
+}
+
+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
+ */
+int
+vppcom_app_create (char *app_name)
+{
+ vppcom_cfg_t *vcl_cfg = &vcm->cfg;
+ int rv;
+
+ if (vcm->is_init)
+ {
+ VDBG (1, "already initialized");
+ return VPPCOM_EEXIST;
+ }
+
+ vcm->is_init = 1;
+ vppcom_cfg (&vcm->cfg);
+ vcl_cfg = &vcm->cfg;
+
+ vcm->main_cpu = pthread_self ();
+ vcm->main_pid = getpid ();
+ vcm->app_name = format (0, "%s", app_name);
+ vppcom_init_error_string_table ();
+ 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 (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 ();
+
+ /* API hookup and connect to VPP */
+ vppcom_api_hookup ();
+ vcl_elog_init (vcm);
+ vcm->app_state = STATE_APP_START;
+ rv = vppcom_connect_to_vpp (app_name);
+ if (rv)
+ {
+ VERR ("couldn't connect to VPP!");
+ return rv;
+ }
+ VDBG (0, "sending session enable");
+ rv = vppcom_app_session_enable ();
+ if (rv)
+ {
+ VERR ("vppcom_app_session_enable() failed!");
+ return rv;
+ }
+
+ VDBG (0, "sending app attach");
+ rv = vppcom_app_attach ();
+ if (rv)
+ {
+ VERR ("vppcom_app_attach() failed!");
+ return rv;
+ }
+
+ VDBG (0, "app_name '%s', my_client_index %d (0x%x)", app_name,
+ vcm->workers[0].my_client_index, vcm->workers[0].my_client_index);
+
+ return VPPCOM_OK;
+}
+
+void
+vppcom_app_destroy (void)
+{
+ int rv;
+ f64 orig_app_timeout;
+
+ if (!pool_elts (vcm->workers))
+ return;
+
+ vcl_evt (VCL_EVT_DETACH, vcm);
+
+ if (pool_elts (vcm->workers) == 1)
+ {
+ vppcom_app_send_detach ();
+ orig_app_timeout = vcm->cfg.app_timeout;
+ vcm->cfg.app_timeout = 2.0;
+ rv = vcl_wait_for_app_state_change (STATE_APP_ENABLED);
+ vcm->cfg.app_timeout = orig_app_timeout;
+ 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_get_current (), 1 /* notify vpp */ );
+ }
+
+ vcl_set_worker_index (~0);
+ vcl_elog_stop (vcm);
+ vl_client_disconnect_from_vlib ();
+}
+
+int