service: add component runstate
authorHarry van Haaren <harry.van.haaren@intel.com>
Mon, 21 Aug 2017 12:58:14 +0000 (13:58 +0100)
committerThomas Monjalon <thomas@monjalon.net>
Fri, 15 Sep 2017 11:46:47 +0000 (13:46 +0200)
This commit adds a new flag that the component (or "backend")
can use to indicate readyness. The service function callback
will not be called until the component sets itself as ready.

The use-case behind adding this feature is eg: a service that
requires configuration before it can start. Any service that
emulates an ethdev will have rte_eth_dev_configure() called,
and only after that the service will know how many queues/etc
to allocate. Once that configuration is complete, the service
marks itself as ready using rte_service_component_runstate_set().

This feature request results from prototyping services, and
requiring a flag in each service to note "internal" readyness.
Instead that logic is now lifted to the service library.

The unit tests have been updated to test the component runstate.

Signed-off-by: Harry van Haaren <harry.van.haaren@intel.com>
Acked-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
lib/librte_eal/bsdapp/eal/rte_eal_version.map
lib/librte_eal/common/include/rte_service_component.h
lib/librte_eal/common/rte_service.c
lib/librte_eal/linuxapp/eal/rte_eal_version.map
test/test/test_service_cores.c

index b705e28..47a09ea 100644 (file)
@@ -214,6 +214,7 @@ EXPERIMENTAL {
        rte_eal_hotplug_remove;
        rte_service_component_register;
        rte_service_component_unregister;
+       rte_service_component_runstate_set;
        rte_service_dump;
        rte_service_get_by_id;
        rte_service_get_by_name;
index af632c6..5e4573b 100644 (file)
@@ -131,6 +131,23 @@ int32_t rte_service_component_unregister(uint32_t id);
  */
 int32_t rte_service_start_with_defaults(void);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Set the backend runstate of a component.
+ *
+ * This function allows services to be registered at startup, but not yet
+ * enabled to run by default. When the service has been configured (via the
+ * usual method; eg rte_eventdev_configure, the service can mark itself as
+ * ready to run. The differentiation between backend runstate and
+ * service_runstate is that the backend runstate is set by the service
+ * component while the service runstate is reserved for application usage.
+ *
+ * @retval 0 Success
+ */
+int32_t rte_service_component_runstate_set(uint32_t id, uint32_t runstate);
+
 /**
  * @warning
  * @b EXPERIMENTAL: this API may change without prior notice
index ddcf3a8..2b5f9bd 100644 (file)
@@ -71,7 +71,8 @@ struct rte_service_spec_impl {
        rte_atomic32_t execute_lock;
 
        /* API set/get-able variables */
-       int32_t runstate;
+       int8_t app_runstate;
+       int8_t comp_runstate;
        uint8_t internal_flags;
 
        /* per service statistics */
@@ -272,6 +273,21 @@ rte_service_component_unregister(uint32_t id)
        return 0;
 }
 
+int32_t
+rte_service_component_runstate_set(uint32_t id, uint32_t runstate)
+{
+       struct rte_service_spec_impl *s;
+       SERVICE_VALID_GET_OR_ERR_RET(id, s, -EINVAL);
+
+       if (runstate)
+               s->comp_runstate = RUNSTATE_RUNNING;
+       else
+               s->comp_runstate = RUNSTATE_STOPPED;
+
+       rte_smp_wmb();
+       return 0;
+}
+
 int32_t
 rte_service_runstate_set(uint32_t id, uint32_t runstate)
 {
@@ -279,9 +295,9 @@ rte_service_runstate_set(uint32_t id, uint32_t runstate)
        SERVICE_VALID_GET_OR_ERR_RET(id, s, -EINVAL);
 
        if (runstate)
-               s->runstate = RUNSTATE_RUNNING;
+               s->app_runstate = RUNSTATE_RUNNING;
        else
-               s->runstate = RUNSTATE_STOPPED;
+               s->app_runstate = RUNSTATE_STOPPED;
 
        rte_smp_wmb();
        return 0;
@@ -292,8 +308,10 @@ rte_service_runstate_get(uint32_t id)
 {
        struct rte_service_spec_impl *s;
        SERVICE_VALID_GET_OR_ERR_RET(id, s, -EINVAL);
-
-       return (s->runstate == RUNSTATE_RUNNING) && (s->num_mapped_cores > 0);
+       rte_smp_rmb();
+       return (s->app_runstate == RUNSTATE_RUNNING) &&
+               (s->comp_runstate == RUNSTATE_RUNNING) &&
+               (s->num_mapped_cores > 0);
 }
 
 static inline void
@@ -328,7 +346,8 @@ rte_service_runner_func(void *arg)
                        if (!service_valid(i))
                                continue;
                        struct rte_service_spec_impl *s = &rte_services[i];
-                       if (s->runstate != RUNSTATE_RUNNING ||
+                       if (s->comp_runstate != RUNSTATE_RUNNING ||
+                                       s->app_runstate != RUNSTATE_RUNNING ||
                                        !(service_mask & (UINT64_C(1) << i)))
                                continue;
 
@@ -609,8 +628,7 @@ rte_service_lcore_stop(uint32_t lcore)
        for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
                int32_t enabled =
                        lcore_states[i].service_mask & (UINT64_C(1) << i);
-               int32_t service_running = rte_services[i].runstate !=
-                                               RUNSTATE_STOPPED;
+               int32_t service_running = rte_service_runstate_get(i);
                int32_t only_core = rte_services[i].num_mapped_cores == 1;
 
                /* if the core is mapped, and the service is running, and this
index f94bdb1..8c08b8d 100644 (file)
@@ -219,6 +219,7 @@ EXPERIMENTAL {
        rte_eal_hotplug_remove;
        rte_service_component_register;
        rte_service_component_unregister;
+       rte_service_component_runstate_set;
        rte_service_dump;
        rte_service_get_by_id;
        rte_service_get_by_name;
index 5ae7b20..ddea7f0 100644 (file)
@@ -166,9 +166,12 @@ dummy_register(void)
                        "Invalid name");
        snprintf(service.name, sizeof(service.name), DUMMY_SERVICE_NAME);
 
-       TEST_ASSERT_EQUAL(0, rte_service_component_register(&service, NULL),
+       uint32_t id;
+       TEST_ASSERT_EQUAL(0, rte_service_component_register(&service, &id),
                        "Failed to register valid service");
 
+       rte_service_component_runstate_set(id, 1);
+
        return TEST_SUCCESS;
 }
 
@@ -470,13 +473,11 @@ service_threaded_test(int mt_safe)
        if (mt_safe) {
                service.callback = dummy_mt_safe_cb;
                service.capabilities |= RTE_SERVICE_CAP_MT_SAFE;
-       } else {
-               /* initialize to pass, see callback comment for details */
-               test_params[1] = 1;
+       } else
                service.callback = dummy_mt_unsafe_cb;
-       }
 
-       TEST_ASSERT_EQUAL(0, rte_service_component_register(&service, NULL),
+       uint32_t id;
+       TEST_ASSERT_EQUAL(0, rte_service_component_register(&service, &id),
                        "Register of MT SAFE service failed");
 
        const uint32_t sid = 0;
@@ -494,9 +495,26 @@ service_threaded_test(int mt_safe)
        rte_service_lcore_stop(slcore_1);
        rte_service_lcore_stop(slcore_2);
 
+       TEST_ASSERT_EQUAL(0, test_params[1],
+                       "Service run with component runstate = 0");
+
+       /* enable backend runstate: the service should run after this */
+       rte_service_component_runstate_set(id, 1);
+
+       /* initialize to pass, see callback comment for details */
+       if (!mt_safe)
+               test_params[1] = 1;
+
+       rte_service_lcore_start(slcore_1);
+       rte_service_lcore_start(slcore_2);
+
+       /* wait for the worker threads to run */
+       rte_delay_ms(500);
+       rte_service_lcore_stop(slcore_1);
+       rte_service_lcore_stop(slcore_2);
+
        TEST_ASSERT_EQUAL(1, test_params[1],
                        "MT Safe service not run by two cores concurrently");
-
        TEST_ASSERT_EQUAL(0, rte_service_runstate_set(sid, 0),
                        "Failed to stop MT Safe service");