Chapter 20. CMS Multitasking.

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:

Characteristics

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.

Implementation.

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.

Example using REXX.

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

  1. Acquire two virtual machines - one will be the example client and one will be the example server.  In the rest of this document, we will assume the former's user ID is CLIENT and that the latter user ID is SERVER.

    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.

  2. In CLIENT, put these files on the A-disk:
             QDEMO EXEC          -- starts client program
             QCLIENT EXEC        -- sample client program
             UCOMDIR NAMES       -- CMS Communications Directory file
    
  3. In SERVER, put these files on the A-disk:
             QSERVER EXEC        -- sample server program
             $SERVER$ NAMES      -- CMS private resource registration file
    
  4. Make sure that the CP directory entry for SERVER includes the following records:
             IUCV ALLOW
             IPL CMS PARM AUTOCR
    
  5. Make sure that the PROFILE EXEC for SERVER contains these commands:
             SET SERVER ON
             SET AUTOREAD OFF
             SET FULLSCREEN OFF
    
  6. To use the example, logon to CLIENT and issue the command QDEMO.

Note the following 

  1. SERVER does not have to be logged on.  You will be able to type in commands and send them to the server.
  2. When the client prompts you for the name of the remote queue, the response you enter must correspond to the value of a :nick. tag in $QUEUES$ NAMES.  In the sample, the correct response to the prompt is SERVER.
  3. If you cause the server to begin executing some interactive program (for example, FILELIST), you must log onto the server and end the interactive program by hand before it will accept another command from the client.

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.