Modifying the strategy routine
This section describes an
strategy( )
routine that has not been converted for multiprocessor access,
and then explains how to enhance the code
so that it can take advantage of a multiprocessor environment.
The following code illustrates the
strategy( )
routine of a driver
that has not been converted for multiprocessor access.
Single-threaded xxstrategy fragment
1 s = spl5();
2 disksort(&xxtab, bp);
3 xxstart(xxstart_arg);
4 splx(s);
Line 1-
The spl(5) call blocks interrupts from devices with
IPLs of 1 to 5.
Line 2-
Calls
disksort(D3oddi)
to sort the disk requests.
Line 3-
Calls
xxstart( )
to perform the disk I/O
Line 4-
Restores the spl
level back to its previous value.
To convert this code to take advantage of multiprocessing, the critical
code sections need to be protected
with locks as illustrated in the following code fragment:
Multithreaded xxstrategy fragment
1 s = lockb(&lock_xxtab);
2 disksort(&xxtab, bp);
3 if (xxtab.b_active == 0) {
4 if (can_doio(MP_ATBUS))
5 xxstart(xxstart_arg);
6 else {
7 unlockb(&lock_xxtab, -1);
8 startio(xxhandle, xxstart_arg);
9 }
10 splx(s);
11 }
12 else {
13 unlockb(&lock_xxtab, s);
14 return;
15 }
NOTE:
Not all drivers send requests at interrupt time;
some drivers use the
start(D2oddi)
and
strategy(D2oddi)
entry point routines.
This example assumes that further requests are sent at interrupt time
if the device is busy.
Line 1-
Before calling
disksort(D3oddi),
the
strategy( )
routine needs to protect critical code sections
so that access to the linked list of
I/O requests is protected.
In this code, the spl5 call
is replaced with a call to
lockb(D3oddi).
lockb is passed the address of the lock
(the lock structure
defined in the <sys/ci/cilock.h> header file).
Line 2-
The disksort call is the same as the
original.
Line 3-
The flag in the xxtab structure
is checked to determine
whether the driver is performing I/O.
The
b_active
flag is set in the driver's
start( )
routine to indicate that it is active.
Line 4-
If the driver is not already performing I/O,
can_doio(D3oddi)
is called to see if the current
processor can access the I/O bus type.
Line 5-
If the processor can access the specified bustype,
the start routine is called directly.
Line 7-
If access to the I/O bus
is not possible from the current processor,
the critical code section is unlocked.
The -1 argument to
unlockb(D3oddi)
indicates that
unlockb(D3oddi)
will not restore the spl value; that is,
your driver will call splx after the
unlockb(D3oddi)
call.
Line 8-
startio(D3oddi)
is called to run the
start( )
routine by interrupting a processor that can access
the I/O bus. The first argument to the
startio(D3oddi)
routine is the return value from a previous
call to
intralloc(D3oddi);
the second argument is the
parameter with which you want to call
start( ).
Line 10-
splx(D3oddi)
restores the original spl level for the
conditions where start or
startio(D3oddi)
were called.
Lines 13-14-
If the driver is already performing I/O,
then execution of the critical code section is complete,
so the lock is unlocked and the routine exits.
NOTE:
Remove any spl calls between
lockb(D3oddi)
and
unlockb(D3oddi)
calls.
© 2005 The SCO Group, Inc. All rights reserved.