Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Help needed with / confused by AST routine (VAX,COBOL)

9 views
Skip to first unread message

Wilm Boerhout

unread,
Aug 14, 2008, 1:05:53 PM8/14/08
to
This is on VAX/VMS 7.3, COBOL 5.7-63

I need to extend some program's functionality and came up with an idea
to let an AST routine do periodic reporting. I was brutally ACCVIO'd by
the program, and made a small reproducer. I'm sure I don't understand
all about AST programming (it's relatively new to me), but why it would
fail in exactly this manner baffles me.

The real program will have a network listener instead of a
DISPLAY/ACCEPT loop, but you'll get the general idea. Also, the MIS area
will have really useful data, trust me.

The reproducer ACCVIO's in the compute statement marked with two
asterisks (**) below.
Two questions:
- can you reproduce the error?
- if yes, can you tell me why it ACCVIOs, and how to avoid it?

TIA,
Wilm
*-------------------------------------------- cut here -----------
identification division.
program-id. TESTIMR initial.

data division.
working-storage section.
01 SS$_NORMAL pic S9(9) comp value external SS$_NORMAL.
01 ASTSERV pic S9(9) comp value external ASTSERV.
01 SYSTAT pic S9(9) comp.

01 TELLER pic 9.

01 MIS external.
02 SOM pic 9(6) occurs 10 times.

procedure division.
TEST-TIMER section.
00.
move zeroes to TELLER, SOM(8).

* fire the AST routine once:
call "SYS$DCLAST" using
by value ASTSERV,
omitted, omitted
giving SYSTAT
if SYSTAT not = SS$_NORMAL call "LIB$STOP"
using by value SYSTAT.

* schedule the AST routine after defined interval:
call "ASTFIRE".
01.
display "Getal: " with no advancing
accept TELLER
if TELLER = zero then go to 02.

* suspend AST delivery while adding:
call "SYS$SETAST" using
by value 0
giving SYSTAT
if SYSTAT not = SS$_NORMAL call "LIB$STOP"
using by value SYSTAT.

compute SOM(8) = SOM(8) + TELLER. (**)

* resume AST delivery:
call "SYS$SETAST" using
by value 1
giving SYSTAT
if SYSTAT not = SS$_NORMAL call "LIB$STOP"
using by value SYSTAT.

go to 01.
02.
exit program.
end program TESTIMR.
/
identification division.
program-id. ASTFIRE.

data division.
working-storage section.
01 AMINUTE pic X(13) value "0 00:00:10.00".
01 BMINUTE pic S9(11) comp.
01 SYSTAT pic S9(9) comp.

01 SS$_NORMAL pic S9(9) comp value external SS$_NORMAL.
01 ASTSERV pic S9(9) comp value external ASTSERV.

procedure division.
AST-FIRE section.
00.
call "SYS$BINTIM" using
by descriptor AMINUTE,
by reference BMINUTE
giving SYSTAT
if SYSTAT not = SS$_NORMAL call "LIB$STOP"
using by value SYSTAT.

call "SYS$SETIMR" using
omitted,
by reference BMINUTE,
by value ASTSERV,
omitted, omitted
giving SYSTAT
if SYSTAT not = SS$_NORMAL call "LIB$STOP"
using by value SYSTAT.

end program ASTFIRE.
/
identification division.
program-id. ASTSERV.

data division.
working-storage section.

01 MIS external.
02 SOM pic 9(6) occurs 10 times.

procedure division.
AST-SERV section.
00.
display "Som = ", SOM(8)
move zeroes to SOM(8).

* reschedule AST
call "ASTFIRE".

end program ASTSERV.

--
Wilm Boerhout Zwolle, NL
remove OLD PAINT from return address to reply

John Sauter

unread,
Aug 14, 2008, 1:59:36 PM8/14/08
to
Wilm Boerhout wrote:
> This is on VAX/VMS 7.3, COBOL 5.7-63
>
> I need to extend some program's functionality and came up with an idea
> to let an AST routine do periodic reporting. I was brutally ACCVIO'd by
> the program, and made a small reproducer. I'm sure I don't understand
> all about AST programming (it's relatively new to me), but why it would
> fail in exactly this manner baffles me.
>
> The real program will have a network listener instead of a
> DISPLAY/ACCEPT loop, but you'll get the general idea. Also, the MIS area
> will have really useful data, trust me.
>
> The reproducer ACCVIO's in the compute statement marked with two
> asterisks (**) below.
> Two questions:
> - can you reproduce the error?
> - if yes, can you tell me why it ACCVIOs, and how to avoid it?
>
> TIA,
> Wilm
[COBOL program text snipped]

I am not familiar with the VAX COBOL run-time library, but I had a
similar experience with the VAX BASIC run-time library. I found that
doing I/O in an AST routine would cause an ACCVIO. Fortunately, I was
developing the VAX BASIC run-time library at the time, so I was able to
fix the problems.

I speculate that the VAX COBOL run-time library is not AST-reentrant.

That said, however, I don't see how your program is getting an access
violation on the compute statement. Perhaps the reporting of the access
violation is mangled, and the error was actually happening somewhere
else, such as in the display statement being executed as AST level, and
not reported until the compute statement executed. Can you provide more
information about the error message? Does the problem still happen when
you run the program under the debugger? If so, can you pinpoint the
failing VAX instruction?
John Sauter (John_...@systemeyescomputerstore.com)

Hein RMS van den Heuvel

unread,
Aug 14, 2008, 2:10:13 PM8/14/08
to
Wilm,

Main problems:

1) Testing for SS$_NORMAL when a simple "IF FAILURE" should be used.


2) SYS$SETAST does NOT return a status, but a flag setting SS$_WASCLR
(1) or SS$_WASSET (9)

