Topic
IC4NOTICE: developerWorks Community will be offline May 29-30, 2015 while we upgrade to the latest version of IBM Connections. For more information, read our upgrade FAQ.
12 replies Latest Post - ‏2013-01-11T11:44:35Z by SystemAdmin
SystemAdmin
SystemAdmin
6195 Posts
ACCEPTED ANSWER

Pinned topic Calling RPG from generated iSeries COBOL

‏2012-12-27T13:11:43Z |
Dear collective wisdom,
we have EGL applications targeting COBOL and running on iSeries and we need to call RPG programs (created with Plex if that matters). I presume that is possible. However, googling has resulted in very little documentatation. I have only found documentation about calling RPG using Java, but we do not wish to run Java in iSeries just to be able to call RPG.

Below is a sample program.

function main() 

try SysLib.writeStdout(
"start"); call 
"RPGPGM" (a, b, c, d); onException(e AnyException) SysLib.writeStdout(e.message); end SysLib.writeStdout(
"done"); end

Our RPG-savvy friends have translated the parameters into EGL for us so they should be correct. Calling the program goes fine (the RPG program generates no error codes) but the having printed "done" the program ends with MCH3601 as follows:

start logs from the RPGPGM done Pointer not set 

for location referenced. Toimintakatko. Valvomaton sanoma MCH3601 ohjelman QLNRMAIN lauseen 0000000005 käskystä X
'0000'. EGL Server COBOL error handler was invoked to end the run unit. EGL Server encountered a critical internal processing error. Ohjelmistohäiriöiden kirjaus ei ole käynnissä. Pointer not set 

for location referenced. Exception recursion detected. Application error. *N unmonitored by *N at statement *N, instruction X
'4000'.

No exception is raised (not that I expected it to work between EGL amd RPG). Examining the values of the parameters would also create a MCH3601.

