Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ alp(7) — DG/UX 5.4.2A

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

alpq(1)



alp(7)                           DG/UX 5.4.2                          alp(7)


NAME
       alp - Algorithm Pool management module

DESCRIPTION
       The STREAMS module alp maintains a pool of algorithms (in the form of
       STREAMS-compatible subroutines) that may be used for processing
       STREAMS data messages.  Interfaces are defined allowing modules to
       request and initiate processing by any of the algorithms maintained
       in the pool.  It is expected to help centralize and standardize the
       interfaces to algorithms that now represent a proliferation of
       similar-but-different STREAMS modules.  Its major use is envisioned
       as a central registry of available codeset conversion algorithms or
       other types of common data-manipulating routines.

       An algorithm pool is a registry (or pool) of available functions; in
       this case, routines for performing transformations on STREAMS data
       messages.  Registered functions may keep information on attached
       users, which means that algorithms need not be ``stateless'', but may
       maintain extensive state information related to each connection.  An
       algorithm from the pool is called by another in-kernel module with
       arguments that are a STREAMS data message and a unique identifier.
       If a message is passed back to the caller, it is the algorithm's
       output, otherwise the algorithm may store partially convertible input
       until enough input is received to give back output on a subsequent
       call.

       This pool is one means for providing a consistent and flexible
       interface for codeset conversion within STREAMS modules, especially
       attkbd, but it may also be used to provide other services that are
       commonly duplicated by several modules.

       The alp module contains some subroutines dealing with its (minor)
       role as a module, a data definition for an algorithm list, connection
       and disconnection routines, and a search routine for finding
       registered items.  The module interface incorporated into alp serves
       the purpose of providing an ioctl interface, so that users can find
       out what algorithms are registered [see alpq(1)].

       The programmer of a function for use with alp provides a simple
       module with a simple specified interface.  The module must have an
       initialization routine (xxxinit) which is called at system startup
       time to register itself with alp, an open routine, and an interface
       routine (which actually implements the algorithm).

       The registry method of dynamically building the list of available
       functions obviates the need for recompiling modules or otherwise
       updating a list or reconfiguring other parts of the system to
       accommodate additions or deletions.  To install a new function
       module, one merely links it with the kernel in whatever manner is
       standard for that system; there is no need for updating or re-
       configuring any other parts of the kernel (including alp itself).
       The remainder of this discussion concerns the in-kernel operation and
       use of the module.




Licensed material--property of copyright holder(s)                         1




alp(7)                           DG/UX 5.4.2                          alp(7)


   Calling Sequence
       An algorithm is called from the pool by first requesting a connection
       via the alp connection interface.  The alp module returns the
       function address of an interface routine, and fills in a unique
       identifier (id) for the connection.  The returned function address is
       NULL on failure (and id is undefined).  This is a sample of making a
       connection to a function managed by alp:
            ...
            #include <sys/alp.h>

            unsigned char *name;    /* algorithm name */
            caddrt id;             /* unique id */
            mblkt *(*func)();      /* ptr to func ret'ng ptr to mblkt */
       /*
        *   mblkt *(*alpcon(unsigned char *, caddrt))(mblkt *, caddrt);
        */
            ...

            if (func = alpcon(name, (caddrt) &id))
                 regular processing;
            else
                 error processing;

       Once the connection has been made, the interface routine can be
       called directly by the connecting module to process messages:
            mblkt *inp, *outp;
            mblkt *(*func)();
            ...
            outp = (*func)(inp, id);
            inp = NULL;   /* inp cannot be re-used! */
            if (outp)
                 regular processing;

       If the interface routine processed the entire message, then outp is a
       valid pointer to the algorithm's output message.  If, however, the
       routine needs more information, or is buffering something, outp will
       be a null pointer.  In either case, the original message (inp) may
       not be subsequently accessed by the caller.  The interface routine
       takes charge of the message inp, and may free it or otherwise dispose
       of it (it may even return the same message).  The caller may pass a
       null message pointer to an interface routine to cause a flush of any
       data being held by the routine; this is useful for end-of-file
       conditions to insure that all data has been passed through.
       (Interface routines must thus recognize a null message pointer and
       deal with it.)

       Synchronization between input and output messages is not guaranteed
       for all items in the pool.  If one message of input does not produce
       one message of output, this fact should be documented for that
       particular module.  Many multibyte codeset conversion algorithms, to
       cite one instance, buffer partial sequences, so that if a multibyte
       character happens to be spread across more than one message, it may
       take two or more output messages to complete translation; in this
       case, it is only possible to synchronize when input message



