× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.




Hello Buck,

Scott's example sounds like a Finite State Machine.  FSMs are commonly
implemented via a SELECT construct.  However as you said, if you have many
states then the construct becomes unwieldy.

One common approach to this is to have a pool of jobs that handle the client
requests and a single 'manager' job that handles the socket select()
function.  Use local sockets [socketpair()] to communicate between the
manager and the pool jobs.  The pool jobs do the real work.  It is even
possible to have a single pool job handle multiple clients.

If that seems too much work then the FSM code can be simplified by changing
the structure a bit.  Build a table (data structure) mapping states to
procedure pointers.  Create a separate procedure to handle each state.  If
possible, define the same parameter structure for each procedure or at least
a pointer to a data structure.  That way all the procedures can be called
using the same interface.  You could also just pass an occurence number for
a global MODS.  You can populate the array of function pointers in your
initialisation routine or statically initialise them.

Now all your code must do is determine the current state for a client,
lookup the state array to find it and call the appropriate function.  The
function does its work based on the data passed in, sets the next state, and
returns.  The whole process can be implemented in a straightforward loop.

I started to include example code but found I had to verify things with the
compiler so here is the complete example I put together.  It was compiled
and run on VRM440 with reasonably current PTFs.  It supports 4 states and 1
client but is easily extendable to support additional states and clients.
It should be reasonably understandable.  Feel free to continue the
discussion if you have questions.  Comments and criticism from others is
welcomed but may be ignored.

     H DFTACTGRP(*NO) ACTGRP(*NEW)

      * Valid states for Finite State Machine
     D $VLD_UID        C                   CONST(1)
     D $VLD_PWD        C                   CONST(2)
     D $GET_ORD        C                   CONST(3)
     D $CNL_ORD        C                   CONST(4)

     D $MAX_STATES     C                   CONST(4)
     D $MAX_CLIENTS    C                   CONST(1)

      * Table of states and associated function pointers
      *   Note the 14-byte filler to make the 16-byte alignment obvious
     D functionDS      DS
     D                                5I 0 INZ($VLD_UID)
     D                               14
     D                                 *   PROCPTR
INZ(%PADDR('VALIDATEUSERID'))
     D                                5I 0 INZ($VLD_PWD)
     D                               14
     D                                 *   PROCPTR
     D
INZ(%PADDR('VALIDATEUSERPWD'))
     D                                5I 0 INZ($GET_ORD)
     D                               14
     D                                 *   PROCPTR
INZ(%PADDR('GETNEXTORDER'))
     D                                5I 0 INZ($CNL_ORD)
     D                               14
     D                                 *   PROCPTR
INZ(%PADDR('CANCELORDER'))
     D functionTbl                   32    DIM($MAX_STATES)
