External Call Facility: Difference between revisions

From m204wiki
Jump to navigation Jump to search
m (misc formatting)
 
(9 intermediate revisions by 2 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&nbsp;204</var> 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:</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&nbsp;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>[[#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>
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>[[#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>
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>[[#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>
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&nbsp;204</var> and an external module via a <var class="product">Model&nbsp;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>
Data is passed between <var class="product">Model&nbsp;204</var> and an external module via a <var class="product">Model&nbsp;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===
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>[[#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>[[#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>[[#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><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>
</ul>
</ul>


Line 49: 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>EXTERNAL CALL</var> statement does not interrupt the external module. The external module is allowed to complete &mdash; however long that takes &mdash;and then the bump takes effect.</p>
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 &mdash; however long that takes &mdash;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>EXTERNAL STOP</var> statement with the <var>FORCE</var> option.</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>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 60: 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>


==<b id="extStmt"></b>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>
Line 73: Line 71:
<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>EXTERNAL LOAD</var> statement, using a call name that was previously specified in an <var>EXTERNAL NAME</var> statement.</dd>
<dt>Privileges</dt>
<dt>Privileges</dt>
<dd>
<dd>
Any user</dd>
Any user</dd>
<dt>Syntax</dt>
<dt>Syntax</dt>
<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>
<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&nbsp;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&nbsp;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>
Line 123: Line 124:
<dt>Syntax</dt>
<dt>Syntax</dt>
<dd>
<dd>
<p class="syntax">EXTERNAL DELETE <span class="term">module-name</span>
<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>EXTERNAL DELETE</var> statement for Language Environment modules.</dd>
<dd>Do <i>not</i> use the <var>External Delete</var> statement for Language Environment modules.</dd>
</dl>
</dl>


Line 144: Line 145:
<dl>
<dl>
<dt>Function</dt>
<dt>Function</dt>
<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>
<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">EXTERNAL LOAD <span class="term">module-name</span>
<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>
<div id="EXTERNAL MODULE statement"></div>


===<b id="module"></b>External Module statement===
===<b id="module"></b>External Module statement===
<!--Warning: <div> above-->
<dl>
<dl>
<dt>Function</dt>
<dt>Function</dt>
Line 177: Line 175:
<dt>Syntax</dt>
<dt>Syntax</dt>
<dd>
<dd>
<p class="syntax">EXTERNAL MODULE <span class="term">module-name</span> [DDNAME=<span class="term">ddname</span>]
<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>]
Line 204: 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>EXTERNAL CALL</var> statement. Optional.  
<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 214: 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>EXTERNAL CALL</var> statements.  
<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>EXTERNAL CALL</var> statement fails. </p>
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 246: Line 244:
<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).
<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.
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.
Specifying this option for a module other than IDCAMS is likely to result in abends in the module when called.
Line 256: Line 254:
<dd>
<dd>
<ul>
<ul>
<li>You can use an <var>EXTERNAL MODULE</var> statement to define a module using either:
<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>
Line 272: Line 270:
<dl>
<dl>
<dt>Function</dt>
<dt>Function</dt>
<dd>Use the <var>EXTERNAL NAME</var> statement to:
<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>EXTERNAL MODULE</var> statement</li>
<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 283: Line 281:
<dt>Syntax</dt>
<dt>Syntax</dt>
<dd>
<dd>
<p class="syntax">EXTERNAL NAME <span class="term">call-name</span> FOR <span class="term">module-name</span>
<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
External Name <span class="term">call-name</span> REMOVE
</p>
</p>
<p>Where:</p>
<p>Where:</p>
Line 316: Line 314:
<dt>Syntax</dt>
<dt>Syntax</dt>
<dd>
<dd>
<p class="syntax">EXTERNAL START <span class="term">module-name</span>
<p class="syntax">External Start <span class="term">module-name</span>
</p>
</p>
<p>Where:</p>
<p>Where:</p>
Line 332: Line 330:


<dt>Usage</dt>
<dt>Usage</dt>
<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>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>
Line 345: Line 343:


<dt>Syntax</dt>
<dt>Syntax</dt>
<dd><p class="syntax">EXTERNAL STOP <span class="term">module-name</span> [FORCE]
<dd><p class="syntax">External Stop <span class="term">module-name</span> [FORCE]
</p>
</p>
<p>Where:</p>
<p>Where:</p>
Line 366: Line 364:


<dt>Usage</dt>
<dt>Usage</dt>
<dd>The following table describes how an <var>EXTERNAL STOP</var> command is evaluated.
<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>EXTERNAL STOP</var> command is issued </th>
<th>When <var>External Stop</var> statement is issued </th>
<th>
<th>
Then</th>
Then</th>
Line 395: Line 393:
</table>
</table>
<p>
<p>
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>
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&nbsp;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&nbsp;204</var> cannot ensure that the external module is terminated cleanly.</p></dd>
</dl>
</dl>
Line 666: 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>EXTERNAL CALL</var> statement by managing the load modules and subtasks as described in the following sections.</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>External Call</var> statement by managing the load modules and subtasks as described in the following sections.</p>
   
   
===Subtasks assignment===
===Subtasks assignment===
Line 677: Line 675:
</ul>
</ul>
<p>
<p>
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>
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>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>
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 688: Line 686:
</ul>
</ul>
<p>
<p>
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>
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&nbsp;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&nbsp;204</var> Online.</p>
Line 694: 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>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>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 701: Line 699:
===Load modules===
===Load modules===
<p>
<p>
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>
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&nbsp;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>
Normally, one <var class="product">Model&nbsp;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>EXTERNAL MODULE</var> statement that defined the module characteristics specified the <var>REENTRANT</var> option, then multiple <var class="product">Model&nbsp;204</var> users are allowed to simultaneously issue an <var>EXTERNAL CALL</var> statement for the module &mdash; subject to subtask availability.</p>
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&nbsp;204</var> users are allowed to simultaneously issue an <var>External Call</var> statement for the module &mdash; subject to subtask availability.</p>
   
   
===Fulfillment order===
===Fulfillment order===
<p>
<p>
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>
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 715: 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>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 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>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>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 741: Line 739:
===Wait types for ECF===
===Wait types for ECF===
<p>
<p>
See the table of codes in [[Controlling system operations (CCAIN)#Job step return codes|Job step return codes]] for a listing of wait types that includes the External Call Facility, wait types 43 through 46.</p>
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 772: Line 770:
</ul>
</ul>
<p>
<p>
Statistics include only <var>EXTERNAL CALL</var> statements that actually called a module &mdash; 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>
Statistics include only <var>External Call</var> statements that actually called a module &mdash; 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 1,107: Line 1,105:
</table>
</table>
   
   
<span id="idcams"></span>
===IDCAMS example===
===IDCAMS example===
<p>
<p>
Line 1,112: Line 1,111:


====Module definition====
====Module definition====
The following <var>External Call</var> statements make IDCAMS available:
The following <var>External</var> statements make IDCAMS available:
<p class="code">b
<p class="code">b
external module idcams idcams
external module idcams idcams
Line 1,120: Line 1,119:
</p>
</p>


When IDCAMS 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 IDCAMS are appended to the Universal Buffer, also separated by new lines.                                                      
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 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:
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>
<ul>
<li>Use the same value for all invocations.</li>
<li>Use the same value for all invocations.</li>
Line 1,130: Line 1,129:


====Return codes====
====Return codes====
The <var>IDCAMS</var> interface can return one of the following Return Codes:                             
The <var>IDCAMS</var> interface can return one of the following return codes:                             
<table class="thJustBold">
<table class="thJustBold">
<tr><th>20</th>
<tr><th>20</th>
Line 1,142: Line 1,141:


<tr><th><i>Else</i></th>
<tr><th><i>Else</i></th>
<td>The return code is from IDCAMS.</td></tr>                                           
<td>The return code is from the IDCAMS program.</td></tr>                                           
</table>
</table>


====SOUL code====
====SOUL code====
<p class="code">b
<p class="code">b    
                                                                               
  %idcams.in    is longstring  
  %idcams.in    is longstring                                                  
  %idcams.out  is longstring  
  %idcams.out  is longstring                                                  
  %lines.in    is object stringlist  
  %lines.in    is object stringlist                                            
  %lines.out    is object stringlist  
  %lines.out    is object stringlist                                            
 
                                                                               
  %hlq          is string len 8  
  %hlq          is string len 8                                                
  %options      is string len 32
  %options      is string len 32                                                
  %input.len    is float
  %input.len    is float                                                        
  %rc          is float  
  %rc          is float                                                        
 
                                                                               
  %hlq = 'DRAKE'  
  %hlq = 'DRAKE'                                                                
  %options = 'VOLUMES'        
  %options = 'VOLUMES'                                                          
                                                                               
  * Prepare IDCAMS input lines in stringlist. Note that that the  
  * Prepare IDCAMS input lines in stringlist. Note that that the                
  * TEXT TO statement supports expressions allowing %variables and  
  * TEXT TO statement supports expressions allowing %variables and              
  * functions to be used as the trivial example shows.  
  * functions to be used as the trivial example shows.                          
  %lines.in = new  
                                                                               
  Text nocont To %lines.in  
  %lines.in = new                                                              
   {} LISTCAT -  
  Text nocont To %lines.in                                                      
     LEVEL({%hlq}) -  
   {} LISTCAT -                                                                
     {%options}
     LEVEL({%hlq}) -                                                            
  End Text  
     {%options}                                                                
 
  End Text                                                                      
  * Note: the null expression {} in front of LISTCAT is to force  
                                                                               
  * indentation, since IDCAMS commands cannnot begin in column 1.  
  * 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  
  * Convert the stringlist to a longstring with EBCDIC new line                  
  * Model 204 Universal Buffer feature, which only understands  
  * delimiters at the end of each line. This is needed to use the                
  * byte strings.      
  * Model 204 Universal Buffer feature, which only understands                  
  %idcams.in = %lines.in:CreateLines      
  * byte strings.                                                                
 
                                                                               
  * Force Universal Buffer allocation of sufficient size  
  %idcams.in = %lines.in:CreateLines                                            
  modify buffer size=65536 nopreserve clear      
                                                                               
 
  * Force Universal Buffer allocation of sufficient size                        
  * Prime Universal Buffer with input for IDCAMS, save its length  
  modify buffer size=65536 nopreserve clear                                    
  %input.len = $Lstr_Set_UserBuffer(%idcams.in)  
                                                                               
 
  * Prime Universal Buffer with input for IDCAMS, save its length                
  * Call the IDCAMS wrapper, appending output to Universal Buffer  
  %input.len = $Lstr_Set_UserBuffer(%idcams.in)                                
  external call idcams
                                                                               
  Printtext $status={$STATUS}, $STATUSD={$STATUSD}, $ECFSTAT={$ECFSTAT}  
  * Call the DRAKE wrapper, appending output to Universal Buffer                
  %rc = +$substr($ecfstat,4,5)        
  external call wrapper                                                         
  Printtext In simpler terms, the IDCAMS return code was {%rc}.  
                                                                               
 
  Printtext $status={$STATUS}, $STATUSD={$STATUSD}, $ECFSTAT={$ECFSTAT}        
  * Retrieve output data from Universal Buffer (too bad there isn't  
                                                                               
  * a starting offset parameter) and parse lines to stringLlist.  
  %rc = +$substr($ecfstat,4,5)                                                  
  %idcams.out = $lstr_substr($lstr_Get_UserBuffer,%input.len+1)
                                                                               
  %lines.out = new  
  Printtext In simpler terms, the IDCAMS return code was {%rc}.                
  %lines.out:ParseLines(%idcams.out)  
                                                                               
     
  * Retrieve output data from Universal Buffer (too bad there isn't              
  Printtext IDCAMS passed the following {%lines.in:count} lines:  
  * a starting offset parameter) and parse lines to stringLlist.                
  %lines.in:print  
  %idcams.out = $lstr_substr($lstr_Get_UserBuffer,%input.len+1)                
     
  %lines.out = new                                                              
  Printtext Which produced {%lines.out:count} lines of output:  
  %lines.out:ParseLines(%idcams.out)                                            
  %lines.out:print  
                                                                               
end
  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>
</p>


[[Category:System management]]
[[Category:System management]]
[[Category:System-level capabilities of Model 204]]
[[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.

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.

ECF return codes
$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 either RMODE(ANY) or RMODE(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