Licensed material--property of copyright holder(s)                         2




alp(7)                           DG/UX 5.4.2                          alp(7)


       boundaries coincide with character boundaries.

   Building an Algorithm for the Pool
       As mentioned, the modules managed by alp are implemented as simple
       modules--not STREAMS modules--each with an initialization routine, an
       open routine, and a user-interface routine.  The initialization
       routine is called when the system is booted and prior to nearly
       everything else that happens at boot-time.  The routine takes no
       arguments and its sole purpose is to register the algorithm with the
       alp module, so that it may subsequently accessed.  Any other required
       initialization may also be performed at that time.  A generic
       initialization routine for a module called GEN, with prefix gen is as
       follows:
            ...
            #include <sys/alp.h>

            static mblkt *genfunc(); /* interface routine */
            caddrt genopen();
            static struct algo genlogo = {
                 0,        /* in-core */
                 (queuet *)0,  /* read queue */
                 (queuet *)0,  /* write queue */
                 genfunc,  /* interface routine */
                 genopen,  /* open/close routine */
                 (unsigned char *)"name",
                 (unsigned char *)"explanation",
                 (struct algo *)0
            };
       /*
        *   int alpregister(struct algo *);
        */

            geninit()
            {
                 int rval; /* return value from registrar */

                 rval = alpregister(&genlogo);
                 if (rval) cmnerr(CEWARN, "warning message");
            }

       The registration routine, alpregister takes one argument and returns
       zero if successful.  The argument is a pointer to the structure algo
       which has members (1) a pointer to the algorithm's entry point (in
       this case, the function genfunc), (2) a pointer to its name, and (3)
       a pointer to a character string containing a brief explanation.  The
       name should be limited to under 16 bytes, and the explanation to
       under 60 bytes, as shown in the following example.  Neither the name
       nor the explanation need include a newline.

       It is possible for a single module to contain several different,
       related algorithms, which can each be registered separately by a
       single init routine.

       A module's open routine is called by alpcon when a connection is



Licensed material--property of copyright holder(s)                         3




alp(7)                           DG/UX 5.4.2                          alp(7)


       first requested by a user (that is, a module that wishes to use it).
       The open routine takes two arguments.  The first argument is an
       integer; if it is non-zero, the request is an ``open'' request, and
       the second argument is unused.  The function should allocate a unique
       identifier and return it as a generic address pointer.  If the first
       argument is zero, the request is a ``close'' request, and the second
       argument is the unique identifier that was returned by a previous
       open request, indicating which of (potentially several) connections
       is to be closed.  The routine does any necessary clean-up and closes
       the connection; thereafter, any normal interface requests on that
       identifier will fail.  This use of unique identifiers allows these
       modules to keep state information relating to each open connection;
       no format is imposed upon the unique identifier, so it may contain
       any arbitrary type of information, equivalent in size to a core
       address; alp and most callers will treat it as being of type caddrt,
       in a manner similar to the private data held by each instantiation of
       a STREAMS module.

       A skeleton for the gen module's open routine is:
            caddrt
            genopen(arg, id)
                 int arg;
                 caddrt id;
            {
                 if ( arg ) {
                      open processing;
                      return( unique-id );
                 }
                 close processing for id;
                 return(0);
            }

       Once a connection has been made, users may proceed as in the example
       in the previous section.  When the connection is to be closed (for
       example, the connecting module is being popped), a call is made to
       alpdiscon, passing the unique id and the name:
            ...
            #include <sys/alp.h>

            caddrt id;
            char *name;
            mblkt *mp;
       /*
        *   mblkt *alpdiscon(unsigned char *, caddrt);
        */
            ...
            mp = alpdiscon(name, id);
            if (mp)
                 process ``left-over'' data;


       If the disconnect request returns a valid message pointer (mp) then
       there was unprocessed or partially processed data left in an internal
       buffer, and it should be dealt with by the caller (for example, by



Licensed material--property of copyright holder(s)                         4




alp(7)                           DG/UX 5.4.2                          alp(7)


       flushing it or sending it to the neighboring module).

   The ioctl and Query Interfaces
       A kernel-level query interface is provided in addition to the query
       interface supported by the alpq command.  The routine alpquery takes
       a single argument, a pointer to a name.  If the name matches a
       registered function, alpquery returns a pointer to the function's
       explanation string, otherwise it returns a null pointer.  A calling
       example is:
            ...
            #include <sys/alp.h>

            unsigned char *name, *expl;
       /*
        *   unsigned char *alpquery(unsigned char *);
        */
            ...
            if (expl = alpquery(name))
                 regular processing;
            else
                 error processing;

       The ioctl interface provides calls for querying registered functions
       (for which the explanation discussed above is necessary); this is
       supported by the alpq command, which may be used whenever user-level
       programs need the associated information.

   Uses
       The alp module can be used to replace various kernel-resident codeset
       conversion functions in international or multi-language environments.
       The KBD subsystem (which supplies codeset conversion and keyboard
       mapping) supports the use of alp algorithms as processing elements.

       Since state information may be maintained, functions may also
       implement processing on larger or more structured data elements, such
       as transaction records and network packets.  Currently, STREAMS CPU
       priority is assumed by alp or should be set individually by interface
       and open routines.