OVERLAY(functionDS)
     D  state                         5I 0 OVERLAY(functionTbl:1)
     D  function                       *   PROCPTR OVERLAY(functionTbl:17)

      * Function pointer used to invoke one of the following procedures
      * We must define a dummy prototype for this because RPG IV will not
      * let us code:
      ****    D validateUserID  PR              N   EXTPROC(@function)
      ****    D  @parmStruct                    *
      * AND have a procedure in this program with the same name as the
      * prototype.  Yet another example of a crippled implementation.
     D @function       S               *   PROCPTR
     D theFunction     PR              N   EXTPROC(@function)
     D  @parmStrut                    *

      * Prototypes for functions which do the actual work.  They all accept
      *  a pointer.  We do this because each function may require different
      *  information.  There are other methods but this is easiest.
     D validateUserId  PR              N
     D  @parmStruct                    *
     D validateUserPwd...
     D                 PR              N
     D  @parmStruct                    *
     D getNextOrder    PR              N
     D  @parmStruct                    *
     D cancelOrder     PR              N
     D  @parmStruct                    *

     D setNextState    PR              N
     D  occurence                     5I 0

      * Add fields as necessary to track client state
     D clientData      DS                   OCCURS($MAX_CLIENTS) INZ
     D   clientState                  5I 0  INZ($VLD_UID)
     D   clientOccur                  5I 0

      * Work space for client data passed as parameter to each function
     D parmStruct      S           1024
     D @parmStruct     S               *    INZ(%ADDR(parmStruct))

      * Add fields as necessary to each structure
      *   (So why can't I simply code BASED(%ADDR(parmStruct)) ??)
      *   (more RPG IV short-sightedness !!!)
     D vui_data        DS                  BASED(@parmStruct)
     D                                5I 0
     D   vui_occur                         LIKE(clientOccur)
     D vup_data        DS                  BASED(@parmStruct)
     D                                5I 0
     D   vup_occur                         LIKE(clientOccur)
     D gno_data        DS                  BASED(@parmStruct)
     D                                5I 0
     D   gno_occur                         LIKE(clientOccur)
     D co_data         DS                  BASED(@parmStruct)
     D                                5I 0
     D   co_occur                          LIKE(clientOccur)

     D i               S              5I 0

      * ÝÝÝÝÐM A I N L I N E ÝÝÝÝÝ
      * For as many states as the machine supports
     C                   DO        $MAX_STATES

      *   Determine which client we are processing
     C     1             OCCUR     clientData
     C                   EVAL      clientOccur Ð1

      *   Locate the current state and run the associated procedure
     C                   EVAL      i Ð1
     C     clientState   LOOKUP    state(i)                               99
     C                   IF        *IN99
     C                   EVAL      parmStruct ÐclientData
      ****  (So why can't I code:
      ****                  IF        NOT(function(i)(@parmStruct))
      ****  (or even)
      ****                  IF        NOT(@function(@parmStruct))
      ****  (more RPG IV short-sightedness!!)
     C                   EVAL      @function Ðfunction(i)
     C                   IF        NOT(theFunction(@parmStruct))
     C     'Buggered!'   DSPLY
     C                   ENDIF
     C                   ENDIF

     C                   ENDDO

     C                   SETON                                        LR
     C                   RETURN

      * ÝÝÝÝÝÝÝÝÝÝ   P setNextState    B
     D setNextState    PI              N
     D  occurrence                    5I 0
     C     occurrence    OCCUR     clientData
     C                   EVAL      clientState ÐclientState + 1
     C                   RETURN    *ON
     P setNextState    E

      * ÝÝÝÝÝÝÝÝÝÝ   P validateUserId  B
     D validateUserId  PI              N
     D  @parmStruct                    *

     D vui_data        DS                  BASED(@parmStruct)
     D                                5I 0
     D   vui_occur                         LIKE(clientOccur)

     D ok              S               N   INZ(*ON)

      * Do whatever is required to handle this process
     C     'state 1'     DSPLY

      * If all is OK then set next state
     C                   IF        ok
     C                   RETURN    seNextState( vui_occur )
     C                   ELSE
     C                   RETURN    *OFF
     C                   ENDIF
     P validateUserId  E

      * ÝÝÝÝÝÝÝÝÝÝ   P validateUserPwd...
     P                 B
     D validateUserPwd...
     D                 PI              N
     D  @parmStruct                    *

     D vup_data        DS                  BASED(@parmStruct)
     D                                5I 0
     D   vup_occur                         LIKE(clientOccur)

     D ok              S               N   INZ(*ON)

      * Do whatever is required to handle this process
     C     'state 2'     DSPLY

      * If all is OK then set next state
     C                   IF        ok
     C                   RETURN    setNextState( vup_occur )
     C                   ELSE
     C                   RETURN    *OFF
     C                   ENDIF
     P validateUserPwd...
     P                 E

      * ÝÝÝÝÝÝÝÝÝÝ   P getNextOrder    B
     D getNextOrder    PI              N
     D  @parmStruct                    *

     D gno_data        DS                  BASED(@parmStruct)
     D                                5I 0
     D   gno_occur                         LIKE(clientOccur)

     D ok              S               N   INZ(*ON)

      * Do whatever is required to handle this process
     C     'state 3'     DSPLY

      * If all is OK then set next state
     C                   IF        ok
     C                   RETURN    setNextState( gno_occur )
     C                   ELSE
     C                   RETURN    *OFF
     C                   ENDIF
     P getNextOrder    E

      * ÝÝÝÝÝÝÝÝÝÝ   P cancelOrder     B
     D cancelOrder     PI              N
     D  @parmStruct                    *

     D co_data         DS                  BASED(@parmStruct)
     D                                5I 0
     D   co_occur                          LIKE(clientOccur)

     D ok              S               N   INZ(*ON)

      * Do whatever is required to handle this process
     C     'state 4'     DSPLY

      * If all is OK then set next state
     C                   IF        ok
     C                   RETURN    setNextState( co_occur )
     C                   ELSE
     C                   RETURN    *OFF
     C                   ENDIF
     P cancelOrder     E

Regards,
Simon Coulter.

«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»
«» FlyByNight Software         AS/400 Technical Specialists       «»
«» Eclipse the competition - run your business on an IBM AS/400.  «»
«»                                                                «»
«» Phone: +61 3 9419 0175   Mobile: +61 0411 091 400        /"\   «»
«» Fax:   +61 3 9419 0175   mailto: shc@flybynight.com.au   \ /   «»
«»                                                           X    «»
«»               ASCII Ribbon campaign against HTML E-Mail  / \   «»
«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»


As an Amazon Associate we earn from qualifying purchases.

This thread ...


Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].

Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.