External Call Facility: Difference between revisions
m (typo) |
|||
(45 intermediate revisions by 5 users not shown) | |||
Line 9: | Line 9: | ||
===Loading an external module=== | ===Loading an external module=== | ||
<p> | <p> | ||
Each external module that is called using ECF is dynamically loaded once into memory from a nominated load library or from //STEPLIB. If <var class="product">Model 204</var> is APF authorized, then any nominated load library identified for use by ECF must also be APF authorized. Otherwise, the | Each external module that is called using ECF is dynamically loaded once into memory from a nominated load library or from //STEPLIB. If <var class="product">Model 204</var> is APF authorized, then any nominated load library identified for use by ECF must also be APF authorized. Otherwise, the <var>External Load</var> statement will fail with:</p> | ||
<p class="code">COMPLETION CODE=S306 REASON CODE=000C. | <p class="code">COMPLETION CODE=S306 REASON CODE=000C. | ||
</p> | </p> | ||
<p> | <p> | ||
The load is done by an authorized user executing the <var>[[# | The load is done by an authorized user executing the <var>[[#load|External Load]]</var> statement; for example, by User 0 during startup. The load is issued from a dedicated ECF subtask that is used exclusively for module loads and deletes.</p> | ||
<p> | <p> | ||
After an external module is loaded, a call-name of up to 48 characters is associated with it. An association is set up by an authorized user executing the <var>[[# | After an external module is loaded, a call-name of up to 48 characters is associated with it. An association is set up by an authorized user executing the <var>[[#name|External Name]]</var> statement; typically by User 0 during startup. More than one call name can be associated with the same load module name.</p> | ||
<p> | <p> | ||
Callers of the external module always refer to the call (logical) name rather than the load module (physical) name. Thus, if a load module name or location changes, only the setup statements need to be changed; no application code changes are required.</p> | Callers of the external module always refer to the call (logical) name rather than the load module (physical) name. Thus, if a load module name or location changes, only the setup statements need to be changed; no application code changes are required.</p> | ||
Line 21: | Line 21: | ||
===Calling an external module=== | ===Calling an external module=== | ||
<p> | <p> | ||
A previously loaded external module is called by a user executing the <var>[[# | A previously loaded external module is called by a user executing the <var>[[#call|External Call]]</var> statement. This invokes a separate ECF subtask to run the external module, and causes the user to enter a swappable, bumpable wait state. When the external module completes, control returns to the user. There are no restrictions on the length of time the external module can run.</p> | ||
<p> | <p> | ||
Data is passed between <var class="product">Model 204</var> and an external module via a <var class="product">Model 204</var> image. A copy of the image is made when the module is called, so that the caller need not remain in the server while the external module runs. The external module can modify the copy of the image. The modified image is returned to the caller, unless the <var>[[# | Data is passed between <var class="product">Model 204</var> and an external module via a <var class="product">Model 204</var> [[Images|image]]. A copy of the image is made when the module is called, so that the caller need not remain in the server while the external module runs. The external module can modify the copy of the image. The modified image is returned to the caller, unless the <var>[[#module|External Module]]</var> statement specified <code>PARMTYPE=INPUT</code>.</p> | ||
===Avoiding data corruption and incorrect results=== | ===Avoiding data corruption and incorrect results=== | ||
<p> | <p> | ||
Line 38: | Line 38: | ||
Authorized users can stop an external module in the following ways; by executing:</p> | Authorized users can stop an external module in the following ways; by executing:</p> | ||
<ul> | <ul> | ||
<li><var>[[# | <li><var>[[#stop|External Stop]]</var> statement, usage of a load module can be disabled by an authorized user. It can be enabled again by the <var>[[#start|External Start]]</var> statement.</li> | ||
<li><var>[[# | <li><var>[[#delete|External Delete]]</var> statement, a load module can be removed from storage by an authorized user. An <var>External Delete</var> statement must not be used for Language Environment (LE) modules, because z/OS does not support the use of DELETE of Language Environment main programs and an abend can result.</li> | ||
</li> | |||
</ul> | </ul> | ||
===ECF statistics and messages=== | ===ECF statistics and messages=== | ||
<p> | <p> | ||
Line 50: | Line 49: | ||
===BUMP command enhanced with the FORCE option for ECF users=== | ===BUMP command enhanced with the FORCE option for ECF users=== | ||
<p> | <p> | ||
Simply bumping a user that is executing an <var> | Simply bumping a user that is executing an <var>External Call</var> statement does not interrupt the external module. The external module is allowed to complete — however long that takes —and then the bump takes effect.</p> | ||
<p> | <p> | ||
To interrupt an external module, you must issue a <var>[[BUMP command|BUMP]]</var> command with the <var>FORCE</var> option. Or, you can continue to use the <var> | To interrupt an external module, you must issue a <var>[[BUMP command|BUMP]]</var> command with the <var>FORCE</var> option. Or, you can continue to use the <var>External Stop</var> statement with the <var>FORCE</var> option.</p> | ||
<p> | <p> | ||
If the <var>FORCE</var> option is specified on a <var>BUMP</var> command, then the users who are running an external module are interrupted. The <var>FORCE</var> option may be combined with any other <var>BUMP</var> options. When you specify the <var>FORCE</var> option, it must be the first option on the command.</p> | If the <var>FORCE</var> option is specified on a <var>BUMP</var> command, then the users who are running an external module are interrupted. The <var>FORCE</var> option may be combined with any other <var>BUMP</var> options. When you specify the <var>FORCE</var> option, it must be the first option on the command.</p> | ||
Line 61: | Line 60: | ||
BUMP FORCE SUBSYS MYAPSY | BUMP FORCE SUBSYS MYAPSY | ||
BUMP FORCE MODULE MYPGM | BUMP FORCE MODULE MYPGM</p> | ||
</p> | |||
<p> | <p> | ||
For users who are not running an external module, the presence or absence of the <var>FORCE</var> option is irrelevant. Adding the <var>FORCE</var> option affects only users who are running an external module. The <var>FORCE</var> option does not interrupt users that are in an unbumpable wait.</p> | For users who are not running an external module, the presence or absence of the <var>FORCE</var> option is irrelevant. Adding the <var>FORCE</var> option affects only users who are running an external module. The <var>FORCE</var> option does not interrupt users that are in an unbumpable wait.</p> | ||
==ECF SOUL statements== | ==<b id="extStmt"></b>ECF SOUL statements== | ||
<p> | <p> | ||
You must check <var>[[$Status]]</var> and <var>[[$StatusD]]</var> return codes after each ECF statement.</p> | You must check <var>[[$Status]]</var> and <var>[[$StatusD]]</var> return codes after each ECF statement.</p> | ||
=== | ===<b id="call"></b>External Call statement=== | ||
<dl> | <dl> | ||
<dt>Function</dt> | <dt>Function</dt> | ||
<dd> | <dd>Calls an external module that was previously loaded using an <var>External Load</var> statement, using a call name that was previously specified in an <var>External Name</var> statement.</dd> | ||
Calls an external module that was previously loaded using an <var> | |||
<dt>Privileges</dt> | <dt>Privileges</dt> | ||
<dd> | <dd> | ||
Any user</dd> | Any user</dd> | ||
<dt>Syntax</dt> | <dt>Syntax</dt> | ||
<dd><p class="syntax"> | <dd><p class="syntax">External Call <span class="term">call-name</span> [WITH <span class="term">image-1</span> [,<span class="term">image-2</span>,...<span class="term">image-60</span>]] </p> | ||
<p>Where:</p> | <p>Where:</p> | ||
Line 112: | Line 109: | ||
<li>Without a parameter area, the external module cannot directly pass any data back to a SOUL program other than via its return code. It can, of course, indirectly pass data back: for example, by updating a sequential data set that the SOUL program can then inspect.</li> | <li>Without a parameter area, the external module cannot directly pass any data back to a SOUL program other than via its return code. It can, of course, indirectly pass data back: for example, by updating a sequential data set that the SOUL program can then inspect.</li> | ||
<li>If Model 204 is using an external authorizer such as ACF2, RACF, or Top/Secret: The default external-authorizer profile under which a job invoked by a privileged ECF statement runs is changed in version 7.7 of Model 204. Instead of such a job running under the <i>job's</i> external-authorizer profile (as it did prior to 7.7), the job runs by default in 7.7 under the <i>user's</i> external-authorizer profile. | |||
<p> | |||
The default behavior can be changed by turning on the system parameter <var>[[ECPRIV parameter|ECPRIV]]</var> 4 bit. </p></li> | |||
</ul></dd> | </ul></dd> | ||
</dl> | </dl> | ||
=== | ===<b id="delete"></b>External Delete statement=== | ||
<dl> | <dl> | ||
<dt>Function</dt> | <dt>Function</dt> | ||
Line 123: | Line 124: | ||
<dt>Syntax</dt> | <dt>Syntax</dt> | ||
<dd> | <dd> | ||
<p class="syntax"> | <p class="syntax">External Delete <span class="term">module-name</span> | ||
</p> | </p> | ||
<p> | <p> | ||
Line 138: | Line 139: | ||
</table></dd> | </table></dd> | ||
<dt>Usage</dt> | <dt>Usage</dt> | ||
<dd>Do <i>not</i> use the <var> | <dd>Do <i>not</i> use the <var>External Delete</var> statement for Language Environment modules.</dd> | ||
</dl> | </dl> | ||
=== | ===<b id="load"></b>External Load statement=== | ||
<dl> | <dl> | ||
<dt>Function</dt> | <dt>Function</dt> | ||
<dd>Loads an external module into storage. The module, previously defined by an <var> | <dd>Loads an external module into storage. The module, previously defined by an <var>External Module</var> statement, is loaded and is then available to all users.</dd> | ||
<dt>Privileges</dt> | <dt>Privileges</dt> | ||
<dd>System manager or User 0</dd> | <dd>System manager or User 0</dd> | ||
<dt>Syntax</dt> | <dt>Syntax</dt> | ||
<dd> | <dd> | ||
<p class="syntax"> | <p class="syntax">External Load <span class="term">module-name</span> | ||
</p> | </p> | ||
<p> | <p> | ||
Line 165: | Line 166: | ||
</table></dd> | </table></dd> | ||
</dl> | </dl> | ||
=== | ===<b id="module"></b>External Module statement=== | ||
<dl> | <dl> | ||
<dt>Function</dt> | <dt>Function</dt> | ||
Line 174: | Line 175: | ||
<dt>Syntax</dt> | <dt>Syntax</dt> | ||
<dd> | <dd> | ||
<p class="syntax"> | <p class="syntax">External Module <span class="term">module-name</span> [DDNAME=<span class="term">ddname</span>] | ||
[PARMTYPE=INPUT | OUTPUT] | [PARMTYPE=INPUT | OUTPUT] | ||
[PARMSIZE=<span class="term">value</span>] | [PARMSIZE=<span class="term">value</span>] | ||
[PARMMODE=[24 | 31]] | [PARMMODE=[24 | 31]] | ||
[REENTRANT | AFFINITY] | [REENTRANT | AFFINITY] | ||
[IDCAMS] | |||
</p> | </p> | ||
<p>Where:</p> | <p>Where:</p> | ||
Line 200: | Line 202: | ||
<tr> | <tr> | ||
<th><var>PARMTYPE</var> </th> | <th><var>PARMTYPE</var> </th> | ||
<td>The parameter (image) type passed to the external module on an <var> | <td>The parameter (image) type passed to the external module on an <var>External Call</var> statement. Optional. | ||
<ul> | <ul> | ||
<li><var>INPUT</var> means that any changes made by the external module to the parameter are discarded. </li> | <li><var>INPUT</var> means that any changes made by the external module to the parameter are discarded. </li> | ||
Line 210: | Line 212: | ||
<tr> | <tr> | ||
<th><var>PARMSIZE</var> </th> | <th><var>PARMSIZE</var> </th> | ||
<td>A literal or %variable that is the required size of the parameter (image) passed to the external module on all <var> | <td>A literal or %variable that is the required size of the parameter (image) passed to the external module on all <var>External Call</var> statements. | ||
<p> | <p> | ||
If the actual parameter size does not match the required size, the <var> | If the actual parameter size does not match the required size, the <var>External Call</var> statement fails. </p> | ||
<p> | <p> | ||
If <var>PARMSIZE</var> is not specified, the parameter size is not checked. </p> | If <var>PARMSIZE</var> is not specified, the parameter size is not checked. </p> | ||
Line 236: | Line 238: | ||
<th><var>AFFINITY</var> </th> | <th><var>AFFINITY</var> </th> | ||
<td>Module always runs on the same subtask. Conversely, that subtask runs only that module.</td> | <td>Module always runs on the same subtask. Conversely, that subtask runs only that module.</td> | ||
</tr> | |||
<tr> | |||
<th><var>IDCAMS</var> </th> | |||
<td>The module is the [https://en.wikipedia.org/wiki/IBM_mainframe_utility_programs#IDCAMS IBM IDCAMS utility]. Specifying this option causes the IDCAMS module to be invoked in such a way that, rather than reading data from the <var>SYSIN</var> DD and sending output to the <var>SYSPRINT</var> DD, data is read from and written to the user buffer (sometimes known as the Universal Buffer). | |||
The <var>IDCAMS</var> option is available as of Model 204 7.7. For an example, see [[#IDCAMS example|IDCAMS example]], below. | |||
Specifying this option for a module other than IDCAMS is likely to result in abends in the module when called. | |||
</td> | |||
</tr> | </tr> | ||
</table></dd> | </table></dd> | ||
<dt>Usage</dt> | <dt>Usage</dt> | ||
<dd> | <dd> | ||
<ul> | <ul> | ||
<li>You can use an <var> | <li>You can use an <var>External Module</var> statement to define a module using either: | ||
<ul> | <ul> | ||
<li>New name and attributes.</li> | <li>New name and attributes.</li> | ||
<li>Existing name. Attributes associated with an existing name are replaced by new attributes. | <li>Existing name. Attributes associated with an existing name are replaced by new attributes.</li> | ||
</li> | |||
</ul></li> | </ul></li> | ||
Line 254: | Line 266: | ||
</ul></dd> | </ul></dd> | ||
</dl> | </dl> | ||
=== | ===<b id="name"></b>External Name statement=== | ||
<dl> | <dl> | ||
<dt>Function</dt> | <dt>Function</dt> | ||
<dd>Use the <var> | <dd>Use the <var>External Name</var> statement to: | ||
<ul> | <ul> | ||
<li>Associate a logical call name with the name of a module that was previously defined by issuing an <var> | <li>Associate a logical call name with the name of a module that was previously defined by issuing an <var>External Module</var> statement</li> | ||
<li>Remove a previously set up association. A module can have multiple call names.</li> | <li>Remove a previously set up association. A module can have multiple call names.</li> | ||
Line 269: | Line 281: | ||
<dt>Syntax</dt> | <dt>Syntax</dt> | ||
<dd> | <dd> | ||
<p class="syntax"> | <p class="syntax">External Name <span class="term">call-name</span> FOR <span class="term">module-name</span> | ||
External Name <span class="term">call-name</span> REMOVE | |||
</p> | </p> | ||
<p>Where:</p> | <p>Where:</p> | ||
Line 291: | Line 303: | ||
</table></dd> | </table></dd> | ||
</dl> | </dl> | ||
=== | ===<b id="start"></b>External Start statement=== | ||
<dl> | <dl> | ||
<dt>Function</dt> | <dt>Function</dt> | ||
Line 302: | Line 314: | ||
<dt>Syntax</dt> | <dt>Syntax</dt> | ||
<dd> | <dd> | ||
<p class="syntax"> | <p class="syntax">External Start <span class="term">module-name</span> | ||
</p> | </p> | ||
<p>Where:</p> | <p>Where:</p> | ||
Line 318: | Line 330: | ||
<dt>Usage</dt> | <dt>Usage</dt> | ||
<dd>Initially a module is in the START state. You need not issue an <var> | <dd>Initially a module is in the START state. You need not issue an <var>External Start</var> statement unless you want to reverse a prior <var>External Stop</var> statement. | ||
</dd> | </dd> | ||
</dl> | </dl> | ||
=== | ===<b id="stop"></b>External Stop statement=== | ||
<dl> | <dl> | ||
<dt>Function</dt> | <dt>Function</dt> | ||
Line 331: | Line 343: | ||
<dt>Syntax</dt> | <dt>Syntax</dt> | ||
<dd><p class="syntax"> | <dd><p class="syntax">External Stop <span class="term">module-name</span> [FORCE] | ||
</p> | </p> | ||
<p>Where:</p> | <p>Where:</p> | ||
Line 352: | Line 364: | ||
<dt>Usage</dt> | <dt>Usage</dt> | ||
<dd>The following table describes how an <var> | <dd>The following table describes how an <var>External Stop</var> statement is evaluated. | ||
<table> | <table> | ||
<tr class="head"> | <tr class="head"> | ||
<th>When <var> | <th>When <var>External Stop</var> statement is issued </th> | ||
<th> | <th> | ||
Then</th> | Then</th> | ||
Line 381: | Line 393: | ||
</table> | </table> | ||
<p> | <p> | ||
In all cases, subsequent attempts by any user to call the module with an <var> | In all cases, subsequent attempts by any user to call the module with an <var>External Call</var> statement result in a <var>$Status</var> of 8. </p> | ||
<p class="note"><b>Note:</b> Rocket Software does not recommend using the <var>FORCE</var> option, as <var class="product">Model 204</var> cannot ensure that the external module is terminated cleanly.</p></dd> | <p class="note"><b>Note:</b> Rocket Software does not recommend using the <var>FORCE</var> option, as <var class="product">Model 204</var> cannot ensure that the external module is terminated cleanly.</p></dd> | ||
</dl> | </dl> | ||
==ECF return codes and $function== | ==ECF return codes and $function== | ||
<p> | <p> | ||
Line 600: | Line 612: | ||
===$EcfStat function=== | ===$EcfStat function=== | ||
<p> | <p> | ||
The <var>$EcfStat</var> function returns the detailed completion code from the previous <var>EXTERNAL</var> statement. | The <var>[[$EcfStat]]</var> function returns the detailed completion code from the previous <var>EXTERNAL</var> statement. | ||
</p> | </p> | ||
==ECF User 0 parameters== | ==ECF User 0 parameters== | ||
<p> | <p> | ||
Line 652: | Line 664: | ||
==Subtask and load module management== | ==Subtask and load module management== | ||
<p> | <p> | ||
Some z/OS overhead accrues in loading an external module into storage and attaching a z/OS subtask under which it runs. ECF avoids incurring this cost for every <var> | Some z/OS overhead accrues in loading an external module into storage and attaching a z/OS subtask under which it runs. ECF avoids incurring this cost for every <var>External Call</var> statement by managing the load modules and subtasks as described in the following sections.</p> | ||
===Subtasks assignment=== | ===Subtasks assignment=== | ||
Line 663: | Line 675: | ||
</ul> | </ul> | ||
<p> | <p> | ||
When a user issues an <var> | When a user issues an <var>External Call</var> statement, an unused ECF subtask is selected on which to run the external module, up to the limit of <var>ECMSUBS</var>. Users unable to get a subtask enter a wait of up to <var>ECWAIT</var> milliseconds for a subtask to become available. When an in-use ECF subtask becomes available, because the module that was running under it ends, it is assigned to a user waiting for a subtask. If a user's wait time expires before a subtask is available, a no-subtask-available failure is returned.</p> | ||
===Subtask affinity=== | ===Subtask affinity=== | ||
<p> | <p> | ||
Normally, when an external module is called via the <var> | Normally, when an external module is called via the <var>External Call</var> statement, ECF selects any free subtask on which to execute the module. Although this is appropriate for most external modules, some modules might need to always be executed on the same subtask. This is known as subtask affinity. Subtask affinity for a module is specified by the <var>AFFINITY</var> option on the <var>External Module</var> statement. The <var>AFFINITY</var> option is incompatible with the <var>REENTRANT</var> option.</p> | ||
<ul> | <ul> | ||
<li>If the <var>AFFINITY</var> option is not specified, the module does not have subtask affinity. This is the default. </li> | <li>If the <var>AFFINITY</var> option is not specified, the module does not have subtask affinity. This is the default. </li> | ||
Line 674: | Line 686: | ||
</ul> | </ul> | ||
<p> | <p> | ||
When the first <var> | When the first <var>External Call</var> of the module is executed, a dedicated subtask for the module is attached. A two-way association between the module and the subtask is established. That module will run on only that subtask, not on any other subtask. That subtask is used to run only that module, not any other module.</p> | ||
<p> | <p> | ||
If a module has subtask affinity, and the dedicated subtask for that module is abnormally terminated for any reason, the previous dedicated subtask is detached, and a new dedicated subtask for the module is attached. A subtask could be abnormally terminated if the module it was running has an abend, or the user running the module is bumped. Therefore, specifying <var>AFFINITY</var> does not guarantee that the same subtask is always used for that module for the duration of a <var class="product">Model 204</var> Online.</p> | If a module has subtask affinity, and the dedicated subtask for that module is abnormally terminated for any reason, the previous dedicated subtask is detached, and a new dedicated subtask for the module is attached. A subtask could be abnormally terminated if the module it was running has an abend, or the user running the module is bumped. Therefore, specifying <var>AFFINITY</var> does not guarantee that the same subtask is always used for that module for the duration of a <var class="product">Model 204</var> Online.</p> | ||
Line 680: | Line 692: | ||
If you use modules with subtask affinity, ensure that <var>ECISUBS</var> and <var>ECMSUBS</var> are appropriately set. In particular, <var>ECISUBS</var> and <var>ECMSUBS</var> must be greater than or equal to the number of modules with subtask affinity.</p> | If you use modules with subtask affinity, ensure that <var>ECISUBS</var> and <var>ECMSUBS</var> are appropriately set. In particular, <var>ECISUBS</var> and <var>ECMSUBS</var> must be greater than or equal to the number of modules with subtask affinity.</p> | ||
<ul> | <ul> | ||
<li>The <var>ECISUBS</var> parameter specifies the number of subtasks attached during system initialization. These subtasks are never used for modules with subtask affinity; the first <var> | <li>The <var>ECISUBS</var> parameter specifies the number of subtasks attached during system initialization. These subtasks are never used for modules with subtask affinity; the first <var>External Call</var> of a module with subtask affinity always results in a new subtask being attached (subject to <var>ECMSUBS</var>). </li> | ||
<li>The <var>ECMSUBS</var> parameter specifies the maximum number of ECF subtasks used to run modules. The number of subtasks used for modules with subtask affinity plus the number of subtasks used for modules without subtask affinity will be a maximum of <var>ECMSUBS</var>.</li> | <li>The <var>ECMSUBS</var> parameter specifies the maximum number of ECF subtasks used to run modules. The number of subtasks used for modules with subtask affinity plus the number of subtasks used for modules without subtask affinity will be a maximum of <var>ECMSUBS</var>.</li> | ||
Line 687: | Line 699: | ||
===Load modules=== | ===Load modules=== | ||
<p> | <p> | ||
An external module is usually loaded into storage just once. The exception is when an <var> | An external module is usually loaded into storage just once. The exception is when an <var>External Load</var> statement, possibly preceded by an <var>External Delete</var> statement, is used to reload a previously-loaded module.</p> | ||
<p> | <p> | ||
Normally, one <var class="product">Model 204</var> user at a time is allowed to issue an <var> | Normally, one <var class="product">Model 204</var> user at a time is allowed to issue an <var>External Call</var> statement for the module. Other users who attempt to call the module while it is in use, enter a wait-state of up to <var>ECWAIT</var> milliseconds for the module to become available. When a module is freed, because the current execution of it ends, it is assigned to one of the users waiting for it. If a user's wait time expires before the module is assigned, a module-in-use failure is returned. </p> | ||
<p> | <p> | ||
If a load module was link-edited with the REENTRANT (also written, RENT) attribute, and if the <var> | If a load module was link-edited with the REENTRANT (also written, RENT) attribute, and if the <var>External Module</var> statement that defined the module characteristics specified the <var>REENTRANT</var> option, then multiple <var class="product">Model 204</var> users are allowed to simultaneously issue an <var>External Call</var> statement for the module — subject to subtask availability.</p> | ||
===Fulfillment order=== | ===Fulfillment order=== | ||
<p> | <p> | ||
An <var> | An <var>External Call</var> statement can invoke an external module only if both an ECF subtask is free, and for a serially reusable module, if the module is not in use by another user. The check that the module is not in use by another user is done before the allocation of a subtask so that the most restrictive condition is checked first.</p> | ||
==Restrictions and cautions== | ==Restrictions and cautions== | ||
Line 701: | Line 713: | ||
The following restrictions and cautions apply to the use of ECF:</p> | The following restrictions and cautions apply to the use of ECF:</p> | ||
<ul> | <ul> | ||
<li>ECF loads an external module only once, when the <var> | <li>ECF loads an external module only once, when the <var>External Load</var> statement is issued. Thereafter, every user who issues an <var>External Call</var> statement for that module uses the same copy of the module. Therefore, you must write your module to initialize itself properly on every call.</li> | ||
<li>ECF passes the copy of the parameter area to the external module using standard z/OS linkage conventions. Your external module must support these conventions to receive the parameters.</li> | <li>ECF passes the copy of the parameter area to the external module using standard z/OS linkage conventions. Your external module must support these conventions to receive the parameters.</li> | ||
<li>ECF does not provide any special initialization of the environment when you issue an <var> | <li>ECF does not provide any special initialization of the environment when you issue an <var>External Call</var> statement; it merely branches to the in-memory copy of the module. Therefore, your module must perform any required initialization and termination of its run-time environment. In particular, this means that an external module, written in any language, should be written as a main routine and not a subroutine.</li> | ||
<li>Only one copy of a load module can be in memory at a time. This is a z/OS restriction.</li> | <li>Only one copy of a load module can be in memory at a time. This is a z/OS restriction.</li> | ||
Line 727: | Line 739: | ||
===Wait types for ECF=== | ===Wait types for ECF=== | ||
<p> | <p> | ||
See the table of codes in [[ | See the table of codes in the [[ONLINE_monitoring#Wait_type_values| listing of wait types]] that includes the External Call Facility, wait types 43 through 46.</p> | ||
===ECF statistics=== | ===ECF statistics=== | ||
<p> | <p> | ||
Line 758: | Line 770: | ||
</ul> | </ul> | ||
<p> | <p> | ||
Statistics include only <var> | Statistics include only <var>External Call</var> statements that actually called a module — even if the module subsequently abended. ECF statistics do not include <var>External Call</var> statements with parameter errors or those that timed out trying to get a module or subtask.</p> | ||
==ECF examples== | ==ECF examples== | ||
Line 966: | Line 978: | ||
IMAGE PARMS | IMAGE PARMS | ||
NUMBER.ONE.BINARY IS BINARY LEN 4 | NUMBER.ONE.BINARY IS BINARY LEN 4 | ||
NUMBER.TWO.BINARY IS BINARY LEN 4 | NUMBER.TWO.BINARY IS BINARY LEN 4 | ||
NUMBER.SUM.BINARY IS BINARY LEN 4 | NUMBER.SUM.BINARY IS BINARY LEN 4 | ||
END IMAGE | END IMAGE | ||
Line 1,094: | Line 1,105: | ||
</table> | </table> | ||
[[Category:System | <span id="idcams"></span> | ||
[[Category:System-level capabilities | ===IDCAMS example=== | ||
<p> | |||
This example uses the <var>IDCAMS</var> option (available as of Model 204 7.7) on the ECF <var>Module</var> statement to have IDCAMS input and output go from/to the user buffer.</p> | |||
====Module definition==== | |||
The following <var>External</var> statements make IDCAMS available: | |||
<p class="code">b | |||
external module idcams idcams | |||
external load idcams | |||
external name idcams for idcams | |||
end | |||
</p> | |||
When <var>IDCAMS</var> is invoked by <var>External Call</var>, the user's [[Universal Buffer]] must contain the input lines to be passed to <code>SYSIN</code>, separated by EBCDIC linefeed characters (X'25'). The output lines from <var>IDCAMS</var> are appended to the Universal Buffer, also separated by new lines. | |||
Before calling <var>IDCAMS</var>, the Universal Buffer must be allocated to a length sufficient to hold all of the input lines and all of the expected output lines. If the buffer is too small, output is truncated. While it is possible to calculate the optimum Universal Buffer length on each invocation, it is better to do the following to minimize storage fragmentation: | |||
<ul> | |||
<li>Use the same value for all invocations.</li> | |||
<li>Use a multiple of 8K. </li> | |||
</ul> | |||
====Return codes==== | |||
The <var>IDCAMS</var> interface can return one of the following return codes: | |||
<table class="thJustBold"> | |||
<tr><th>20</th> | |||
<td>Universal Buffer was overflowed, output truncated.</td></tr> | |||
<tr><th>24</th> | |||
<td>Minimum outspace (2,000 bytes) not available in Universal Buffer.</td></tr> | |||
<tr><th>28</th> | |||
<td>No input data in Universal Buffer.</td></tr> | |||
<tr><th><i>Else</i></th> | |||
<td>The return code is from the IDCAMS program.</td></tr> | |||
</table> | |||
====SOUL code==== | |||
<p class="code">b | |||
%idcams.in is longstring | |||
%idcams.out is longstring | |||
%lines.in is object stringlist | |||
%lines.out is object stringlist | |||
%hlq is string len 8 | |||
%options is string len 32 | |||
%input.len is float | |||
%rc is float | |||
%hlq = 'DRAKE' | |||
%options = 'VOLUMES' | |||
* Prepare IDCAMS input lines in stringlist. Note that that the | |||
* TEXT TO statement supports expressions allowing %variables and | |||
* functions to be used as the trivial example shows. | |||
%lines.in = new | |||
Text nocont To %lines.in | |||
{} LISTCAT - | |||
LEVEL({%hlq}) - | |||
{%options} | |||
End Text | |||
* Note: the null expression {} in front of LISTCAT is to force | |||
* indentation, since IDCAMS commands cannnot begin in column 1. | |||
* Convert the stringlist to a longstring with EBCDIC new line | |||
* delimiters at the end of each line. This is needed to use the | |||
* Model 204 Universal Buffer feature, which only understands | |||
* byte strings. | |||
%idcams.in = %lines.in:CreateLines | |||
* Force Universal Buffer allocation of sufficient size | |||
modify buffer size=65536 nopreserve clear | |||
* Prime Universal Buffer with input for IDCAMS, save its length | |||
%input.len = $Lstr_Set_UserBuffer(%idcams.in) | |||
* Call the IDCAMS wrapper, appending output to Universal Buffer | |||
external call idcams | |||
Printtext $status={$STATUS}, $STATUSD={$STATUSD}, $ECFSTAT={$ECFSTAT} | |||
%rc = +$substr($ecfstat,4,5) | |||
Printtext In simpler terms, the IDCAMS return code was {%rc}. | |||
* Retrieve output data from Universal Buffer (too bad there isn't | |||
* a starting offset parameter) and parse lines to stringLlist. | |||
%idcams.out = $lstr_substr($lstr_Get_UserBuffer,%input.len+1) | |||
%lines.out = new | |||
%lines.out:ParseLines(%idcams.out) | |||
Printtext IDCAMS passed the following {%lines.in:count} lines: | |||
%lines.in:print | |||
Printtext Which produced {%lines.out:count} lines of output: | |||
%lines.out:print | |||
end | |||
</p> | |||
[[Category:System management]] | |||
[[Category:System-level capabilities of Model 204]] |
Latest revision as of 12:30, 13 May 2019
Overview
The External Call Facility (ECF) is a method for programs written in SOUL to invoke external, non-Model 204 modules, such as non-IFAM COBOL modules. Data can be passed between Model 204 and external modules. External modules can open non-Model 204 data sets, read or write to them, and close them. In addition, multiple modules can be called multiple times in a single run.
ECF is available only under z/OS.
Working with ECF
Loading an external module
Each external module that is called using ECF is dynamically loaded once into memory from a nominated load library or from //STEPLIB. If Model 204 is APF authorized, then any nominated load library identified for use by ECF must also be APF authorized. Otherwise, the External Load statement will fail with:
COMPLETION CODE=S306 REASON CODE=000C.
The load is done by an authorized user executing the External Load statement; for example, by User 0 during startup. The load is issued from a dedicated ECF subtask that is used exclusively for module loads and deletes.
After an external module is loaded, a call-name of up to 48 characters is associated with it. An association is set up by an authorized user executing the External Name statement; typically by User 0 during startup. More than one call name can be associated with the same load module name.
Callers of the external module always refer to the call (logical) name rather than the load module (physical) name. Thus, if a load module name or location changes, only the setup statements need to be changed; no application code changes are required.
Calling an external module
A previously loaded external module is called by a user executing the External Call statement. This invokes a separate ECF subtask to run the external module, and causes the user to enter a swappable, bumpable wait state. When the external module completes, control returns to the user. There are no restrictions on the length of time the external module can run.
Data is passed between Model 204 and an external module via a Model 204 image. A copy of the image is made when the module is called, so that the caller need not remain in the server while the external module runs. The external module can modify the copy of the image. The modified image is returned to the caller, unless the External Module statement specified PARMTYPE=INPUT
.
Avoiding data corruption and incorrect results
External modules must not access any data set that Model 204 or any other external module has already opened.
Attention: Failure to observe this could result in data corruption or abends, either in the external module or Model 204.
External modules invoked using ECF run under separate z/OS subtasks in the same address space as the Model 204 Online that invoked the module. This means that external modules run in parallel with Model 204 (and each other), even if you do not use MP/204 (multiprocessor).
Most errors that can occur in the external module are isolated from Model 204. However, it is still possible for programming errors in external modules to corrupt or overwrite storage belonging to Model 204. A programming error in your external module could result in data corruption, abends, or incorrect results in the external module or in Model 204.
Stopping an external load module
Authorized users can stop an external module in the following ways; by executing:
- External Stop statement, usage of a load module can be disabled by an authorized user. It can be enabled again by the External Start statement.
- External Delete statement, a load module can be removed from storage by an authorized user. An External Delete statement must not be used for Language Environment (LE) modules, because z/OS does not support the use of DELETE of Language Environment main programs and an abend can result.
ECF statistics and messages
See the table in Statistics with descriptions for the System-final, user-logout, user-since-last, SMF-logout, and SMF-since-last statistics that relate to ECF.
BUMP command enhanced with the FORCE option for ECF users
Simply bumping a user that is executing an External Call statement does not interrupt the external module. The external module is allowed to complete — however long that takes —and then the bump takes effect.
To interrupt an external module, you must issue a BUMP command with the FORCE option. Or, you can continue to use the External Stop statement with the FORCE option.
If the FORCE option is specified on a BUMP command, then the users who are running an external module are interrupted. The FORCE option may be combined with any other BUMP options. When you specify the FORCE option, it must be the first option on the command.
Examples
BUMP FORCE ALL BUMP FORCE SUBSYS MYAPSY BUMP FORCE MODULE MYPGM
For users who are not running an external module, the presence or absence of the FORCE option is irrelevant. Adding the FORCE option affects only users who are running an external module. The FORCE option does not interrupt users that are in an unbumpable wait.
ECF SOUL statements
You must check $Status and $StatusD return codes after each ECF statement.
External Call statement
- Function
- Calls an external module that was previously loaded using an External Load statement, using a call name that was previously specified in an External Name statement.
- Privileges
- Any user
- Syntax
External Call call-name [WITH image-1 [,image-2,...image-60]]
Where:
Argument Specifies... call-name Logical name, either a literal or %variable, of the external module to invoke. WITH clause The optional WITH clause specifies the images to pass as a parameter area between the SOUL program and the external module. If no parameter area is required, you can omit the WITH clause. image-1,...image-60 Name(s) of a previously defined image(s) to pass to the external module. - Usage
-
- You can specify from one to sixty images separated by commas.
- A return code of zero does not mean that the external module performed as it was designed; it simply means that the module was successfully invoked and completed without an abend.
- Without a parameter area, the external module cannot directly pass any data back to a SOUL program other than via its return code. It can, of course, indirectly pass data back: for example, by updating a sequential data set that the SOUL program can then inspect.
- If Model 204 is using an external authorizer such as ACF2, RACF, or Top/Secret: The default external-authorizer profile under which a job invoked by a privileged ECF statement runs is changed in version 7.7 of Model 204. Instead of such a job running under the job's external-authorizer profile (as it did prior to 7.7), the job runs by default in 7.7 under the user's external-authorizer profile.
The default behavior can be changed by turning on the system parameter ECPRIV 4 bit.
External Delete statement
- Function
- Removes a previously loaded external module from storage.
- Privileges
- System manager or User 0
- Syntax
-
External Delete module-name
Where:
Argument Specifies... module-name A literal or a %variable that is the module name of a previously loaded external module. - Usage
- Do not use the External Delete statement for Language Environment modules.
External Load statement
- Function
- Loads an external module into storage. The module, previously defined by an External Module statement, is loaded and is then available to all users.
- Privileges
- System manager or User 0
- Syntax
-
External Load module-name
Where:
Argument Specifies... module-name A literal or a %variable that is the name of the external module, a PDS member name.
External Module statement
- Function
- Defines an external module for later loading.
- Privileges
- System manager or User 0
- Syntax
-
External Module module-name [DDNAME=ddname] [PARMTYPE=INPUT | OUTPUT] [PARMSIZE=value] [PARMMODE=[24 | 31]] [REENTRANT | AFFINITY] [IDCAMS]
Where:
Argument Specifies... module-name A literal or %variable that is the name of the external module, a PDS member name. Required. ddname A literal or %variable that is the DDNAME of the PDS where the load module is located. If omitted, the standard search order or //STEPLIB is used. Optional. Note: If Model 204 is APF authorized, then this data set must also be APF authorized.
PARMTYPE The parameter (image) type passed to the external module on an External Call statement. Optional. - INPUT means that any changes made by the external module to the parameter are discarded.
- OUTPUT, the default, means that any changes are retained.
PARMSIZE A literal or %variable that is the required size of the parameter (image) passed to the external module on all External Call statements. If the actual parameter size does not match the required size, the External Call statement fails.
If PARMSIZE is not specified, the parameter size is not checked.
PARMMODE Where storage to hold the copy of the parameter area is allocated. Optional. - 24 means allocate in 24-bit, below-the-line storage.
- 31, the default, means allocate in 31-bit, above the line storage.
- Do not specify
PARMMODE=24
unless the module has a specific requirement for this setting.
REENTRANT Module that can be used by more than one user at a time. This optional argument takes effect only if the module was link-edited with the REENTRANT attribute. AFFINITY Module always runs on the same subtask. Conversely, that subtask runs only that module. IDCAMS The module is the IBM IDCAMS utility. Specifying this option causes the IDCAMS module to be invoked in such a way that, rather than reading data from the SYSIN DD and sending output to the SYSPRINT DD, data is read from and written to the user buffer (sometimes known as the Universal Buffer). The IDCAMS option is available as of Model 204 7.7. For an example, see IDCAMS example, below.
Specifying this option for a module other than IDCAMS is likely to result in abends in the module when called.
- Usage
-
- You can use an External Module statement to define a module using either:
- New name and attributes.
- Existing name. Attributes associated with an existing name are replaced by new attributes.
- Subtask affinity, which is specified by the AFFINITY keyword, is required in some situations. For example, when an external module opens a data set on one call, but does not close it till a subsequent call. Subtask affinity is required because z/OS requires that you open and close a data set from the same subtask.
- The AFFINITY keyword is incompatible with the REENTRANT keyword. A compilation error is generated, if both are specified for the same module. You specify one or the other or neither, but not both.
- You can use an External Module statement to define a module using either:
External Name statement
- Function
- Use the External Name statement to:
- Associate a logical call name with the name of a module that was previously defined by issuing an External Module statement
- Remove a previously set up association. A module can have multiple call names.
- Privileges
- System manager or User 0
- Syntax
-
External Name call-name FOR module-name External Name call-name REMOVE
Where:
Argument Specifies... call-name Logical name to associate with an external module. Up to 48 characters. module-name Name of a previously loaded external module.
External Start statement
- Function
- Enables further calls to an ECF module.
- Privileges
- System manager or User 0
- Syntax
-
External Start module-name
Where:
Argument Specifies... module-name Name of a previously loaded external module. - Usage
- Initially a module is in the START state. You need not issue an External Start statement unless you want to reverse a prior External Stop statement.
External Stop statement
- Function
- Stops further calls to an ECF module. Currently executing calls either complete or, if the FORCE option is used, abend.
- Privileges
- System manager or User 0
- Syntax
External Stop module-name [FORCE]
Where:
Argument Specifies... module-name Name of a previously loaded external module. FORCE Users currently executing the specified module are bumped. - Usage
- The following table describes how an External Stop statement is evaluated.
When External Stop statement is issued Then If no users are executing the module Module is immediately marked stopped. If one or more users are executing the module Module is marked draining until the last user finishes executing the module, then it is marked stopped. If FORCE was specified Current users of the module are bumped. If FORCE was not specified Current users of the module are allowed to complete. In all cases, subsequent attempts by any user to call the module with an External Call statement result in a $Status of 8.
Note: Rocket Software does not recommend using the FORCE option, as Model 204 cannot ensure that the external module is terminated cleanly.
ECF return codes and $function
All EXTERNAL statements set $Status and $StatusD.
$Status | $StatusD | Meaning |
---|---|---|
0 | 0 | ECF function completed without error |
1 | 0 | ECF inactive |
2 | 0 | Not authorized |
3 | 1 | Invalid module name |
2 | Invalid call name | |
3 | Invalid DDNAME | |
4 | Image inactive | |
5 | Invalid PARMSIZE | |
4 | 0 | Call name not defined |
6 | 0 | Module not defined |
7 | 0 | Module not loaded |
8 | 0 | Module unavailable (draining or stopped) |
10 | 0 | Module not deleted |
20 | System busy; timed out | |
1 | Module unavailable | |
2 | No subtask available | |
30 | Load or delete failed | |
1 | DDNAME not present | |
2 | DDNAME open failed | |
3 | DDNAME close failed | |
5 | Load or delete failed; see the $EcfStat function. | |
6 | Internal ECF abend; see the $EcfStat function page. | |
7 | Internal ECF ABEND; load or delete subtask terminated by the operating system. | |
40 | 0 | Module failed |
1 | Module gave nonzero return code; see the $EcfStat function page. | |
2 | Module abend; see the $EcfStat function page. | |
3 | Insufficient memory available to allocate a buffer for the parameter area | |
4 | Actual parameter size is not equal to PARMSIZE | |
5 | When the parameter area, as updated by the external module, was being copied back to the original image(s), ECF detected that the size of one of the images had been changed. This status can occur only if an image contains a variable array whose size is changed by the external module. | |
6 | ECF subtask terminated by the operating system | |
50 | 0 | ECF internal table full |
1 | ECF ECMODS table full; increase ECMODS User 0 parameter | |
2 | ECF ECNAMES table full; increase ECNAMES User 0 parameter |
$EcfStat function
The $EcfStat function returns the detailed completion code from the previous EXTERNAL statement.
ECF User 0 parameters
The following User 0 parameters are used by ECF.
A system manager can reset only the ECWAIT parameter; the other ECF parameters cannot be reset.
User 0 parameter | Returns... |
---|---|
ECISUBS | Subtasks for running external modules initially attached |
ECMODS | External modules to load |
ECMSUBS | Number of ECF subtasks for running modules |
ECNAMES | Number of external call names |
ECPRIV | ECF privileges |
ECPSIZE | Size of largest image used by ECF |
ECWAIT | ECF wait time |
Subtask and load module management
Some z/OS overhead accrues in loading an external module into storage and attaching a z/OS subtask under which it runs. ECF avoids incurring this cost for every External Call statement by managing the load modules and subtasks as described in the following sections.
Subtasks assignment
At system startup, the following subtasks are started:
- One subtask for loading and deleting modules
- One or more subtasks, specified by the ECISUBS parameter, for executing external modules
When a user issues an External Call statement, an unused ECF subtask is selected on which to run the external module, up to the limit of ECMSUBS. Users unable to get a subtask enter a wait of up to ECWAIT milliseconds for a subtask to become available. When an in-use ECF subtask becomes available, because the module that was running under it ends, it is assigned to a user waiting for a subtask. If a user's wait time expires before a subtask is available, a no-subtask-available failure is returned.
Subtask affinity
Normally, when an external module is called via the External Call statement, ECF selects any free subtask on which to execute the module. Although this is appropriate for most external modules, some modules might need to always be executed on the same subtask. This is known as subtask affinity. Subtask affinity for a module is specified by the AFFINITY option on the External Module statement. The AFFINITY option is incompatible with the REENTRANT option.
- If the AFFINITY option is not specified, the module does not have subtask affinity. This is the default.
- If the AFFINITY option is specified, the module has subtask affinity.
When the first External Call of the module is executed, a dedicated subtask for the module is attached. A two-way association between the module and the subtask is established. That module will run on only that subtask, not on any other subtask. That subtask is used to run only that module, not any other module.
If a module has subtask affinity, and the dedicated subtask for that module is abnormally terminated for any reason, the previous dedicated subtask is detached, and a new dedicated subtask for the module is attached. A subtask could be abnormally terminated if the module it was running has an abend, or the user running the module is bumped. Therefore, specifying AFFINITY does not guarantee that the same subtask is always used for that module for the duration of a Model 204 Online.
If you use modules with subtask affinity, ensure that ECISUBS and ECMSUBS are appropriately set. In particular, ECISUBS and ECMSUBS must be greater than or equal to the number of modules with subtask affinity.
- The ECISUBS parameter specifies the number of subtasks attached during system initialization. These subtasks are never used for modules with subtask affinity; the first External Call of a module with subtask affinity always results in a new subtask being attached (subject to ECMSUBS).
- The ECMSUBS parameter specifies the maximum number of ECF subtasks used to run modules. The number of subtasks used for modules with subtask affinity plus the number of subtasks used for modules without subtask affinity will be a maximum of ECMSUBS.
Load modules
An external module is usually loaded into storage just once. The exception is when an External Load statement, possibly preceded by an External Delete statement, is used to reload a previously-loaded module.
Normally, one Model 204 user at a time is allowed to issue an External Call statement for the module. Other users who attempt to call the module while it is in use, enter a wait-state of up to ECWAIT milliseconds for the module to become available. When a module is freed, because the current execution of it ends, it is assigned to one of the users waiting for it. If a user's wait time expires before the module is assigned, a module-in-use failure is returned.
If a load module was link-edited with the REENTRANT (also written, RENT) attribute, and if the External Module statement that defined the module characteristics specified the REENTRANT option, then multiple Model 204 users are allowed to simultaneously issue an External Call statement for the module — subject to subtask availability.
Fulfillment order
An External Call statement can invoke an external module only if both an ECF subtask is free, and for a serially reusable module, if the module is not in use by another user. The check that the module is not in use by another user is done before the allocation of a subtask so that the most restrictive condition is checked first.
Restrictions and cautions
The following restrictions and cautions apply to the use of ECF:
- ECF loads an external module only once, when the External Load statement is issued. Thereafter, every user who issues an External Call statement for that module uses the same copy of the module. Therefore, you must write your module to initialize itself properly on every call.
- ECF passes the copy of the parameter area to the external module using standard z/OS linkage conventions. Your external module must support these conventions to receive the parameters.
- ECF does not provide any special initialization of the environment when you issue an External Call statement; it merely branches to the in-memory copy of the module. Therefore, your module must perform any required initialization and termination of its run-time environment. In particular, this means that an external module, written in any language, should be written as a main routine and not a subroutine.
- Only one copy of a load module can be in memory at a time. This is a z/OS restriction.
- Externally called modules must be
AMODE(31)
and eitherRMODE(ANY)
orRMODE(31)
. - Externally called modules must not attempt to retain any context information from one call to another. You must write the modules so that each call executes independently of any other.
- For efficiency purposes, ECF does not use z/OS to maintain the usage counts or status information for load modules. Control is passed by direct branch rather than use of the z/OS ATTACH, LINK, or XCTL macros. Therefore, one external module must not attempt to load or attach another external module, or attempt to reference code or data in another external module.
- The definition of the parameter area in Model 204 — the image definition — must agree with the definition of the parameter area in the external module (in a COBOL program, the LINKAGE SECTION). If they do not agree, it is possible for the module to modify the wrong storage.
To prevent this, Model 204 checks that the external module put its results in only the assigned area — not somewhere else. Model 204 checks the area immediately past the end of the assigned area. If the unassigned area was used, Model 204 displays the following message and restarts the user:
M204.2563: MODULE=name RETURNED MORE THAN length BYTES
Tracking ECF
Wait types for ECF
See the table of codes in the listing of wait types that includes the External Call Facility, wait types 43 through 46.
ECF statistics
The following statistics help you track the External Call Facility. See Statistics with descriptions for the position in the system-final, user-logout, user-since-last, SMF-logout, and/or SMF-since-last journal record layout as they apply.
- ECCALL
- ECCNCT
- ECCTOUT
- ECCWAITM
- ECCWAITS
- ECDELETE
- ECLOAD
- ECMODMAX
- ECNAMMAX
- ECTSKMAX
- ECTWAITM
- ECTWAITS
Statistics include only External Call statements that actually called a module — even if the module subsequently abended. ECF statistics do not include External Call statements with parameter errors or those that timed out trying to get a module or subtask.
ECF examples
This section illustrates, in various languages, how to write, compile, link and invoke an external module that adds two numbers together and returns the sum. For clarity, the sample code omits error handling, other standard elements, and some JCL elements.
COBOL sample 1
This example uses the Language Environment enabled compiler, IBM COBOL FOR z/OS AND z/VM.
COBOL program
//COBSAMP EXEC PGM=IGYCRCTL,PARM=(NOSEQ,RENT) //SYSLIN DD DSN=YOUR.OBJLIB(COBSAMP),DISP=SHR //SYSIN DD * IDENTIFICATION DIVISION. PROGRAM-ID. COBSAMP. DATA DIVISION. LINKAGE SECTION. 01 M204-PARMS. 03 NUMBER-ONE PIC S9(7) COMP-3. 03 NUMBER-TWO PIC S9(9) BINARY. 03 NUMBER-SUM PIC S9(9) BINARY. PROCEDURE DIVISION USING M204-PARMS. COMPUTE NUMBER-SUM EQUAL NUMBER-ONE + NUMBER-TWO MOVE ZERO TO RETURN-CODE GOBACK.
Language Environment options
//ASMUOPT EXEC PGM=ASMA90,PARM='NOXREF' //SYSLIB DD DSN=SYS1.MACLIB,DISP=SHR // DD DSN=CEE.SCEEMAC,DISP=SHR //SYSPRINT DD SYSOUT=* //SYSLIN DD DSN=YOUR.OBJLIB(CEEUOPT),DISP=SHR //SYSIN DD * CEEUOPT CSECT CEEUOPT AMODE ANY CEEUOPT RMODE ANY PRINT ON,NOGEN CEEXOPT ABTERMENC=(ABEND), RTEREUS=(ON) END
Linkedit
//LINK EXEC PGM=IEWL,PARM='LIST,MAP' //SYSPRINT DD SYSOUT=* //SYSLIB DD DSN=CEE.SCEELKED,DISP=SHR //OBJLIB DD DSN=YOUR.OBJLIB,DISP=SHR //SYSLMOD DD DSN=YOUR.LOADLIB,DISP=SHR //SYSLIN DD * INCLUDE OBJLIB(CEEUOPT) INCLUDE OBJLIB(COBSAMP) NAME COBSAMP(R)
Calling from SOUL
//ONLINE EXEC PGM=ONLINE //STEPLIB DD DSN=M204.LOADLIB,DISP=SHR // DD DSN=YOUR.LOADLIB,DISP=SHR // DD DSN=CEE.SCEERUN,DISP=SHR BEGIN IMAGE PARMS NUMBER.ONE.PACKED IS PACKED LEN 4 NUMBER.TWO.BINARY IS BINARY LEN 4 NUMBER.SUM.BINARY IS BINARY LEN 4 END IMAGE EXTERNAL MODULE COBSAMP EXTERNAL LOAD COBSAMP EXTERNAL NAME MOD_COBSAMP FOR COBSAMP PREPARE IMAGE PARMS %PARMS:NUMBER.ONE.PACKED = 1 %PARMS:NUMBER.TWO.BINARY = 2 EXTERNAL CALL MOD_COBSAMP WITH PARMS PRINT %PARMS:NUMBER.ONE.PACKED WITH ' + ' WITH - %PARMS:NUMBER.TWO.BINARY WITH ' = ' WITH - %PARMS:NUMBER.SUM.BINARY END
Comments
COBOL | Corresponds to SOUL |
---|---|
PIC S9(7) COMP-3 |
PACKED LEN 4 |
PIC S9(9) BINARY |
BINARY LEN 4 |
- The Language Environment option
ABTERMENC=(ABEND)
must be specified. - Specify the Language Environment option
RTEREUS=(ON)
and code GOBACK instead of STOP RUN, as illustrated, to make the runtime environment reusable and to improve performance. - Setting Language Environment options is described in IBM Manual SC28-1939 Language Environment for z/OS & z/VM Programing Guide. In the code in the "Calling from SOUL" section in the example above, Language Environment options are set by linking CEEUOPT with the COBOL module. Other methods are also available; check with your site's Language Environment administrator to determine the appropriate method to use.
COBOL sample 2
This example illustrates the use of multiple images using the Language Environment enabled compiler, IBM COBOL FOR z/OS AND z/VM.
Note: Ordinarily, multiple images are only used if the parameters to be passed cannot fit into a single image. Images are limited in size to 32767 bytes.
COBOL program
IDENTIFICATION DIVISION. PROGRAM-ID. COBSAM2. DATA DIVISION. LINKAGE SECTION. 01 M204-PARMS1. 03 NUMBER-ONE PIC S9(7) COMP-3. 01 M204-PARMS2. 03 NUMBER-TWO PIC S9(9) BINARY. 01 M204-PARMS3. 03 NUMBER-SUM PIC S9(9) BINARY. PROCEDURE DIVISION USING M204-PARMS1, M204-PARMS2, M204-PARMS3. COMPUTE NUMBER-SUM EQUAL NUMBER-ONE + NUMBER-TWO MOVE ZERO TO RETURN-CODE GOBACK.
Calling from SOUL
BEGIN IMAGE PARMS1 NUMBER.ONE.PACKED IS PACKED LEN 4 END IMAGE IMAGE PARMS2 NUMBER.TWO.BINARY IS BINARY LEN 4 END IMAGE IMAGE PARMS3 NUMBER.SUM.BINARY IS BINARY LEN 4 END IMAGE EXTERNAL MODULE COBSAM2 EXTERNAL LOAD COBSAM2 EXTERNAL NAME MOD_COBSAM2 FOR COBSAM2 PREPARE IMAGE PARMS1 PREPARE IMAGE PARMS2 PREPARE IMAGE PARMS3 %PARMS1:NUMBER.ONE.PACKED = 1 %PARMS2:NUMBER.TWO.BINARY = 2 EXTERNAL CALL MOD_COBSAM2 WITH PARMS1, PARMS2, PARMS3 PRINT %PARMS1:NUMBER.ONE.PACKED WITH ' + ' WITH - %PARMS2:NUMBER.TWO.BINARY WITH ' = ' WITH - %PARMS3:NUMBER.SUM.BINARY END
SAS/C sample
This example uses the SAS/C compiler, not the IBM C compiler.
SAS/C program
//C EXEC PGM=LC370B //STEPLIB DD DSN=SASC.LOAD,DISP=SHR //SYSLIB DD DSN=SASC.MACLIBC,DISP=SHR //SYSLIN DD DSN=YOUR.OBJLIB(SASCSAMP),DISP=SHR //SYSPRINT DD SYSOUT=* //SYSIN DD * typedef struct PARMAREA { int A; int B; int C; } parmarea; int main(int argc, char **argv) { parmarea *pptr; if (argc != 2) { /* the parameter list was not in OS format */ return 1000; } pptr = (parmarea *) argv[1]; pptr->C = pptr->A + pptr->B; return 0; }
Linkedit
//LC EXEC PGM=IEWL,PARM='AMODE(31),RMODE(ANY)' //SYSLIB DD DSN=SASC.STDLIB,DISP=SHR // DD DSN=SASC.BASELIB,DISP=SHR //OBJLIB DD DSN=YOUR.OBJLIB,DISP=SHR //SYSLMOD DD DSN=YOUR.LOADLIB,DISP=SHR //SYSPRINT DD SYSOUT=* //SYSLIN DD * INCLUDE OBJLIB(SASCSAMP) ENTRY $MAINC NAME SASCSAMP(R) //*
Calling from SOUL
//ONLINE EXEC PGM=ONLINE //STEPLIB DD DSN=M204.LOADLIB,DISP=SHR // DD DSN=YOUR.LOADLIB,DISP=SHR BEGIN IMAGE PARMS NUMBER.ONE.BINARY IS BINARY LEN 4 NUMBER.TWO.BINARY IS BINARY LEN 4 NUMBER.SUM.BINARY IS BINARY LEN 4 END IMAGE EXTERNAL MODULE SASCSAMP EXTERNAL LOAD SASCSAMP EXTERNAL NAME MOD_SASCSAMP FOR SASCSAMP PREPARE IMAGE PARMS %PARMS:NUMBER.ONE.BINARY = 1 %PARMS:NUMBER.TWO.BINARY = 2 EXTERNAL CALL MOD_SASCSAMP WITH PARMS PRINT %PARMS:NUMBER.ONE.BINARY WITH ' + ' WITH - %PARMS:NUMBER.TWO.BINARY WITH ' = ' WITH - %PARMS:NUMBER.SUM.BINARY END
Comments
SAS/C | Corresponds to SOUL |
---|---|
int |
BINARY LEN 4 |
- The SAS/C program must be coded as a main program, not a subroutine.
- To enable SAS/C to accept parameters in standard OS format, the entry point must be defined as
$MAINC
and the parameters handled as illustrated. This technique is described in the SAS/C Compiler and Library User's Guide.
Assembler sample
This example uses the non-Language Environment assembler.
Assembler program
//ASMSAMP EXEC PGM=ASMA90 //SYSLIB DD DSN=SYS1.MACLIB,DISP=SHR //SYSLIN DD DSN=YOUR.OBJLIB(ASMSAMP),DISP=SHR //SYSPRINT DD SYSOUT=* //SYSIN DD * ASMSAMP CSECT ASMSAMP AMODE 31 ASMSAMP RMODE ANY USING *,15 L 1,0(1) GET ADDRESS OF IMAGE COPY XC WORKAREA,WORKAREA CLEAR WORK AREA MVC WORKAREA+4(4),0(1) GET FIRST NUMBER (PACKED) CVB 0,WORKAREA GET FIRST NUMBER (BINARY) A 0,4(1) ADD SECOND NUMBER (BINARY) ST 0,8(1) STORE SUM (BINARY) XR 15,15 ZERO RETURN CODE BR 14 RETURN DS 0D WORKAREA DS PL8 WORKING STORAGE END ASMSAMP
Linkedit
//LASM EXEC PGM=IEWL //OBJLIB DD DSN=YOUR.OBJLIB,DISP=SHR //SYSLMOD DD DSN=YOUR.LOADLIB,DISP=SHR //SYSPRINT DD SYSOUT=* //SYSLIN DD * INCLUDE OBJLIB(ASMSAMP) NAME ASMSAMP(R)
Calling from SOUL
//ONLINE EXEC PGM=ONLINE //STEPLIB DD DSN=M204.LOADLIB,DISP=SHR // DD DSN=YOUR.LOADLIB,DISP=SHR BEGIN IMAGE PARMS NUMBER.ONE.PACKED IS PACKED LEN 4 NUMBER.TWO.BINARY IS BINARY LEN 4 NUMBER.SUM.BINARY IS BINARY LEN 4 END IMAGE EXTERNAL MODULE ASMSAMP EXTERNAL LOAD ASMSAMP EXTERNAL NAME MOD_ASMSAMP FOR ASMSAMP PREPARE IMAGE PARMS %PARMS:NUMBER.ONE.PACKED = 1 %PARMS:NUMBER.TWO.BINARY = 2 EXTERNAL CALL MOD_ASMSAMP WITH PARMS CALL CHECK.STATUS PRINT %PARMS:NUMBER.ONE.PACKED WITH ' + ' WITH - %PARMS:NUMBER.TWO.BINARY WITH ' = ' WITH - %PARMS:NUMBER.SUM.BINARY END
Comments
Assembler | Corresponds to SOUL |
---|---|
DS PL4 |
PACKED LEN 4 |
DS F |
BINARY LEN 4 |
IDCAMS example
This example uses the IDCAMS option (available as of Model 204 7.7) on the ECF Module statement to have IDCAMS input and output go from/to the user buffer.
Module definition
The following External statements make IDCAMS available:
b external module idcams idcams external load idcams external name idcams for idcams end
When IDCAMS is invoked by External Call, the user's Universal Buffer must contain the input lines to be passed to SYSIN
, separated by EBCDIC linefeed characters (X'25'). The output lines from IDCAMS are appended to the Universal Buffer, also separated by new lines.
Before calling IDCAMS, the Universal Buffer must be allocated to a length sufficient to hold all of the input lines and all of the expected output lines. If the buffer is too small, output is truncated. While it is possible to calculate the optimum Universal Buffer length on each invocation, it is better to do the following to minimize storage fragmentation:
- Use the same value for all invocations.
- Use a multiple of 8K.
Return codes
The IDCAMS interface can return one of the following return codes:
20 | Universal Buffer was overflowed, output truncated. |
---|---|
24 | Minimum outspace (2,000 bytes) not available in Universal Buffer. |
28 | No input data in Universal Buffer. |
Else | The return code is from the IDCAMS program. |
SOUL code
b %idcams.in is longstring %idcams.out is longstring %lines.in is object stringlist %lines.out is object stringlist %hlq is string len 8 %options is string len 32 %input.len is float %rc is float %hlq = 'DRAKE' %options = 'VOLUMES' * Prepare IDCAMS input lines in stringlist. Note that that the * TEXT TO statement supports expressions allowing %variables and * functions to be used as the trivial example shows. %lines.in = new Text nocont To %lines.in {} LISTCAT - LEVEL({%hlq}) - {%options} End Text * Note: the null expression {} in front of LISTCAT is to force * indentation, since IDCAMS commands cannnot begin in column 1. * Convert the stringlist to a longstring with EBCDIC new line * delimiters at the end of each line. This is needed to use the * Model 204 Universal Buffer feature, which only understands * byte strings. %idcams.in = %lines.in:CreateLines * Force Universal Buffer allocation of sufficient size modify buffer size=65536 nopreserve clear * Prime Universal Buffer with input for IDCAMS, save its length %input.len = $Lstr_Set_UserBuffer(%idcams.in) * Call the IDCAMS wrapper, appending output to Universal Buffer external call idcams Printtext $status={$STATUS}, $STATUSD={$STATUSD}, $ECFSTAT={$ECFSTAT} %rc = +$substr($ecfstat,4,5) Printtext In simpler terms, the IDCAMS return code was {%rc}. * Retrieve output data from Universal Buffer (too bad there isn't * a starting offset parameter) and parse lines to stringLlist. %idcams.out = $lstr_substr($lstr_Get_UserBuffer,%input.len+1) %lines.out = new %lines.out:ParseLines(%idcams.out) Printtext IDCAMS passed the following {%lines.in:count} lines: %lines.in:print Printtext Which produced {%lines.out:count} lines of output: %lines.out:print end