FUTURE DIRECTIONS
       It should also provide a service interface, so that the algorithms
       registered there might be used directly by programs running at user-
       level.

EXAMPLES
       /* Copyright (c) 1989, 1990 AT&T.  All Rights Reserved. */
       #ident    "@(#)dely.c    1.0 AT&T USO PACIFIC 1990/03"

       /*
        * This is a SAMPLE module that registers with ALP and performs
        * a one-message delay.
        */
       #include <sys/types.h>
       #include <sys/stream.h>



Licensed material--property of copyright holder(s)                         5




alp(7)                           DG/UX 5.4.2                          alp(7)


       #include <sys/stropts.h>
       #include <sys/kmem.h>
       #include <sys/alp.h>

       static mblkt *dely();
       caddrt delyopen();

       /*
        * Our state structure.  Keeps its own address and a pointer.
        */
       struct dstruct {
            caddrt dunique;
            mblkt *dmp;
       };

       /*
        * The name is "Dely".  It has an open routine "delyopen"
        * and an interface "dely".
        */
       static struct algo delyalgo =
       {
            0, (queuet *) 0, (queuet *) 0, dely, delyopen,
            (unsigned char *) "Dely",
            (unsigned char *) "One Message Delay Buffer",
            (struct algo *) 0
       };

       /*
        * This is the sysinit routine, called when the system is
        * being brought up.  It registers "Dely" with ALP.
        */
       delyinit()
       {
            if (alpregister(&delyalgo))  /* then register with ALP */
                 printf("DELY: register failed\n");
       }

       /*
        * This is the interface routine itself.
        * Holds onto "mp" and returns whatever it had before.
        */
       static mblkt *
       dely(mp, id)
            mblkt *mp;
            caddrt id;
       {
            register mblkt *rp;
            register struct dstruct *d;

            d = (struct dstruct *) id;    /* clarify the situation */
            rp = d->dmp;
            d->dmp = mp;
            return(rp);         /* return the previous message */
       }



Licensed material--property of copyright holder(s)                         6




alp(7)                           DG/UX 5.4.2                          alp(7)


       /*
        * The open (and close) routine.
        * Use kmemzalloc() to get a private
        * structure for saving state info.
        */
       caddrt
       delyopen(arg, id)
            int arg;       /* 1 = open, 0 = close */
            caddrt id;    /* ignored on open; is unique id on close */
       {
            register struct dstruct *d;
            register mblkt *rp;

            if (! arg) {   /* close processing */
                 d = (struct dstruct *) id;
                 d->dunique = (caddrt) -1;
                 rp = d->dmp;
                 kmemfree(d, sizeof(struct dstruct));
                 return((caddrt) rp);
            }
            /* otherwise, open processing */
            d = (struct dstruct *) kmemzalloc(sizeof(struct dstruct),
                 KMNOSLEEP);
            d->dunique = (caddrt) &d;
            return((caddrt) d);
       }

SEE ALSO
       alpq(1), attkbd(7).




























Licensed material--property of copyright holder(s)                         7


Typewritten Software • bear@typewritten.org • Edmonds, WA 98026