From 95fdf37c89322faa62c585cf1a65772e82e8a60d Mon Sep 17 00:00:00 2001 From: Harry van Haaren Date: Mon, 21 Aug 2017 13:58:14 +0100 Subject: [PATCH] service: add component runstate 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 Acked-by: Pavan Nikhilesh --- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 1 + .../common/include/rte_service_component.h | 17 ++++++++++ lib/librte_eal/common/rte_service.c | 34 ++++++++++++++----- .../linuxapp/eal/rte_eal_version.map | 1 + test/test/test_service_cores.c | 32 +++++++++++++---- 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map index b705e2840e..47a09ea7fe 100644 --- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map +++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map @@ -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; diff --git a/lib/librte_eal/common/include/rte_service_component.h b/lib/librte_eal/common/include/rte_service_component.h index af632c6e1d..5e4573b5ad 100644 --- a/lib/librte_eal/common/include/rte_service_component.h +++ b/lib/librte_eal/common/include/rte_service_component.h @@ -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 diff --git a/lib/librte_eal/common/rte_service.c b/lib/librte_eal/common/rte_service.c index ddcf3a845e..2b5f9bdebe 100644 --- a/lib/librte_eal/common/rte_service.c +++ b/lib/librte_eal/common/rte_service.c @@ -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 diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map index f94bdb198b..8c08b8d1ee 100644 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map @@ -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; diff --git a/test/test/test_service_cores.c b/test/test/test_service_cores.c index 5ae7b20c7a..ddea7f0ba1 100644 --- a/test/test/test_service_cores.c +++ b/test/test/test_service_cores.c @@ -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"); -- 2.20.1