Provided by: freebsd-manpages_12.2-1_all bug

NAME

     kern_testfrwk — A kernel testing framework

SYNOPSIS

     kld_load kern_testfrwk

DESCRIPTION

     So what is this sys/tests directory in the kernel all about?

     Have you ever wanted to test a part of the FreeBSD kernel in some way and you had no real
     way from user-land to make what you want to occur happen?  Say an error path or situation
     where locking occurs in a particular manner that happens only once in a blue moon?

     If so, then the kernel test framework is just what you are looking for.  It is designed to
     help you create the situation you want.

     There are two components to the system: the test framework and your test.  This document
     will describe both components and use the test submitted with the initial commit of this
     code to discuss the test (callout_test(4)).  All of the tests become kernel loadable
     modules.  The test you write should have a dependency on the test framework.  That way it
     will be loaded automatically with your test.  For example, you can see how to do this in the
     bottom of callout_test.c in sys/tests/callout_test/callout_test.c.

     The framework itself is in sys/tests/framework/kern_testfrwk.c.  Its job is to manage the
     tests that are loaded.  (More than one can be loaded.)  The idea is pretty simple; you load
     the test framework and then load your test.

     When your test loads, you register your tests with the kernel test framework.  You do that
     through a call to kern_testframework_register().  Usually this is done at the module load
     event as shown below:

                   switch (type) {
                   case MOD_LOAD:
                           err = kern_testframework_register("callout_test",
                               run_callout_test);

     Here the test is "callout_test" and it is registered to run the function run_callout_test()
     passing it a struct kern_test *ptr.  The kern_test structure is defined in kern_testfrwk.h.

           struct kern_test {
                   char name[TEST_NAME_LEN];
                   int num_threads;  /* Fill in how many threads you want */
                   int tot_threads_running;       /* Private to framework */
                   uint8_t test_options[TEST_OPTION_SPACE];
           };

     The user sends this structure down via a sysctl to start your test.  He or she places the
     same name you registered ("callout_test" in our example) in the name field.  The user can
     also set the number of threads to run with num_threads.

     The framework will start the requested number of kernel threads, all running your test at
     the same time.  The user does not specify anything in tot_threads_running; it is private to
     the framework.  As the framework calls each of your tests, it will set the
     tot_threads_running to the index of the thread that your call is made from.  For example, if
     the user sets num_threads to 2, then the function run_callout_test() will be called once
     with tot_threads_running to 0, and a second time with tot_threads_running set to 1.

     The test_options field is a test-specific set of information that is an opaque blob.  It is
     passed in from user space and has a maximum size of 256 bytes.  You can pass arbitrary test
     input in the space.  In the case of callout_test we reshape that to:

           struct callout_test {
                   int number_of_callouts;
                   int test_number;
           };

     So the first lines of run_callout_test() does the following to get at the user specific
     data:

                   struct callout_test *u;
                   size_t sz;
                   int i;
                   struct callout_run *rn;
                   int index = test->tot_threads_running;

                   u = (struct callout_test *)test->test_options;

     That way it can access: u->test_number (there are two types of tests provided with this
     test) and u->number_of_callouts (how many simultaneous callouts to run).

     Your test can do anything with these bytes.  So the callout_test in question wants to create
     a situation where multiple callouts are all run, that is the number_of_callouts, and it
     tries to cancel the callout with the new callout_async_drain().  The threads do this by
     acquiring the lock in question, and then starting each of the callouts.  It waits for the
     callouts to all go off (the executor spins waits).  This forces the situation that the
     callouts have expired and are all waiting on the lock that the executor holds.  After the
     callouts are all blocked, the executor calls callout_async_drain() on each callout and
     releases the lock.

     After all the callouts are done, a total status is printed showing the results via
     printf(9).  The human tester can run dmesg(8) to see the results.  In this case it is
     expected that if you are running test 0, all the callouts expire on the same CPU so only one
     callout_drain function would have been called.  the number of zero_returns should match the
     number of callout_drains that were called, i.e., 1.  The one_returns should be the remainder
     of the callouts.  If the test number was 1, the callouts were spread across all CPUs.  The
     number of zero_returns will again match the number of drain calls made which matches the
     number of CPUs that were put in use.

     More than one thread can be used with this test, though in the example case it is probably
     not necessary.

     You should not need to change the framework.  Just add tests and register them after
     loading.

AUTHORS

     The kernel test framework was written by Randall Stewart <rrs@FreeBSD.org> with help from
     John Mark Gurney <jmg@FreeBSD.org>.