Fix:
call "SYS$SETAST" using by value 0 giving SYSTAT.
display "set ast returned : ", SYSTAT with conversion.

3) Trusting a line number when compiled with optimizer.

Fix:
$COBOL/NOOPT [/DEBUG]
This will report line 45 as the offending line.

4) Using a pic s9(9) to hold an address, when cobol has a 'usage
POINTER'

Met vriendelijke groetjes,

Hein

Wilm Boerhout

unread,
Aug 14, 2008, 2:27:39 PM8/14/08
to
on 14-8-2008 20:10 Hein RMS van den Heuvel wrote...

> Wilm,
>
> Main problems:
>
> 1) Testing for SS$_NORMAL when a simple "IF FAILURE" should be used.

Programming practice carried over from my Fortran days. Not sure whether
fixing this would help.

>
> 2) SYS$SETAST does NOT return a status, but a flag setting SS$_WASCLR
> (1) or SS$_WASSET (9)
>
> Fix:
> call "SYS$SETAST" using by value 0 giving SYSTAT.
> display "set ast returned : ", SYSTAT with conversion.

Ah, I missed that one.


> 3) Trusting a line number when compiled with optimizer.
>
> Fix:
> $COBOL/NOOPT [/DEBUG]
> This will report line 45 as the offending line.

I would never have guessed this one. Since optimizing is carried out
entirely by the compiler, I would have thought it could count.

> 4) Using a pic s9(9) to hold an address, when cobol has a 'usage
> POINTER'

This is in all the examples I found in respectable places, including HP
docs.

> Met vriendelijke groetjes,
>
> Hein

Ook zo! En bedankt...
Wilm

(It must be a combination of 2 above and trying to DISPLAY in the AST
routine)

Bob Gezelter

unread,
Aug 14, 2008, 3:02:50 PM8/14/08
to
On Aug 14, 1:27 pm, Wilm Boerhout <w6OLD.PAINTboerh...@planet.nl>
wrote:


Wilm,

I have not had a chance to digest your sample, but you may find my
DECUS presentation on "Introduction to AST Programming" (slides
available at http://www.rlgsc.com/cets/2000/435.html ).

- Bob Gezelter, http://www.rlgsc.com

Hein RMS van den Heuvel

unread,
Aug 14, 2008, 3:03:40 PM8/14/08
to
On Aug 14, 2:27 pm, Wilm Boerhout <w6OLD.PAINTboerh...@planet.nl>
wrote:

> on 14-8-2008 20:10 Hein RMS van den Heuvel wrote...
>
> > Wilm,
>
> > Main problems:
>
> > 1) Testing for SS$_NORMAL when a simple "IF FAILURE" should be used.
>
> Programming practice carried over from my Fortran days. Not sure whether
> fixing this would help.

