Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ alp(7) — Reliant UNIX 5.44c4

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

alpq(1)

kbd(7)

alp(7)                         04 Jun 1992                           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 main-
     tain extensive state information related to each connection. An algo-
     rithm from the pool is called by another in-kernel module with argu-
     ments 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 inter-
     face for codeset conversion within STREAMS modules, especially kbd,
     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 algo-
     rithms 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 initiali-
     zation routine (xxxinit) which is called at system startup time to
     register it 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 accommo-
     date 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 dis-
     cussion concerns the in-kernel operation and use of the module.




Page 1                       Reliant UNIX 5.44                       6, 194

alp(7)                         04 Jun 1992                           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 */
          caddr_t id;             /* unique id */
          mblk_t *(*func)();      /* ptr to func ret'ng ptr to mblkt */
     /*
      *   mblk_t *(*alp_con(unsigned char *, caddr_t))(mblk_t *, caddr_t);
      */
          ...

          if (func = alp_con(name, (caddr_t) &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:
          mblk_t *mp, *outp;
          mblk_t *(*func)();
          ...
          outp = (*func)(mp, id);
          mp = NULL;   /* mp 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 rou-
     tine needs more information, or is buffering something, outp will be a
     null pointer.  In either case, the original message (mp) may not be
     subsequently accessed by the caller.  The interface routine takes
     charge of the message mp, and may free it or otherwise dispose of it
     (it may even return the same message). The caller may pass a null mes-
     sage 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 partic-
     ular 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


Page 2                       Reliant UNIX 5.44                       6, 194

alp(7)                         04 Jun 1992                           alp(7)

     possible to synchronize when input message 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 rou-
     tine is called when the system is booted and prior to nearly every-
     thing 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 be subsequently accessed.  Any other required initiali-
     zation 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 mblk_t *genfunc(); /* interface routine */
          caddr_t genopen();
          static struct alp_d genalg =
               INIT_KERN_ALG(genopen, genfunc, "name",
                    "explanation");
     /*
      *   int alp_register(struct alp_d *);
      */

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

               rval = alp_register(&genalg);
               if (rval) cmn_err(CE_WARN, "warning message");
          }

     The registration routine, alp_register takes one argument and returns
     zero if successful. The argument is a pointer to the structure alp_d
     which is initialized with the macro INIT_KERN_ALG. The arguments to
     INIT_KERN_ALG are: a pointer to the algorithm open routine, a pointer
     to the algorithm interface routine, a pointer to the name of the algo-
     rithm, and a pointer to a character string containing a brief descrip-
     tion of the algorithm. The name should be limited to under 16 bytes,
     and the explanation to under 60 bytes, as shown in the following exam-
     ple.  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 sin-
     gle init routine.

     A module's open routine is called by alp_con when a connection is
     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


Page 3                       Reliant UNIX 5.44                       6, 194

alp(7)                         04 Jun 1992                           alp(7)

     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 con-
     nection; 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 caddr_t, in a manner simi-
     lar to the private data held by each instantiation of a STREAMS
     module.

     A skeleton for the gen module's open routine is:
          caddr_t
          genopen(arg, id)
               int arg;
               caddr_t 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
     alp_discon, passing the unique id and the name:
          ...
          #include <sys/alp.h>

          caddr_t id;
          char *name;
          mblk_t *mp;
     /*
      *   mblk_t *alp_discon(unsigned char *, caddr_t);
      */
          ...
          mp = alp_discon(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
     flushing it or sending it to the neighboring module).




Page 4                       Reliant UNIX 5.44                       6, 194

alp(7)                         04 Jun 1992                           alp(7)

   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 alp_query takes a
     single argument, a pointer to a name.  If the name matches a
     registered function, alp_query 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 *alp_query(unsigned char *);
      */
          ...
          if (expl = alp_query(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 sup-
     ported by the alpq command, which may be used whenever user-level pro-
     grams 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 map-
     ping) supports the use of alp algorithms as processing elements.

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

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

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>
     #include <sys/stropts.h>
     #include <sys/kmem.h>


Page 5                       Reliant UNIX 5.44                       6, 194

alp(7)                         04 Jun 1992                           alp(7)

     #include <sys/alp.h>

     static mblk_t *dely();
     caddr_t delyopen();

     /*
      * Our state structure.  Keeps its own address and a pointer.
      */
     struct dstruct {
          caddr_t d_unique;
          mblk_t *d_mp;
     };

     /*
      * The name is "Dely".  It has an open routine "delyopen"
      * and an interface "dely".
      */
     static struct alp_d delyalgo =
          INIT_KERN_ALG(delyopen, dely, "Dely",
               "One Message Delay Buffer");

     /*
      * This is the sysinit routine, called when the system is
      * being brought up.  It registers "Dely" with ALP.
      */
     delyinit()
     {
          if (alp_register(&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 mblk_t *
     dely(mp, id)
          mblk_t *mp;
          caddr_t id;
     {
          register mblk_t *rp;
          register struct dstruct *d;

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

     /*
      * The open (and close) routine.
      * Use kmem_zalloc() to get a private


Page 6                       Reliant UNIX 5.44                       6, 194

alp(7)                         04 Jun 1992                           alp(7)

      * structure for saving state info.
      */
     caddr_t
     delyopen(arg, id)
          int arg;       /* 1 = open, 0 = close */
          caddr_t id;    /* ignored on open; is unique id on close */
     {
          register struct dstruct *d;
          register mblk_t *rp;

          if (! arg) {   /* close processing */
               d = (struct dstruct *) id;
               d->d_unique = (caddr_t) -1;
               rp = d->d_mp;
               kmem_free(d, sizeof(struct dstruct));
               return((caddr_t) rp);
          }
          /* otherwise, open processing */
          d = (struct dstruct *) kmem_zalloc(sizeof(struct dstruct),
               KM_NOSLEEP);
          d->d_unique = (caddr_t) &d;
          return((caddr_t) d);
     }































Page 7                       Reliant UNIX 5.44                       6, 194

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