After you decide that the complex lock method is the appropriate method for locking specific resources, you use the complex lock routines to accomplish the locking. To use complex locks in a kernel module, perform the following tasks:
Declare a complex lock data structure (Section 8.1)
Initialize a complex lock (Section 8.2)
Perform access operations on a complex lock (Section 8.3)
Terminate a complex lock (Section 8.4)
To illustrate the use of these routines, the chapter uses code from
an example kernel module called
if_fta
, which operates
on some
FTA
device.
8.1 Declaring a Complex Lock Data Structure
Before you use a complex lock, declare a complex lock data structure
for the resource that you want to lock.
The following code fragment shows
how to declare a complex lock data structure for a specific field of the
fta_kern_str
structure:
#include <kern/lock.h> [1] . struct cmd_buf { u_long *req_buf; u_long *rsp_buf; short timeout; struct cmd_buf *next; }; [2]
.
.
.
struct fta_kern_str { . 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 command */ /* request queue */
.
.
.
}; [3]
.
.
.
Includes the header file
/usr/sys/include/kern/lock.h
.
The
lock.h
file defines the simple spin
lock and complex lock structures that kernel modules use for synchronization
on single-processor and multiprocessor systems.
[Return to example]
Defines a
cmd_buf
data structure.
The
fta_kern_str
structure declares two instances of
cmd_buf
.
This structure describes a command queue and is a candidate for
locking in a symmetric multiprocessing (SMP) environment.
You must protect
the integrity of the data that is stored in the command queue from multiple
writes by more than one kernel thread.
[Return to example]
Defines an
fta_kern_str
data structure.
The example shows only those fields that are related to the discussion of
complex locks.
In this example, the
fta_kern_str
structure contains
the following fields:
q_first
Specifies a pointer to a
cmd_buf
data structure.
This field represents the first command queue in the linked list.
q_last
Specifies a pointer to a
cmd_buf
data structure.
This field represents the last command queue in the linked list.
cmd_buf_q_lock
Declares a lock structure called
cmd_buf_q_lock
.
The purpose of this lock is to protect the integrity of the data that is stored
in the linked list of
cmd_buf
data structures.
The alternate
name
lock_data_t
declares the complex lock structure.
Embedding
the complex lock in the
fta_kern_str
structure protects
the
cmd_buf
structure for any number of instances.
After you declare the complex lock data structure, you initialize it
by calling the
lock_init
routine.
The following code fragment
shows a call to
lock_init
by the
if_fta
module's
ftaattach
routine.
The
ftaattach
routine performs the tasks that establish communication with the actual device.
One of these tasks is to initialize any global data structures.
Thus, the
ftaattach
routine initializes the complex lock data structure
cmd_buf_q_lock
.
The code fragment also shows the include file that is associated with
complex locks, definitions of the
cmd_buf
and
fta_kern_str
structures, and the declaration of the complex lock.
.
.
.
#include <kern/lock.h> [1]
.
.
.
struct cmd_buf { u_long *req_buf; u_long *rsp_buf; short timeout; struct cmd_buf *next; }; [2]
.
.
.
struct fta_kern_str {
.
.
.
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 command */ /* request queue */
.
.
.
}; [3]
.
.
.
ftaattach(struct controller *ctlr) { struct fta_kern_str *sc = &fta_kern_str[ctlr->ctlr_num];
.
.
.
/* Tasks to perform controller-specific initialization */
.
.
.
lock_init(&sc->cmd_buf_q_lock, TRUE); [4]
.
.
.
/* Perform other tasks */ }
Includes the header file
/usr/sys/include/kern/lock.h
.
The
lock.h
file defines the simple spin
lock and complex lock structures that kernel modules use for synchronization
on single-processor and multiprocessor systems.
[Return to example]
Defines a
cmd_buf
data structure.
The
fta_kern_str
structure declares two instances of
cmd_buf
.
This structure describes a command queue and is a candidate for
locking in an SMP environment.
You must protect the integrity of the data
that is stored in the command queue from multiple writes by more than one
kernel thread.
[Return to example]
Defines an
fta_kern_str
data structure.
The example shows only those fields that are related to the discussion of
complex locks.
In this example, the
fta_kern_str
structure contains
the following fields:
q_first
Specifies a pointer to a
cmd_buf
data structure.
This field represents the first command queue in the linked list.
q_last
Specifies a pointer to a
cmd_buf
data structure.
This field represents the last command queue in the linked list.
cmd_buf_q_lock
Declares a lock structure called
cmd_buf_q_lock
.
This lock protects the integrity of the data that is stored in the linked
list of
cmd_buf
data structures.
The alternate name
lock_data_t
declares the complex lock structure.
Embedding the complex
lock in the
fta_kern_str
structure protects the
cmd_buf
structure for any number of instances.
Calls the
lock_init
routine to initialize
the simple lock structure called
cmd_buf_q_lock
.
The
lock_init
routine takes two arguments:
The first argument specifies a pointer to the complex lock
structure.
In this call, the
ftaattach
routine passes the
address of the
cmd_buf_q_lock
field of the
fta_kern_str
structure pointer.
You need to initialize the complex lock structure
only once.
The second argument specifies a Boolean value that indicates
whether to allow kernel threads to block (sleep) if the complex lock is asserted.
You can pass to this argument only the value
TRUE
(allow
kernel threads to block if the lock is asserted).
After you declare and initialize the complex lock data structure, you can perform the following access operations on the complex lock:
Assert a complex lock (Section 8.3.1)
Release a previously asserted complex lock (Section 8.3.2)
Try to assert a complex lock (Section 8.3.3)
Each of these tasks is discussed in the following sections.
8.3.1 Asserting a Complex Lock
After you declare and initialize the complex lock data structure, you
can assert a complex lock with read-only access or a complex lock with write
access by calling the
lock_read
or
lock_write
routine.
The following sections describe how to use these routines.
8.3.1.1 Asserting a Complex Lock with Read-Only Access
The
lock_read
routine asserts a lock with read-only
access for the resource that is associated with the specified
lock
structure pointer.
The following code fragment shows a call to
lock_read
by the
if_fta
module's
ftaioctl
routine.
The
ftaioctl
routine is called as the result of an
ioctl
system call.
The
ftaioctl
routine performs the following tasks:
Determines the type of request
Executes the request
Returns data
Returns the value 0 (zero) to the
ioctl
system call to indicate success
The code fragment also shows the include file that is associated with
complex locks, definitions of the
cmd_buf
and
fta_kern_str
structures, the declaration of the complex lock structure
in the
fta_kern_str
structure, and the initialization of
the complex lock structure by the kernel module's
ftaattach
routine.
Section 8.2
provides descriptions of these
tasks.
#include <kern/lock.h>
.
.
.
struct cmd_buf { u_long *req_buf; u_long *rsp_buf; short timeout; struct cmd_buf *next; };
.
.
.
struct fta_kern_str {
.
.
.
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 command */ /* request queue */
.
.
.
};
.
.
.
ftaattach(struct controller *ctlr) { struct fta_kern_str *sc = &fta_kern_str[ctlr->ctlr_num];
.
.
.
/* Tasks to perform controller-specific initialization */
.
.
.
lock_init(&sc->cmd_buf_q_lock, TRUE);
.
.
.
/* Perform other tasks */ }
.
.
.
ftaioctl(register struct ifnet *ifp, unsigned int cmd, caddr_t dataifp) { struct fta_kern_str *sc = &fta_kern_str[ifp->if_unit];
.
.
.
switch (cmd) { case SIOCENABLBACK: {
.
.
.
if (ifp->if_flags & IFF_RUNNING) { [1] lock_read(&sc->cmd_buf_q_lock); /* Performs read operation on the resource */ if(sc->q_first->req_buf = (u_long*)(data);
.
.
.
}
Calls the
lock_read
routine if the
IFF_RUNNING
bit flag is set in the
if_flags
field
of the
ifp
structure pointer.
The
lock_read
routine takes one argument: a pointer
to the complex lock structure
lock
.
This lock structure
is associated with the resource on which you want to assert a complex lock
with read-only access.
The
ftaioctl
routine passes the
address of the
cmd_buf_q_lock
field of the
fta_kern_str
structure pointer.
Figure 8-1
shows what
happens when multiple instances of the
if_fta
kernel module
assert a read-only complex lock on the specified code block.
As the figure
shows, kernel threads from the
if_fta
kernel module that
are executing on CPU1, CPU2, and CPU3 assert read-only complex locks on the
specified code block.
The
lock_read
routine allows multiple
kernel threads to have read-only access to the resource at the same time.
When a read lock is asserted, the protected resource is guaranteed not to
change.
In this case, the
cmd_buf
resource is guaranteed
not to change.
[Return to example]
8.3.1.2 Asserting a Complex Lock with Write Access
The
lock_write
routine asserts a lock with exclusive
write access for the resource that is associated with the specified
lock
structure pointer.
After a write lock is asserted, no other
kernel thread can gain read or write access to the resource until it is released.
The following code fragment shows a call to
lock_write
by the
if_fta
module's
ftaioctl
routine.
The
ftaioctl
routine is called as the result of an
ioctl
system call.
The
ftaioctl
routine performs the following tasks:
Determines the type of request
Executes the request
Returns data
Returns the value 0 (zero) to the
ioctl
system call to indicate success
The code fragment also shows the include file that is associated with
complex locks, definitions of the
cmd_buf
and
fta_kern_str
structures, the declaration of the complex lock structure
in the
fta_kern_str
structure, and the initialization of
the complex lock structure by the kernel module's
ftaattach
routine.
Section 8.2
provides descriptions of these
tasks.
#include <kern/lock.h>
.
.
.
struct cmd_buf { u_long *req_buf; u_long *rsp_buf; short timeout; struct cmd_buf *next; };
.
.
.
struct fta_kern_str { . 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 command /* /* request queue */
.
.
.
};
.
.
.
ftaattach(struct controller *ctlr) { struct fta_kern_str *sc = &fta_kern_str[ctlr->ctlr_num];
.
.
.
/* Tasks to perform controller-specific initialization */
.
.
.
lock_init(&sc->cmd_buf_q_lock, TRUE);
.
.
.
/* Perform other tasks */ }
.
.
.
ftaioctl(register struct ifnet *ifp, unsigned int cmd, caddr_t data) { struct fta_kern_str *sc = &fta_kern_str[ifp->if_unit];
.
.
.
switch (cmd) { case SIOCENABLBACK: {
.
.
.
if (ifp->if_flags & IFF_RUNNING) { [1] lock_write(&sc->cmd_buf_q_lock); sc->q_first->req_buf = (u_long*) (data);
Calls the
lock_write
routine if the
IFF_RUNNING
bit flag is set in the
if_flags
field
of the
ifp
structure pointer.
The
lock_write
routine takes one argument: a pointer
to the complex lock structure
lock
.
This lock structure
is associated with the resource on which you want to assert a complex lock
with write access.
The
ftaioctl
routine passes the address
of the
cmd_buf_q_lock
field of the
fta_kern_str
structure pointer.
Figure 8-2
shows what happens
when multiple instances of the
if_fta
kernel module assert
a write complex lock on the specified code block.
As the figure shows, kernel
threads from the
if_fta
module that are executing on CPU1,
CPU2, and CPU3 assert write complex locks on the specified code block.
The
kernel thread from CPU3 asserts the write complex lock before the kernel threads
from CPU1 and CPU2.
The kernel thread from CPU3 writes to the
req_buf
field.
The
lock_write
routine blocks (puts to sleep) the
kernel threads from CPU1 and CPU2 by placing the requests on a lock queue.
This example shows that after
lock_write
successfully asserts
a complex write lock, no other kernel thread can gain read or write access
to the resource until the resource is released.
[Return to example]
8.3.2 Releasing a Previously Asserted Complex Lock
After you finish manipulating the resource that is associated with the
complex lock, you need to release the lock.
To release a complex lock that
you previously asserted with a call to
lock_read
or
lock_write
, call the
lock_done
routine.
The following
code fragment shows a call to
lock_done
by the
if_fta
kernel module's
ftaioctl
routine.
The
ftaioctl
routine is called as the result of an
ioctl
system call.
The
ftaioctl
routine performs the following tasks:
Determines the type of request
Executes the request
Returns data
Returns the value 0 (zero) to the
ioctl
system call to indicate success
The code fragment also shows the include file that is associated with
complex locks, definitions of the
cmd_buf
and
fta_kern_str
structures, the declaration of the complex lock structure
in the
fta_kern_str
structure, the initialization of the
complex lock structure by the module's
ftaattach
routine,
and the assertion of a complex write lock on the code block by the kernel
module's
ftaioctl
routine.
Section 8.2
and
Section 8.3.1.2
provide
descriptions of these tasks.
.
.
.
#include <kern/lock.h>
.
.
.
struct cmd_buf { u_long *req_buf; u_long *rsp_buf; short timeout; struct cmd_buf *next; };
.
.
.
struct fta_kern_str {
.
.
.
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 command */ /* request queue */
.
.
.
};
.
.
.
ftaattach(struct controller *ctlr) { struct fta_kern_str *sc = &fta_kern_str[ctlr->ctlr_num];
.
.
.
/* Tasks to perform controller-specific initialization */
.
.
.
lock_init(&sc->cmd_buf_q_lock, TRUE);
.
.
.
/* Perform other tasks */ }
.
.
.
ftaioctl(register struct ifnet *ifp, unsigned int cmd, caddr_t data) { struct fta_kern_str *sc = &fta_kern_str[ifp->if_unit];
.
.
.
switch (cmd) { case SIOCENABLBACK: {
.
.
.
if (ifp->if_flags & IFF_RUNNING) { lock_write(&sc->cmd_buf_q_lock); sc->q_first->req_buf = (u_long*) (data);
.
.
.
lock_done(&sc->cmd_buf_q_lock); [1]
.
.
.
}
Calls the
lock_done
routine to release the
complex write lock that
lock_write
previously asserted.
The
lock_done
routine takes one argument: a pointer
to the complex lock structure
lock
.
This lock structure
is associated with the resource on which you want to assert a complex lock
with write access.
The
ftaioctl
routine passes the address
of the
cmd_buf_q_lock
field of the
fta_kern_str
structure pointer.
Figure 8-3
shows what happens
when one instance of the
if_fta
module releases a previously
asserted complex write lock on the code block that writes to the command buffer
queue.
As the figure shows, the CPU3 kernel thread releases the complex write
lock on the code block that writes to the command buffer queue.
The CPU1 and
CPU2 kernel threads are blocked, waiting on the wait queue for the complex
write lock to be freed.
Because the CPU1 kernel thread is first on the wait
queue, it now obtains the complex write lock.
Furthermore, the figure shows
that the CPU3 kernel thread makes another attempt to assert a complex write
lock on the code block.
This time
lock_write
blocks (puts
to sleep) the CPU3 kernel thread by placing it on the wait queue behind the
CPU2 kernel thread.
[Return to example]
8.3.3 Trying to Assert a Complex Lock
After you declare and initialize the complex lock data structure, you
can try to assert a complex lock with read-only access or a complex lock with
write access by calling the
lock_try_read
or
lock_try_write
routine.
Unlike the
lock_read
or
lock_write
routines, the
lock_try_read
and
lock_try_write
routines do not block if another kernel
thread owns the lock associated with the resource.
The following sections describe how to use these routines.
8.3.3.1 Trying to Assert a Complex Lock with Read-Only Access
To try to assert a complex lock with read-only access, call the
lock_try_read
routine.
The
lock_try_read
routine
tries to assert a complex lock (without blocking) with read-only access for
the resource that is associated with the specified
lock
structure pointer.
The following code fragment shows a call to
lock_try_read
by the
if_fta
module's
ftaioctl
routine.
The code fragment also shows the include file that is associated with complex
locks, definitions of the
cmd_buf
and
fta_kern_str
structures, the declaration of the complex lock structure in the
fta_kern_str
structure, and the initialization of the complex lock
structure by the module's
ftaattach
routine.
Section 8.2
provides descriptions of these tasks.
In addition, the code fragment shows
a call to
lock_done
if the complex read-only lock is successfully
asserted.
.
.
.
#include <kern/lock.h>
.
.
.
struct cmd_buf { u_long *req_buf; u_long *rsp_buf; short timeout; struct cmd_buf *next; };
.
.
.
struct fta_kern_str {
.
.
.
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 command */ /* request queue */
.
.
.
};
.
.
.
ftaattach(struct controller *ctlr) { struct fta_kern_str *sc = &fta_kern_str[ctlr->ctlr_num];
.
.
.
/* Tasks to perform controller-specific initialization */
.
.
.
lock_init(&sc->cmd_buf_q_lock, TRUE);
.
.
.
/* Perform other tasks */ }
.
.
.
ftaioctl(register struct ifnet *ifp, unsigned int cmd, caddr_t data) { struct fta_kern_str *sc = &fta_kern_str[ifp->if_unit]; boolean_t try_ret_val; [1]
.
.
.
switch (cmd) { case SIOCENABLBACK: {
.
.
.
if (ifp->if_flags & IFF_RUNNING) { [2] try_ret_val = lock_try_read(&sc->cmd_buf_q_lock); if (try_ret_val == TRUE) { [3] if (sc->q_first->req_buf == (u_long*) (data)) {
.
.
.
lock_done(&sc->cmd_buf_q_lock); [4] } } }
.
.
.
else [5]
.
.
.
/* Code that executes when try_ret_val == FALSE */
.
.
.
}
.
.
.
}
.
.
.
}
Declares a variable to store one of the following return values
from the
lock_try_read
routine:
TRUE
The attempt to acquire the read-only complex lock was successful.
FALSE
The attempt to acquire the read-only complex lock was unsuccessful.
Calls the
lock_try_read
routine if the
IFF_RUNNING
bit flag is set in the
if_flags
field
of the
ifp
structure pointer.
The
lock_try_read
routine takes one argument: a
pointer to the complex lock structure
lock
.
This lock structure
is associated with the resource on which you want to try to assert a complex
lock with read-only access.
The
ftaioctl
routine passes
the address of the
cmd_buf_q_lock
field of the
fta_kern_str
structure pointer.
[Return to example]
If the return from
lock_try_read
is
TRUE
, obtains the read-only complex lock on the code block that
performs the read operation.
[Return to example]
After completing the read operation, releases the read-only
complex lock by calling
lock_done
.
[Return to example]
If the return from
lock_try_read
is
FALSE
, did not obtain the read-only complex lock on the code block
that performs the read operation.
In this case, it is not necessary to call
lock_done
.
Figure 8-4
shows what
happens when two instances of the
if_fta
module attempt
to assert a read-only complex lock on the code block that performs a read
operation on the resource.
As the figure shows, both the CPU1 and CPU2 kernel
threads try to assert a read-only complex lock on the code block that performs
a read operation on the command buffer queue.
Because this is a read-only
operation, the CPU1 and CPU2 kernel threads obtain the read-only complex lock,
and as a result,
lock_try_read
returns the value
TRUE
in both cases.
[Return to example]
8.3.3.2 Trying to Assert a Complex Lock with Write Access
To try to assert a complex lock with write access, call the
lock_try_write
routine.
The
lock_try_write
routine
tries to assert a complex lock (without blocking) with write access for the
resource that is associated with the specified
lock
structure
pointer.
The following code fragment shows a call to
lock_try_write
by the
if_fta
module's
ftaioctl
routine.
The code fragment also shows the include file that is associated
with complex locks, definitions of the
cmd_buf
and
fta_kern_str
structures, the declaration of the complex lock structure
in the
fta_kern_str
structure, and the initialization of
the complex lock structure by the module's
ftaattach
routine.
Section 8.2
provides descriptions of these tasks.
In
addition, the code fragment shows a call to
lock_done
if
the complex write lock is successfully asserted.
.
.
.
#include <kern/lock.h>
.
.
.
struct cmd_buf { u_long *req_buf; u_long *rsp_buf; short timeout; struct cmd_buf *next; };
.
.
.
struct fta_kern_str {
.
.
.
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 command */ /* request queue */
.
.
.
};
.
.
.
ftaattach(struct controller *ctlr) { struct fta_kern_str *sc = &fta_kern_str[ctlr->ctlr_num];
.
.
.
/* Tasks to perform controller-specific initialization */
.
.
.
lock_init(&sc->cmd_buf_q_lock, TRUE);
.
.
.
/* Perform other tasks */ }
.
.
.
ftaioctl(register struct ifnet *ifp, unsigned int cmd, caddr_t data) { struct fta_kern_str *sc = &fta_kern_str[ifp->if_unit]; boolean_t try_ret_val; [1]
.
.
.
switch (cmd) { case SIOCENABLBACK: {
.
.
.
if (ifp->if_flags & IFF_RUNNING) { [2] try_ret_val = lock_try_write(&sc->cmd_buf_q_lock); if (try_ret_val == TRUE) { [3] sc->q_first->req_buf = (u_long*) (data);
.
.
.
lock_done(&sc->cmd_buf_q_lock); [4] }
.
.
.
else [5]
.
.
.
/* Code that executes when try_ret_val == FALSE */
.
.
.
}
.
.
.
}
.
.
.
}
Declares a variable to store one of the following return values
from the
lock_try_write
routine:
TRUE
The attempt to acquire the write complex lock was successful.
FALSE
The attempt to acquire the write complex lock was unsuccessful.
Calls the
lock_try_write
routine if the
IFF_RUNNING
bit flag is set in the
if_flags
field
of the
ifp
structure pointer.
The
lock_try_write
routine takes one argument: a
pointer to the complex lock structure
lock
.
This lock structure
is associated with the resource on which you want to try to assert write access.
The
ftaioctl
routine passes the address of the
cmd_buf_q_lock
field of the
fta_kern_str
structure
pointer.
[Return to example]
If the return from
lock_try_write
is
TRUE
, obtains the write complex lock on the code block that performs
the write operation.
[Return to example]
After completing the write operation, releases the write complex
lock by calling
lock_done
.
[Return to example]
If the return from
lock_try_write
is
FALSE
, did not obtain the write complex lock on the code block that
performs the write operation.
In this case, it is not necessary to call
lock_done
.
Figure 8-5
shows what
happens when two instances of the
if_fta
module attempt
to assert a write complex lock on the code block that performs a write operation
on the resource.
As the figure shows, both the CPU1 and CPU2 kernel threads
try to assert a write complex lock on the code block that performs a write
operation on the command buffer queue.
The CPU1 kernel thread obtains the
write complex lock first and as a result
lock_try_write
returns the value
TRUE
.
Because the CPU2 kernel thread
was not successful in obtaining the write complex lock,
lock_try_write
immediately returns (does not block the kernel thread) the value
FALSE
.
[Return to example]
8.4 Terminating a Complex Lock
After you unlock a complex read or write lock and know that you are
finished using the lock for this resource, you can terminate the lock by calling
the
lock_terminate
routine.
Typically, you terminate any
locks in the kernel module's controller (or device)
unattach
routine.
These routines are associated with loadable kernel modules.
One task
that is associated with a controller or device
unattach
routine is to terminate any locks initialized in the kernel module's
attach
routine.
The following code fragment shows a call to
lock_terminate
by the
if_fta
module's
fta_ctlr_unattach
routine.
The code fragment also shows the include file that is
associated with complex locks, definitions of the
cmd_buf
and
fta_kern_str
structures, the declaration of the complex
lock structure in the
fta_kern_str
structure, and the initialization
of the complex lock structure by the kernel module's
ftaattach
routine.
Section 8.2
provides descriptions of these
tasks.
In addition, the code fragment shows calls to
lock_write
and
lock_done
.
.
.
.
#include <kern/lock.h>
.
.
.
struct cmd_buf { u_long *req_buf; u_long *rsp_buf; short timeout; struct cmd_buf *next; };
.
.
.
struct fta_kern_str {
.
.
.
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 command */ /* request queue */
.
.
.
};
.
.
.
ftaattach(struct controller *ctlr) { struct fta_kern_str *sc = &fta_kern_str[ctlr->ctlr_num];
.
.
.
/* Tasks to perform controller-specific initialization */
.
.
.
lock_init(&sc->cmd_buf_q_lock, TRUE);
.
.
.
/* Perform other tasks */ }
.
.
.
ftaioctl(register struct ifnet *ifp, unsigned int cmd, caddr_t data) { struct fta_kern_str *sc = &fta_kern_str[ifp->if_unit];
.
.
.
switch (cmd) { case SIOCENABLBACK: {
.
.
.
if (ifp->if_flags & IFF_RUNNING) { lock_write(&sc->cmd_buf_q_lock); sc->q_first->req_buf = (u_long*) (data);
.
.
.
lock_done(&sc->cmd_buf_q_lock);
.
.
.
}
.
.
.
fta_ctlr_unattach(struct bus *bus, struct controller *ctlr) { register int unit = ctlr->ctlr_num; if ((unit > num_fta) || (unit < 0) { return(1); } if (fta_is_dynamic == 0) { return(1); } /* Performs controller unattach tasks */
.
.
.
lock_terminate(&sc->cmd_buf_q_lock); [1]
.
.
.
}
Calls the
lock_terminate
routine to determine
that the
if_fta
module is permanently done using this complex
lock.
The
lock_terminate
routine takes one argument: a
pointer to the complex lock structure
lock
.
In this call,
the
fta_ctlr_unattach
routine passes the address of the
cmd_buf_q_lock
field of the
fta_kern_str
structure
pointer.
In calling
lock_terminate
, the
if_fta
module must not reference this complex lock again.
[Return to example]