[Return to Library] [Contents] [Previous Chapter] [Next Section] [Next Chapter] [Index] [Help]


7    Using Kernel Threads-Related Interfaces

This chapter discusses the kernel interfaces that allow you to peform kernel threads-related operations. Specifically, these interfaces allow you to:

In addition, the chapter discusses the thread and task data structures that these kernel threads-related interfaces use.


[Return to Library] [Contents] [Previous Chapter] [Next Section] [Next Chapter] [Index] [Help]


7.1    Data Structures That Kernel Thread Interfaces Use

This section discusses the two data structures that kernel threads-related interfaces use: thread and task. The thread data structure contains kernel threads-related information. Device drivers typically use the wait_result member (along with the current_thread interface) to check for the result of the wait. The header file thread.h shows a typedef statement that assigns the alternate name thread_t for a pointer to the thread structure. Many of the kernel threads-related interfaces operate on these pointers to thread structures.

The thread structure is an opaque data structure; that is, all of its associated members (except for the wait_result member) are referenced and manipulated by the Digital UNIX operating system and not by the user of kernel threads.

The task data structure contains task-related information. The header file task.h shows a typedef statement that assigns the alternate name task_t for a pointer to the task structure. Some of the kernel threads-related interfaces require that you pass a pointer to the task structure.

The task structure is an opaque data structure; that is, all of its associated members are referenced and manipulated by the Digital UNIX operating system and not by the user of kernel threads.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.2    Starting a Kernel Thread

You can start (and create) a kernel thread with the following interfaces:

The following sections describe each of these interfaces.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.2.1    Starting a Kernel Thread at a Specified Entry Point

To start (and create) a kernel thread at a specified entry point and with a specified argument, call the kernel_thread_w_arg interface. The kernel_thread_w_arg interface creates and starts a kernel thread in the specified task at the specified entry point with a specified argument. The kernel_thread_w_arg interface passes the specified argument to the newly created kernel thread. The kernel_thread_w_arg interface creates and starts a kernel thread with timeshare scheduling. A kernel thread created with timeshare scheduling means that its priority degrades if it consumes an inordinate amount of CPU resources. A device driver should call kernel_thread_w_arg only for long-running tasks. A device driver should always attach a kernel thread to the ``first task.''

This interface is actually a convenience wrapper for the thread_create interface (which creates the kernel thread) and the thread_start interface (which starts the newly created kernel thread).

The following code fragment shows a call to kernel_thread_w_arg by the if_fta device driver's fta_transition_state interface. The fta_transition_state interface changes the state of the driver by performing certain fixed functions for any given particular state.


.
.
.
#include <kern/thread.h> [1]
.
.
.
#define ADAP "fta"
.
.
.
extern task_t first_task; [2]
.
.
.

