2017-12-19 15:49:05 +00:00
|
|
|
/* SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
* Copyright(c) 2010-2014 Intel Corporation
|
2012-09-04 12:54:00 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdint.h>
|
2021-01-25 15:05:39 +00:00
|
|
|
#include <sys/resource.h>
|
|
|
|
#include <sys/time.h>
|
2012-09-04 12:54:00 +00:00
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <rte_debug.h>
|
|
|
|
#include <rte_common.h>
|
2013-06-03 00:00:00 +00:00
|
|
|
#include <rte_eal.h>
|
test/debug: fix EAL cleanup when forking
Before this patch, the debug_autotest would call fork(),
call rte_panic() or rte_exit() in the child process, and
examine the return code to verify that rte_panic() and
rte_exit() were correctly reporting failures.
With the inclusion of the rte_eal_cleanup() patch, rte_exit()
was modified to cleanly tear-down EAL allocations. Currently
only one library (service cores) is allocated by EAL at startup
and should be cleaned up. This library has a check on a normal
(non-hugepage) variable to protect against double cleanup. The
service cores finalize() function itself frees back hugepage mem.
Given the fork() approach from the unit test, and the fact that
the double-free check is on an ordinary variable, causes multiple
child processed (fork()-ed from the unit-test runner) to attempt
to free the huge-page memory multiple times. The variable to
protect against double-cleanup was not effective, as the fork()
would restore it to show initialized in the next child.
The solution is to call rte_service_finalize() *before* calling
fork(), which results in the service cores double-cleanup variable
to be zero before the fork(), and hence the child processes never
free the hugepage service-cores memory (correct behavior, as the
unit-test suite is still running, and owns the hugepages).
Fixes: aec9c13c5257 ("eal: add function to release internal resources")
Reported-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
Signed-off-by: Harry van Haaren <harry.van.haaren@intel.com>
2018-01-30 18:26:09 +00:00
|
|
|
#include <rte_service_component.h>
|
2012-09-04 12:54:00 +00:00
|
|
|
|
|
|
|
#include "test.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Debug test
|
|
|
|
* ==========
|
|
|
|
*/
|
|
|
|
|
2014-09-26 14:04:01 +00:00
|
|
|
/* use fork() to test rte_panic() */
|
2012-09-04 12:54:00 +00:00
|
|
|
static int
|
|
|
|
test_panic(void)
|
|
|
|
{
|
|
|
|
int pid;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
pid = fork();
|
|
|
|
|
2021-01-25 15:05:39 +00:00
|
|
|
if (pid == 0) {
|
|
|
|
struct rlimit rl;
|
|
|
|
|
|
|
|
/* No need to generate a coredump when panicking. */
|
|
|
|
rl.rlim_cur = rl.rlim_max = 0;
|
|
|
|
setrlimit(RLIMIT_CORE, &rl);
|
2012-09-04 12:54:00 +00:00
|
|
|
rte_panic("Test Debug\n");
|
2021-01-25 15:05:39 +00:00
|
|
|
} else if (pid < 0) {
|
2012-09-04 12:54:00 +00:00
|
|
|
printf("Fork Failed\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
wait(&status);
|
|
|
|
if(status == 0){
|
|
|
|
printf("Child process terminated normally!\n");
|
|
|
|
return -1;
|
|
|
|
} else
|
|
|
|
printf("Child process terminated as expected - Test passed!\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-09-26 14:04:01 +00:00
|
|
|
/* use fork() to test rte_exit() */
|
2012-09-04 12:54:00 +00:00
|
|
|
static int
|
|
|
|
test_exit_val(int exit_val)
|
|
|
|
{
|
|
|
|
int pid;
|
|
|
|
int status;
|
|
|
|
|
test/debug: fix EAL cleanup when forking
Before this patch, the debug_autotest would call fork(),
call rte_panic() or rte_exit() in the child process, and
examine the return code to verify that rte_panic() and
rte_exit() were correctly reporting failures.
With the inclusion of the rte_eal_cleanup() patch, rte_exit()
was modified to cleanly tear-down EAL allocations. Currently
only one library (service cores) is allocated by EAL at startup
and should be cleaned up. This library has a check on a normal
(non-hugepage) variable to protect against double cleanup. The
service cores finalize() function itself frees back hugepage mem.
Given the fork() approach from the unit test, and the fact that
the double-free check is on an ordinary variable, causes multiple
child processed (fork()-ed from the unit-test runner) to attempt
to free the huge-page memory multiple times. The variable to
protect against double-cleanup was not effective, as the fork()
would restore it to show initialized in the next child.
The solution is to call rte_service_finalize() *before* calling
fork(), which results in the service cores double-cleanup variable
to be zero before the fork(), and hence the child processes never
free the hugepage service-cores memory (correct behavior, as the
unit-test suite is still running, and owns the hugepages).
Fixes: aec9c13c5257 ("eal: add function to release internal resources")
Reported-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
Signed-off-by: Harry van Haaren <harry.van.haaren@intel.com>
2018-01-30 18:26:09 +00:00
|
|
|
/* manually cleanup EAL memory, as the fork() below would otherwise
|
|
|
|
* cause the same hugepages to be free()-ed multiple times.
|
|
|
|
*/
|
|
|
|
rte_service_finalize();
|
|
|
|
|
2012-09-04 12:54:00 +00:00
|
|
|
pid = fork();
|
|
|
|
|
|
|
|
if (pid == 0)
|
|
|
|
rte_exit(exit_val, __func__);
|
|
|
|
else if (pid < 0){
|
|
|
|
printf("Fork Failed\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
wait(&status);
|
|
|
|
printf("Child process status: %d\n", status);
|
|
|
|
if(!WIFEXITED(status) || WEXITSTATUS(status) != (uint8_t)exit_val){
|
2012-12-19 23:00:00 +00:00
|
|
|
printf("Child process terminated with incorrect status (expected = %d)!\n",
|
|
|
|
exit_val);
|
2012-09-04 12:54:00 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
test_exit(void)
|
|
|
|
{
|
|
|
|
int test_vals[] = { 0, 1, 2, 255, -1 };
|
|
|
|
unsigned i;
|
2020-01-24 04:55:42 +00:00
|
|
|
for (i = 0; i < RTE_DIM(test_vals); i++) {
|
2012-09-04 12:54:00 +00:00
|
|
|
if (test_exit_val(test_vals[i]) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
printf("%s Passed\n", __func__);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-06-03 00:00:00 +00:00
|
|
|
static void
|
|
|
|
dummy_app_usage(const char *progname)
|
|
|
|
{
|
|
|
|
RTE_SET_USED(progname);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
test_usage(void)
|
|
|
|
{
|
|
|
|
if (rte_set_application_usage_hook(dummy_app_usage) != NULL) {
|
|
|
|
printf("Non-NULL value returned for initial usage hook\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (rte_set_application_usage_hook(NULL) != dummy_app_usage) {
|
|
|
|
printf("Incorrect value returned for application usage hook\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-08-18 11:29:23 +00:00
|
|
|
static int
|
2012-09-04 12:54:00 +00:00
|
|
|
test_debug(void)
|
|
|
|
{
|
|
|
|
rte_dump_stack();
|
|
|
|
if (test_panic() < 0)
|
|
|
|
return -1;
|
|
|
|
if (test_exit() < 0)
|
|
|
|
return -1;
|
2013-06-03 00:00:00 +00:00
|
|
|
if (test_usage() < 0)
|
|
|
|
return -1;
|
2012-09-04 12:54:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2014-08-18 11:29:23 +00:00
|
|
|
|
2016-07-13 12:38:13 +00:00
|
|
|
REGISTER_TEST_COMMAND(debug_autotest, test_debug);
|