|
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 mailing list archive is Copyright 1997-2025 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.