This raises a few questions: The RPG programs are OPM no ILE - does that matter? Is there something I should do about the activation groups? Is the handling of parameters different when calling RPG than when calling COBOL generated from EGL? Or, in general, where can I look for guidance?
Updated on 2013-01-11T11:44:35Z at 2013-01-11T11:44:35Z by SystemAdmin
  • markevans
    markevans
    2778 Posts
    ACCEPTED ANSWER

    Re: Calling RPG from generated iSeries COBOL

    ‏2013-01-02T20:27:31Z  in response to SystemAdmin
    Tuukka,

    As a general rule, if you can call it from native COBOL, then you can call it from EGL generated COBOL. We generate a COBOL Call statement and pass the parms by reference in the COBOL Call statement. In your case, it would pass 4 separate pointers to the RPGPGM..one each for a, b, c, and d. This will translate to normal calling conventions between programs.

    I know I have successfully called native COBOL, C, and CL Programs from EGL. You can create a linkage entry to tell EGL that it is a non EGL program, but I don't think that would make any difference. The linkage part is specified at generation time and you would create a localCall entry for RPGPGM.

    So..I am not sure what is happening unless it is an incompatibility between ILE COBOL (what EGL uses) and OPM RPG.

    A couple of questions/observations:

    a.) Have you tried to generate the EGL program with statementTrace=yes in the build descriptor. This trace output would tell us how far EGL got when it was trying to terminate (which I assume is where the error came out).

    b.) Have you tried from a simple native COBOL program built/compiled as an ILE program?

    c.) Activation Groups can sometimes be an issue and after a brief Google, this seemed to be likely with ILE to OPM calls. I would build the RPG programs using *CALLER if at all possible, then it will take on the activation group of EGL (QEGL by default). The QEGL can be changed if you want by updating the FDAPREP REXX program we ship that is used to "build" EGL COBOL programs.

    d.) Does an RPG program built by Plex run within some kind of runtime environment so that the RPG program cannot be called directly or it is not terminated on exit. Since you can call and return, this does not sound like the issue, but I have seen it with some generator products (not an issue with EGL though).

    take care.
    • SystemAdmin
      SystemAdmin
      6195 Posts
      ACCEPTED ANSWER

      Re: Calling RPG from generated iSeries COBOL

      ‏2013-01-03T11:58:55Z  in response to markevans
      Hello Mark,
      very good observations (as usual). A few comments.

      a.) It seems that statementTrace=yes is available only when targeting COBOL (see here).

      b.) I have not tried. I do not speak COBOL but I'll try to find someone that does.

      c.) We had some trouble with activation groups before (PMR 09106,999,702) and as a result we changed activation group definitions in FDAPREP so main programs have activation group QEGL and called programs have activation group *CALLER. (This advice was directly from the person who apparently wrote FDAPREP in the first place, so it should be correct.) The RPG programs are all OPM programs (as are our EGL main programs). This page states that OPM programs automatically run in the OPM default activation group. Hence, it seems that their activation group can be changed.

      d.) The Plex runtime environment is included in the library list. According to job log the Plex program seems to finish without an error.

      I presume my next step is to try to call the Plex program from COBOL and see what happens. It seems that Plex programs run nicely in their their own sandbox and so do RBD/EGL programs, but it is the interoperability that causes concerns. Vice versa, I might try calling plain RPG from EGL to see if that succeeds.

      Finally, in case the culprit turns out to be the interoperability of RBD/EGL and Plex/RPG, the outlook for finding a solution seems a little dim, since finding a person that knows both environments could be difficult.
      • markevans
        markevans
        2778 Posts
        ACCEPTED ANSWER

        Re: Calling RPG from generated iSeries COBOL

        ‏2013-01-03T17:11:22Z  in response to SystemAdmin
        Tuukka,

        Thanks for the observations as well.

        Correct...statementTrace is only available for EGL COBOL Gen. This will generate a COBOL DISPLAY (println in Java Terms) for each EGL Statement as well as some for entry/exit for the generated paragraphs. The output is in the job log. The reason I suggested this is that you/we would be able to see where in the EGL shut down the problem is occurring or if it is when the activation group is being terminated after the last EGL infrastructure code ends on shutdown of a program.

        I did some more reading and as you stated, it looks like OPM always runs in the default Activation Group.. From what I could read there was no way to change this.

        So, it appears you need to make the EGL generated COBOL Run in the default activation group. Again, as I read it this is possible if a.) you set the activation group to the *CALLER for EGL main programs and b.) you start the program from the command line.

        There were some cautions about running an ILE program under the default activation group, so I really don't know what would happen if running under the default activation group instead of the normal named activation group (QEGL) and as ILE.

        I think this is really just a "ILE" vs "OPM" issue when an ILE program is calling into a OPM program and related activation groups, but hard to say without more detailed info. The use of a native COBOL to this would be useful as a data point.
        • markevans
          markevans
          2778 Posts
          ACCEPTED ANSWER

          Re: Calling RPG from generated iSeries COBOL

          ‏2013-01-03T17:22:42Z  in response to markevans
          One other thought...that may or may not be part of the issue.

          In some fixpack (can't remember which one right now), the programs in the QEGL (EGL COBOL Runtime) were changed to use the activation group of *CALLER instead of QEGL. Can you look at your QEGL modules (especially QVGNHS) and see what activation group it is using.

          If it is not *CALLER, then maybe it would work better if the QEGL runtime was updated as well (shipped with the fixpacks/releases).
          • SystemAdmin
            SystemAdmin
            6195 Posts
            ACCEPTED ANSWER

            Re: Calling RPG from generated iSeries COBOL

            ‏2013-01-04T12:45:00Z  in response to markevans
            Hello Mark,
            I am aware of the activation group having been changed to *CALLER since PM52770 in which the fix was to change activation groups was created due to a PMR I opened :)

            During the PMR we received re-compiled versions of library causing trouble and the case was closed. As a result, we have currently a mixed set of activation groups: VGNSTR is *CALLER but VGNSYS is QEGL. Also activation groups *NEW, QEGLCCU, QVGNMEM, QVGN and QILE are found as activation group among the objects in QEGL. QVGNHS has activation group *CALLER.

            During the PMR I was told that there would be an updated runtime. The fixpack you refer to is probably 7.5.1.8 and I wrote here a message New COBOL runtime in 7.5.1.8? in this forum since I did not see a new runtime mentioned in the release notes. I will update our runtime and examine the activation groups. We'll see if that helps.
            • SystemAdmin
              SystemAdmin
              6195 Posts
              ACCEPTED ANSWER

              Re: Calling RPG from generated iSeries COBOL

              ‏2013-01-08T12:35:18Z  in response to SystemAdmin
              After some debugging, the problem turned out to be rather mundane. The culprit turned out to be defining one of the parameters as an array
              data char(33)[250];
              
              even if it is defined as an array in the RPG source of the called program. Changing that parameter to
              data char(8250);
              
              made the MCH3601 error disappear altogether. Well, lesson learned.
              Updated on 2014-03-25T04:36:59Z at 2014-03-25T04:36:59Z by iron-man
              • markevans
                markevans
                2778 Posts
                ACCEPTED ANSWER

                Re: Calling RPG from generated iSeries COBOL

                ‏2013-01-08T14:22:15Z  in response to SystemAdmin
                Thanks for posting the solution... Obviously, I did not think of that kind of problem either.
                • SystemAdmin
                  SystemAdmin
                  6195 Posts
                  ACCEPTED ANSWER

                  Re: Calling RPG from generated iSeries COBOL

                  ‏2013-01-09T08:57:29Z  in response to markevans
                  A further note. It seems that when passing an array as a parameter, it must be defined in an structured record with level numbers. When a parameter is defined as
                  record DataArray type BasicRecord
                  10      data char(33)[250];
                  end
                  
                  everything goes smoothly, but if omitting level definition
                  record DataArray type BasicRecord
                          data char(33)[250];
                  end
                  
                  results in MCH3601. Calling EGL programs (generated to COBOL with RBD) goes fine with unstructured records but interoperability of EGL programs and RPG seems to be more restrictive with regards to parameter definition. However, the funky thing is that it is the EGL program that results in MCH3601, the called RPG program seems to do fine even when the level numbers are omitted. I wonder if this is intended.
                  Updated on 2014-03-25T04:36:50Z at 2014-03-25T04:36:50Z by iron-man
                  • markevans
                    markevans
                    2778 Posts
                    ACCEPTED ANSWER

                    Re: Calling RPG from generated iSeries COBOL

                    ‏2013-01-09T17:11:40Z  in response to SystemAdmin
                    Tuukka,

                    As a general rule, a structured record in EGL COBOL is created as a structure of contiguous bytes. An unstructured record may or may not be. In other words, the fields in an unstructured record can really be allocated independently and some of them we just handle with pointers to the storage. The use of structured vs unstructured can also affect whether the array is treated as a fixed size array vs a dynamic array which also affects how the storage is allocated.

                    So, it could be when the RPG program is running with the arrays/record being treated as contiguous storage, something is being overwritten and when it gets back to EGL, it takes a MCH3601 (pointer not set).

                    When communicating with RPG, I would always recommend using structured records (whether remote from Java or from generated COBOL).

                    take care.
                    • SystemAdmin
                      SystemAdmin
                      6195 Posts
                      ACCEPTED ANSWER

                      Re: Calling RPG from generated iSeries COBOL

                      ‏2013-01-10T10:43:02Z  in response to markevans
                      Hello Mark,
                      interesting info - thank you. I tried to compare the generated COBOL for two programs in which the only difference was that one had a structured record and the other had just a record. Quite a few changes! After your explanation the following two lines in the beginning of the non-structured COBOL source start to make sense.
                      *---PERFORMANCE CONSIDERATIONS------------------------------
                      *        EGL line *6* creates a new dynamic array
                      

                      Later in the source code the record is referenced as
                      * DATA ===> DATA-11
                                         04  DATA-11 USAGE IS POINTER.
                      
                      whereas the same lines in structured COBOL program is
                      * DATA ===> DATA-11
                                         04  DATA-11 PIC X(33) OCCURS 250 TIMES.
                      

                      And so on. I did not count them, but it seems that turning a single structured record to an unstructured record results in hundreds of lines of different code.

                      I learned my lesson and I'll stick to structured records whenever RPG (or ILE) is concerned.
                      Updated on 2014-03-25T04:36:42Z at 2014-03-25T04:36:42Z by iron-man
                      • markevans
                        markevans
                        2778 Posts
                        ACCEPTED ANSWER

                        Re: Calling RPG from generated iSeries COBOL

                        ‏2013-01-10T13:30:45Z  in response to SystemAdmin
                        Tuukka,

                        Good observations

                        The use of static arrays (i.e. occurrences in a structured record) is a better performer in COBOL since it maps directly to a COBOL structure. We had to implement our own support for dynamic arrays on top of COBOL which is why you see the extra code.

                        If you have not seen it already, this type of best practice is listed int the coding for performance white paper on the EGL Wiki (Cafe).

                        https://www.ibm.com/developerworks/mydeveloperworks/wikis/home?lang=en#/wiki/W75c8733d99bb_4d55_9ee8_4dbc8c56ebee/page/Coding%20For%20Performance

                        The extra code/processing you found is one of the reasons static occurs is a better performer. We also decided to add the "performance considerations" to the COBOL so you could see the known expensive (relative) items that we can detect at gen time.

                        None of the above is to try and convince you not to use the new language elements in EGL. On the contrary, they are very useful and productive...but as in most programming/languages, there are performance tradeoffs and the type of array is one.

                        Anyway..back to the original issue..as you stated, when dealing with RPG, COBOL, C, Assembler, PLI, etc... which are generally "contiguous byte" type of languages..it is best to use structured records as the parms/arguments.
                        • SystemAdmin
                          SystemAdmin
                          6195 Posts
                          ACCEPTED ANSWER

                          Re: Calling RPG from generated iSeries COBOL

                          ‏2013-01-11T11:44:35Z  in response to markevans
                          Hello Mark,
                          again, very interesting information. I had not read the best practice document before - I will read it very carefully and discuss with my team if our programming practices need to change.

                          My main focus in programming is maintainability. I have been repeating the following edict for years: The first principle of optimization is "Don't." (You might recognize similarities to a recent discussion in the LinkedIn EGL group here.) Most likely my choice between using structured records or newer constructs depends on which creates more readable source code - provided that both of the do the work (which was not the case when calling RPG). I would assume that processing an array is O(n) both for structured records and dynamic arrays even if the latter is slower (but only by a constant factor).

                          In any case, it is good to know the performance side as well in order to make informed decisions taking into account both maintainability and performance. While I truly appreciate the productivity of the new language elements, having the performance document at hand is useful if we run into performance issues in the future.