OpenVMS Cobol (and pascal , and...) have a nice 'IF SUCCES/FAILURE'
test which just looks for the low bit to be set. The WASSET and WASCLR
values both have those set (no conicidence).

> > 3) Trusting a line number when compiled with optimizer.
>
> > Fix:
> >       $COBOL/NOOPT [/DEBUG]
> > This will report line 45 as the offending line.
>
> I would never have guessed this one. Since optimizing is carried out
> entirely by the compiler, I would have thought it could count.

It can count, but it can not decide...
Check it out with COBOL/LIST/MACHINE and look for 00049 with the
editor.
You'll see it being partly executed in many places.
Too many to keep a full inventory for runtime usage.

> > 4) Using a pic s9(9) to hold an address, when cobol has a 'usage
> > POINTER'
>
> This is in all the examples I found in respectable places, including HP docs.

I realize that. I should have listed is as a recommendation, not a
problem.
My own example for cobol AST's, published in 'Ask the Wizard' (amongst
others) uses the COMP S9(9) hack.
That's what we all used to do,
http://h71000.www7.hp.com/wizard/wiz_8137.html

Hein.

Bob Gezelter

unread,
Aug 14, 2008, 3:04:53 PM8/14/08
to
On Aug 14, 1:27 pm, Wilm Boerhout <w6OLD.PAINTboerh...@planet.nl>
wrote:


Wimn,

It is also generally not safe to call RTL routines from both AST/
regular threads, unless one has specific knowledge that the RTL
routine does not have any static data areas).

Wilm Boerhout

unread,
Aug 14, 2008, 3:19:01 PM8/14/08
to
on 14-8-2008 21:04 Bob Gezelter wrote...
[snip]

> It is also generally not safe to call RTL routines from both AST/
> regular threads, unless one has specific knowledge that the RTL
> routine does not have any static data areas).

That is why I avoid it. The $DCLAST system service is used for that
purpose. I'm under the impression that this is the recommended way to
"run" an AST routine immediately.

Wilm Boerhout

unread,
Aug 14, 2008, 3:20:39 PM8/14/08
to
on 14-8-2008 21:02 Bob Gezelter wrote...
[snip]

> I have not had a chance to digest your sample, but you may find my
> DECUS presentation on "Introduction to AST Programming" (slides
> available at http://www.rlgsc.com/cets/2000/435.html ).

Thanks. This is good stuff.

Richard Maher

unread,
Aug 14, 2008, 5:23:46 PM8/14/08
to
Hi Wilm,

> - if yes, can you tell me why it ACCVIOs, and how to avoid it?

As Hein pointed out, it's the ss$_wasset/ss$_wasclr i.e. LIB$STOPping with
ss$_wasset will look like an accvio.

You should check "not = ss$_wasset and ss$_wasclr." also you probably don't
want to turn it back on again if it was clear in the first place.

Apart from that, feel free to keep checking your status values for known
results (especially if you're interested in warning statii such as data
truncations), lower-case is really good, and "add" can often beat compute in
many areas.

Cheers Richard Maher

PS. You can use a small MACRO file to achieve compile-time initialization of
MIS if you're into that?

"Wilm Boerhout" <w6OLD.PAI...@planet.nl> wrote in message
news:48a465f3$0$6003$ba62...@text.nova.planet.nl...

Jeff Campbell

unread,
Aug 14, 2008, 8:48:56 PM8/14/08
to

Here is a different example, which does nothing 8-) , of
using an AST in COBOL.

------------------------------------------

identification division.
program-id. x.

environment division.
data division.
working-storage section.
01 ast-proc-addr pointer value external ast_routine.

01 delta-time pic s9(9) comp value -50000000.

01 return-value pic s9(9) comp.

* the SYS$SETIMR call returns these condition values:
88 ss$_accvio value external ss$_accvio.
88 ss$_exquota value external ss$_exquota.
88 ss$_illefc value external ss$_illefc.
88 ss$_insfmem value external ss$_insfmem.
88 ss$_normal value external ss$_normal.
88 ss$_unasefc value external ss$_unasefc.

procedure division.
call-set-timer-service.

