I don't know all the pitfalls of this problem, but ...

since you are calling from TSO/ISPF, I can add some experience that we made, doing a similar thing. We wanted to call a C program which contained all the DB2 work for a certain application and communicated with the rest (written in REXX) using ISPF variables (or with other C programs without DB2 using normal C to C interfaces ... pointers to structs). The C-DB2-interface, BTW, is not hand-written, but generated from a file, which contains SQL-Statements and the interface definitions; the generator can produce statement for DB2 and, if needed, also for Oracle. Static SQL in both cases.

We wanted the C-DB2-interface program to be loaded only once and to stay in storage at the same address, because the "lower parts" were called using LOAD ... BALR, where the address returned on first load is stored statically (that is, all modules needed must stay in storage all the time, so that the addresses stay the same all the time).

The only solution we found was to do an extra load on the C program's module at the start of the application.

This is needed, because any other call mechanism in TSO/ISPF (ISPF's SELECT PGM or SELECT CMD, for example) loads and deletes the modules (that is, they disappear after the call). SELECT CMD even creates a subtask, IIRC.

With the extra LOAD, the module kept its place, and all worked (and still works) well.

The modules have to be RENT, of course, so that they can be reused and no new copy is fetched.

Kind regards

Bernd


Am 01.03.2026 um 18:01 schrieb Farley, Peter:
My reply was indeed a “Yes” answer to your question as to whether what you want 
can be done.

Yes, I believe that using CEEPIPI to set up all the entry points you want to 
use in the C/C++ code will let the statics and heap persist across Rexx 
invocations of the C/C++ code, but the CEEPIPI areas that hold the addresses of 
the called routines need to be preserved in obtained storage.

Yes, Name/Token services was the function whose name I could not remember, but 
I like your idea of using the host environment command table TOKEN field 
better, since that table must have a unique environment name value thus 
removing the “user word” conflict issue.  Anyone who uses your host environment 
name for something other than your environment can’t use your environment, so 
no conflict possible.

I did not intend to convey that the actual functionality of the environment 
(the C/C++ logic) would need to be coded in assembler or MetalC, only that the 
Rexx environment establishment, termination, and CALL interface mechanism would 
need to be coded in one of those languages.

Unless I misunderstand Rexx ADDRESS functionality, I think only an initial CALL of the 
environment establishment code (to use IRXSUBCM to set up the HOST environment) is 
required.  Termination can be just one of the "functions" supported by the HOST 
environment.  Something instead like this:

CALL "HOSTMGR" "ADD", env-name, 'LE runtime parms', etc.
ADDRESS env-name
“function_one params"
IF RC = whatever THEN . . . .
“function_two params"
ADDRESS TSO
"LISTDS" whatever
ADDRESS env-name
“function_three params"
ADDRESS env-name "TERMINATE"

I am on the CBT Discord and will discuss this project further with you there.

Peter

From: IBM Mainframe Discussion List <[email protected]> On Behalf Of 
Charles Mills
Sent: Sunday, March 1, 2026 6:14 AM
To: [email protected]
Subject: Re: Is anyone familiar with CEEPIPI (LE pre-initialization)?

Thank you all for your prompt replies. Let me see if I can't respond to 
everyone at once and minimize the listserv noise.

Charles, you will need two levels to accomplish this from Rexx.  First you need a Rexx 
function or ADDRESS mode package written in assembler or MetalC that will load and call 
your C code the first time, using CEEPIPI to initialize the C environment, and save the 
entry point address and the address of the GETMAIN'ed CEEPIPI area in the user area of 
one of the Rexx control blocks or in a saved named whatchamacallit (I forget the macro 
name – the z/OS mechanism behind CICS named counters) for subsequent calls.  And for 
completeness you'll probably need an "exit" call as well to clean up the loaded 
code and dynamic storage before Rexx termination.
I assume I should take your reply as a Yes to my question. Using CEEPIPI will 
let the statics and heap persist across Rexx invocations of the C++ code.

Yes, I pictured the first of those "levels." I see a sequence in Rexx something 
like

CALL LEENVMGR 'ADD', env-name, 'LE runtime parms', etc.
ADDRESS env-name whatever
IF RC = 'blah blah blah' THEN ...
ADDRESS env-name whatever
ADDRESS env-name whatever
CALL LEENVMGR 'DELETE', env-name

I had not considered the second of those "levels"-- saving the address of the CEEPIPI 
block and so forth -- but no big deal. I would use the command environment table TOKEN field, or 
else MVS Name-Token Services, which avoids any conflicts around "user words."

The problem is that z/OS Rexx has no concept of a “load this external function once and 
call the same copy the next time”.  It sure would be nice if someone wrote generalized 
"loaded function" glue code for z/OS Rexx and contributed it to CBT, but sadly 
we do not have that yet.
This is part of a project destined for the CBT. I would send you the source code for the 
environment manager once it was working and you could do that, or if you wanted to write 
up some informal "requirements" for the glue code as you see it I would get it 
onto the CBT once the main project was done. You're on the CBT Discord, right? You can 
write me there. I'm assuming that what I have described here is more or less what you are 
talking about.

Could the C or Assembler refreshable  function keep any needed
persistent data in Obtained storage and return the address of
such a block to REXX?

As I said in the OP, "No, an "anchored" GETMAIN is not sufficient. The C++ code 
makes extensive use of library functions such as map, which is tightly integrated with the language 
heap."

I think that's about it. Writing the environment in HLASM rather than C++ is 
not on the table. The problem at hand is as stated in the OP.

Thanks again,
Charles

On Sat, 28 Feb 2026 07:55:39 -0600, Charles Mills <[email protected]> wrote:

Here's the problem I am trying to solve. I want to be able to call (from Rexx, 
FWIW) one or more entry points in a C++ program multiple times, and have each 
call after the first find the heap and statics as the previous call left them.

In other words, if the Rexx called entry point A and then entry point B, on 
entry to B, the statics and heap would be as they were on exit from A.

Will CEEPIPI let me do this? It looks to me like CEEPIPI(init_sub) will let me 
do this. Is that correct?

CEEPIPI looks IBM-complicated, of course. Is there an easier way to accomplish 
what I want? Something with DLL linkage?

The CEEPIPI doc talks mostly about performance. That's one of the reasons I wonder if 
this is the wrong approach. I "get" why pre-initialization would improve 
performance, and improved performance is of course a Good Thing, but that is not my 
primary goal. The primary goal is being able to put things in the heap and in statics and 
use them on subsequent calls. There would typically be half a dozen or so calls, so 
improving performance is not a big consideration.

No, an "anchored" GETMAIN is not sufficient. The C++ code makes extensive use 
of library functions such as map, which is tightly integrated with the language heap.
This message and any attachments are intended only for the use of the addressee 
and may contain information that is privileged and confidential. If the reader 
of the message is not the intended recipient or an authorized representative of 
the intended recipient, you are hereby notified that any dissemination of this 
communication is strictly prohibited. If you have received this communication 
in error, please notify us immediately by e-mail and delete the message and any 
attachments from your system.


----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to [email protected] with the message: INFO IBM-MAIN

----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to [email protected] with the message: INFO IBM-MAIN

Reply via email to