X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=app%2Ftest%2Ftest_service_cores.c;h=ced6ed008175008a4419731eb08d2560b840e340;hb=6496922368fe03be9ab4137f2d615dba1a766f39;hp=981e212130bfcc6edfe12287be234db02faaf0ed;hpb=9ec8f11369dd816da9347afc516d8ccdd35f3755;p=dpdk.git diff --git a/app/test/test_service_cores.c b/app/test/test_service_cores.c index 981e212130..ced6ed0081 100644 --- a/app/test/test_service_cores.c +++ b/app/test/test_service_cores.c @@ -30,7 +30,7 @@ static int testsuite_setup(void) { slcore_id = rte_get_next_lcore(/* start core */ -1, - /* skip master */ 1, + /* skip main */ 1, /* wrap */ 0); return TEST_SUCCESS; @@ -53,20 +53,22 @@ static int32_t dummy_cb(void *args) static int32_t dummy_mt_unsafe_cb(void *args) { /* before running test, the initialization has set pass_test to 1. - * If the cmpset in service-cores is working correctly, the code here + * If the CAS in service-cores is working correctly, the code here * should never fail to take the lock. If the lock *is* taken, fail the * test, because two threads are concurrently in a non-MT safe callback. */ uint32_t *test_params = args; - uint32_t *atomic_lock = &test_params[0]; + uint32_t *lock = &test_params[0]; uint32_t *pass_test = &test_params[1]; - int lock_taken = rte_atomic32_cmpset(atomic_lock, 0, 1); + uint32_t exp = 0; + int lock_taken = __atomic_compare_exchange_n(lock, &exp, 1, 0, + __ATOMIC_RELAXED, __ATOMIC_RELAXED); if (lock_taken) { /* delay with the lock held */ rte_delay_ms(250); - rte_atomic32_clear((rte_atomic32_t *)atomic_lock); + __atomic_store_n(lock, 0, __ATOMIC_RELAXED); } else { - /* 2nd thread will fail to take lock, so set pass flag */ + /* 2nd thread will fail to take lock, so clear pass flag */ *pass_test = 0; } @@ -83,13 +85,15 @@ static int32_t dummy_mt_safe_cb(void *args) * that 2 threads are running the callback at the same time: MT safe */ uint32_t *test_params = args; - uint32_t *atomic_lock = &test_params[0]; + uint32_t *lock = &test_params[0]; uint32_t *pass_test = &test_params[1]; - int lock_taken = rte_atomic32_cmpset(atomic_lock, 0, 1); + uint32_t exp = 0; + int lock_taken = __atomic_compare_exchange_n(lock, &exp, 1, 0, + __ATOMIC_RELAXED, __ATOMIC_RELAXED); if (lock_taken) { /* delay with the lock held */ rte_delay_ms(250); - rte_atomic32_clear((rte_atomic32_t *)atomic_lock); + __atomic_store_n(lock, 0, __ATOMIC_RELAXED); } else { /* 2nd thread will fail to take lock, so set pass flag */ *pass_test = 1; @@ -114,10 +118,22 @@ unregister_all(void) } rte_service_lcore_reset_all(); + rte_eal_mp_wait_lcore(); return TEST_SUCCESS; } +/* Wait until service lcore not active, or for 100x SERVICE_DELAY */ +static void +wait_slcore_inactive(uint32_t slcore_id) +{ + int i; + + for (i = 0; rte_service_lcore_may_be_active(slcore_id) == 1 && + i < 100; i++) + rte_delay_ms(SERVICE_DELAY); +} + /* register a single dummy service */ static int dummy_register(void) @@ -302,7 +318,15 @@ service_attr_get(void) TEST_ASSERT_EQUAL(1, cycles_gt_zero, "attr_get() failed to get cycles (expected > zero)"); - rte_service_lcore_stop(slcore_id); + TEST_ASSERT_EQUAL(0, rte_service_map_lcore_set(id, slcore_id, 0), + "Disabling valid service and core failed"); + TEST_ASSERT_EQUAL(0, rte_service_lcore_stop(slcore_id), + "Failed to stop service lcore"); + + wait_slcore_inactive(slcore_id); + + TEST_ASSERT_EQUAL(0, rte_service_lcore_may_be_active(slcore_id), + "Service lcore not stopped after waiting."); TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_calls, &attr_value), "Valid attr_get() call didn't return success"); @@ -361,6 +385,9 @@ service_lcore_attr_get(void) "Service core add did not return zero"); TEST_ASSERT_EQUAL(0, rte_service_map_lcore_set(id, slcore_id, 1), "Enabling valid service and core failed"); + /* Ensure service is not active before starting */ + TEST_ASSERT_EQUAL(0, rte_service_lcore_may_be_active(slcore_id), + "Not-active service core reported as active"); TEST_ASSERT_EQUAL(0, rte_service_lcore_start(slcore_id), "Starting service core failed"); @@ -381,7 +408,19 @@ service_lcore_attr_get(void) lcore_attr_id, &lcore_attr_value), "Invalid lcore attr didn't return -EINVAL"); - rte_service_lcore_stop(slcore_id); + /* Ensure service is active */ + TEST_ASSERT_EQUAL(1, rte_service_lcore_may_be_active(slcore_id), + "Active service core reported as not-active"); + + TEST_ASSERT_EQUAL(0, rte_service_map_lcore_set(id, slcore_id, 0), + "Disabling valid service and core failed"); + TEST_ASSERT_EQUAL(0, rte_service_lcore_stop(slcore_id), + "Failed to stop service lcore"); + + wait_slcore_inactive(slcore_id); + + TEST_ASSERT_EQUAL(0, rte_service_lcore_may_be_active(slcore_id), + "Service lcore not stopped after waiting."); TEST_ASSERT_EQUAL(0, rte_service_lcore_attr_reset_all(slcore_id), "Valid lcore_attr_reset_all() didn't return success"); @@ -532,12 +571,12 @@ service_lcore_add_del(void) TEST_ASSERT_EQUAL(1, rte_service_lcore_count(), "Service core count not equal to one"); uint32_t slcore_1 = rte_get_next_lcore(/* start core */ -1, - /* skip master */ 1, + /* skip main */ 1, /* wrap */ 0); TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_1), "Service core add did not return zero"); uint32_t slcore_2 = rte_get_next_lcore(/* start core */ slcore_1, - /* skip master */ 1, + /* skip main */ 1, /* wrap */ 0); TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_2), "Service core add did not return zero"); @@ -583,19 +622,19 @@ service_threaded_test(int mt_safe) /* add next 2 cores */ uint32_t slcore_1 = rte_get_next_lcore(/* start core */ -1, - /* skip master */ 1, + /* skip main */ 1, /* wrap */ 0); TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_1), "mt safe lcore add fail"); uint32_t slcore_2 = rte_get_next_lcore(/* start core */ slcore_1, - /* skip master */ 1, + /* skip main */ 1, /* wrap */ 0); TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_2), "mt safe lcore add fail"); - /* Use atomic locks to verify that two threads are in the same function - * at the same time. These are passed to the unit tests through the - * callback userdata parameter + /* Use locks to verify that two threads are in the same function + * at the same time. These are passed to the unit tests through + * the callback userdata parameter. */ uint32_t test_params[2]; memset(test_params, 0, sizeof(uint32_t) * 2); @@ -684,7 +723,7 @@ service_mt_safe_poll(void) } /* tests a NON mt safe service with two cores, the callback is serialized - * using the atomic cmpset. + * using the CAS. */ static int service_mt_unsafe_poll(void) @@ -706,17 +745,17 @@ delay_as_a_mt_safe_service(void *args) RTE_SET_USED(args); uint32_t *params = args; - /* retrieve done flag and atomic lock to inc/dec */ + /* retrieve done flag and lock to add/sub */ uint32_t *done = ¶ms[0]; - rte_atomic32_t *lock = (rte_atomic32_t *)¶ms[1]; + uint32_t *lock = ¶ms[1]; while (!*done) { - rte_atomic32_inc(lock); + __atomic_add_fetch(lock, 1, __ATOMIC_RELAXED); rte_delay_us(500); - if (rte_atomic32_read(lock) > 1) + if (__atomic_load_n(lock, __ATOMIC_RELAXED) > 1) /* pass: second core has simultaneously incremented */ *done = 1; - rte_atomic32_dec(lock); + __atomic_sub_fetch(lock, 1, __ATOMIC_RELAXED); } return 0; @@ -910,6 +949,59 @@ service_may_be_active(void) return unregister_all(); } +/* check service may be active when service is running on a second lcore */ +static int +service_active_two_cores(void) +{ + if (!rte_lcore_is_enabled(0) || !rte_lcore_is_enabled(1) || + !rte_lcore_is_enabled(2)) + return TEST_SKIPPED; + + const uint32_t sid = 0; + int i; + + uint32_t lcore = rte_get_next_lcore(/* start core */ -1, + /* skip main */ 1, + /* wrap */ 0); + uint32_t slcore = rte_get_next_lcore(/* start core */ lcore, + /* skip main */ 1, + /* wrap */ 0); + + /* start the service on the second available lcore */ + TEST_ASSERT_EQUAL(0, rte_service_runstate_set(sid, 1), + "Starting valid service failed"); + TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore), + "Add service core failed when not in use before"); + TEST_ASSERT_EQUAL(0, rte_service_map_lcore_set(sid, slcore, 1), + "Enabling valid service on valid core failed"); + TEST_ASSERT_EQUAL(0, rte_service_lcore_start(slcore), + "Service core start after add failed"); + + /* ensures core really is running the service function */ + TEST_ASSERT_EQUAL(1, service_lcore_running_check(), + "Service core expected to poll service but it didn't"); + + /* ensures that service may be active reports running state */ + TEST_ASSERT_EQUAL(1, rte_service_may_be_active(sid), + "Service may be active did not report running state"); + + /* stop the service */ + TEST_ASSERT_EQUAL(0, rte_service_runstate_set(sid, 0), + "Error: Service stop returned non-zero"); + + /* give the service 100ms to stop running */ + for (i = 0; i < 100; i++) { + if (!rte_service_may_be_active(sid)) + break; + rte_delay_ms(SERVICE_DELAY); + } + + TEST_ASSERT_EQUAL(0, rte_service_may_be_active(sid), + "Error: Service not stopped after 100ms"); + + return unregister_all(); +} + static struct unit_test_suite service_tests = { .suite_name = "service core test suite", .setup = testsuite_setup, @@ -931,6 +1023,7 @@ static struct unit_test_suite service_tests = { TEST_CASE_ST(dummy_register, NULL, service_app_lcore_mt_safe), TEST_CASE_ST(dummy_register, NULL, service_app_lcore_mt_unsafe), TEST_CASE_ST(dummy_register, NULL, service_may_be_active), + TEST_CASE_ST(dummy_register, NULL, service_active_two_cores), TEST_CASES_END() /**< NULL terminate unit test array */ } };