Calling Multitasking Functions from Assembler

The services provided by CMS can be treated as external subroutines to the tasking application. They are invoked using BALR 14,15 linkage with R1 containing the address of a list of addresses of parameters, as defined by standard Type-1 linkage conventions:
Register Usage
R1 Address of a list of addresses of the parameters
R14 Return address
R15 Address of the entry point for the function

The external symbols and parameter address list DSECTs are defined in the assembler binding files. The application can call CMS functions without using the parameter list DSECTs provided. They are provided only as a convenience, in case the programmer wishes to use symbolic names for the entries in the address list. The names of the DSECT fields are documented only in the binding files themselves. However, the important point is that the order of parameters is defined in the reference documentation for each function. That is all you need to know to build the parameter list.

An assembler call to the ThreadYield function would look like:
    L     R1,address of data area
    USING VMTHRYI_PLIST,R1
    MVC   VMTHRYI_PLIST_RC,=A(RC)       Address of return code
    MVC   VMTHRYI_PLIST_RE,=A(RE)       Address of reason code
    MVC   VMTHRYI_PLIST_TID,=A(TID)     Address of Thread ID
    L     R15,=A(THREADYIELD)
    BALR  R14,R15                       Invoke ThreadYield
The assembler language technique presented above produces only serially-reusable code. This is because parameters RC, RE, and TID all reside in storage locations whose addresses are constants computed by the loader at load time (note the use of =A in referring to those parameters). If reentrant code is required, then all parameters and the parameter list must reside in dynamically-obtained storage. This means that the parameter list must be built at run time using LA and ST instructions. For example, if we assume that R1 points to a fragment of dynamically-obtained storage for the parameter list, and if we assume that a base register for dynamically-obtained storage for the parameters themselves (for example, R13) has already been set up, then the following code fragment produces reentrant code:
     USING    VMTHRYI_PLIST,R1
     LA       R2,RC
     ST       R2,VMTHRYI_PLIST_RC
     LA       R2,RE
     ST       R2,VMTHRYI_PLIST_RE
     LA       R2,TID
     ST       R2,VMTHRYI_PLIST_TID
     L        R15,=A(THREADYIELD)
     BALR     R14,R15

If a section of code is shared among threads in a single dispatch class, and if that code contains a point at which control could be lost, then that code must be reentrant. If a section of code is shared among threads in multiple dispatch classes, then that section of code must be multiprocessor-capable.

A simpler way to handle the construction of the parameter address list and the function invocation is to use the CALL macro provided by CMS. It builds the parameter list automatically and generates the BALR instruction. The CALL macro does not support long names, so instead of specifying the routine name, use the register form.

The format of the CALL macro is:
Read syntax diagramSkip visual syntax diagramCALL ( reg) , (,parm)
Note: You must use the direct call format of the CALL macro. You cannot use CALL DMSCSL or the CSLFPI macro to call CMS multitasking functions.
So the call to ThreadYield would look like this:
    L      R15,=A(THREADYIELD)
    CALL   (15),(RC,RE,TID)
If you use the parameter list DSECTs provided, you can determine both the length of a particular parameter list DSECT and the largest parameter list DSECT included in your program. The length of a particular parameter list DSECT is in a variable named funcname_PLIST_LENGTH. The parameter list DSECT for ThreadYield looks like:
VMTHRYI_PLIST            DSECT
VMTHRYI_PLIST_RC         DS     F
VMTHRYI_PLIST_RE         DS     F
VMTHRYI_PLIST_THREAD_ID  DS     F
VMTHRYI_PLIST_LENGTH     EQU    *-VMTHRYI_PLIST

Determining the largest parameter list DSECT included in a program requires a few more assembler instructions. The length of the largest parameter list DSECT is found in a global macro variable called &DMAX. To use this length:

  1. Include the assembler binding files at the end of the program.
  2. Declare the global macro variable &DMAX before the assembler binding files.
  3. Define the variable with the largest parameter list DSECT length after the assembler binding files. The largest length is the address of &DMAX. A CSECT statement is required between the assembler binding files and the largest length variable.
Finding the largest length in the parameter list DSECTs provided would look like this:
TESTASM           CSECT
          .
          .
          .
                  GBLA      &DMAX
                  VMASMMT
TESTASM           CSECT
MAX_PLIST_LENGTH  DC        A(&DMAX)
                  END