Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ alp(7) — mips UMIPS RISC/os 5.01

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

alpq(1)

kbd(7)



ALP(7)              RISC/os Reference Manual               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 func-
     tions; 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 argu-
     ments that are a STREAMS data message and a unique identif-
     ier.  If a message is passed back to the caller, it is the
     algorithm's output, otherwise the algorithm may store par-
     tially 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 flexi-
     ble interface 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 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 (xxx init) 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



                        Printed 11/19/92                   Page 1





ALP(7)              RISC/os Reference Manual               ALP(7)



     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.

   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 mblk_t */
     /*
      *   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 mes-
     sages:

          mblk_t *inp, *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 routine 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



 Page 2                 Printed 11/19/92





ALP(7)              RISC/os Reference Manual               ALP(7)



     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 use-
     ful for end-of-file conditions to insure that all data has
     been passed through.  (Interface routines must thus recog-
     nize 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 mul-
     tibyte 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 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 initializa-
     tion 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 pur-
     pose is to register the algorithm with the alp module, so
     that it may subsequently accessed.  Any other required ini-
     tialization 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 algo genlogo = {
               0,        /* in-core */
               (queue_t *)0,  /* read queue */
               (queue_t *)0,  /* write queue */
               genfunc,  /* interface routine */
               genopen,  /* open/close routine */
               (unsigned char *)"name",
               (unsigned char *)"explanation",
               (struct algo *)0
          };
     /*
      *   int alp_register(struct algo *);
      */

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



                        Printed 11/19/92                   Page 3




ALP(7)              RISC/os Reference Manual               ALP(7)



               rval = alp_register(&genlogo);
               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 algo which has members (1) a pointer to the
     algorithm's entry point (in this case, the function gen-
     func), (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 dif-
     ferent, related algorithms, which can each be registered
     separately by a single init routine.

     A module's open routine is called by alp_con when a connec-
     tion 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 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 rou-
     tine 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 con-
     nection; 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 similar 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);



 Page 4                 Printed 11/19/92





ALP(7)              RISC/os Reference Manual               ALP(7)



          }


     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).

   The ioctl and Query Interfaces
     A kernel-level query interface is provided in addition to
     the query interface supported by the alpq command.  The rou-
     tine 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;






                        Printed 11/19/92                   Page 5





ALP(7)              RISC/os Reference Manual               ALP(7)



     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 sup-
     plies 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 pro-
     grams running at user-level.

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>
     #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;
     };




 Page 6                 Printed 11/19/92





ALP(7)              RISC/os Reference Manual               ALP(7)



     /*
      * The name is "Dely".  It has an open routine "delyopen"
      * and an interface "dely".
      */
     static struct algo delyalgo =
     {
          0, (queue_t *) 0, (queue_t *) 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 (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
      * 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;



                        Printed 11/19/92                   Page 7





ALP(7)              RISC/os Reference Manual               ALP(7)



          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 8                 Printed 11/19/92



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