cgroup: selftests: Add tests for freezer time
Test cgroup v2 freezer time stat. Freezer time accounting should be independent of other cgroups in the hierarchy and should increase iff a cgroup is CGRP_FREEZE (regardless of whether it reaches CGRP_FROZEN). Skip these tests on systems without freeze time accounting. Signed-off-by: Tiffany Yang <ynaffit@google.com> Cc: Michal Koutný <mkoutny@suse.com> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
@@ -804,6 +804,662 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the current frozen_usec for the cgroup.
|
||||
*/
|
||||
static long cg_check_freezetime(const char *cgroup)
|
||||
{
|
||||
return cg_read_key_long(cgroup, "cgroup.stat.local",
|
||||
"frozen_usec ");
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that the freeze time will behave as expected for an empty cgroup.
|
||||
*/
|
||||
static int test_cgfreezer_time_empty(const char *root)
|
||||
{
|
||||
int ret = KSFT_FAIL;
|
||||
char *cgroup = NULL;
|
||||
long prev, curr;
|
||||
|
||||
cgroup = cg_name(root, "cg_time_test_empty");
|
||||
if (!cgroup)
|
||||
goto cleanup;
|
||||
|
||||
/*
|
||||
* 1) Create an empty cgroup and check that its freeze time
|
||||
* is 0.
|
||||
*/
|
||||
if (cg_create(cgroup))
|
||||
goto cleanup;
|
||||
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr < 0) {
|
||||
ret = KSFT_SKIP;
|
||||
goto cleanup;
|
||||
}
|
||||
if (curr > 0) {
|
||||
debug("Expect time (%ld) to be 0\n", curr);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (cg_freeze_nowait(cgroup, true))
|
||||
goto cleanup;
|
||||
|
||||
/*
|
||||
* 2) Sleep for 1000 us. Check that the freeze time is at
|
||||
* least 1000 us.
|
||||
*/
|
||||
usleep(1000);
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr < 1000) {
|
||||
debug("Expect time (%ld) to be at least 1000 us\n",
|
||||
curr);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 3) Unfreeze the cgroup. Check that the freeze time is
|
||||
* larger than at 2).
|
||||
*/
|
||||
if (cg_freeze_nowait(cgroup, false))
|
||||
goto cleanup;
|
||||
prev = curr;
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr <= prev) {
|
||||
debug("Expect time (%ld) to be more than previous check (%ld)\n",
|
||||
curr, prev);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 4) Check the freeze time again to ensure that it has not
|
||||
* changed.
|
||||
*/
|
||||
prev = curr;
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr != prev) {
|
||||
debug("Expect time (%ld) to be unchanged from previous check (%ld)\n",
|
||||
curr, prev);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = KSFT_PASS;
|
||||
|
||||
cleanup:
|
||||
if (cgroup)
|
||||
cg_destroy(cgroup);
|
||||
free(cgroup);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* A simple test for cgroup freezer time accounting. This test follows
|
||||
* the same flow as test_cgfreezer_time_empty, but with a single process
|
||||
* in the cgroup.
|
||||
*/
|
||||
static int test_cgfreezer_time_simple(const char *root)
|
||||
{
|
||||
int ret = KSFT_FAIL;
|
||||
char *cgroup = NULL;
|
||||
long prev, curr;
|
||||
|
||||
cgroup = cg_name(root, "cg_time_test_simple");
|
||||
if (!cgroup)
|
||||
goto cleanup;
|
||||
|
||||
/*
|
||||
* 1) Create a cgroup and check that its freeze time is 0.
|
||||
*/
|
||||
if (cg_create(cgroup))
|
||||
goto cleanup;
|
||||
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr < 0) {
|
||||
ret = KSFT_SKIP;
|
||||
goto cleanup;
|
||||
}
|
||||
if (curr > 0) {
|
||||
debug("Expect time (%ld) to be 0\n", curr);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 2) Populate the cgroup with one child and check that the
|
||||
* freeze time is still 0.
|
||||
*/
|
||||
cg_run_nowait(cgroup, child_fn, NULL);
|
||||
prev = curr;
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr > prev) {
|
||||
debug("Expect time (%ld) to be 0\n", curr);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (cg_freeze_nowait(cgroup, true))
|
||||
goto cleanup;
|
||||
|
||||
/*
|
||||
* 3) Sleep for 1000 us. Check that the freeze time is at
|
||||
* least 1000 us.
|
||||
*/
|
||||
usleep(1000);
|
||||
prev = curr;
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr < 1000) {
|
||||
debug("Expect time (%ld) to be at least 1000 us\n",
|
||||
curr);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 4) Unfreeze the cgroup. Check that the freeze time is
|
||||
* larger than at 3).
|
||||
*/
|
||||
if (cg_freeze_nowait(cgroup, false))
|
||||
goto cleanup;
|
||||
prev = curr;
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr <= prev) {
|
||||
debug("Expect time (%ld) to be more than previous check (%ld)\n",
|
||||
curr, prev);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 5) Sleep for 1000 us. Check that the freeze time is the
|
||||
* same as at 4).
|
||||
*/
|
||||
usleep(1000);
|
||||
prev = curr;
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr != prev) {
|
||||
debug("Expect time (%ld) to be unchanged from previous check (%ld)\n",
|
||||
curr, prev);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = KSFT_PASS;
|
||||
|
||||
cleanup:
|
||||
if (cgroup)
|
||||
cg_destroy(cgroup);
|
||||
free(cgroup);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that freezer time accounting works as expected, even while we're
|
||||
* populating a cgroup with processes.
|
||||
*/
|
||||
static int test_cgfreezer_time_populate(const char *root)
|
||||
{
|
||||
int ret = KSFT_FAIL;
|
||||
char *cgroup = NULL;
|
||||
long prev, curr;
|
||||
int i;
|
||||
|
||||
cgroup = cg_name(root, "cg_time_test_populate");
|
||||
if (!cgroup)
|
||||
goto cleanup;
|
||||
|
||||
if (cg_create(cgroup))
|
||||
goto cleanup;
|
||||
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr < 0) {
|
||||
ret = KSFT_SKIP;
|
||||
goto cleanup;
|
||||
}
|
||||
if (curr > 0) {
|
||||
debug("Expect time (%ld) to be 0\n", curr);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1) Populate the cgroup with 100 processes. Check that
|
||||
* the freeze time is 0.
|
||||
*/
|
||||
for (i = 0; i < 100; i++)
|
||||
cg_run_nowait(cgroup, child_fn, NULL);
|
||||
prev = curr;
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr != prev) {
|
||||
debug("Expect time (%ld) to be 0\n", curr);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 2) Wait for the group to become fully populated. Check
|
||||
* that the freeze time is 0.
|
||||
*/
|
||||
if (cg_wait_for_proc_count(cgroup, 100))
|
||||
goto cleanup;
|
||||
prev = curr;
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr != prev) {
|
||||
debug("Expect time (%ld) to be 0\n", curr);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 3) Freeze the cgroup and then populate it with 100 more
|
||||
* processes. Check that the freeze time continues to grow.
|
||||
*/
|
||||
if (cg_freeze_nowait(cgroup, true))
|
||||
goto cleanup;
|
||||
prev = curr;
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr <= prev) {
|
||||
debug("Expect time (%ld) to be more than previous check (%ld)\n",
|
||||
curr, prev);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < 100; i++)
|
||||
cg_run_nowait(cgroup, child_fn, NULL);
|
||||
prev = curr;
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr <= prev) {
|
||||
debug("Expect time (%ld) to be more than previous check (%ld)\n",
|
||||
curr, prev);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 4) Wait for the group to become fully populated. Check
|
||||
* that the freeze time is larger than at 3).
|
||||
*/
|
||||
if (cg_wait_for_proc_count(cgroup, 200))
|
||||
goto cleanup;
|
||||
prev = curr;
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr <= prev) {
|
||||
debug("Expect time (%ld) to be more than previous check (%ld)\n",
|
||||
curr, prev);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 5) Unfreeze the cgroup. Check that the freeze time is
|
||||
* larger than at 4).
|
||||
*/
|
||||
if (cg_freeze_nowait(cgroup, false))
|
||||
goto cleanup;
|
||||
prev = curr;
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr <= prev) {
|
||||
debug("Expect time (%ld) to be more than previous check (%ld)\n",
|
||||
curr, prev);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 6) Kill the processes. Check that the freeze time is the
|
||||
* same as it was at 5).
|
||||
*/
|
||||
if (cg_killall(cgroup))
|
||||
goto cleanup;
|
||||
prev = curr;
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr != prev) {
|
||||
debug("Expect time (%ld) to be unchanged from previous check (%ld)\n",
|
||||
curr, prev);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 7) Freeze and unfreeze the cgroup. Check that the freeze
|
||||
* time is larger than it was at 6).
|
||||
*/
|
||||
if (cg_freeze_nowait(cgroup, true))
|
||||
goto cleanup;
|
||||
if (cg_freeze_nowait(cgroup, false))
|
||||
goto cleanup;
|
||||
prev = curr;
|
||||
curr = cg_check_freezetime(cgroup);
|
||||
if (curr <= prev) {
|
||||
debug("Expect time (%ld) to be more than previous check (%ld)\n",
|
||||
curr, prev);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = KSFT_PASS;
|
||||
|
||||
cleanup:
|
||||
if (cgroup)
|
||||
cg_destroy(cgroup);
|
||||
free(cgroup);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that frozen time for a cgroup continues to work as expected,
|
||||
* even as processes are migrated. Frozen cgroup A's freeze time should
|
||||
* continue to increase and running cgroup B's should stay 0.
|
||||
*/
|
||||
static int test_cgfreezer_time_migrate(const char *root)
|
||||
{
|
||||
long prev_A, curr_A, curr_B;
|
||||
char *cgroup[2] = {0};
|
||||
int ret = KSFT_FAIL;
|
||||
int pid;
|
||||
|
||||
cgroup[0] = cg_name(root, "cg_time_test_migrate_A");
|
||||
if (!cgroup[0])
|
||||
goto cleanup;
|
||||
|
||||
cgroup[1] = cg_name(root, "cg_time_test_migrate_B");
|
||||
if (!cgroup[1])
|
||||
goto cleanup;
|
||||
|
||||
if (cg_create(cgroup[0]))
|
||||
goto cleanup;
|
||||
|
||||
if (cg_check_freezetime(cgroup[0]) < 0) {
|
||||
ret = KSFT_SKIP;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (cg_create(cgroup[1]))
|
||||
goto cleanup;
|
||||
|
||||
pid = cg_run_nowait(cgroup[0], child_fn, NULL);
|
||||
if (pid < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (cg_wait_for_proc_count(cgroup[0], 1))
|
||||
goto cleanup;
|
||||
|
||||
curr_A = cg_check_freezetime(cgroup[0]);
|
||||
if (curr_A) {
|
||||
debug("Expect time (%ld) to be 0\n", curr_A);
|
||||
goto cleanup;
|
||||
}
|
||||
curr_B = cg_check_freezetime(cgroup[1]);
|
||||
if (curr_B) {
|
||||
debug("Expect time (%ld) to be 0\n", curr_B);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Freeze cgroup A.
|
||||
*/
|
||||
if (cg_freeze_wait(cgroup[0], true))
|
||||
goto cleanup;
|
||||
prev_A = curr_A;
|
||||
curr_A = cg_check_freezetime(cgroup[0]);
|
||||
if (curr_A <= prev_A) {
|
||||
debug("Expect time (%ld) to be > 0\n", curr_A);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Migrate from A (frozen) to B (running).
|
||||
*/
|
||||
if (cg_enter(cgroup[1], pid))
|
||||
goto cleanup;
|
||||
|
||||
usleep(1000);
|
||||
curr_B = cg_check_freezetime(cgroup[1]);
|
||||
if (curr_B) {
|
||||
debug("Expect time (%ld) to be 0\n", curr_B);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
prev_A = curr_A;
|
||||
curr_A = cg_check_freezetime(cgroup[0]);
|
||||
if (curr_A <= prev_A) {
|
||||
debug("Expect time (%ld) to be more than previous check (%ld)\n",
|
||||
curr_A, prev_A);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = KSFT_PASS;
|
||||
|
||||
cleanup:
|
||||
if (cgroup[0])
|
||||
cg_destroy(cgroup[0]);
|
||||
free(cgroup[0]);
|
||||
if (cgroup[1])
|
||||
cg_destroy(cgroup[1]);
|
||||
free(cgroup[1]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* The test creates a cgroup and freezes it. Then it creates a child cgroup.
|
||||
* After that it checks that the child cgroup has a non-zero freeze time
|
||||
* that is less than the parent's. Next, it freezes the child, unfreezes
|
||||
* the parent, and sleeps. Finally, it checks that the child's freeze
|
||||
* time has grown larger than the parent's.
|
||||
*/
|
||||
static int test_cgfreezer_time_parent(const char *root)
|
||||
{
|
||||
char *parent, *child = NULL;
|
||||
int ret = KSFT_FAIL;
|
||||
long ptime, ctime;
|
||||
|
||||
parent = cg_name(root, "cg_test_parent_A");
|
||||
if (!parent)
|
||||
goto cleanup;
|
||||
|
||||
child = cg_name(parent, "cg_test_parent_B");
|
||||
if (!child)
|
||||
goto cleanup;
|
||||
|
||||
if (cg_create(parent))
|
||||
goto cleanup;
|
||||
|
||||
if (cg_check_freezetime(parent) < 0) {
|
||||
ret = KSFT_SKIP;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (cg_freeze_wait(parent, true))
|
||||
goto cleanup;
|
||||
|
||||
usleep(1000);
|
||||
if (cg_create(child))
|
||||
goto cleanup;
|
||||
|
||||
if (cg_check_frozen(child, true))
|
||||
goto cleanup;
|
||||
|
||||
/*
|
||||
* Since the parent was frozen the entire time the child cgroup
|
||||
* was being created, we expect the parent's freeze time to be
|
||||
* larger than the child's.
|
||||
*
|
||||
* Ideally, we would be able to check both times simultaneously,
|
||||
* but here we get the child's after we get the parent's.
|
||||
*/
|
||||
ptime = cg_check_freezetime(parent);
|
||||
ctime = cg_check_freezetime(child);
|
||||
if (ptime <= ctime) {
|
||||
debug("Expect ptime (%ld) > ctime (%ld)\n", ptime, ctime);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (cg_freeze_nowait(child, true))
|
||||
goto cleanup;
|
||||
|
||||
if (cg_freeze_wait(parent, false))
|
||||
goto cleanup;
|
||||
|
||||
if (cg_check_frozen(child, true))
|
||||
goto cleanup;
|
||||
|
||||
usleep(100000);
|
||||
|
||||
ctime = cg_check_freezetime(child);
|
||||
ptime = cg_check_freezetime(parent);
|
||||
|
||||
if (ctime <= ptime) {
|
||||
debug("Expect ctime (%ld) > ptime (%ld)\n", ctime, ptime);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = KSFT_PASS;
|
||||
|
||||
cleanup:
|
||||
if (child)
|
||||
cg_destroy(child);
|
||||
free(child);
|
||||
if (parent)
|
||||
cg_destroy(parent);
|
||||
free(parent);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* The test creates a parent cgroup and a child cgroup. Then, it freezes
|
||||
* the child and checks that the child's freeze time is greater than the
|
||||
* parent's, which should be zero.
|
||||
*/
|
||||
static int test_cgfreezer_time_child(const char *root)
|
||||
{
|
||||
char *parent, *child = NULL;
|
||||
int ret = KSFT_FAIL;
|
||||
long ptime, ctime;
|
||||
|
||||
parent = cg_name(root, "cg_test_child_A");
|
||||
if (!parent)
|
||||
goto cleanup;
|
||||
|
||||
child = cg_name(parent, "cg_test_child_B");
|
||||
if (!child)
|
||||
goto cleanup;
|
||||
|
||||
if (cg_create(parent))
|
||||
goto cleanup;
|
||||
|
||||
if (cg_check_freezetime(parent) < 0) {
|
||||
ret = KSFT_SKIP;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (cg_create(child))
|
||||
goto cleanup;
|
||||
|
||||
if (cg_freeze_wait(child, true))
|
||||
goto cleanup;
|
||||
|
||||
ctime = cg_check_freezetime(child);
|
||||
ptime = cg_check_freezetime(parent);
|
||||
if (ptime != 0) {
|
||||
debug("Expect ptime (%ld) to be 0\n", ptime);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ctime <= ptime) {
|
||||
debug("Expect ctime (%ld) <= ptime (%ld)\n", ctime, ptime);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = KSFT_PASS;
|
||||
|
||||
cleanup:
|
||||
if (child)
|
||||
cg_destroy(child);
|
||||
free(child);
|
||||
if (parent)
|
||||
cg_destroy(parent);
|
||||
free(parent);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* The test creates the following hierarchy:
|
||||
* A
|
||||
* |
|
||||
* B
|
||||
* |
|
||||
* C
|
||||
*
|
||||
* Then it freezes the cgroups in the order C, B, A.
|
||||
* Then it unfreezes the cgroups in the order A, B, C.
|
||||
* Then it checks that C's freeze time is larger than B's and
|
||||
* that B's is larger than A's.
|
||||
*/
|
||||
static int test_cgfreezer_time_nested(const char *root)
|
||||
{
|
||||
char *cgroup[3] = {0};
|
||||
int ret = KSFT_FAIL;
|
||||
long time[3] = {0};
|
||||
int i;
|
||||
|
||||
cgroup[0] = cg_name(root, "cg_test_time_A");
|
||||
if (!cgroup[0])
|
||||
goto cleanup;
|
||||
|
||||
cgroup[1] = cg_name(cgroup[0], "B");
|
||||
if (!cgroup[1])
|
||||
goto cleanup;
|
||||
|
||||
cgroup[2] = cg_name(cgroup[1], "C");
|
||||
if (!cgroup[2])
|
||||
goto cleanup;
|
||||
|
||||
if (cg_create(cgroup[0]))
|
||||
goto cleanup;
|
||||
|
||||
if (cg_check_freezetime(cgroup[0]) < 0) {
|
||||
ret = KSFT_SKIP;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (cg_create(cgroup[1]))
|
||||
goto cleanup;
|
||||
|
||||
if (cg_create(cgroup[2]))
|
||||
goto cleanup;
|
||||
|
||||
if (cg_freeze_nowait(cgroup[2], true))
|
||||
goto cleanup;
|
||||
|
||||
if (cg_freeze_nowait(cgroup[1], true))
|
||||
goto cleanup;
|
||||
|
||||
if (cg_freeze_nowait(cgroup[0], true))
|
||||
goto cleanup;
|
||||
|
||||
usleep(1000);
|
||||
|
||||
if (cg_freeze_nowait(cgroup[0], false))
|
||||
goto cleanup;
|
||||
|
||||
if (cg_freeze_nowait(cgroup[1], false))
|
||||
goto cleanup;
|
||||
|
||||
if (cg_freeze_nowait(cgroup[2], false))
|
||||
goto cleanup;
|
||||
|
||||
time[2] = cg_check_freezetime(cgroup[2]);
|
||||
time[1] = cg_check_freezetime(cgroup[1]);
|
||||
time[0] = cg_check_freezetime(cgroup[0]);
|
||||
|
||||
if (time[2] <= time[1]) {
|
||||
debug("Expect C's time (%ld) > B's time (%ld)", time[2], time[1]);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (time[1] <= time[0]) {
|
||||
debug("Expect B's time (%ld) > A's time (%ld)", time[1], time[0]);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = KSFT_PASS;
|
||||
|
||||
cleanup:
|
||||
for (i = 2; i >= 0 && cgroup[i]; i--) {
|
||||
cg_destroy(cgroup[i]);
|
||||
free(cgroup[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define T(x) { x, #x }
|
||||
struct cgfreezer_test {
|
||||
int (*fn)(const char *root);
|
||||
@@ -819,6 +1475,13 @@ struct cgfreezer_test {
|
||||
T(test_cgfreezer_stopped),
|
||||
T(test_cgfreezer_ptraced),
|
||||
T(test_cgfreezer_vfork),
|
||||
T(test_cgfreezer_time_empty),
|
||||
T(test_cgfreezer_time_simple),
|
||||
T(test_cgfreezer_time_populate),
|
||||
T(test_cgfreezer_time_migrate),
|
||||
T(test_cgfreezer_time_parent),
|
||||
T(test_cgfreezer_time_child),
|
||||
T(test_cgfreezer_time_nested),
|
||||
};
|
||||
#undef T
|
||||
|
||||
|
||||
Reference in New Issue
Block a user