Dynamic function replacement for streams framework5815707Abstract An extension to the STREAMS framework, referred to as dynamic function replacement, uses data structures that contain function pointers which allow STREAMS to execute various module or driver functions without requiring framework modification, or understanding what these functions actually do beyond their rudimentary classifications. This provides a simple, yet elegant, mechanism for replacing these function definitions and, hence, changing the execution behavior of STREAMS modules and drivers without requiring the modules or drivers to be rewritten or modified. Claims We claim: Description BACKGROUND OF THE INVENTION
______________________________________
/* Streams queue initialization structure */
struct qinit {
int (*qi.sub.-- putp)();
/* Queue put procedure
*/
int (*qi.sub.-- srvp)();
/* Queue service procedure
*/
int (*qi.sub.-- qopen)();
/* Queue open procedure
*/
int (*qi.sub.-- qclose)();
/* Queue close procedure
*/
int (*qi.sub.-- qadmin)();
/* Queue administrative
*/
procedure
struct module.sub.-- info * qi.sub.-- minfo;
struct module.sub.-- stat * qi.sub.-- mstat;
/* Streams driver and module declaration structure */
struct streamtab {
struct qinit * st.sub.-- rdinit;
/* defines read QUEUE
*/
struct qinit * st.sub.-- wrinit;
/* defines write QUEUE
*/
struct qinit * st.sub.-- muxrinit;
/* for multiplexing drivers only
*/
struct qinit * st.sub.-- muxwinit;
/* ditto */
}
/* Streams queue structure */
struct queue {
struct qinit * q.sub.-- qinfo;
/* procedures and limits for
*/
queue
struct msgb * q.sub.-- first;
/* head of message queue
*/
struct msgb * q.sub.-- last;
/* tail of message queue
*/
struct queue * q.sub.-- next;
/* next QUEUE in Stream
*/
struct queue * q.sub.-- link;
/* link to scheduling queue
*/
void * q.sub.-- ptr;
/* to private data structure
*/
ulong q.sub.-- count;
/* weighted count of characters
*/
on q
ulong q.sub.-- flag;
/* QUEUE state */
long q.sub.-- minpsz;
/* min packet size accepted
*/
long q.sub.-- maxpsz;
/* max packet size accepted
*/
ulong q.sub.-- hiwat;
/* high water mark, for flow
*/
control
ulong q.sub.-- lowat;
/* low water mark */
struct qband * q.sub.-- bandp;
/* band information */
unsigned char q.sub.-- nband;
/* number of bands */
unsigned char q.sub.-- pad1›3!
/* reserved */
struct queue * q.sub.-- other;
/* pointer to other Q in queue
*/
pair
QUEUE.sub.-- KERNEL.sub.-- FIELDS
}
______________________________________
These basic fields within these data structures are standardized via the SVR4.2 Device Driver Reference commonly referred to as the DDI (Device Driver Interface, discussed above). External Specification For Configuring Alternative Streamtabs New str.sub.-- alt.sub.-- install() routine configures the alternative streamtab's for Streams modules/drivers. The flags parameter specifies whether it is a module or driver: STR.sub.-- IS.sub.-- MODULE for a module and STR.sub.-- IS.sub.-- DEVICE for a driver.
______________________________________
str.sub.-- alt.sub.-- install(name, flags, n, streamtabs)
char *name; /* name of module or driver
*/
unsigned int
flags; /* STR.sub.-- IS.sub.-- MODULE/DEVICE
*/
int n; /* number of alternative streamtabs
*/
struct *streamtabs›!;
/* array of pointers to streamtabs
*/
streamtab
Str.sub.-- alt.sub.-- install() returns 0 on success and -1 on
______________________________________
failure.
For example, consider a Streams driver foo. The foo driver has the following alternative routines for tracing, debugging, and performance measurement:
______________________________________
foo.sub.-- rput.sub.-- trace(q, mp)
ktrc.sub.-- write();
/* call NETTL packet tracing routine
*/
foo.sub.-- rput(q, mp);
/* call original rput routine
*/
}
foo.sub.-- rput.sub.-- debug(q, mp)
{
/*
* Original rput routine plus debugging code.
*/
}
foo.sub.-- rput.sub.-- timestamp(q, mp)
{
timestamp();
/* record entry timestamp
*/
foo.sub.-- rput(q, mp);
/* call original rput routine
*/
timestamp();
/* record exit timestamp
*/
}
______________________________________
Similarly, routines for rsrv, wput, wsrv, open, and close routines are defined, if desired. Then, qinit structures resemble the following:
______________________________________
struct qinit foo.sub.-- rinit.sub.-- trace = {
foo.sub.-- rput.sub.-- trace,foo.sub.-- rsrv.sub.-- trace,foo.sub.--
open,foo.sub.-- close,NULL,
&foo.sub.-- minfo,NULL}
struct qinit foo.sub.-- rinit.sub.-- debug = {
foo.sub.-- rput.sub.-- debug,foo.sub.-- rsrv.sub.-- debug,foo.sub.--
open,foo.sub.-- close,NULL,
&foo.sub.-- minfo,NULL}
struct qinit foo.sub.-- rinit.sub.-- timestamp = {
foo.sub.-- rput.sub.-- timestamp,foo.sub.-- rsrv.sub.-- timestamp,foo.sub.
-- open,foo.sub.-- close,NULL,
&foo.sub.-- minfo,NULL}
______________________________________
Similarly, qinit's for write side are defined. Then, the alternative streamtab's are defined:
______________________________________
struct streamtab foo.sub.-- trace.sub.-- info
= {&foo.sub.-- rinit.sub.-- trace,
&foo.sub.-- winit.sub.-- trace};
struct streamtab foo.sub.-- debug.sub.-- info
= {&foo.sub.-- rinit.sub.-- debug,
&foo.sub.-- winit.sub.-- debug};
struct streamtab foo.sub.-- timestamp.sub.-- info
= {&foo.sub.-- rinit.sub.-- timestamp,
&foo.sub.-- winit.sub.-- timestamp};
______________________________________
Finally, the alternative streamtab's are configured via str.sub.-- alt.sub.-- install():
______________________________________
struct streamtab * streamtabs›3!
= { &foo.sub.-- trace.sub.-- info,
&foo.sub.-- debug.sub.-- info,
&foo.sub.-- timnestamp.sub.-- info }
str.sub.-- alt.sub.-- install("foo", STR.sub.-- IS.sub.-- DEVICE, 3,
streamtabs);
______________________________________
The str.sub.-- alt.sub.-- install(name, flags, n, streamtabs) fails if one of the following conditions occurs: .circle-solid. name is NULL. .circle-solid. n is negative. .circle-solid. n is positive but streamtabs is NULL. .circle-solid. Flags do not contain STR.sub.-- IS.sub.-- MODULE or STR.sub.-- IS.sub.-- DEVICE. .circle-solid. The module/driver specified by the name has not been installed. .circle-solid. Alternative streamtabs has been already installed AND there is an active instance of the module/driver. When there is currently no alternative streamtabs installed, then, even if there is an active instance of the module/driver, str.sub.-- alt.sub.-- install() allows an alternative streamtabs to be installed. To change or uninstall the already installed alternative streamtabs, all the active instances of the module/driver must be closed first. Uninstalling the alternative streamtabs is done by calling str.sub.-- alt.sub.-- install(name, flags, O, NULL). Besides the above developer-provided alternative streamtab's, STREAMS automatically provides a default alternative streamtab for each Streams module/driver that is automatically configured when the normal streamtab is configured. This default alternative streamtab exists even when there are no developer-supplied alternative streamtab's for the module/driver. All the contents of the qinit's of the default alternative streamtab are identical to that of the normal streamtab except for the put routines. The put routines of the default alternative streamtab do the following: --Call network tracing and logging ("NETTL") to trace the message: ktrc.sub.-- write() with
______________________________________
subsys.sub.-- id =
STREAMS
kind = PDU.sub.-- IN for M.sub.-- DATA at read-side,
HDR.sub.-- IN for other message types at read-side,
PDU.sub.-- OUT for M.sub.-- DATA at write-side,
HDR.sub.-- OUT for other message types at write-side.
path.sub.-- id =
module id
______________________________________
--Call the original routine. External Specification For Dynamically Alternating Streamtabs Two new STREAMS ioctl commands are used to alternate dynamically the Streams module's/driver's streamtab's. One of the ioctl commands is used to alter active instances of a module, and the other ioctl command is used to alter future instances of a module. #include <sys/types.h> #include <stropts.h> #include <stream.h> int ioctl (int fd, int command, arg); I.sub.-- ALTSTRTAB.sub.-- ACTIVE is the new STREAMS ioctl command and it allows the owner of the target stream or the super-privileged administrator to alternate qinit routines for the given active instance of a module/driver. The arg must point to straltactive structure which contains the following members:
______________________________________
long alt.sub.-- major;
/* major number
*/
long alt.sub.-- minor;
/* minor number
*/
int alt.sub.-- index;
/* alternative streamtab
*/
/* index
un- alt.sub.-- flags;
/* STR.sub.-- IS.sub.-- MODULE/
*/
signed DEVICE
int
char alt.sub.-- name›FMNAMESZ+1!;
/* name of module or
*/
driver
______________________________________
.circle-solid. The alt.sub.-- name is the name of the target module/driver terminated by a null character, and it must match with the name that was passed in str.sub.-- install() or str.sub.-- alt.sub.-- install(). .circle-solid. The alt.sub.-- flags specifies that the target is a module or a driver. .circle-solid. The pair of alt.sub.-- major and alt.sub.-- minor specifies the stream in which the target module/driver is searched for. If alt.sub.-- major is ALT.sub.-- OWN.sub.-- MAJOR, then alt.sub.-- minor is ignored and the stream on which this ioctl is called is the target stream. If alt.sub.-- major is not ALT.sub.-- OWN.sub.-- MAJOR, the credential of the caller is checked and only the privileged user is allowed to proceed. If the alt.sub.-- minor is ALT.sub.-- ALL.sub.-- MINORS, all the active streams specified by the alt.sub.-- major is the target streams. The privileged user can typically use the streams administration driver ("SAD"), which is a standard component of all STREAMS implementations, to alter the arbitrary stream's module/driver, but it does not have to be the SAD driver. The SAD driver is a STREAMS administration driver that knows every STREAM in the system, and that knows where each STREAM is located. .circle-solid. The alt.sub.-- index field specifies which alternative routines are to be used. Suppose the module configure N alternative streamtab's via str.sub.-- alt.sub.-- install(), then it may take on one of the following values:
______________________________________
NORMAL.sub.-- L STRTAB
Routines in the original streamtab.
DEFAULT.sub.-- ALT.sub.-- STRTAB
Routines in the default alternative
streamtab.
0 Routines in the first streamtab passed
via str.sub.-- alt.sub.-- install.
1 Routines in the second streamtab passed
via str.sub.-- alt.sub.-- install.
.
.
N-1 Routines in the Nth streamtab passed via
str.sub.-- alt.sub.-- install.
On failure, errno is set to the following value:
EACCES The alt.sub.-- major is not
ALT.sub.-- OWN.sub.-- MAJOR and the user does
not have the super-privilege.
EFALUT The arg points outside the allocated
address space.
EINVAL The alt.sub.-- name, alt.sub.-- major, alt.sub.-- minor,
alt.sub.-- flags, or alt.sub.-- index is
______________________________________
invalid.
To allow alternating qinit routines of the modules/drivers of the streams that are linked under multiplexors, I.sub.-- ALTSTRTAB.sub.-- ACTIVE ioctl can be called to the streams that are linked under a multiplexor. For example, to alternate lower mux routines, I.sub.-- ALTSTRTAB.sub.-- ACTIVE ioctl can be called to the lower stream specifying the name of the multiplexor. To allow alternate qinit routines of lower multiplexors, I.sub.-- ALTSTRTAB.sub.-- ACTIVE ioctl can be called to the streams that are linked under a multiplexor. I.sub.-- ALTSTRTAB.sub.-- FUTURE is the other command and it alters the qinit routines of subsequently opened instances of the module/driver. This command also alters the module info that is sent to the module specified by the alternative streamtab, i.e. the subsequent open's of the module/driver use the alternative streamtab: alternative qinit's and alternative module.sub.-- info. This ioctl command does not affect the active instances of the module/driver. The arg must point to a straltfuture structure which contains the following members:
______________________________________
int alt.sub.-- index;
/* alternative streamtab
*/
index
un- alt.sub.-- flags;
/* STR.sub.-- IS.sub.-- MODULE/
*/
signed DEVICE
int
char alt.sub.-- name›FMNAMESZ+1!;
/* name of module or
*/
driver
______________________________________
The alt.sub.-- name field and alt.sub.-- index field are described above. On failure, errno is set to the following value: EACCES The user does not have the super-privilege. EFALUT The arg points outside the allocated address space. EINVAL The alt.sub.-- name, alt.sub.-- flags, or alt.sub.-- index is invalid. Internal Design The following discussion is directed to read-side routines. For other routines, i.e. write-side, mux-read-side, and mux-write-side, the dynamic function replacement mechanism herein described works similarly. The following streamtab's are provided per module, not per an instance of a module. .circle-solid. Original normal streamtab. .circle-solid. Default alternative streamtab. .circle-solid. The alternative streamtab's that the module installed via str.sub.-- alt.sub.-- install(). Also there is one modsw structure for each installed module/driver. New struct modsw is as follows:
______________________________________
struct modsw {
struct d.sub.-- next; /* next modsw */
modsw *
struct d.sub.-- prev; /* previous modsw
*/
modsw *
char d.sub.-- name›FMNAMESZ+1!;
/* unique module
*/
name
char d.sub.-- flags; /* OLD.sub.-- OPEN,
*/
UP.sub.-- MODE
SQHP d.sub.-- sqh; /* for module/else-
*/
where synch
int d.sub.-- curstr;
/* current streamtab
*/
index
struct d.sub.-- str; /* normal streamtab
*/
streamtab *
struct d.sub.-- default.sub.-- alt;
/* default alternative
*/
streamtab * streamtab
int d.sub.-- naltstr;
/* # of alternative
*/
streamtabs
struct d.sub.-- altstr;
/* alternative streamtab
*/
streamtab * array
int d.sub.-- sq.sub.-- level
/* synch level
*/
int d.sub.-- nrefcnt;
/* reference count
*/
int d.sub.-- major; /* major # (should be
*/
unique)
};
______________________________________
The struct queue has a new filed within QUEUE.sub.-- KERNEL.sub.-- FIELDS:
______________________________________
struct modsw * q.sub.-- modsw;
/* pointer to struct modsw */
______________________________________
The essence of the algorithms for I.sub.-- ALTSTRTAB.sub.-- ACTIVE ioctl and I.sub.-- ALTSTRTABL.sub.-- FUTRUE ioctl are as follows:
______________________________________
I.sub.-- ALTSTRTAB.sub.-- ACTIVE ioctl
if (alt.sub.-- major == ALT.sub.-- OWN.sub.-- MAJOR)
current sth is the target stream:
}
else
{
check the caller's credentials;
find sth for ›alt.sub.-- major, alt.sub.-- minor!;
}
acquire mult.sub.-- sqh lock to prevent plumbing;
search for the target queue specified by alt.sub.-- name›!;
q->q.sub.-- qinfo = pointer to the appropriate alternative qinit;
I.sub.-- ALTSTRTABL.sub.-- FUTRUE ioctl
check the caller's credentials
find modsw for module specified by alt.sub.-- name›!;
modsw.d.sub.-- curstr = alt.sub.-- index;
______________________________________
FIG. 7 is a block schematic diagram showing a data structure that implements dynamic function replacement for a STREAMS framework in accordance with the invention. The data structure 10 is implemented in a computer system 11 that provides a bidirectional data path 13 between a user process 12, a module 14 which is an intermediate processing element that can be dynamically added to, or removed from, said data path, and a device driver 15. The device driver is resident in a system kernel 18 and controls a peripheral device 16 to transfer data between said kernel and said device. Data written by the user process travel downstream toward the driver, and data received by the driver from the device travel upstream to be retrieved by a user 20. After a module/driver is installed via the utilities that are used to install a module/driver into the system, i.e. str.sub.-- install() and str.sub.-- alt.sub.-- install(), the data structures resemble those shown on FIG. 8, which illustrates the simplicity of replacing functionality on-the-fly, based on application needs. The preferred embodiment of the invention primarily updates data structures, which not only adds simplicity, but also avoids problems associated with multiprocessor implementations and scaling. These data structures may be updated such that there are no race or timing issues because such structures are controlled by the STREAMS framework and not by the module/driver developer. In addition, by using standard structures, it is not necessary to provide developers with specialized training, should they desire to implement their products in accordance with the herein described invention. Thus, the invention speeds development time, reduces cost, and makes developer acceptance more likely. The data structure minimally includes a normal function 110 that implements a specific module or driver instance; at least one alternative function 120, 130 that implements an optional module or driver instance; and a controller 140 that generates a control command that dynamically replaces the normal function with at least one alternative function, while either still executing an original execution path or executing a new execution path, and without requiring any modification to the module and the driver. The data structure can include an alternative function, for example that customizes system tracing facilities to trace only specific events or under specific conditions; that provides support facilities for applying custom failure catchers to target specified system problems; that applies a patch on a per instance basis; that allows testing to a single data path and that allows increased flexibility and control of data path execution; or that allows replacement of either all module or driver instances or replacement on a per instance basis. The data structure is implemented in a STREAMS framework 19, wherein each module or driver defines a streamtab structure that contains pointers to qinit structures (see FIG. 8). In the data structure, the qinit structures are for read, write, read multiplexor, and write multiplexor queues which are created by said STREAMS framework, while the qinit structures contain function addresses for open, close, put, service, and administrative functions which are invoked by the STREAMS framework on behalf of a module or driver. Functions defined within the qinit structures are automatically executed by the STREAMS framework based on a current application execution path. Thus, the controller 140 generates control commands that remap addresses of said structures to alternative streamtabs and qinit structures that define new function addresses. In one embodiment of the invention, all contents of the qinit structures of an default alternative streamtab are identical to those of a normal streamtab except for put routines. The controller generates control commands that may include at least one STREAMS ioctl command that is used to alternate dynamically STREAMS module's/driver's streamtab's, an ioctl command that is used to alter active instances of a module, and/or an ioctl command that is used to alter future instances of a module. The data structures include the MODSW table 100 which defines all the driver information. In the MODSW table there are pointers into the different streamtabs 110, 120, 130. The herein disclosed data structure adds at least one new streamtab entry to the MODSW table, e.g. the d.sub.-- default.sub.-- alt entry, which is used to select a default alternative streamtab 120. When a specific driver or module is installed into the system, the user or developer can define what they want that default to be. The herein described data structure then allows any number of alternative streamtabs via a linked list of streamtabs. Thus, if the user wanted to perform conformance testing, and then wanted to perform functional testing, it would not be necessary to reload the system. Rather, it is only necessary to select a new streamtab. By arranging the data structures, it is possible to add enhancements or optional data structures. For example, when a STREAM is opened inside each queue, there is a read queue and a write queue (as discussed above). In the read queue, there are pointers referred to as queue info. The queue info points back to another streamtab, such that it is possible to select any of these alternatives streamtabs on the fly. By default, the system selects a particular streamtab, e.g. normal streamtab 110. But if desired, the queue pointer can be set to any of the alternative streamtabs 120, 130 that are configured within the system. From a user space point of view, it is only necessary to implement a controller that generates one or more IOCTL commands to specify which streamtab is to be selected. As a result of such selection, there is no modification to the STREAMS' framework, i.e. it is not necessary to stop an application. Thus, the STREAMS framework itself is adapted to implement such alternative functions and enhancements. It is only necessary to enable the additional IOCTL commands, and then the data structures are created that include predefined functions. In the modsw (FIG. 8), the pointer d.sub.-- curstr is the current streamtab. Thus, when an alternative streamtab is selected and then the system is returned to a current state, the pointer d.sub.-- curstr sets the system back to the current streamtab. Accordingly, FIG. 8 provides a block schematic representation of a template in accordance with the invention that includes a structure, for example for a QINIT for tracing, debugging and time stamping; for alternative streamtabs, for example for installing an enhanced or optional function; and sample code that can be invoked by a user or developer, for example for specific system testing. Although the invention is described herein with reference to the preferred embodiment, one skilled in the art will readily appreciate that other applications may be substituted for those set forth herein without departing from the spirit and scope of the present invention. Accordingly, the invention should only be limited by the Claims included below.
|
Same subclass Same class Consider this |
||||||||||
