Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ alp(7) — UnixWare 2.01

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

alpq(1)

kbd(7)






       alp(7)                                                        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 code set 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 code set 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 (xxxinit) which is called
             at system startup time to register itself with alp, an open
             routine, and an interface routine (which actually implements


                           Copyright 1994 Novell, Inc.               Page 1













      alp(7)                                                        alp(7)


            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.

         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:

                  unsigned char *name;    /* algorithm name */
                  caddr_t id;             /* unique id */
                  mblk_t *(*func)();      /* func returns ptr to mblk_t */
                  mblk_t *(*alp_con())(); /* returns pointer to mblk_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 *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


                          Copyright 1994 Novell, Inc.               Page 2













       alp(7)                                                        alp(7)


             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
             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 have 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 code
             set 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 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:

                   geninit()
                   {
                         mblk_t *genfunc(); /* interface routine */
                         int rval;          /* return value from registrar */
                         rval = alp_register(genfunc, "name", "explanation");
                         if (rval) cmn_err(CE_WARN, "warning message");
                   }

             The registration routine, alp_register takes three arguments
             and returns zero if successful.  The arguments are (1) a
             pointer to the algorithm's entry point (in this case, the
             function genfunc), (2) a pointer to its name, and (3) a


                           Copyright 1994 Novell, Inc.               Page 3













      alp(7)                                                        alp(7)


            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.
                  i = alp_register(sjisfunc, "stou",
                        "Shift-JIS to UJIS converter");

            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 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 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 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:
                  genopen(arg, id)
                        int arg;
                        caddr_t id;
                  {
                        if ( arg ) {
                              open processing;
                              return( unique-id );
                        }
                        close processing for id;
                        return(0);
                  }



                          Copyright 1994 Novell, Inc.               Page 4













       alp(7)                                                        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:
                   caddr_t id;
                   char *name;
                   mblk_t *alp_discon(), *mp;
                   ...
                   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 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:
                   unsigned char *alp_query(), *name, *expl;
                   ...
                   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 supported by the alpq command, which may
             be used whenever user-level programs need the associated
             information.

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



                           Copyright 1994 Novell, Inc.               Page 5













      alp(7)                                                        alp(7)


            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.

         Examples
            /*
             * 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;
            };
            /*
             * 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");
            }
            /*


                          Copyright 1994 Novell, Inc.               Page 6













       alp(7)                                                        alp(7)


              * 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_alloc() 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; 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);
             }

       REFERENCES
             alpq(1), kbd(7)






                           Copyright 1994 Novell, Inc.               Page 7








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