call "sys$setimr"
using
omitted
by reference delta-time
by value ast-proc-addr
omitted
omitted
giving
return-value
end-call

if ss$_normal
display "Sleeping for 5 seconds"

call "sys$hiber"
giving return-value

end-call

display "Awakened!"

else
evaluate true
when ss$_accvio
display "Expiration time not readable"

when ss$_exquota
display "Process AST or timer quota exceeded"

when ss$_illefc
display "Illegal event flag number specified"

when ss$_insfmem
display "Not enough dynamic memory to allocate timer
element"

when ss$_unasefc
display "Process does not have the specified event flag"

end-evaluate

end-if

stop run

.

end program x.

identification division.
program-id. ast_routine.

environment division.
data division.
working-storage section.
01 return-value pic s9(9) comp.

procedure division.
ast-fired.

call "sys$wake"
using
omitted
omitted
giving
return-value
end-call

exit program

.

end program ast_routine.

---------------------------------

Jeff


----== Posted via Pronews.Com - Unlimited-Unrestricted-Secure Usenet News==----
http://www.pronews.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= - Total Privacy via Encryption =---

Wilm Boerhout

unread,
Aug 15, 2008, 1:14:31 AM8/15/08
to
on 14-8-2008 23:23 Richard Maher wrote...

[snip]

> PS. You can use a small MACRO file to achieve compile-time initialization of
> MIS if you're into that?

