We think it is usefull to include some introduction to CMS Multitasking, as it provides new functionality for REXX, such as waiting for various events like APPC, queues (even cross system), timers (even smaller than 1 second), etc..
CMS Application Multitasking was introduced in VM/ESA Release 1.2.0.
It is very similar to the OS/2 multitasking model and uses:
It is of use to high-performance servers that need:
It supports following languages through CSL calls:
The multitasking services allow a program to sub-divide itself into several independent executable parts, and coordinate these execution streams so that they together accomplish the objective of the program.
These services also allow multitasking programs running in different virtual machines to communicate with each other and to coordinate their processing.
A multitasking application can also take advantage of multiple CPUs in the computer complex. Multiprocessor exploitation is supported only in XA- or XC-mode virtual machines. The other aspects of multitasking are equally supported in all virtual machine modes.
The primary goal is to provide multitasking support for high performance CMS-based servers and provide a means for CMS applications to exploit the power of the multiprocessor capability of the underlying computer complex.
Multitasking supports an environment in which only one multitasking application is executing in a particular virtual machine at any one time. It allows a programmer to write a multitasking application, but is not intended to provide a means for a CMS end-user to run several separate applications at the same time. In other words, users still execute one command at a time.
Multitasking function calls are coded in the application source as though they were ordinary functions or subroutines. CMS provides a set of programming language binding files that declare external functions, constants, and return and reason codes.
The program source must include at least one of the language binding files for multitasking services to be usable from the application. You must ensure that all the function definitions used are included in the program. A safe approach is to include all the functions at once. If you include function definitions selectively, you must also include the return and reason code definitions.
Very soon after IPL, CMS will try to find the Multitasking CSL routines. CMS will try to load a shared segment named VMMTLIB if it exists.
It is loaded by DMSINS before the SYSPROF ever gets control. The default segment name is VMMTLIB, but can be overridden or disabled at IPL of CMS via IPL CMS PARM MTSEG segname|NO.
Whereas REXX can not create other tasks, the CMS Multitasking (CMS/MT) functions can be useful in REXX.
CMS/MT introduces queuing interfaces: one task can write to a queue, while another task can wait on it (or other events too). Such a queue has a name.
|
What is great is that
the queue creating task and the queue writing tasks don't need to live
in the same Virtual Machine, and via definitions in NAMES files it is completely
transparent to the application program where the queue lives. If it
is remote, CMS/MT will open an APPC session to talk to it's partner.
Then VM/APPC can automatically help you a bit: if your partner isn't
logon yet, CP will autolog it.
And, all this can be done from REXX, continue reading to see how easy this all is... (good-bye WAKEUP & SMSG ?). |
Below you will find a complete example written by one of the CMS/MT developers.
These REXX programs demonstrate the use of CMS distributed queues on CMS. They simulate a sample client and server.
Installation and usage
In your first experiments, I'd encourage you to put CLIENT and SERVER on the same VM/ESA system and not use the TSAF (Transparent Service Access Facility) or AVS (APPC/VM VTAM Support) networking servers. After you've gotten the hang of things, you may choose to put CLIENT and SERVER on different VM/ESA systems and connect those systems by TSAF and/or AVS. In both cases, CLIENT and SERVER work alike, but if you change the relative locations of the client and the server, you will have to make Communications Directory changes.
QDEMO EXEC -- starts client program QCLIENT EXEC -- sample client program UCOMDIR NAMES -- CMS Communications Directory file
QSERVER EXEC -- sample server program $SERVER$ NAMES -- CMS private resource registration file
IUCV ALLOW IPL CMS PARM AUTOCR
SET SERVER ON SET AUTOREAD OFF SET FULLSCREEN OFF
Note the following
These are the contents of the different files listed above:
The client can execute this QDEMO procedure:
/* QDEMO Procedure */ 'SET COMDIR FILE USER UCOMDIR NAMES *' 'SET COMDIR RELOAD' 'EXEC QCLIENT' return
The $QUEUES$ NAMES file looks like this:
*** * $QUEUES$ NAMES file for q demo program *** :nick.server :scope.NETWORK :carrier.APPC/VM :qn.qdemo :sdn.sdn
This file defines where the CMS/MT named queues reside. The APPC/VM keyword tells the communication is via APPC. The APPC resource name is sdn. APPC functions will always look in the CMS Communications Directories (UCOMDIR NAMES or SCOMDIR NAMES files), thus the following User Communications Names file indicates to APPC/VM that the nickname sdn should start a conversation with user SERVER on this same VM system (you'd change the :luname. tag if your server virtual machine would be on another system in the VM complex). The APPC routines will then pass the VMIPC transaction name to the server.
*** * UCOMDIR NAMES for q demo program *** :nick.sdn :tpn.VMIPC :luname.*USERID SERVER
When CP autologs the SERVER virtual machine due to the APPC request, this machine will IPL CMS and execute the PROFILE EXEC. The SET SERVER ON command in the profile makes that CMS will scan this $SERVER$ NAMES file for the transaction program name (VMIPC), and in this example understand that it has to execute the program QSERVER, which is the EXEC listed thereafter.
*** * $SERVER$ NAMES for q demo program *** :nick.VMIPC :module.QSERVER :list.*
The rest of the flow of events can be found in the QCLIENT and QSERVER procedures:
QCLIENT EXEC |
---|
/* sample queue client */ call apiload(vmrexmt) /* load rexx interface variables */ maxtries = 3 /* maximum retries for connection */ delay = 3000 /* delay between retries */ say 'Queue Demonstration Program (REXX)' say 'Enter the name of the remote queue, please.' parse pull qn say ' ' say 'Starting the slave program... one moment, please...' i = 0 /* counter */ ok = 0 qnl = length(qn) sv.1 = vm_ipc_nlevel sv.2 = 0 sv.3 = 0 svl = 1 /* Next request will make that the server gets autologged. Once this */ /* is done, the server is supposed to create the queue. */ do while ((i < maxtries) & (ok = 0)) /* loop until open */ call csl 'QueueOpen mtrc mtre qn qnl sv svl qh el' say 'RC='mtrc 'RE='mtre 'from QueueOpen' if (mtrc = vm_ipc_success) then ok=1 /* queue open */ else do i = i + 1 call csl 'ThreadDelay mtrc mtre delay' /* wait a while */ end end /* dispatch on result */ if ¬ok then call errexit 4,, 'The QueueOpen of' qn 'didn''t work.',, 'Check your $QUEUES$ NAMES and ComDir stuff.' else do say ' ' say 'Enter a CMS command and it will be executed on the' say 'slave machine. Enter ''$exit'' to end the demo.' parse value '0 0 0' with ok ko kl do while ¬ok say 'Enter your command now...' parse pull cmscmd cmdlen = length(cmscmd) call csl 'QueueSend mtrc mtre qh cmscmd cmdlen ko kl' /* send cmd */ if (cmscmd = '$exit') then do say 'Ending...' call csl 'QueueClose mtrc mtre qh' ok=1 end end end call exit 0,'All done' |
QSERVER EXEC |
---|
/* sample queue-based server */ /* load API definitions */ call apiload(vmrexmtr) call apiload(vmrexipc) /* set up constants for QueueCreate */ qn = 'qdemo' qnl = length(qn) /* set up constants for QueueReceiveBlock */ matchkey = '*' matchkeylen = length(matchkey) timeout = 0 rcvbuflen = 256 /* announce myself */ say 'Queue Demonstration Slave (REXX) is starting...' /* create service queue */ created = 0 call csl 'QueueCreate mtrc mtre qn qnl vm_ipc_nlevel qh' if (mtrc ^= vm_ipc_success) then call errexit 8,, 'RC='mtrc 'RE='mtre 'creating service queue' else do created = 1 /* receive and process until done */ ok = 0 do while ¬ok say 'Waiting for work...' /*********************/ call csl 'QueueReceiveBlock mtrc mtre qh ', /* wait until some- */ 'matchkey matchkeylen timeout ', /* thing arrives on */ 'cmscmd rcvbuflen cmdlen ', /* the queue... */ 'ko kl suid spid rt' /*********************/ if (mtrc ^= vm_ipc_success) then do say 'RC='mtrc 'RE='mtre 'from QueueReceiveBlock' erc = 8 ok = 1 end; else do /* got a message... process accordingly */ cmscmd = left(cmscmd,cmdlen) if (cmscmd = '$exit') then do erc = 0 end; else do say suid 'says to do...' say cmscmd cmscmd end end end end /* delete service queue */ if (created = 1) then do call csl 'QueueDelete mtrc mtre qn qnl vm_ipc_nlevel' if (mtrc ^= vm_ipc_success) then do say 'RC='mtrc 'RE='mtre 'from QueueDelete' end end call errexit erc |
We leave it up to you to study these procedures and to try this on your system. Chapter 21 is the very last chapter of this course. It explains some options that may improve the performance of your procedures.