struct fta_softc {
.
.
.
short reinit_thread_started; /* reinit thread running? */
.
.
.
}; [3]
.
.
.
struct ifnet {
.
.
.
short if_unit; /* subunit for lower-level driver */
.
.
.
};
.
.
.
fta_transition_state(sc, unit, state) struct fta_softc *sc; short unit; short state; {
.
.
.
switch(state) {
.
.
.
case PI_OPERATIONAL: { int s; NODATA_CMD *req_buff; thread_t thread; [4] if (sc->reinit_thread_started == FALSE) { [5] thread = kernel_thread_w_arg(first_task, fta_error_recovery, (void *)sc); [6] if (thread == NULL) { [7] printf("%s%d: Cannot start error recovery thread.\n", ADAP, ifp->if_unit); } sc->reinit_thread_started = TRUE; }
.
.
.
}

  1. Includes the header file /usr/sys/include/kern/thread.h. The thread.h file defines structures that kernel threads-related interfaces use. [Return to example]

  2. Declares a pointer to a task structure and calls it first_task. Every kernel thread must be part of a task. You pass this pointer to the kernel_thread_w_arg interface. [Return to example]

  3. Defines an fta_softc data structure. The example shows only the member related to the discussion of the kernel_thread_w_arg interface. [Return to example]

  4. Declares a pointer to a thread structure and calls it thread. This variable stores the thread structure pointer returned by kernel_thread_w_arg. [Return to example]

  5. If the reinitialized kernel thread evaluates to FALSE (the reinit kernel thread is not running), calls the kernel_thread_w_arg interface. [Return to example]

  6. Calls the kernel_thread_w_arg interface.

    The kernel_thread_w_arg interface takes three arguments:

    [Return to example]

  7. Upon successful completion, kernel_thread_w_arg returns a pointer to the thread structure associated with the kernel thread started at the specified entry point. Device drivers can use this pointer as a handle to a specific kernel thread in calls to other kernel threads-related interfaces.

    The fta_transition_state interface checks the return. If the return is NULL, kernel_thread_w_arg did not create the error recovery kernel thread. The fta_transition_state interface calls printf to display an appropriate message on the console terminal.

    If the return is not NULL, fta_transition_state sets the reinit_thread_started member to the value TRUE to indicate that the error recovery kernel thread is started. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.2.2    Starting a Fixed Priority Kernel Thread Dedicated to Interrupt Service

To start (and create) a fixed priority kernel thread dedicated to interrupt service, call the kernel_isrthread interface. The kernel_isrthread interface creates and starts a kernel thread at the specified entry point. This kernel thread handles only interrupt service requests in the specified task and at the specified priority level. A device driver should always attach a kernel thread to the ``first task.''

The following code fragment shows a call to kernel_isrthread by the if_fta device driver's ftaprobe interface.

The ftaprobe interface determines if the adapter exists, fills in a variety of register values, and initializes a variety of descriptors.


.
.
.
#include <kern/thread.h> [1]
.
.
.
extern task_t first_task; [2]
.
.
.
ftaprobe(reg, ctlr) io_handle_t reg; struct controller *ctlr; {
.
.
.
thread = kernel_isrthread(first_task, fta_rec_intr, BASEPRI_SYSTEM); [3]
.
.
.
}

  1. Includes the header file /usr/sys/include/kern/thread.h. The thread.h file defines structures that kernel threads-related interfaces use. [Return to example]

  2. Declares a pointer to a task structure and calls it first_task. Every kernel thread must be part of a task. You pass this pointer to the kernel_isrthread interface. [Return to example]

  3. Calls the kernel_isrthread interface.

    The kernel_isrthread interface takes three arguments:

    [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.3    Blocking (Putting to Sleep) a Kernel Thread

You can block (put to sleep) a kernel thread with the following interfaces:

Each of these interfaces is described in the following sections.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.3.1    Asserting That the Current Kernel Thread Is About to Block Until the Specified Event Occurs

To assert that the current kernel thread is about to block until some specified event occurs, call the assert_wait_mesg interface. To actually block (put to sleep) the current kernel thread, call thread_block.

The following code fragment shows a call to assert_wait_mesg and thread_block by the if_fta device driver's fta_error_recovery interface. The fta_error_recovery interface is a kernel thread that starts up when the adapter becomes operational. This kernel thread resets the adapter if a fatal error occurs. The code fragment also shows the code that contains the call to kernel_thread_w_arg, which calls fta_error_recovery.


.
.
.
#include <kern/thread.h> [1]
.
.
.
#define ADAP "fta"
.
.
.
extern task_t first_task; [2]
.
.
.

struct fta_softc {
.
.
.
short reinit_thread_started; /* reinit thread running? */
.
.
.
short error_recovery_flag; /* flag to wake up a process */
.
.
.
}; [3]
.
.
.
struct ifnet {
.
.
.
short if_unit; /* subunit for lower-level driver */
.
.
.
};
.
.
.
fta_transition_state(sc, unit, state) struct fta_softc *sc; short unit; short state; {
.
.
.
switch(state) {
.
.
.
case PI_OPERATIONAL: { int s; NODATA_CMD *req_buff; thread_t thread; [4] if (sc->reinit_thread_started == FALSE) { [5] thread = kernel_thread_w_arg(first_task, fta_error_recovery, (void *)sc); [6] if (thread == NULL) { [7] printf("%s%d: Cannot start error recovery thread.\n", ADAP, ifp->if_unit); } sc->reinit_thread_started = TRUE; }

.
.
.
void fta_error_recovery(sc) [8] struct fta_softc *sc; [9] { struct ifnet *ifp; /* * Collect the argument left by the kernel_thread_w_arg(). */ ifp = &sc->is_if; for(;;) { [10] assert_wait_mesg((vm_offset_t)&sc->error_recovery_flag, TRUE,"ftaerr"); [11] thread_block(); [12] /* Performs tasks to reset the adapter */
.
.
.
}
.
.
.
}

  1. Includes the header file /usr/sys/include/kern/thread.h. The thread.h file defines structures that kernel threads-related interfaces use. [Return to example]

  2. Declares a pointer to a task structure and calls it first_task. Every kernel thread must be part of a task. You pass this pointer to the kernel_thread_w_arg interface. [Return to example]

  3. Defines an fta_softc data structure. The example shows only the members related to the discussion of the kernel_thread_w_arg, assert_wait_mesg, and thread_block interfaces. [Return to example]

  4. Declares a pointer to a thread structure and calls it thread. This variable stores the thread structure pointer returned by kernel_thread_w_arg. [Return to example]

  5. If the reinitialized kernel thread evaluates to FALSE (the reinit kernel thread is not running), calls the kernel_thread_w_arg interface. [Return to example]

  6. Calls the kernel_thread_w_arg interface.

    The kernel_thread_w_arg interface takes three arguments:

    [Return to example]

  7. Upon successful completion, kernel_thread_w_arg returns a pointer to the thread structure associated with the kernel thread started at the specified entry point. Device drivers can use this pointer as a handle to a specific kernel thread in calls to other kernel threads-related interfaces.

    The fta_transition_state interface checks the return. If the return is NULL, kernel_thread_w_arg did not create the error recovery kernel thread. The fta_transition_state interface calls printf to display an appropriate message on the console terminal.

    If the return is not NULL, fta_transition_state sets the reinit_thread_started member to the value TRUE to indicate that the error recovery kernel thread is started. [Return to example]

  8. The fta_error_recovery interface is a kernel thread that starts up when the adapter becomes operational. This kernel thread resets the adapter if a fatal error occurs.

    A fatal error requires resetting the adapter; this error is discovered during a device interrrupt. It is necessary to block in the interrupt service interface while resetting the adapter. Because it is not legal to block in an interrupt service interface, the fta_transition_state calls this kernel thread to perform the reset operation on the adapter. [Return to example]

  9. This is the argument passed to fta_error_recovery by the kernel_thread_w_arg interface. [Return to example]

  10. Sets up an infinite loop that executes when the adapter becomes operational. [Return to example]

  11. Calls the assert_wait_mesg interface to assert that the current kernel thread is about to block (sleep).

    The assert_wait_mesg interface takes three arguments:

    The assert_wait_mesg interface does not return a value. [Return to example]

  12. Calls the thread_block interface. The thread_block interface blocks (puts to sleep) the current kernel thread and selects the next kernel thread to start (run). The interface schedules the next kernel thread onto this CPU.

    The thread_block interface does not return a value. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.3.2    Using the Symmetric Multiprocessor Sleep Interface

To block the current kernel thread, call the mpsleep interface. The following code fragment shows a call to mpsleep by the if_fta device driver's fta_error_recovery interface. The fta_error_recovery interface is a kernel thread that starts up when the adapter becomes operational. This kernel thread resets the adapter if a fatal error occurs. The code fragment also shows the use of a simple lock with the mpsleep interface.


.
.
.
struct fta_softc {
.
.
.
short error_recovery_flag; /* flag to wake up a process */
.
.
.
int is_state; [1] simple_lock_data_t lk_fta_softc; [2]
.
.
.
};
.
.
.
void fta_error_recovery(sc) struct fta_softc *sc; { struct ifnet *ifp; /* * Collect the argument left by the kernel_thread_w_arg(). */ ifp = &sc->is_if; simple_lock (&sc->lk_fta_softc); [3] while (sc->is_state == RUN_NOT) { [4] for(;;) { [5] mpsleep ((vm_offset_t)&sc->error_recovery_flag, PCATCH, "ftaerr", 0, &sc->lk_fta_softc, MS_LOCK_SIMPLE | MS_LOCK_ON_ERROR)) [6]
/* Performs tasks to reset the adapter */
.
.
.
} } }
.
.
.

  1. Declares a member to hold state flags. [Return to example]

  2. Declares a simple lock structure pointer as a member of the fta_softc structure to protect the integrity of the data stored in the members of this structure. Assume that this simple lock was initialized in the example driver's attach interface. The fta_error_recovery interface passes this simple lock structure pointer to the mpsleep interface. [Return to example]

  3. Calls the simple_lock interface to assert an exclusive access on the following code block. [Return to example]

  4. While the is_state flag is equal to the RUN_NOT flag, execute the for loop. [Return to example]

  5. Sets up an infinite loop that executes when the is_state flag is equal to the RUN_NOT flag. [Return to example]

  6. Calls the mpsleep interface to block (put to sleep) the current kernel thread.

    The mpsleep interface takes six arguments:

    The mpsleep interface blocks (puts to sleep) the current kernel thread until a wakeup is issued on the address you specified in the channel argument. This interface is the symmetric multiprocessor (SMP) sleep call. The kernel thread blocks (sleeps) a maximum of timo divided by hz seconds. The value zero (0) means there is no timeout.

    If you pass the PCATCH flag to the pri argument, mpsleep checks signals before and after blocking (sleeping). Otherwise, mpsleep does not check signals.

    The mpsleep interface allows you to specify a pointer to a simple or complex lock structure that is associated with some resource. This interface unlocks this resource prior to blocking (sleeping). The flags argument specifies the lock type. The mpsleep interface releases the lock when the current kernel thread successfully performs an assert wait on the specified channel.

    The mpsleep interface returns the value zero (0) if awakened (success) and EWOULDBLOCK if the timeout specified in the timo argument expires (failure). On success, mpsleep relocks the lock if you did not set MS_LOCK_NO_RELOCK in flags. On failure, it leaves the lock unlocked. If you set the flags argument to MS_LOCK_ON_ERROR, mpsleep relocks the lock on failures. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.4    Unblocking (Awakening) Kernel Threads

You can unblock (awaken) a kernel thread with the following interfaces:

The following code fragment compares the calls to thread_wakeup_one and thread_wakeup by the if_fta device driver's ftaintr interface.

ftaintr(unit)
int unit;
{

.
.
.
fta_transition_state(sc, unit, PI_OPERATIONAL); [1]
.
.
.
/******************************************************* * Code fragment 1: Shows call to thread_wakeup_one * *******************************************************/
.
.
.
thread_wakeup_one((vm_offset_t)&sc->error_recovery_flag); [2] }

ftaintr(unit)
int unit;
{

.
.
.
fta_transition_state(sc, unit, PI_OPERATIONAL); [1]
.
.
.
/******************************************************* * Code fragment 2: Shows call to thread_wakeup * *******************************************************/
.
.
.
thread_wakeup((vm_offset_t)&sc->error_recovery_flag); [2] }

  1. The two code fragments show the call to fta_transition_state. The fta_transition_state interface changes the state of the driver by performing certain fixed functions for any given particular state.

    After fta_transition_state performs its tasks, it returns to ftaintr, which calls one of the following unblocking (or wakeup) kernel threads interfaces: thread_wakeup_one or thread_wakeup. Both of these interfaces take an event as the first argument. [Return to example]

  2. Code fragments 1 and 2 show that the first argument for each of the interfaces specifies the event associated with the current kernel thread. Both code fragments pass the address of the value stored in the error_recovery_flag member.

    The driver's fta_error_recovery interface is the kernel thread created and started to perform error recovery tasks. The fta_error_recovery interface blocked on the event stored in the error_recovery_flag member. [Return to example]

The thread_wakeup_one interface wakes up only the first kernel thread in the hash chain waiting for the event specified in the event argument. This interface is actually a convenience wrapper for the thread_wakeup_prim interface with the one_thread argument set to TRUE (wake up only the first kernel thread) and the result argument set to THREAD_AWAKENED (wakeup is normal).

The thread_wakeup interface wakes up all kernel threads waiting for the event specified in the event argument. This interface is actually a convenience wrapper for the thread_wakeup_prim interface with the one_thread argument set to FALSE (wake up all kernel threads) and the result argument set to THREAD_AWAKENED (wakeup is normal).


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.5    Terminating a Kernel Thread

To terminate a kernel thread, call the thread_terminate interface. The thread_terminate interface prepares to stop or permanently stops execution of the specified kernel thread. You created and started this kernel thread in a previous call to the kernel_isrthread or kernel_thread_w_arg interface. These interfaces return a pointer to the thread structure associated with the newly created and started kernel thread. Device drivers use this pointer as a handle to identify the specific kernel thread that thread_terminate stops executing.

Typically, a kernel thread terminates itself. However, one kernel thread can terminate another kernel thread. A kernel thread that terminates itself must call thread_halt_self immediately after the call to thread_terminate. The reason for this is that thread_terminate only prepares the self-terminating kernel thread to stop execution. The thread_halt_self interface completes the work needed to stop execution (by performing the appropriate cleanup work) of the self-terminating kernel thread.

You do not need to terminate every kernel thread that you create. You should not terminate a kernel thread that is waiting for some event. The basic rule is that you should terminate only those kernel threads that you do not need anymore. For example, if a dynamically configured device driver uses kernel threads, you should terminate them in the CFG_OP_UNCONFIGURE entry point of the loadable driver's configure interface. The kernel threads are no longer needed after the driver is unconfigured.

Note that the thread_terminate interface (for kernel threads that terminate other kernel threads) not only permanently stops execution of the specified kernel thread, but it also frees any resources associated with that kernel thread; thus, this kernel thread can no longer be used.

The following code fragment shows you how the if_fta device driver's fta_error_recovery kernel thread terminates itself by calling thread_terminate and thread_halt_self. The fta_error_recovery interface is a kernel thread that starts up when the adapter becomes operational. This kernel thread resets the adapter if a fatal error occurs. The code fragment also shows the code that contains the call to kernel_thread_w_arg, which calls fta_error_recovery.


.
.
.
#include <kern/thread.h>
.
.
.
#define ADAP "fta"
.
.
.
extern task_t first_task;
.
.
.
struct fta_softc {
.
.
.
short reinit_thread_started; /* reinit thread running? */
.
.
.
short error_recovery_flag; /* flag to wake up a process */
.
.
.
};
.
.
.
struct ifnet {
.
.
.
short if_unit; /* subunit for lower-level driver */
.
.
.
};
.
.
.
fta_transition_state(sc, unit, state) struct fta_softc *sc; short unit; short state; {
.
.
.
switch(state) {
.
.
.
case PI_OPERATIONAL: { int s; NODATA_CMD *req_buff; thread_t err_recov_thread; if (sc->reinit_thread_started == FALSE) { err_recov_thread = kernel_thread_w_arg(first_task, fta_error_recovery, (void *)sc); if (err_recov_thread == NULL) { printf("%s%d: Cannot start error recovery thread.\n", ADAP, ifp->if_unit); } sc->reinit_thread_started = TRUE; }
.
.
.
/* Perform other cases */
.
.
.
void fta_error_recovery(sc) struct fta_softc *sc; { struct ifnet *ifp; int ret_val; /* * Collect the argument left by the kernel_thread_w_arg(). */ ifp = &sc->is_if; for(;;) { assert_wait_mesg((vm_offset_t)&sc->error_recovery_flag, TRUE,"ftaerr"); thread_block(); if (current_thread()->wait_result == THREAD_SHOULD_TERMINATE) { [1] ret_val = thread_terminate(err_recov_thread); [2] thread_halt_self(); [3] } }
.
.
.
/* Performs tasks to reset the adapter */
.
.
.
}

  1. If the wait_result member of the thread structure pointer associated with the current kernel thread is set to the THREAD_SHOULD_TERMINATE constant, there is no need to keep this error recovery kernel thread. The fta_error_recovery interface uses the current_thread interface (macro) to obtain the pointer to the currently running kernel thread.

    The current_thread interface (macro) is a pointer to the currently running kernel thread. Typically, device drivers use this interface to reference the wait_result member of the thread structure pointer associated with the currently running kernel thread. A device driver calls current_thread after calls to assert_wait_mesg and thread_block. If the device driver needs to set a timeout, then it calls current_thread after calls to assert_wait_mesg, thread_set_timeout, and thread_block. [Return to example]

  2. Calls the thread_terminate interface to terminate the error recovery kernel thread.

    The thread_terminate interface takes a thread_to_terminate argument, which is a pointer to the thread structure associated with the kernel thread that you want to terminate. This pointer was returned in a previous call to the kernel_isrthread or kernel_thread_w_arg interface.

    The kernel_thread_w_arg interface returns this pointer to the err_recov_thread variable. This variable is passed to thread_terminate.

    Upon successfully terminating the specified kernel thread, thread_terminate returns the constant KERN_SUCCESS. If the thread structure pointer passed to the thread_to_terminate argument does not identify a valid kernel thread, thread_terminate returns the constant KERN_INVALID_ARGUMENT. On any other error, thread_terminate returns the constant KERN_FAILURE. [Return to example]

  3. A kernel thread that terminates itself must call thread_halt_self immediately after the call to thread_terminate. The reason for this is that thread_terminate only prepares the self-terminating kernel thread to stop execution. The thread_halt_self interface completes the work needed to stop execution (by performing the appropriate cleanup work) of the self-terminating kernel thread. [Return to example]

The following code fragment shows you how the if_fta device driver's fta_transition_state interface terminates another kernel thread (in this example, the error recovery kernel thread) by calling only thread_terminate. The fta_transition_state interface changes the state of the driver by performing certain fixed tasks for a given state.


.
.
.
#include <kern/thread.h>
.
.
.
#define ADAP "fta"
.
.
.
extern task_t first_task;
.
.
.
struct fta_softc {
.
.
.
short reinit_thread_started; /* reinit thread running? */
.
.
.
short error_recovery_flag; /* flag to wake up a process */
.
.
.
};
.
.
.
struct ifnet {
.
.
.
short if_unit; /* subunit for lower-level driver */
.
.
.
};
.
.
.
fta_transition_state(sc, unit, state) struct fta_softc *sc; short unit; short state; {
.
.
.
int ret_val;
.
.
.
switch(state) {
.
.
.
case PI_OPERATIONAL: { int s; NODATA_CMD *req_buff; thread_t err_recov_thread; if (sc->reinit_thread_started == FALSE) { err_recov_thread = kernel_thread_w_arg(first_task, fta_error_recovery, (void *)sc); if (err_recov_thread == NULL) { printf("%s%d: Cannot start error recovery thread.\n", ADAP, ifp->if_unit); } sc->reinit_thread_started = TRUE; }
.
.
.
/* Perform other cases */
.
.
.
/* After performing all other cases, no more need for the */ /* kernel thread */ case PI_SHUTDOWN: { [1] ret_val = thread_terminate(err_recov_thread); [2]
.
.
.
void fta_error_recovery(sc) struct fta_softc *sc; { struct ifnet *ifp; /* * Collect the argument left by the kernel_thread_w_arg(). */ ifp = &sc->is_if; for(;;) { assert_wait_mesg((vm_offset_t)&sc->error_recovery_flag, TRUE,"ftaerr"); thread_block(); /* Performs tasks to reset the adapter */
.
.
.
}
.
.
.
}

  1. After the fta_error_recovery interface completes its work and returns to fta_transition_state, there is no need to keep this error recovery kernel thread. The fta_transition_state interface sets up a case statement to handle the termination of the error recovery kernel thread. [Return to example]

  2. Calls the thread_terminate interface to terminate the error recovery kernel thread.

    The thread_terminate interface takes a thread_to_terminate argument, which is a pointer to the thread structure associated with the kernel thread that you want to terminate. This pointer was returned in a previous call to the kernel_isrthread or kernel_thread_w_arg interface.

    The kernel_thread_w_arg interface returns this pointer to the err_recov_thread variable. This variable is passed to thread_terminate.

    Upon successfully terminating the specified kernel thread, thread_terminate returns the constant KERN_SUCCESS. If the thread structure pointer passed to the thread_to_terminate argument does not identify a valid kernel thread, thread_terminate returns the constant KERN_INVALID_ARGUMENT. On any other error, thread_terminate returns the constant KERN_FAILURE. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Chapter] [Index] [Help]


7.6    Setting a Timer for the Current Kernel Thread

To set a time delay on the current kernel thread, call the thread_set_timeout interface. The thread_set_timeout interface must be called as follows:

  1. Lock the resource.

  2. Call assert_wait_mesg to assert that the current kernel thread is about to block.

  3. Unlock the resource.

  4. Call thread_set_timeout to set the time of delay for the current kernel thread.

  5. Call thread_block to block (put to sleep) the current kernel thread.

The following code fragment shows a call to thread_set_timeout by the if_fta device driver's fta_cmd_req interface. This interface puts a DMA request onto the request queue of the adapter.


.
.
.
#include <kern/thread.h> [1]
.
.
.
struct fta_softc {
.
.
.
struct cmd_buf *q_first; /* first in the request queue */ struct cmd_buf *q_last; /* last in the request queue */ lock_data_t cmd_buf_q_lock; /* lock for the cmdreq queue */
.
.
.
}; [2]
.
.
.
short fta_cmd_req(cmdbuf, sc, command) struct cmd_buf *cmdbuf; struct fta_softc *sc; short command; {
.
.
.
lock_write(&sc->cmd_buf_q_lock); [3]

.
.
.
assert_wait_mesg((vm_offset_t)cmdbuf, TRUE, "dmareq"); [4] lock_done(&sc->cmd_buf_q_lock); [5] thread_set_timeout(hz * 2); [6] thread_block(); [7]
.
.
.
}

  1. Includes the header file /usr/sys/include/kern/thread.h. The thread.h file defines structures that kernel threads-related interfaces use. [Return to example]

  2. Defines an fta_softc data structure. For the purposes of this example, the fta_softc structure contains the following members:

    [Return to example]

  3. Calls the lock_write interface to lock the command request queue.

    The lock_write interface takes one argument: a pointer to the complex lock structure, lock. This is the lock structure associated with the resource on which you want to assert a complex lock with write access. The fta_cmd_req interface passes the address of the cmd_buf_q_lock member of the fta_softc structure pointer. [Return to example]

  4. Calls the assert_wait_mesg interface to assert that the current kernel thread is about to block.

    The assert_wait_mesg interface takes three arguments:

    [Return to example]

  5. Calls the lock_done interface to unlock the command request queue.

    The lock_done interface takes one argument: a pointer to the complex lock structure, lock. The fta_cmd_req interface passes the address of the cmd_buf_q_lock member of the fta_softc structure pointer. [Return to example]

  6. Calls the thread_set_timeout interface to set a timer for the current kernel thread.

    The thread_set_timeout interface takes one argument: the amount of time to wait for an event. The time is used in conjunction with the assert_wait interface. The fta_cmd_req interface passes the value hz * 2.

    The time you specify to wait for the event is automatically canceled when the kernel thread awakes.

    The thread_set_timeout interface does not return a value. [Return to example]

  7. Calls the thread_block interface to block (put to sleep) the current kernel thread. [Return to example]