Thanks for joining Richard. I inherited this COBOL program recently
(it's 20 years old now) and am still struggling with the finer details
of the language. Apparently, an EXTERNAL data area cannnot be
initialized by VALUE clauses. What would your macro look like?

/Wilm

Wilm Boerhout

unread,
Aug 15, 2008, 1:19:17 AM8/15/08
to
on 15-8-2008 2:48 Jeff Campbell wrote...
[snip]

> evaluate true
> when ss$_accvio
> display "Expiration time not readable"

Jeff, I learn something new every day. Please explain the "evaluate
true" construction. How can comapring "true" with the condition codes do
the switching? COBOL never ceases to amaze me.

Tom Linden

unread,
Aug 15, 2008, 11:45:22 AM8/15/08
to

Why do you need macro? You could certainly do it with a small PL/I program
without any executable statements using the INITIAL attribute on the
declaration

External implies static, of course, which precludes reentrancy. If that
is an
issue you may need to rethink the design.


> /Wilm

--
PL/I for OpenVMS
www.kednos.com

Wilm Boerhout

unread,
Aug 15, 2008, 2:39:24 PM8/15/08
to
on 15-8-2008 17:45 Tom Linden wrote...

[snip]

> Why do you need macro? You could certainly do it with a small PL/I program
> without any executable statements using the INITIAL attribute on the
> declaration

No compiler licenses other than COBOL on the system. It's not hobbyist.

> External implies static, of course, which precludes reentrancy. If that
> is an
> issue you may need to rethink the design.

This one static area holds variables filled at random time intervals,
initiated by external events, by the main program. Every minute, the AST
routine collects the variables from the static area and sends them away
to a {screen/application/webserver, tbd} and zeroes the variables. No
other agents work on the static area. Zeroing is done in the AST
routine, and thus cannot be interrupted in user mode. Putting the
variables into the area by the main program is shielded by a $SETAST
(off,on) pair.

If you can think of any other design for a main progam that runs
synchronously since its inception, let me know. I've learned a lot in
the past 48 hours, and am willing to learn more.

Wilm Boerhout

unread,
Aug 15, 2008, 2:44:15 PM8/15/08
to
on 14-8-2008 23:23 Richard Maher wrote...

[snip]

Reproducer program now works fine, with changes suggested by Richard &
Hein &al.:

- communication between main program and AST server routine is done via
common AST area
- condition value testing done via "is failure" construct. This removes
my $SETAST error, cause of the ACCVIO
- I/O from AST server routine not via DISPLAY (COB$xxx routines), but
via separate channel to terminal and $QIO.

Now on to build this into the original program!

Thanks all.

JF Mezei

unread,
Aug 15, 2008, 4:07:47 PM8/15/08
to
Wilm Boerhout wrote:

> If you can think of any other design for a main progam that runs
> synchronously since its inception, let me know. I've learned a lot in
> the past 48 hours, and am willing to learn more.


You can do a lot within an AST. But any IO should be done with $QIO and
not higher level RTL. ($QIO does what it says: it queues an IO and does
not wait).

$QIOW in an AST is a no-no because if the IO doesn't complete, your
program freezes and no other ASTs (such as important ASTs) can be delivered.

If you want total freedom in code, then you AST can simply set some flag
(variable = 1), then wake the mainline program. Mainline program then
checks that variable, if it is set to 1, it performs the "execute every
minute" code and sets the variable to 0, otherwise, it just performs the
normal work.

Wilm Boerhout

unread,
Aug 15, 2008, 4:16:31 PM8/15/08
to
on 15-8-2008 22:07 JF Mezei wrote...

This is useful JF. Hadn't thought about the QIOW not completing -as I
said, AST's are new to me. But you said "wake the mainline program". It
never hibernates, and sometime waits longer than a minute for an
external event (mailbox reads, synchronously). It is important howver
for the AST to report on minutes that have no activity (no counters
accumulated). I have to think this through.

JF Mezei

unread,
Aug 15, 2008, 6:31:06 PM8/15/08
to
Wilm Boerhout wrote:

> This is useful JF. Hadn't thought about the QIOW not completing -as I
> said, AST's are new to me. But you said "wake the mainline program". It
> never hibernates, and sometime waits longer than a minute for an
> external event (mailbox reads, synchronously). It is important howver
> for the AST to report on minutes that have no activity (no counters
> accumulated). I have to think this through.


If your mainline can be stuck in an IO, then you'll need to do the "each
minute" logic all inside the AST. In this case, you need to be careful
how you do this.

If this is to be done with TCPIP, I would recommend you use the $QIO
interface. Not as pretty but will be better suited to AST driven logic.

Note however, that one possible problem when you don't wait for
completion is that if the pipe gets clogged (reader at other end is
stuck or whatever), you will continue to send QIO and at one point, your
QIO queue (BUFCNT) will be full and your QIO will either fail or get
stuck waiting for space on the queue. In practice, this may or may not
be a serious enough problem, but something to be aware of.

Another possibility would be to have multi threaded approach. But not
sure you'd want to do that in COBOL :-)

There is a LOT of stuff that can be done inside an AST. Just remember
that it will interrupt whatever code was executing in the mainline.

There are some RTL routines that may not be re-entrant (aka: only one
instance of that routine can execute in a process at a time). So if you
can LIB$DO_SOMETHING in your mainline, you might not be able to call
LIB$DO_SOMETHING in your AST.

(the issue here is that you may not know exactly what COBOL does behind
the scenes).

Stuff like SYS$BINTIM , SYS$QIO etc are all pretty basic and work well
inside ASTs.

Jeff Campbell

unread,
Aug 16, 2008, 12:51:17 AM8/16/08
to
Wilm Boerhout wrote:
> on 15-8-2008 2:48 Jeff Campbell wrote...
> [snip]
>
>> evaluate true
>> when ss$_accvio
>> display "Expiration time not readable"
>
> Jeff, I learn something new every day. Please explain the "evaluate
> true" construction. How can comapring "true" with the condition codes do
> the switching? COBOL never ceases to amaze me.
>

EVALUATE TRUE will check the state of the variable the 88 condition
values are defined against. It's a shorthand way of saying:

if return-status = ss$accvio then ....

<http://h71000.www7.hp.com/doc/82final/6296/6296pro_066.html#evaluate_com>

FrankS

unread,
Aug 16, 2008, 7:39:55 AM8/16/08
to
On Aug 16, 12:51 am, Jeff Campbell <n8...@arrl.net> wrote:
> EVALUATE TRUE  will check the state of the variable the 88 condition
> values are defined against. It's a shorthand way of saying:

Or any other conditional expression ...

evaluate true
when (myvariable = something)
perform one-routine

when (anythingelse = somethingelse)
perform two-routine

when (yetanotherconditional)
perform three-routine

when other
perform catch-all
end-evaluate.

It will evaluate each conditional expression in the WHEN clauses until
it finds one that is TRUE.

Tom Linden

unread,
Aug 16, 2008, 10:22:54 AM8/16/08
to

It is basically a copy of a subset of the PL/I SELECT statement.

0 new messages