Command Section

KERN_TESTFRWK(9)       FreeBSD Kernel Developer's Manual      KERN_TESTFRWK(9)

NAME
     kern_testfrwk - A kernel testing framework

SYNOPSIS
     kldload 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>.

FreeBSD 13.1-RELEASE-p6        November 12, 2015       FreeBSD 13.1-RELEASE-p6

Command Section

man2web Home...