Hi Charles,
You said, "reclaiming TRYAG1" I was thinking that was a typo and you
meant "reclaiming TRGAG2"
It wasn't a typo. I meant TRYAG1.
TRYAG2 has /already/ been reclaimed, as Alan pointed out at the start of
this discussion. Reclaiming it again isn't going to do anything, since
it's not currently active.
Here's what's happening:
1) TRYAG1 activation group is created.
2) The TRYAG1 program is activated into the TRYAG1 activation group.
3) All variables used by TRYAG1 program will be stored in TRYAG1 actgrp.
Because that's what activations are...
4) TRYAG2 activation group is created.
5) The TRYAG2 service program (which includes the tryag2() procedure) is
activated into the TRYAG2 activation group.
6) The TRYAG1 program resolves a procedure pointer to the tryag2()
procedure. Although the procedure itself is in the TRYAG2 activation
group, the procptr is in the TRYAG1 activation group, since the pointer
is a variable in the TRYAG1 program.
7) The TRYAG2 program uses the procptr to call tryag2()
8) tryag2() crashes, which takes out the TRYAG2 activation group, and
everything in it.
9) TRYAG1 catches the error with MONITOR.
10) TRYAG1 tries to call tryag2() again using the same pointer...
however, since the TRYAG2 actgrp is gone, the pointer is invalid, and
kaboom.
My point: If you reclaimed the TRYAG1 activation group, this would
reset the procptr, and therefore TRYAG1 could once again call tryag2().
So how could you do that? Well, you'd have to add an extra layer, a
program that was able to recognize the failure, reclaim the activation
group, and restart it. Again, like I said to Mark, this won't work in
every situation, and isn't right for every situation, might it might
make sense in some.
For example, you might add a TRYAG0 (zero) that calls TRYAG1 repeatedly
until TRYAG1 is able to be successful.
Example... well, TRYAG2 wouldn't change, it'd still look like this:
*> CRTRPGMOD TRYAG2 SRCFILE(QRPGLESRC) DBGVIEW(*LIST)
*> CRTSRVPGM TRYAG2 EXPORT(*ALL) ACTGRP(TRYAG2)
H NOMAIN
D TRYAG2 pr
P TRYAG2 b export
D QMHSNDPM PR ExtPgm('QMHSNDPM')
D MessageID 7A Const
D QualMsgF 20A Const
D MsgData 32767A Const options(*varsize)
D MsgDtaLen 10I 0 Const
D MsgType 10A Const
D CallStkEnt 10A Const
D CallStkCnt 10I 0 Const
D MessageKey 4A
D ErrorCode 8192A options(*varsize)
d MsgKey s 4a
d ErrorCode ds
d x 10i 0 inz(0)
d y 10i 0 inz(0)
/free
QMHSNDPM( 'CPF9897'
: 'QCPFMSG *LIBL'
: 'Test'
: 4
: '*ESCAPE'
: '*'
: 0
: MsgKey
: ErrorCode );
/end-free
P e
TRYAG1 would change a little bit, it'd have to keep track of whether
TRYAG2 was successful or not... so it'd have to be something like this:
*> CRTRPGMOD TRYAG1 SRCFILE(QRPGLESRC) DBGVIEW(*LIST)
*> CRTPGM TRYAG1 BNDSRVPGM(TRYAG2) ACTGRP(TRYAG1)
D tryag2 pr
D tryag1 pr
D result 10a
D tryag1 pi
D result 10a
/free
result = 'SUCCESS';
monitor;
tryag2();
on-error;
result = 'FAIL';
endmon;
*inlr = *on;
/end-free
And the new program, TRYAG0, would simply call TRYAG1, reclaim it's AG,
then call it again, etc, until it was successful:
*> CRTRPGMOD TRYAG0 SRCFILE(QRPGLESRC) DBGVIEW(*LIST)
*> CRTPGM TRYAG0 BNDSRVPGM(TRYAG1) ACTGRP(TRYAG0)
D tryag1 pr extpgm('TRYAG1')
D result 10a
D qcmdexc pr extpgm('QCMDEXC')
D cmd 200a const
D len 15p 5 const
D result s 10a
/free
dou result = 'SUCCESS';
tryag1(result);
qcmdexc('rclactgrp tryag1': 200);
enddo;
*inlr = *on;
/end-free
A few notes, however:
1) Note that my code, above, will make an endless loop. TRYAG0 repeats
until TRYAG1 reports success -- which will never happen, as written,
since TRYAG2 always crashes :)
2) If TRYAG1 needs to be a *PGM instead of a *SRVPGM... That should be
clear from the compile commands above, but it's worth mentioning again,
because if you made TRYAG1 into a *SRVPGM, then you'd get the "reference
to object that no longer exists" on both layers.
3) I'm _not_ posting this as a recommendation. Merely as a technical,
mechanical, possibility that helps folks understand the situation. My
actual recommendation would be to add proper error handling into
TRYAG2... I tried to say this earlier, but somehow got embroiled into
this whole fiasco.
As an Amazon Associate we earn from qualifying purchases.