Discussion:
Returning data from Cobol AST routine.
Add Reply
Jan-Erik Söderholm
2021-09-20 22:55:02 UTC
Reply
Permalink
Hi.

I have been looking at the Cobol AST example here:
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm

This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?

I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?

The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.

This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.

Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...

Regards,
Jan-Erik.
Arne Vajhøj
2021-09-21 01:27:39 UTC
Reply
Permalink
Post by Jan-Erik Söderholm
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...
external works for me.

identification division.
program-id. x.
environment division.
data division.
working-storage section.
01 magic-value pic 9(10) display external.
01 ast-proc-addr pointer value external ast_routine.
01 delta-time pic s9(18) comp value -50000000.
01 return-value pic s9(18) 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
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
display magic-value
stop run
.
end program x.
identification division.
program-id. ast_routine.
environment division.
data division.
working-storage section.
01 magic-value pic s9(10) display external.
01 return-value pic s9(18) comp.
procedure division.
ast-fired.
call "sys$wake"
using
omitted
omitted
giving
return-value
end-call
move 123 to magic-value
exit program
.
end program ast_routine.

$ cobol x
$ link x
$ run x
sleeping for 5 seconds
000000012C

Arne
Jan-Erik Söderholm
2021-09-21 07:15:16 UTC
Reply
Permalink
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...
external works for me.
identification division.
program-id. x.
environment division.
data division.
working-storage section.
01  magic-value         pic 9(10)  display external.
01  ast-proc-addr       pointer           value external ast_routine.
01  delta-time          pic s9(18)  comp  value -50000000.
01  return-value        pic s9(18)  comp.
    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
    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
    display magic-value
    stop run
    .
end program x.
identification division.
program-id. ast_routine.
environment division.
data division.
working-storage section.
01  magic-value         pic s9(10)  display external.
01  return-value        pic s9(18)  comp.
procedure division.
ast-fired.
    call "sys$wake"
        using
            omitted
            omitted
        giving
            return-value
    end-call
    move 123 to magic-value
    exit program
    .
end program ast_routine.
$ cobol x
$ link x
$ run x
sleeping for 5 seconds
000000012C
Arne
Ah, OK! that will be tested. Hm, is this limited to numeric variables?
My test was using a x(3) variable...

Hm, if this would had been a read-AST on a mailbos instead of a timer,
maybe the ast_routine can just awake the main code and the mailbox
been read in the main code. The ast_routine could set a variable that
just signals the reason fo the wakeup.

Good input anyway!

Jan-Erik.
Arne Vajhøj
2021-09-21 13:00:51 UTC
Reply
Permalink
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...
external works for me.
identification division.
program-id. x.
environment division.
data division.
working-storage section.
01  magic-value         pic 9(10)  display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program x.
identification division.
program-id. ast_routine.
environment division.
data division.
working-storage section.
01  magic-value         pic s9(10)  display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program ast_routine.
$ cobol x
$ link x
$ run x
sleeping for 5 seconds
000000012C
Ah, OK! that will be tested. Hm, is this limited to numeric variables?
My test was using a x(3) variable...
Try it!

Per documentation then external just moves the variable to a PSECT
with the same name as the variable to tell the linker to overlay
them.

I would expect that to work with any data type.
Post by Jan-Erik Söderholm
Hm, if this would had been a read-AST on a mailbos instead of a timer,
maybe the ast_routine can just awake the main code and the mailbox
been read in the main code. The ast_routine could set a variable that
just signals the reason fo the wakeup.
I don't understand the problem.

If you want the main flow to wait until something is in the mailbox,
then why not do a blocking read?

Arne
Jan-Erik Söderholm
2021-09-21 13:06:16 UTC
Reply
Permalink
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...
external works for me.
identification division.
program-id. x.
environment division.
data division.
working-storage section.
01  magic-value         pic 9(10)  display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program x.
identification division.
program-id. ast_routine.
environment division.
data division.
working-storage section.
01  magic-value         pic s9(10)  display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program ast_routine.
$ cobol x
$ link x
$ run x
sleeping for 5 seconds
000000012C
Ah, OK! that will be tested. Hm, is this limited to numeric variables?
My test was using a x(3) variable...
Try it!
Per documentation then external just moves the variable to a PSECT
with the same name as the variable to tell the linker to overlay
them.
I would expect that to work with any data type.
Post by Jan-Erik Söderholm
Hm, if this would had been a read-AST on a mailbos instead of a timer,
maybe the ast_routine can just awake the main code and the mailbox
been read in the main code. The ast_routine could set a variable that
just signals the reason fo the wakeup.
I don't understand the problem.
If you want the main flow to wait until something is in the mailbox,
then why not do a blocking read?
Arne
No, sorry... The main code does other things (the regular business
processing) all the time. I just do not want it to have to poll the
mailbox with some fixed interval. I expect an AST to be faster also
with a more "on-demand" response time.

Will do some more testing this evening after regular business hours...
abrsvc
2021-09-21 13:22:04 UTC
Reply
Permalink
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...
external works for me.
identification division.
program-id. x.
environment division.
data division.
working-storage section.
01 magic-value pic 9(10) display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program x.
identification division.
program-id. ast_routine.
environment division.
data division.
working-storage section.
01 magic-value pic s9(10) display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program ast_routine.
$ cobol x
$ link x
$ run x
sleeping for 5 seconds
000000012C
Ah, OK! that will be tested. Hm, is this limited to numeric variables?
My test was using a x(3) variable...
Try it!
Per documentation then external just moves the variable to a PSECT
with the same name as the variable to tell the linker to overlay
them.
I would expect that to work with any data type.
Post by Jan-Erik Söderholm
Hm, if this would had been a read-AST on a mailbos instead of a timer,
maybe the ast_routine can just awake the main code and the mailbox
been read in the main code. The ast_routine could set a variable that
just signals the reason fo the wakeup.
I don't understand the problem.
If you want the main flow to wait until something is in the mailbox,
then why not do a blocking read?
Arne
No, sorry... The main code does other things (the regular business
processing) all the time. I just do not want it to have to poll the
mailbox with some fixed interval. I expect an AST to be faster also
with a more "on-demand" response time.
Will do some more testing this evening after regular business hours...
Can't you just post an asynchronous QIO read to the mailbox with an AST routine to service the read within the main program? In this fashion, the writing to the mailbox will trigger the action. In this fashion, the main program will continue to proceed as normal only getting interrupted when the mailbox read copletes.
Jan-Erik Söderholm
2021-09-21 13:30:16 UTC
Reply
Permalink
Post by abrsvc
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...
external works for me.
identification division.
program-id. x.
environment division.
data division.
working-storage section.
01 magic-value pic 9(10) display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program x.
identification division.
program-id. ast_routine.
environment division.
data division.
working-storage section.
01 magic-value pic s9(10) display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program ast_routine.
$ cobol x
$ link x
$ run x
sleeping for 5 seconds
000000012C
Ah, OK! that will be tested. Hm, is this limited to numeric variables?
My test was using a x(3) variable...
Try it!
Per documentation then external just moves the variable to a PSECT
with the same name as the variable to tell the linker to overlay
them.
I would expect that to work with any data type.
Post by Jan-Erik Söderholm
Hm, if this would had been a read-AST on a mailbos instead of a timer,
maybe the ast_routine can just awake the main code and the mailbox
been read in the main code. The ast_routine could set a variable that
just signals the reason fo the wakeup.
I don't understand the problem.
If you want the main flow to wait until something is in the mailbox,
then why not do a blocking read?
Arne
No, sorry... The main code does other things (the regular business
processing) all the time. I just do not want it to have to poll the
mailbox with some fixed interval. I expect an AST to be faster also
with a more "on-demand" response time.
Will do some more testing this evening after regular business hours...
Can't you just post an asynchronous QIO read to the mailbox with an AST routine to service the read within the main program? In this fashion, the writing to the mailbox will trigger the action. In this fashion, the main program will continue to proceed as normal only getting interrupted when the mailbox read copletes.
Yes, that is my plan. What I had issues with was how to get the data
from the mailbox message back from the AST routine to the main code.
Since the AST routine has to be a separate PROGAM section. And it
cannot be a sub-program within the main code, the POINTER EXTERNAL,
to get the address to the AST routine, does not work in that case.
At least not if I understood my tests correctly.

But I think I understand the basic AST processing as such...
Dave Froble
2021-09-21 18:19:48 UTC
Reply
Permalink
Post by Jan-Erik Söderholm
Post by abrsvc
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...
external works for me.
identification division.
program-id. x.
environment division.
data division.
working-storage section.
01 magic-value pic 9(10) display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program x.
identification division.
program-id. ast_routine.
environment division.
data division.
working-storage section.
01 magic-value pic s9(10) display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program ast_routine.
$ cobol x
$ link x
$ run x
sleeping for 5 seconds
000000012C
Ah, OK! that will be tested. Hm, is this limited to numeric variables?
My test was using a x(3) variable...
Try it!
Per documentation then external just moves the variable to a PSECT
with the same name as the variable to tell the linker to overlay
them.
I would expect that to work with any data type.
Post by Jan-Erik Söderholm
Hm, if this would had been a read-AST on a mailbos instead of a timer,
maybe the ast_routine can just awake the main code and the mailbox
been read in the main code. The ast_routine could set a variable that
just signals the reason fo the wakeup.
I don't understand the problem.
If you want the main flow to wait until something is in the mailbox,
then why not do a blocking read?
Arne
No, sorry... The main code does other things (the regular business
processing) all the time. I just do not want it to have to poll the
mailbox with some fixed interval. I expect an AST to be faster also
with a more "on-demand" response time.
Will do some more testing this evening after regular business hours...
Can't you just post an asynchronous QIO read to the mailbox with an
AST routine to service the read within the main program? In this
fashion, the writing to the mailbox will trigger the action. In this
fashion, the main program will continue to proceed as normal only
getting interrupted when the mailbox read copletes.
Yes, that is my plan. What I had issues with was how to get the data
from the mailbox message back from the AST routine to the main code.
Since the AST routine has to be a separate PROGAM section. And it
cannot be a sub-program within the main code, the POINTER EXTERNAL,
to get the address to the AST routine, does not work in that case.
At least not if I understood my tests correctly.
But I think I understand the basic AST processing as such...
What Dan wrote is a good method for having the program doing it's thing,
with the possibility of an incoming mailbox read firing an AST.

Then comes the question of whether the AST would actually perform any
required actions, or just interrupt the program and have the program
handle the processing.

Is the required actions simple enough and quick enough to have the AST
routine perform the work?

For sharing data, what I have not tried, but I'd be tempted, is to
declare some structure, in Basic it would be a RECORD, and pass the
address (By Ref) to the AST routine, which also would have an identical
RECORD definition, such that the two (main and AST routine) can both
share the data in the structure. All that would be required, I think,
is some variable that can be passed, By Ref, to the AST routine.
--
David Froble Tel: 724-529-0450
Dave Froble Enterprises, Inc. E-Mail: ***@tsoft-inc.com
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
abrsvc
2021-09-21 18:47:54 UTC
Reply
Permalink
Post by Dave Froble
Post by Jan-Erik Söderholm
Post by abrsvc
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...
external works for me.
identification division.
program-id. x.
environment division.
data division.
working-storage section.
01 magic-value pic 9(10) display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program x.
identification division.
program-id. ast_routine.
environment division.
data division.
working-storage section.
01 magic-value pic s9(10) display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program ast_routine.
$ cobol x
$ link x
$ run x
sleeping for 5 seconds
000000012C
Ah, OK! that will be tested. Hm, is this limited to numeric variables?
My test was using a x(3) variable...
Try it!
Per documentation then external just moves the variable to a PSECT
with the same name as the variable to tell the linker to overlay
them.
I would expect that to work with any data type.
Post by Jan-Erik Söderholm
Hm, if this would had been a read-AST on a mailbos instead of a timer,
maybe the ast_routine can just awake the main code and the mailbox
been read in the main code. The ast_routine could set a variable that
just signals the reason fo the wakeup.
I don't understand the problem.
If you want the main flow to wait until something is in the mailbox,
then why not do a blocking read?
Arne
No, sorry... The main code does other things (the regular business
processing) all the time. I just do not want it to have to poll the
mailbox with some fixed interval. I expect an AST to be faster also
with a more "on-demand" response time.
Will do some more testing this evening after regular business hours...
Can't you just post an asynchronous QIO read to the mailbox with an
AST routine to service the read within the main program? In this
fashion, the writing to the mailbox will trigger the action. In this
fashion, the main program will continue to proceed as normal only
getting interrupted when the mailbox read copletes.
Yes, that is my plan. What I had issues with was how to get the data
from the mailbox message back from the AST routine to the main code.
Since the AST routine has to be a separate PROGAM section. And it
cannot be a sub-program within the main code, the POINTER EXTERNAL,
to get the address to the AST routine, does not work in that case.
At least not if I understood my tests correctly.
But I think I understand the basic AST processing as such...
What Dan wrote is a good method for having the program doing it's thing,
with the possibility of an incoming mailbox read firing an AST.
Then comes the question of whether the AST would actually perform any
required actions, or just interrupt the program and have the program
handle the processing.
Is the required actions simple enough and quick enough to have the AST
routine perform the work?
For sharing data, what I have not tried, but I'd be tempted, is to
declare some structure, in Basic it would be a RECORD, and pass the
address (By Ref) to the AST routine, which also would have an identical
RECORD definition, such that the two (main and AST routine) can both
share the data in the structure. All that would be required, I think,
is some variable that can be passed, By Ref, to the AST routine.
--
David Froble Tel: 724-529-0450
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
I agree with Dave, and as long as the data area is only accessed by one execution stream at a time, it should be OK. I think that the issue is whether or not another can interrupt the processing of the first. In this case, as long as the incoming record is processed prior to any issuance of another QIO, it should be OK. You run the risk of filling up the mailbox with records, but from the initial request, these records should be fairly infrequent.
Jan-Erik Söderholm
2021-09-21 21:21:46 UTC
Reply
Permalink
Post by abrsvc
Post by Dave Froble
Post by Jan-Erik Söderholm
Post by abrsvc
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...
external works for me.
identification division.
program-id. x.
environment division.
data division.
working-storage section.
01 magic-value pic 9(10) display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program x.
identification division.
program-id. ast_routine.
environment division.
data division.
working-storage section.
01 magic-value pic s9(10) display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program ast_routine.
$ cobol x
$ link x
$ run x
sleeping for 5 seconds
000000012C
Ah, OK! that will be tested. Hm, is this limited to numeric variables?
My test was using a x(3) variable...
Try it!
Per documentation then external just moves the variable to a PSECT
with the same name as the variable to tell the linker to overlay
them.
I would expect that to work with any data type.
Post by Jan-Erik Söderholm
Hm, if this would had been a read-AST on a mailbos instead of a timer,
maybe the ast_routine can just awake the main code and the mailbox
been read in the main code. The ast_routine could set a variable that
just signals the reason fo the wakeup.
I don't understand the problem.
If you want the main flow to wait until something is in the mailbox,
then why not do a blocking read?
Arne
No, sorry... The main code does other things (the regular business
processing) all the time. I just do not want it to have to poll the
mailbox with some fixed interval. I expect an AST to be faster also
with a more "on-demand" response time.
Will do some more testing this evening after regular business hours...
Can't you just post an asynchronous QIO read to the mailbox with an
AST routine to service the read within the main program? In this
fashion, the writing to the mailbox will trigger the action. In this
fashion, the main program will continue to proceed as normal only
getting interrupted when the mailbox read copletes.
Yes, that is my plan. What I had issues with was how to get the data
from the mailbox message back from the AST routine to the main code.
Since the AST routine has to be a separate PROGAM section. And it
cannot be a sub-program within the main code, the POINTER EXTERNAL,
to get the address to the AST routine, does not work in that case.
At least not if I understood my tests correctly.
But I think I understand the basic AST processing as such...
What Dan wrote is a good method for having the program doing it's thing,
with the possibility of an incoming mailbox read firing an AST.
Then comes the question of whether the AST would actually perform any
required actions, or just interrupt the program and have the program
handle the processing.
Is the required actions simple enough and quick enough to have the AST
routine perform the work?
For sharing data, what I have not tried, but I'd be tempted, is to
declare some structure, in Basic it would be a RECORD, and pass the
address (By Ref) to the AST routine, which also would have an identical
RECORD definition, such that the two (main and AST routine) can both
share the data in the structure. All that would be required, I think,
is some variable that can be passed, By Ref, to the AST routine.
--
David Froble Tel: 724-529-0450
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
I agree with Dave, and as long as the data area is only accessed by one
execution stream at a time, it should be OK. I think that the issue is
whether or not another can interrupt the processing of the first.
But if you haven't made a new QUI, there cannot be any new AST, can there?
Post by abrsvc
In this case, as long as the incoming record is processed prior to any
issuance of another QIO, it should be OK.
Ah, OK. What I wrote... :-)
Post by abrsvc
You run the risk of filling up the mailbox with records, but from the
initial request, these records should be fairly infrequent.
Say, each 2 min. But when they arrive, we want a 1 sec response time
on the screen managed by this application. Today this application is
looping and polling some data each 1 sec. So it puts a constant load
("backround noice") on the system and on Rdb. Even when the system is
idle, Rdb has 10-20 transactions per second, just from the polling.
The application is run on 10-20 screens.

Trying to find a better design, now that we hav a need for some
major application redesign anyway for other reasons.

And, if we do have any non-AST-compatible code in the main code, I'm
also looking for some disable/enable AST functions. They are probably
there, just have to look it up.
Arne Vajhøj
2021-09-21 22:22:06 UTC
Reply
Permalink
Post by Jan-Erik Söderholm
Post by abrsvc
Post by Dave Froble
Then comes the question of whether the AST would actually perform any
required actions, or just interrupt the program and have the program
handle the processing.
Is the required actions simple enough and quick enough to have the AST
routine perform the work?
For sharing data, what I have not tried, but I'd be tempted, is to
declare some structure, in Basic it would be a RECORD, and pass the
address (By Ref) to the AST routine, which also would have an identical
RECORD definition, such that the two (main and AST routine) can both
share the data in the structure. All that would be required, I think,
is some variable that can be passed, By Ref, to the AST routine.
I agree with Dave, and as long as the data area is only accessed by one
execution stream at a time, it should be OK.  I think that the issue is
whether or not another can interrupt the processing of the first.
But if you haven't made a new QUI, there cannot be any new AST, can there?
Post by abrsvc
In this case, as long as the incoming record is processed prior to any
issuance of another QIO, it should be OK.
Ah, OK. What I wrote... :-)
Post by abrsvc
You run the risk of filling up the mailbox with records, but from the
initial request, these records should be fairly infrequent.
Say, each 2 min. But when they arrive, we want a 1 sec response time
on the screen managed by this application. Today this application is
looping and polling some data each 1 sec. So it puts a constant load
("backround noice") on the system and on Rdb. Even when the system is
idle, Rdb has 10-20 transactions per second, just from the polling.
The application is run on 10-20 screens.
Trying to find a better design, now that we hav a need for some
major application redesign anyway for other reasons.
And, if we do have any non-AST-compatible code in the main code, I'm
also looking for some disable/enable AST functions. They are probably
there, just have to look it up.
You may get a much more robust solution by using your IBM MQ instead
of a VMS mailbox.

No AST's and problem with number of messages.

Arne
Jan-Erik Söderholm
2021-09-21 22:55:51 UTC
Reply
Permalink
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Post by abrsvc
Post by Dave Froble
Then comes the question of whether the AST would actually perform any
required actions, or just interrupt the program and have the program
handle the processing.
Is the required actions simple enough and quick enough to have the AST
routine perform the work?
For sharing data, what I have not tried, but I'd be tempted, is to
declare some structure, in Basic it would be a RECORD, and pass the
address (By Ref) to the AST routine, which also would have an identical
RECORD definition, such that the two (main and AST routine) can both
share the data in the structure. All that would be required, I think,
is some variable that can be passed, By Ref, to the AST routine.
I agree with Dave, and as long as the data area is only accessed by one
execution stream at a time, it should be OK.  I think that the issue is
whether or not another can interrupt the processing of the first.
But if you haven't made a new QUI, there cannot be any new AST, can there?
Post by abrsvc
In this case, as long as the incoming record is processed prior to any
issuance of another QIO, it should be OK.
Ah, OK. What I wrote... :-)
Post by abrsvc
You run the risk of filling up the mailbox with records, but from the
initial request, these records should be fairly infrequent.
Say, each 2 min. But when they arrive, we want a 1 sec response time
on the screen managed by this application. Today this application is
looping and polling some data each 1 sec. So it puts a constant load
("backround noice") on the system and on Rdb. Even when the system is
idle, Rdb has 10-20 transactions per second, just from the polling.
The application is run on 10-20 screens.
Trying to find a better design, now that we hav a need for some
major application redesign anyway for other reasons.
And, if we do have any non-AST-compatible code in the main code, I'm
also looking for some disable/enable AST functions. They are probably
there, just have to look it up.
You may get a much more robust solution by using your IBM MQ instead
of a VMS mailbox.
No AST's and problem with number of messages.
Arne
Ah, well. Yes, some message queing tool might also be an option.
And we do use IBM MQ but only for external communication to the
corporate message bus center. There is no MQ server on VMS only
client, so a local MQ solution will be hard.

I kind of like the simplines of mailboxes, in particular since
we got the CREATE/MAILBOX DCL commands. Very simple to setup.

At the moment I'm trying to get the reqidt parameter of the SETIMR
call to work. It should be sent as a parameter to the AST routine.

In the main code:

01 reqidt pic 9(9) comp.
...
move 1234 to reqidt
call "sys$setimr"
using omitted
by reference delta-time
by value ast-proc-addr
by value reqidt
omitted
giving return-value
end-call


In the AST routine:

linkage section.
01 reqidt pic 9(9) comp.
procedure division using reqidt.
ast-fired.
display "reqidt: " reqidt with conversion
call "sys$wake"
using omitted omitted
giving return-value
end-call

This ACCVIO's on the display statement. The weird thing is that
the virtual address in the ACCVIO message is ...00042D, and that
is the hex for the value I used, in decimal 1234.

I must be missing something, it looks like the display statement tries
to use the value in reqidt as an address instead of the actual value...

Hm... Maybe time to make a second try using some C helper routines.
Arne Vajhøj
2021-09-21 23:31:58 UTC
Reply
Permalink
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Trying to find a better design, now that we hav a need for some
major application redesign anyway for other reasons.
And, if we do have any non-AST-compatible code in the main code, I'm
also looking for some disable/enable AST functions. They are probably
there, just have to look it up.
You may get a much more robust solution by using your IBM MQ instead
of a VMS mailbox.
No AST's and problem with number of messages.
Ah, well. Yes, some message queing tool might also be an option.
And we do use IBM MQ but only for external communication to the
corporate message bus center. There is no MQ server on VMS only
client, so a local MQ solution will be hard.
If you have Itanium then you could install the ActiveMQ kit
from VSI. But even with Alpha you could maybe install ActiveMQ
on a Linux VM and use that from VMS. Open source => do not
need approval for CAPEX spend.
Post by Jan-Erik Söderholm
I kind of like the simplines of mailboxes, in particular since
we got the CREATE/MAILBOX DCL commands. Very simple to setup.
ActiveMQ can auto create queues at first reference.

:-)
Post by Jan-Erik Söderholm
At the moment I'm trying to get the reqidt parameter of the SETIMR
call to work. It should be sent as a parameter to the AST routine.
01  reqidt              pic 9(9)    comp.
...
    move 1234 to reqidt
    call "sys$setimr"
        using omitted
              by reference delta-time
              by value ast-proc-addr
              by value reqidt
              omitted
        giving return-value
    end-call
linkage section.
01  reqidt             pic 9(9)   comp.
procedure division using reqidt.
ast-fired.
    display "reqidt: " reqidt with conversion
    call "sys$wake"
        using omitted omitted
        giving return-value
    end-call
This ACCVIO's on the display statement. The weird thing is that
the virtual address in the ACCVIO message is ...00042D, and that
is the hex for the value I used, in decimal 1234.
I must be missing something, it looks like the display statement tries
to use the value in reqidt as an address instead of the actual value...
I know next to nothing about COBOL, but if COBOL use call by ref as
default like FORTRAN, so that the AST routine expects an address,
then the error makes sense. And the solution could be to call with
address of reqidt in main code (I don't know how to do that i COBOL
but it must be possible).
Post by Jan-Erik Söderholm
Hm... Maybe time to make a second try using some C helper routines.
Or that.

:-)

Arne
Jan-Erik Söderholm
2021-09-22 00:31:34 UTC
Reply
Permalink
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Trying to find a better design, now that we hav a need for some
major application redesign anyway for other reasons.
And, if we do have any non-AST-compatible code in the main code, I'm
also looking for some disable/enable AST functions. They are probably
there, just have to look it up.
You may get a much more robust solution by using your IBM MQ instead
of a VMS mailbox.
No AST's and problem with number of messages.
Ah, well. Yes, some message queing tool might also be an option.
And we do use IBM MQ but only for external communication to the
corporate message bus center. There is no MQ server on VMS only
client, so a local MQ solution will be hard.
If you have Itanium then you could install the ActiveMQ kit
from VSI. But even with Alpha you could maybe install ActiveMQ
on a Linux VM and use that from VMS. Open source => do not
need approval for CAPEX spend.
Post by Jan-Erik Söderholm
I kind of like the simplines of mailboxes, in particular since
we got the CREATE/MAILBOX DCL commands. Very simple to setup.
ActiveMQ can auto create queues at first reference.
:-)
Post by Jan-Erik Söderholm
At the moment I'm trying to get the reqidt parameter of the SETIMR
call to work. It should be sent as a parameter to the AST routine.
01  reqidt              pic 9(9)    comp.
...
     move 1234 to reqidt
     call "sys$setimr"
         using omitted
               by reference delta-time
               by value ast-proc-addr
               by value reqidt
               omitted
         giving return-value
     end-call
linkage section.
01  reqidt             pic 9(9)   comp.
procedure division using reqidt.
ast-fired.
     display "reqidt: " reqidt with conversion
     call "sys$wake"
         using omitted omitted
         giving return-value
     end-call
This ACCVIO's on the display statement. The weird thing is that
the virtual address in the ACCVIO message is ...00042D, and that
is the hex for the value I used, in decimal 1234.
I must be missing something, it looks like the display statement tries
to use the value in reqidt as an address instead of the actual value...
I know next to nothing about COBOL, but if COBOL use call by ref as
default like FORTRAN, so that the AST routine expects an address,
then the error makes sense.
Right. When calling *from* Cobol you can specify "by ref", "by val"
and so on. I have looked but I cannot find anything similar when a
Cobol routine is *called*. But yes, it very much looks like that a
called Cobol routine expects a "by ref" (pointer) parameter.

But the SETIMR docs says that this parameter is sent by value.
Post by Arne Vajhøj
And the solution could be to call with
address of reqidt in main code (I don't know how to do that i COBOL
but it must be possible).
Good point... And that solved this issue!


01 reqidt pic 9(9) comp.
...
move 1234 to reqidt
call "sys$setimr"
using omitted
by reference delta-time
by value ast-proc-addr
by reference reqidt <<==
omitted
giving return-value
end-call

Replaced "by value reqidt" with "by reference reqidt".
That will pass the address (pointer) to reqidt.
Silly not thinking about that...

The AST routine just uses the paramater as-is as before
an now prints "reqidt: 1234" as expected.

Fine, then each AST can be identified. QIO has a similar
parameter that will be passed to the AST routine.
Time to replace SETIMR with a QIO to read a mailbox.

Thanks!
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Hm... Maybe time to make a second try using some C helper routines.
Or that.
:-)
Arne
Arne Vajhøj
2021-09-22 01:37:30 UTC
Reply
Permalink
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
This ACCVIO's on the display statement. The weird thing is that
the virtual address in the ACCVIO message is ...00042D, and that
is the hex for the value I used, in decimal 1234.
I must be missing something, it looks like the display statement tries
to use the value in reqidt as an address instead of the actual value...
I know next to nothing about COBOL, but if COBOL use call by ref as
default like FORTRAN, so that the AST routine expects an address,
then the error makes sense.
Right. When calling *from* Cobol you can specify "by ref", "by val"
and so on. I have looked but I cannot find anything similar when a
Cobol routine is *called*. But yes, it very much looks like that a
called Cobol routine expects a "by ref" (pointer) parameter.
But the SETIMR docs says that this parameter is sent by value.
Post by Arne Vajhøj
And the solution could be to call with
address of reqidt in main code (I don't know how to do that i COBOL
but it must be possible).
Good point... And that solved this issue!
01  reqidt              pic 9(9)    comp.
...
    move 1234 to reqidt
    call "sys$setimr"
        using omitted
              by reference delta-time
              by value ast-proc-addr
              by reference reqidt    <<==
              omitted
        giving return-value
    end-call
Replaced "by value reqidt" with "by reference reqidt".
That will pass the address (pointer) to reqidt.
Silly not thinking about that...
The AST routine just uses the paramater as-is as before
an now prints "reqidt: 1234" as expected.
I would probably have preferred to keep the formal
argument as by val and stuffed the address into an integer
and passed that. Slightly more complicated but I just
don't like faking the passing mechanism of a system
service.

Arne
Jan-Erik Söderholm
2021-09-22 07:41:12 UTC
Reply
Permalink
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
This ACCVIO's on the display statement. The weird thing is that
the virtual address in the ACCVIO message is ...00042D, and that
is the hex for the value I used, in decimal 1234.
I must be missing something, it looks like the display statement tries
to use the value in reqidt as an address instead of the actual value...
I know next to nothing about COBOL, but if COBOL use call by ref as
default like FORTRAN, so that the AST routine expects an address,
then the error makes sense.
Right. When calling *from* Cobol you can specify "by ref", "by val"
and so on. I have looked but I cannot find anything similar when a
Cobol routine is *called*. But yes, it very much looks like that a
called Cobol routine expects a "by ref" (pointer) parameter.
But the SETIMR docs says that this parameter is sent by value.
Post by Arne Vajhøj
And the solution could be to call with
address of reqidt in main code (I don't know how to do that i COBOL
but it must be possible).
Good point... And that solved this issue!
01  reqidt              pic 9(9)    comp.
...
     move 1234 to reqidt
     call "sys$setimr"
         using omitted
               by reference delta-time
               by value ast-proc-addr
               by reference reqidt    <<==
               omitted
         giving return-value
     end-call
Replaced "by value reqidt" with "by reference reqidt".
That will pass the address (pointer) to reqidt.
Silly not thinking about that...
The AST routine just uses the paramater as-is as before
an now prints "reqidt: 1234" as expected.
I would probably have preferred to keep the formal
argument as by val and stuffed the address into an integer
and passed that. Slightly more complicated but I just
don't like faking the passing mechanism of a system
service.
Arne
Not that much more complicated, one additional pointer definition:

01 reqidt_addr pointer value reference reqidt.
01 reqidt pic 9(9) comp.
...
move 1234 to reqidt

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

This also works. A matter of taste, I guess. :-)

Now, a bigger issue is that I found this in the Rdb docs:

------------------------------------------------------------
15.3 Avoiding Asynchronous System Traps

You should not use asynchronous system trap (AST) service routines in
an application that accesses Oracle Rdb databases. If you do, Oracle
Rdb cannot guarantee the behavior of the application.

Because several Oracle Rdb components use AST service routines and
because an AST cannot be delivered while an AST service routine is
currently executing at the same mode or more privileged mode, using
an AST service routine in an application can prevent the delivery of
an AST in one of the components of Oracle Rdb.
------------------------------------------------------------

I posted a question on the Rdb mailing list regarding ASTs, and got
this from, what I regard as, an trustworthy source:

------------------------------------------------------------
Seems pretty clear. At any access mode the program can be either in
non-AST or AST mode.

As long as you are very well aware of this, make certain that your
AST-mode code does whatever it does, never calls anything related
to Rdb, and then exits, you are probable just fine. Do not do
anything that might block (e.g. potential synchronous IO or similar;
explicitly avoid RMS directly or indirectly).

Best that you studiously avoid anything to do with timers or
$HIBER/$WAKE to make your future life easier.
------------------------------------------------------------

It is very much the general guidelines for any interrupt handling
on any kind of environment (have done PIC microcontroller work before).
In all cases, keep your interrupt (or AST) rooutines as short as
possible and let the main code do the processing...

We'll see. Still under investigation.
Arne Vajhøj
2021-09-22 12:31:24 UTC
Reply
Permalink
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
01  reqidt              pic 9(9)    comp.
...
     move 1234 to reqidt
     call "sys$setimr"
         using omitted
               by reference delta-time
               by value ast-proc-addr
               by reference reqidt    <<==
               omitted
         giving return-value
     end-call
Replaced "by value reqidt" with "by reference reqidt".
That will pass the address (pointer) to reqidt.
Silly not thinking about that...
The AST routine just uses the paramater as-is as before
an now prints "reqidt: 1234" as expected.
I would probably have preferred to keep the formal
argument as by val and stuffed the address into an integer
and passed that. Slightly more complicated but I just
don't like faking the passing mechanism of a system
service.
01  reqidt_addr         pointer     value reference reqidt.
01  reqidt              pic 9(9)    comp.
...
    move 1234 to reqidt
    call "sys$setimr"
        using omitted
              by reference delta-time
              by value ast-proc-addr
              by value reqidt_addr
              omitted
        giving return-value
    end-call
This also works. A matter of taste, I guess. :-)
Yes. They do the same thing.

It just bother me to see a by reference when the documentation
says by value even though there is a good reason.

Arne
Bob Gezelter
2021-09-22 13:01:33 UTC
Reply
Permalink
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
This ACCVIO's on the display statement. The weird thing is that
the virtual address in the ACCVIO message is ...00042D, and that
is the hex for the value I used, in decimal 1234.
I must be missing something, it looks like the display statement tries
to use the value in reqidt as an address instead of the actual value...
I know next to nothing about COBOL, but if COBOL use call by ref as
default like FORTRAN, so that the AST routine expects an address,
then the error makes sense.
Right. When calling *from* Cobol you can specify "by ref", "by val"
and so on. I have looked but I cannot find anything similar when a
Cobol routine is *called*. But yes, it very much looks like that a
called Cobol routine expects a "by ref" (pointer) parameter.
But the SETIMR docs says that this parameter is sent by value.
Post by Arne Vajhøj
And the solution could be to call with
address of reqidt in main code (I don't know how to do that i COBOL
but it must be possible).
Good point... And that solved this issue!
01 reqidt pic 9(9) comp.
...
move 1234 to reqidt
call "sys$setimr"
using omitted
by reference delta-time
by value ast-proc-addr
by reference reqidt <<==
omitted
giving return-value
end-call
Replaced "by value reqidt" with "by reference reqidt".
That will pass the address (pointer) to reqidt.
Silly not thinking about that...
The AST routine just uses the paramater as-is as before
an now prints "reqidt: 1234" as expected.
I would probably have preferred to keep the formal
argument as by val and stuffed the address into an integer
and passed that. Slightly more complicated but I just
don't like faking the passing mechanism of a system
service.
Arne
01 reqidt_addr pointer value reference reqidt.
01 reqidt pic 9(9) comp.
...
move 1234 to reqidt
call "sys$setimr"
using omitted
by reference delta-time
by value ast-proc-addr
by value reqidt_addr
omitted
giving return-value
end-call
This also works. A matter of taste, I guess. :-)
------------------------------------------------------------
15.3 Avoiding Asynchronous System Traps
You should not use asynchronous system trap (AST) service routines in
an application that accesses Oracle Rdb databases. If you do, Oracle
Rdb cannot guarantee the behavior of the application.
Because several Oracle Rdb components use AST service routines and
because an AST cannot be delivered while an AST service routine is
currently executing at the same mode or more privileged mode, using
an AST service routine in an application can prevent the delivery of
an AST in one of the components of Oracle Rdb.
------------------------------------------------------------
I posted a question on the Rdb mailing list regarding ASTs, and got
------------------------------------------------------------
Seems pretty clear. At any access mode the program can be either in
non-AST or AST mode.
As long as you are very well aware of this, make certain that your
AST-mode code does whatever it does, never calls anything related
to Rdb, and then exits, you are probable just fine. Do not do
anything that might block (e.g. potential synchronous IO or similar;
explicitly avoid RMS directly or indirectly).
Best that you studiously avoid anything to do with timers or
$HIBER/$WAKE to make your future life easier.
------------------------------------------------------------
It is very much the general guidelines for any interrupt handling
on any kind of environment (have done PIC microcontroller work before).
In all cases, keep your interrupt (or AST) rooutines as short as
possible and let the main code do the processing...
We'll see. Still under investigation.
Jan-Erik,

Yes, that comment in the Oracle RDB documentation is the point that I was referring to in my DECUS seminar. The solution is to have the main thread read from an interlocked queue.

- Bob Gezelter, http://www.rlgsc.com
Dave Froble
2021-09-22 01:23:54 UTC
Reply
Permalink
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Post by abrsvc
Post by Dave Froble
Then comes the question of whether the AST would actually perform any
required actions, or just interrupt the program and have the program
handle the processing.
Is the required actions simple enough and quick enough to have the AST
routine perform the work?
For sharing data, what I have not tried, but I'd be tempted, is to
declare some structure, in Basic it would be a RECORD, and pass the
address (By Ref) to the AST routine, which also would have an identical
RECORD definition, such that the two (main and AST routine) can both
share the data in the structure. All that would be required, I think,
is some variable that can be passed, By Ref, to the AST routine.
I agree with Dave, and as long as the data area is only accessed by one
execution stream at a time, it should be OK. I think that the issue is
whether or not another can interrupt the processing of the first.
But if you haven't made a new QUI, there cannot be any new AST, can there?
Post by abrsvc
In this case, as long as the incoming record is processed prior to any
issuance of another QIO, it should be OK.
Ah, OK. What I wrote... :-)
Post by abrsvc
You run the risk of filling up the mailbox with records, but from the
initial request, these records should be fairly infrequent.
Say, each 2 min. But when they arrive, we want a 1 sec response time
on the screen managed by this application. Today this application is
looping and polling some data each 1 sec. So it puts a constant load
("backround noice") on the system and on Rdb. Even when the system is
idle, Rdb has 10-20 transactions per second, just from the polling.
The application is run on 10-20 screens.
Trying to find a better design, now that we hav a need for some
major application redesign anyway for other reasons.
And, if we do have any non-AST-compatible code in the main code, I'm
also looking for some disable/enable AST functions. They are probably
there, just have to look it up.
You may get a much more robust solution by using your IBM MQ instead
of a VMS mailbox.
No AST's and problem with number of messages.
Arne
Ah, well. Yes, some message queing tool might also be an option.
And we do use IBM MQ but only for external communication to the
corporate message bus center. There is no MQ server on VMS only
client, so a local MQ solution will be hard.
I kind of like the simplines of mailboxes, in particular since
we got the CREATE/MAILBOX DCL commands. Very simple to setup.
At the moment I'm trying to get the reqidt parameter of the SETIMR
call to work. It should be sent as a parameter to the AST routine.
01 reqidt pic 9(9) comp.
...
move 1234 to reqidt
call "sys$setimr"
using omitted
by reference delta-time
by value ast-proc-addr
by value reqidt
Haven't done any ASTs for a while, and too lazy to lookup the doc.

But, from memory, you're passing a VALUE, when maybe an address (By Ref)
is expected. So when accessing that "location" (reqidt) you're
accessing a memory location you really should not. Or maybe I don't
understand ...
Post by Jan-Erik Söderholm
omitted
giving return-value
end-call
linkage section.
01 reqidt pic 9(9) comp.
procedure division using reqidt.
ast-fired.
display "reqidt: " reqidt with conversion
Yeah, that's the problem, I think. I haven't looked at Cobol since
forever ....
Post by Jan-Erik Söderholm
call "sys$wake"
using omitted omitted
giving return-value
end-call
This ACCVIO's on the display statement. The weird thing is that
the virtual address in the ACCVIO message is ...00042D, and that
is the hex for the value I used, in decimal 1234.
Right! You passed a value as the address of the data. Bad, bad Jan-Erik.

:-)
Post by Jan-Erik Söderholm
I must be missing something, it looks like the display statement tries
to use the value in reqidt as an address instead of the actual value...
Hm... Maybe time to make a second try using some C helper routines.
--
David Froble Tel: 724-529-0450
Dave Froble Enterprises, Inc. E-Mail: ***@tsoft-inc.com
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Jan-Erik Söderholm
2021-09-21 21:13:41 UTC
Reply
Permalink
Post by Dave Froble
Post by Jan-Erik Söderholm
Post by abrsvc
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...
external works for me.
identification division.
program-id. x.
environment division.
data division.
working-storage section.
01 magic-value pic 9(10) display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program x.
identification division.
program-id. ast_routine.
environment division.
data division.
working-storage section.
01 magic-value pic s9(10) display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program ast_routine.
$ cobol x
$ link x
$ run x
sleeping for 5 seconds
000000012C
Ah, OK! that will be tested. Hm, is this limited to numeric variables?
My test was using a x(3) variable...
Try it!
Per documentation then external just moves the variable to a PSECT
with the same name as the variable to tell the linker to overlay
them.
I would expect that to work with any data type.
Post by Jan-Erik Söderholm
Hm, if this would had been a read-AST on a mailbos instead of a timer,
maybe the ast_routine can just awake the main code and the mailbox
been read in the main code. The ast_routine could set a variable that
just signals the reason fo the wakeup.
I don't understand the problem.
If you want the main flow to wait until something is in the mailbox,
then why not do a blocking read?
Arne
No, sorry... The main code does other things (the regular business
processing) all the time. I just do not want it to have to poll the
mailbox with some fixed interval. I expect an AST to be faster also
with a more "on-demand" response time.
Will do some more testing this evening after regular business hours...
Can't you just post an asynchronous QIO read to the mailbox with an
AST routine to service the read within the main program?  In this
fashion, the writing to the mailbox will trigger the action.  In this
fashion, the main program will continue to proceed as normal only
getting interrupted when the mailbox read copletes.
Yes, that is my plan. What I had issues with was how to get the data
from the mailbox message back from the AST routine to the main code.
Since the AST routine has to be a separate PROGAM section. And it
cannot be a sub-program within the main code, the POINTER EXTERNAL,
to get the address to the AST routine, does not work in that case.
At least not if I understood my tests correctly.
But I think I understand the basic AST processing as such...
What Dan wrote is a good method for having the program doing it's thing,
with the possibility of an incoming mailbox read firing an AST.
Then comes the question of whether the AST would actually perform any
required actions, or just interrupt the program and have the program handle
the processing.
Is the required actions simple enough and quick enough to have the AST
routine perform the work?
We'll see. Also depends on if the Rdb calls are AST-safe. If you can have
Rdb work in the AST routine that will not distureb any Rdb work in the
main code. Have to read up some on that.
Post by Dave Froble
For sharing data, what I have not tried, but I'd be tempted, is to declare
some structure, in Basic it would be a RECORD, and pass the address (By
Ref) to the AST routine, which also would have an identical RECORD
definition, such that the two (main and AST routine) can both share the
data in the structure.  All that would be required, I think, is some
variable that can be passed, By Ref, to the AST routine.
I have not read up that much yet to see if there is any other information
you can pass, besides of the address to the AST routine.

But my guess is that, if you queue QIOs from multiple sources, the AST
routine must have some way to tell which source it was that trigged
the AST. Say you make (made up example, not part of our current target)
10 QIO calls having the address of the same AST routine in the calls,
each QIO reading from its own TNA device, you need to know in the AST
routine which TNA device (like 10 different production machines) it
was that sent something.

I have probably not read enough aboit AST and QUI calls yet...
Dave Froble
2021-09-22 01:46:20 UTC
Reply
Permalink
Post by Jan-Erik Söderholm
Post by Dave Froble
Post by Jan-Erik Söderholm
Post by abrsvc
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...
external works for me.
identification division.
program-id. x.
environment division.
data division.
working-storage section.
01 magic-value pic 9(10) display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program x.
identification division.
program-id. ast_routine.
environment division.
data division.
working-storage section.
01 magic-value pic s9(10) display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program ast_routine.
$ cobol x
$ link x
$ run x
sleeping for 5 seconds
000000012C
Ah, OK! that will be tested. Hm, is this limited to numeric variables?
My test was using a x(3) variable...
Try it!
Per documentation then external just moves the variable to a PSECT
with the same name as the variable to tell the linker to overlay
them.
I would expect that to work with any data type.
Post by Jan-Erik Söderholm
Hm, if this would had been a read-AST on a mailbos instead of a timer,
maybe the ast_routine can just awake the main code and the mailbox
been read in the main code. The ast_routine could set a variable that
just signals the reason fo the wakeup.
I don't understand the problem.
If you want the main flow to wait until something is in the mailbox,
then why not do a blocking read?
Arne
No, sorry... The main code does other things (the regular business
processing) all the time. I just do not want it to have to poll the
mailbox with some fixed interval. I expect an AST to be faster also
with a more "on-demand" response time.
Will do some more testing this evening after regular business hours...
Can't you just post an asynchronous QIO read to the mailbox with an
AST routine to service the read within the main program? In this
fashion, the writing to the mailbox will trigger the action. In this
fashion, the main program will continue to proceed as normal only
getting interrupted when the mailbox read copletes.
Yes, that is my plan. What I had issues with was how to get the data
from the mailbox message back from the AST routine to the main code.
Since the AST routine has to be a separate PROGAM section. And it
cannot be a sub-program within the main code, the POINTER EXTERNAL,
to get the address to the AST routine, does not work in that case.
At least not if I understood my tests correctly.
But I think I understand the basic AST processing as such...
What Dan wrote is a good method for having the program doing it's
thing, with the possibility of an incoming mailbox read firing an AST.
Then comes the question of whether the AST would actually perform any
required actions, or just interrupt the program and have the program
handle the processing.
Is the required actions simple enough and quick enough to have the AST
routine perform the work?
We'll see. Also depends on if the Rdb calls are AST-safe. If you can have
Rdb work in the AST routine that will not distureb any Rdb work in the
main code. Have to read up some on that.
Thinking some more, slowly, I'm not so sure my idea has any merit. I'm
in the habit of doing the least required in an AST routine. However,
while I'm not a user of Rdb, I've got to think that regardless if it's
in an AST routine, it's just code, and should do Ok, with Rdb. That's a
question for someone else.

However, I'm not sure you'd have anything to do in the AST routine,
since I'm assuming you're going to queue up an async read from the main
program, and then continue with whatever the main program is doing.
When the AST fires, it lets you know that the read completed, in some
fashion, and now the message is in whatever buffer in the main program.
I'd assume some flag is set, bu the AST routine, and periodically the
main program tests the flag, and processes the message, at that time.

Which brings up this question. How many mailboxes are you using? A
single mailbox? Or multiple mailboxes (that's a real headache).
Post by Jan-Erik Söderholm
Post by Dave Froble
For sharing data, what I have not tried, but I'd be tempted, is to
declare some structure, in Basic it would be a RECORD, and pass the
address (By Ref) to the AST routine, which also would have an
identical RECORD definition, such that the two (main and AST routine)
can both share the data in the structure. All that would be required,
I think, is some variable that can be passed, By Ref, to the AST routine.
I have not read up that much yet to see if there is any other information
you can pass, besides of the address to the AST routine.
You mentioned elsewhere that you're unaware of how to define the
datatype of an incoming argument. I've done this in Basic. Then the
AST routine just uses the labels in the structure definition. The
address is the address of the first variable defined in the structure.
Post by Jan-Erik Söderholm
But my guess is that, if you queue QIOs from multiple sources, the AST
routine must have some way to tell which source it was that trigged
the AST. Say you make (made up example, not part of our current target)
10 QIO calls having the address of the same AST routine in the calls,
each QIO reading from its own TNA device, you need to know in the AST
routine which TNA device (like 10 different production machines) it
was that sent something.
That sounds like a real headache. Perhaps event flags would help. I
tend to avoid event flags.
Post by Jan-Erik Söderholm
I have probably not read enough aboit AST and QUI calls yet...
ASTs can be fun. I try to use them to set flags or cancel I/O.
Cancelling an I/O causes a completion of an async read. I feel that if
I try to get "tricky", I'll outsmart myself, not so hard to do with dumb
Dave.

:-)
--
David Froble Tel: 724-529-0450
Dave Froble Enterprises, Inc. E-Mail: ***@tsoft-inc.com
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Arne Vajhøj
2021-09-22 01:53:26 UTC
Reply
Permalink
Post by Jan-Erik Söderholm
But my guess is that, if you queue QIOs from multiple sources, the AST
routine must have some way to tell which source it was that trigged
the AST. Say you make (made up example, not part of our current target)
10 QIO calls having the address of the same AST routine in the calls,
each QIO reading from its own TNA device, you need to know in the AST
routine which TNA device (like 10 different production machines) it
was that sent something.
That sounds like a real headache.  Perhaps event flags would help.  I
tend to avoid event flags.
Post by Jan-Erik Söderholm
I have probably not read enough aboit AST and QUI calls yet...
ASTs can be fun.  I try to use them to set flags or cancel I/O.
Cancelling an I/O causes a completion of an async read.  I feel that if
I try to get "tricky", I'll outsmart myself,
That is why I suggested a message queue instead of mailboxes,
$QIO(W) and AST's.

Way less options for experiencing "unexpected features".

Arne
Dave Froble
2021-09-22 01:59:10 UTC
Reply
Permalink
Post by Arne Vajhøj
Post by Dave Froble
Post by Jan-Erik Söderholm
But my guess is that, if you queue QIOs from multiple sources, the AST
routine must have some way to tell which source it was that trigged
the AST. Say you make (made up example, not part of our current target)
10 QIO calls having the address of the same AST routine in the calls,
each QIO reading from its own TNA device, you need to know in the AST
routine which TNA device (like 10 different production machines) it
was that sent something.
That sounds like a real headache. Perhaps event flags would help. I
tend to avoid event flags.
Post by Jan-Erik Söderholm
I have probably not read enough aboit AST and QUI calls yet...
ASTs can be fun. I try to use them to set flags or cancel I/O.
Cancelling an I/O causes a completion of an async read. I feel that
if I try to get "tricky", I'll outsmart myself,
That is why I suggested a message queue instead of mailboxes,
$QIO(W) and AST's.
You'd still have to check the message periodically. Testing a flag, and
already having the message in a buffer, should be more efficient.
Post by Arne Vajhøj
Way less options for experiencing "unexpected features".
Arne
--
David Froble Tel: 724-529-0450
Dave Froble Enterprises, Inc. E-Mail: ***@tsoft-inc.com
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Arne Vajhøj
2021-09-22 13:10:20 UTC
Reply
Permalink
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
But my guess is that, if you queue QIOs from multiple sources, the AST
routine must have some way to tell which source it was that trigged
the AST. Say you make (made up example, not part of our current target)
10 QIO calls having the address of the same AST routine in the calls,
each QIO reading from its own TNA device, you need to know in the AST
routine which TNA device (like 10 different production machines) it
was that sent something.
That sounds like a real headache.  Perhaps event flags would help.  I
tend to avoid event flags.
Post by Jan-Erik Söderholm
I have probably not read enough aboit AST and QUI calls yet...
ASTs can be fun.  I try to use them to set flags or cancel I/O.
Cancelling an I/O causes a completion of an async read.  I feel that
if I try to get "tricky", I'll outsmart myself,
That is why I suggested a message queue instead of mailboxes,
$QIO(W) and AST's.
You'd still have to check the message periodically.  Testing a flag, and
already having the message in a buffer, should be more efficient.
Using a message queue (like IBM MQ or ActiveMQ) will avoid AST's,
avoid $QIO(W) and will avoid mailbox size limits.

But it does not solve the concurrency problem.

I would go for a thread for that.

Arne
Lawrence D’Oliveiro
2021-09-23 01:41:16 UTC
Reply
Permalink
Post by Arne Vajhøj
Using a message queue (like IBM MQ or ActiveMQ) will avoid AST's,
avoid $QIO(W) and will avoid mailbox size limits.
But it does not solve the concurrency problem.
Do you have access to modern languages with async/await functionality?
Bob Gezelter
2021-09-22 13:22:25 UTC
Reply
Permalink
On Tuesday, September 21, 2021 at 9:48:49 PM UTC-4, Dave Froble wrote:
(Omitted for the sake of brevity)
Post by Dave Froble
However, I'm not sure you'd have anything to do in the AST routine,
since I'm assuming you're going to queue up an async read from the main
program, and then continue with whatever the main program is doing.
When the AST fires, it lets you know that the read completed, in some
fashion, and now the message is in whatever buffer in the main program.
I'd assume some flag is set, bu the AST routine, and periodically the
main program tests the flag, and processes the message, at that time.
Which brings up this question. How many mailboxes are you using? A
single mailbox? Or multiple mailboxes (that's a real headache).
Post by Jan-Erik Söderholm
Post by Dave Froble
For sharing data, what I have not tried, but I'd be tempted, is to
declare some structure, in Basic it would be a RECORD, and pass the
address (By Ref) to the AST routine, which also would have an
identical RECORD definition, such that the two (main and AST routine)
can both share the data in the structure. All that would be required,
I think, is some variable that can be passed, By Ref, to the AST routine.
I have not read up that much yet to see if there is any other information
you can pass, besides of the address to the AST routine.
You mentioned elsewhere that you're unaware of how to define the
datatype of an incoming argument. I've done this in Basic. Then the
AST routine just uses the labels in the structure definition. The
address is the address of the first variable defined in the structure.
Post by Jan-Erik Söderholm
But my guess is that, if you queue QIOs from multiple sources, the AST
routine must have some way to tell which source it was that trigged
the AST. Say you make (made up example, not part of our current target)
10 QIO calls having the address of the same AST routine in the calls,
each QIO reading from its own TNA device, you need to know in the AST
routine which TNA device (like 10 different production machines) it
was that sent something.
That sounds like a real headache. Perhaps event flags would help. I
tend to avoid event flags.
Post by Jan-Erik Söderholm
I have probably not read enough aboit AST and QUI calls yet...
ASTs can be fun. I try to use them to set flags or cancel I/O.
Cancelling an I/O causes a completion of an async read. I feel that if
I try to get "tricky", I'll outsmart myself, not so hard to do with dumb
Dave.
:-)
--
David Froble Tel: 724-529-0450
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Dave.

Distinguishing between multiple sources using the same AST routine is straightforward. OpenVMS nee VAX/VMS QIO has a parameter referred to as ASTPARM (ASTPARM was added to the QIO interface with VAX/VMS; the RSX-11 family QIO did not have ASTPARM).

ASTPARM is an untyped longword. It can be:
- a buffer pointer (where the buffer structure includes a pointer to an owning data structure)
- a pointer to a data structure
- an index into a table of pointers

I have done code which had hundreds (or more) active IO connections active simultaneously using this technique with absolutely no problems.

Straightforward to say the least.

- Bob Gezelter, http://www.rlgsc.com
Dave Froble
2021-09-22 16:12:03 UTC
Reply
Permalink
Post by Bob Gezelter
(Omitted for the sake of brevity)
Post by Dave Froble
However, I'm not sure you'd have anything to do in the AST routine,
since I'm assuming you're going to queue up an async read from the main
program, and then continue with whatever the main program is doing.
When the AST fires, it lets you know that the read completed, in some
fashion, and now the message is in whatever buffer in the main program.
I'd assume some flag is set, bu the AST routine, and periodically the
main program tests the flag, and processes the message, at that time.
Which brings up this question. How many mailboxes are you using? A
single mailbox? Or multiple mailboxes (that's a real headache).
Post by Jan-Erik Söderholm
Post by Dave Froble
For sharing data, what I have not tried, but I'd be tempted, is to
declare some structure, in Basic it would be a RECORD, and pass the
address (By Ref) to the AST routine, which also would have an
identical RECORD definition, such that the two (main and AST routine)
can both share the data in the structure. All that would be required,
I think, is some variable that can be passed, By Ref, to the AST routine.
I have not read up that much yet to see if there is any other information
you can pass, besides of the address to the AST routine.
You mentioned elsewhere that you're unaware of how to define the
datatype of an incoming argument. I've done this in Basic. Then the
AST routine just uses the labels in the structure definition. The
address is the address of the first variable defined in the structure.
Post by Jan-Erik Söderholm
But my guess is that, if you queue QIOs from multiple sources, the AST
routine must have some way to tell which source it was that trigged
the AST. Say you make (made up example, not part of our current target)
10 QIO calls having the address of the same AST routine in the calls,
each QIO reading from its own TNA device, you need to know in the AST
routine which TNA device (like 10 different production machines) it
was that sent something.
That sounds like a real headache. Perhaps event flags would help. I
tend to avoid event flags.
Post by Jan-Erik Söderholm
I have probably not read enough aboit AST and QUI calls yet...
ASTs can be fun. I try to use them to set flags or cancel I/O.
Cancelling an I/O causes a completion of an async read. I feel that if
I try to get "tricky", I'll outsmart myself, not so hard to do with dumb
Dave.
:-)
--
David Froble Tel: 724-529-0450
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Dave.
Distinguishing between multiple sources using the same AST routine is straightforward. OpenVMS nee VAX/VMS QIO has a parameter referred to as ASTPARM (ASTPARM was added to the QIO interface with VAX/VMS; the RSX-11 family QIO did not have ASTPARM).
- a buffer pointer (where the buffer structure includes a pointer to an owning data structure)
- a pointer to a data structure
- an index into a table of pointers
I have done code which had hundreds (or more) active IO connections active simultaneously using this technique with absolutely no problems.
Straightforward to say the least.
- Bob Gezelter, http://www.rlgsc.com
I was looking at that argument in the docs just last night. I was
figuring that while the docs declared the argument read only, if it was
the address of some data, the AST could access and modify the data,
assuming it was aware of the size of the data. Then I thought a bit
more about that "aware of the size of the data" and suffered a few shakes.
--
David Froble Tel: 724-529-0450
Dave Froble Enterprises, Inc. E-Mail: ***@tsoft-inc.com
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Stephen Hoffman
2021-09-22 18:09:08 UTC
Reply
Permalink
Post by Dave Froble
Post by Jan-Erik Söderholm
But my guess is that, if you queue QIOs from multiple sources, the AST
routine must have some way to tell which source it was that trigged the
AST. Say you make (made up example, not part of our current target) 10
QIO calls having the address of the same AST routine in the calls, each
QIO reading from its own TNA device, you need to know in the AST
routine which TNA device (like 10 different production machines) it was
that sent something.
That sounds like a real headache. Perhaps event flags would help. I
tend to avoid event flags.
The AST parameter is used for that. This is why I pass around that
context block (data buffer(s), the IOSB, other app-specific data, etc),
and why I requeue the context block to pass around the data.
Post by Dave Froble
Post by Jan-Erik Söderholm
I have probably not read enough aboit AST and QUI calls yet...
ASTs can be fun. I try to use them to set flags or cancel I/O.
Cancelling an I/O causes a completion of an async read. I feel that if
I try to get "tricky", I'll outsmart myself, not so hard to do with
dumb Dave.
Yes; setting a "cancel in progress" bitlock in the app context for that
processing is the wise way to go here, too. Chasing $cancel requests
around is less than fun.
--
Pure Personal Opinion | HoffmanLabs LLC
Arne Vajhøj
2021-09-21 14:19:03 UTC
Reply
Permalink
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...
external works for me.
identification division.
program-id. x.
environment division.
data division.
working-storage section.
01  magic-value         pic 9(10)  display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program x.
identification division.
program-id. ast_routine.
environment division.
data division.
working-storage section.
01  magic-value         pic s9(10)  display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program ast_routine.
$ cobol x
$ link x
$ run x
sleeping for 5 seconds
000000012C
Ah, OK! that will be tested. Hm, is this limited to numeric variables?
My test was using a x(3) variable...
Try it!
Per documentation then external just moves the variable to a PSECT
with the same name as the variable to tell the linker to overlay
them.
I would expect that to work with any data type.
With PIC X(80):

identification division.
program-id. x.
environment division.
data division.
working-storage section.
01 magic-value pic x(80) external.
01 ast-proc-addr pointer value external ast_routine.
01 delta-time pic s9(18) comp value -50000000.
01 return-value pic s9(18) 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
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
display magic-value
stop run
.
end program x.
identification division.
program-id. ast_routine.
environment division.
data division.
working-storage section.
01 magic-value pic x(80) external.
01 return-value pic s9(18) comp.
procedure division.
ast-fired.
call "sys$wake"
using
omitted
omitted
giving
return-value
end-call
move "It works !" to magic-value
exit program
.
end program ast_routine.

Arne
Jan-Erik Söderholm
2021-09-21 14:24:54 UTC
Reply
Permalink
Post by Arne Vajhøj
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
Post by Jan-Erik Söderholm
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...
external works for me.
identification division.
program-id. x.
environment division.
data division.
working-storage section.
01  magic-value         pic 9(10)  display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program x.
identification division.
program-id. ast_routine.
environment division.
data division.
working-storage section.
01  magic-value         pic s9(10)  display external.
...
Post by Jan-Erik Söderholm
Post by Arne Vajhøj
end program ast_routine.
$ cobol x
$ link x
$ run x
sleeping for 5 seconds
000000012C
Ah, OK! that will be tested. Hm, is this limited to numeric variables?
My test was using a x(3) variable...
Try it!
Per documentation then external just moves the variable to a PSECT
with the same name as the variable to tell the linker to overlay
them.
I would expect that to work with any data type.
identification division.
program-id. x.
environment division.
data division.
working-storage section.
01  magic-value         pic x(80)         external.
01  ast-proc-addr       pointer           value external ast_routine.
01  delta-time          pic s9(18)  comp  value -50000000.
01  return-value        pic s9(18)  comp.
    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
    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
    display magic-value
    stop run
    .
end program x.
identification division.
program-id. ast_routine.
environment division.
data division.
working-storage section.
01  magic-value         pic x(80)         external.
01  return-value        pic s9(18)  comp.
procedure division.
ast-fired.
    call "sys$wake"
        using
            omitted
            omitted
        giving
            return-value
    end-call
    move "It works !" to magic-value
    exit program
    .
end program ast_routine.
Arne
Nice! And instead of the sys$wake we'll have the read from the mailbox
and processing of the message accordingly. Good...

And I think it is the "value external" that needs a numeric value.
Dave Froble
2021-09-21 02:41:45 UTC
Reply
Permalink
Post by Jan-Erik Söderholm
Hi.
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...
Regards,
Jan-Erik.
Ok, a question, will the program using an AST be waiting, or will it be
busy doing other work, and interrupted when the AST fires?

Arne mentioned a timer AST, but that doesn't sound like what you want.

If the program is waiting for a message, then just queue up the read
with possibly a timeout.

If the program will be doing other work, then the read is an event to
interrupt current work.
--
David Froble Tel: 724-529-0450
Dave Froble Enterprises, Inc. E-Mail: ***@tsoft-inc.com
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Bob Gezelter
2021-09-21 15:40:21 UTC
Reply
Permalink
Post by Jan-Erik Söderholm
Hi.
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data? Jan-Erik,
Anything similar to an COMMON area in Fortran?
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
Are there more options if not everything is done in Cobol?
We can easily add some C if that helps...
Regards,
Jan-Erik.
Jan-Erik,

I will be happy to send you a copy of my notes from my seminar on ASTs.
In short, you want to do the mailbox read in an AST, with the read completion being another AST routine, which after processing the message, start the main program to process the received information.
The best way to accomplish this is for everything to be in the AST routine.
However, as I noted in the seminar, some packages are not-well suited for this approach. When dealing with such a program or library, the best way is to use interlocked queues in both directions.
I forget if COBOL has intrinsic hooks for interlocked queues, but if nothing else, there are LIB$ equivalents.
If I can be of assistance, please let me know.

- Bob Gezelter, http://www.rlgsc.com
Stephen Hoffman
2021-09-21 16:45:52 UTC
Reply
Permalink
Post by Jan-Erik Söderholm
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
In no particular order...

Start with chapters 6 and 8 in the first VSI Programming Concepts
Manual. Memory sync and AST operations details.

All data shared between mainline and AST must be atomic-accessed, or
must be protected by atomic operations, or some other locking.

The AST can arrive between pretty much any two hardware instructions
within any code sequence, or is best assumed to arrive at the least
opportune moment. Including within an unaligned variable read, or
within a multi-part update operation such as an un-interlocked queue
update.

Interlocked bitflags or interlocked queues are commonly used to avoid
these races. There are other ways too, though these interlocked
operations tend to be fast and fairly lightweight. These were VAX
hardware instructions, and are now available as C built-ins and as
LIBRTL calls. Calls to $SETAST can be used to brute-force block AST
activity.

For cases processing async I/O such as this, an app design maintaining
a set of two or sometimes three queues is fairly common. The mainline
hibernates, if it doesn't have something to do. One queue pre-populated
at startup and used as a free list of data structures available for
use, one queue of data structures from mainline to AST, and one for
structures AST to mainline. The interlocked queues avoid issues with
variable tearing, and with race conditions. The structures can also
contain the IOSB, the data buffer, the interlocked queue headers, and
whatever other data is required.

Make the number of buffers pre-allocated programmable, and add some
instrumentation for when the free list is exhausted. It's absolutely
possible to dynamically add some structures when the freel queue s
empty, at the cost of some added complexity.

Use two unidirectional mailboxes whenever mailbox message traffic is
bidirectional. One reader, one or more writers, for each of the two
mailboxes. Don't try to multiplex a mailbox. That way leads to gnarly.

Always have a scheduled timer AST or (locally preferable) have a
scheduled wakeup call operating in the background, triggering a routine
that processes the queues every ten or thirty or minute, on the off
chance an AST or event flag gets lost somewhere. This happens more
often than any of us would prefer, and the scheduled wakeup. This so
that the AST issues a $wake, and the mainline loops and does its
processing and eventually issues a $hiber when the work-pending queue
is empty. Once started, the mainline initializes the queues and queues
the ASTs, then hibernates. The ASTs arrive as the I/O completions
arrive, and each can trigger a wakeup call and can shuffle buffers
among the interlocked queues and can also re-queue the I/O operation
for the next I/O operation. And the scheduled wakeup call masks any
lost wakeup calls, at minimal cost. (Wakes are coalesced into one, and
I've worked with a few app designs where a wake was occasionally lost.)

For a few of these app cases I've used global sections for app control,
sometimes lock manager doorbell locks, sometimes controlled activity
through signals, sometimes a management mailbox pair, and it's often
possible to pass management commands into the app through the mailbox.

Protect the mailboxes against unauthorized access correctly, and there
can be protocol design cases where looking at the PID of the message
sender can be necessary.

You will want to consider including some sort of a protocol version
within the mailbox message traffic too, as that can makes message
protocol upgrades a whole lot easier.

These app designs pretty quickly become state machines, too. It can be
easier to start out with interlocked queues and state machine than to
try to retrofit this. This having retrofit more than a few state
machines into apps that got way too gnarly.

If there's any chance the other end of the connection is untrusted,
parsing gets vastly more difficult.

COBOL will be more involved, as it doesn't do pointers at all well, and
the designs I tend to use are rather more dynamic.
--
Pure Personal Opinion | HoffmanLabs LLC
Jan-Erik Söderholm
2021-09-21 21:06:42 UTC
Reply
Permalink
Post by Stephen Hoffman
Post by Jan-Erik Söderholm
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
In no particular order...
Start with chapters 6 and 8 in the first VSI Programming Concepts Manual.
Memory sync and AST operations details.
All data shared between mainline and AST must be atomic-accessed, or must
be protected by atomic operations, or some other locking.
I thought of not re-queing the QIO until the current data had been
processed. That way there will not be any new AST until the whole
appliation is ready for that, right?
Post by Stephen Hoffman
The AST can arrive between pretty much any two hardware instructions within
any code sequence, or is best assumed to arrive at the least opportune
moment. Including within an unaligned variable read, or within a multi-part
update operation such as an un-interlocked queue update.
My thought was to only queue an QIO when I know the application is ready.
Post by Stephen Hoffman
Interlocked bitflags or interlocked queues are commonly used to avoid these
races. There are other ways too, though these interlocked operations tend
to be fast and fairly lightweight. These were VAX hardware instructions,
and are now available as C built-ins and as LIBRTL calls.  Calls to $SETAST
can be used to brute-force block AST activity.
For cases processing async I/O such as this, an app design maintaining a
set of two or sometimes three queues is fairly common. The mainline
hibernates, if it doesn't have something to do. One queue pre-populated at
startup and used as a free list of data structures available for use, one
queue of data structures from mainline to AST, and one for structures AST
to mainline. The interlocked queues avoid issues with variable tearing, and
with race conditions. The structures can also contain the IOSB, the data
buffer, the interlocked queue headers, and whatever other data is required.
Make the number of buffers pre-allocated programmable, and add some
instrumentation for when the free list is exhausted. It's absolutely
possible to dynamically add some structures when the freel queue s empty,
at the cost of some added complexity.
Use two unidirectional mailboxes whenever mailbox message traffic is
bidirectional. One reader, one or more writers, for each of the two
mailboxes. Don't try to multiplex a mailbox. That way leads to gnarly.
Always have a scheduled timer AST or (locally preferable) have a scheduled
wakeup call operating in the background, triggering a routine that
processes the queues every ten or thirty or minute, on the off chance an
AST or event flag gets lost somewhere. This happens more often than any of
us would prefer, and the scheduled wakeup. This so that the AST issues a
$wake, and the mainline loops and does its processing and eventually issues
a $hiber when the work-pending queue is empty. Once started, the mainline
initializes the queues and queues the ASTs, then hibernates. The ASTs
arrive as the I/O completions arrive, and each can trigger a wakeup call
and can shuffle buffers among the interlocked queues and can also re-queue
the I/O operation for the next I/O operation. And the scheduled wakeup call
masks any lost wakeup calls, at minimal cost. (Wakes are coalesced into
one, and I've worked with a few app designs where a wake was occasionally
lost.)
For a few of these app cases I've used global sections for app control,
sometimes lock manager doorbell locks, sometimes controlled activity
through signals, sometimes a management mailbox pair, and it's often
possible to pass management commands into the app through the mailbox.
Most of the above I do not understand. But keep it in mind if there
is some scenario where it seems to fit in.
Post by Stephen Hoffman
Protect the mailboxes against unauthorized access correctly, and there can
be protocol design cases where looking at the PID of the message sender can
be necessary.
All access to the mailbox (both "ends") are from our own code.
Post by Stephen Hoffman
You will want to consider including some sort of a protocol version within
the mailbox message traffic too, as that can makes message protocol
upgrades a whole lot easier.
Good idea.
Post by Stephen Hoffman
These app designs pretty quickly become state machines, too. It can be
easier to start out with interlocked queues and state machine than to try
to retrofit this. This having retrofit more than a few state machines into
apps that got way too gnarly.
If there's any chance the other end of the connection is untrusted, parsing
gets vastly more difficult.
All access to the mailbox (both "ends") are from our own code.
Post by Stephen Hoffman
COBOL will be more involved, as it doesn't do pointers at all well, and the
designs I tend to use are rather more dynamic.
Good for you. Our application build environment is Cobol based.
Stephen Hoffman
2021-09-21 21:33:56 UTC
Reply
Permalink
Post by Jan-Erik Söderholm
Post by Stephen Hoffman
Post by Jan-Erik Söderholm
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
In no particular order...
Start with chapters 6 and 8 in the first VSI Programming Concepts
Manual. Memory sync and AST operations details.
All data shared between mainline and AST must be atomic-accessed, or
must be protected by atomic operations, or some other locking.
I thought of not re-queing the QIO until the current data had been
processed. That way there will not be any new AST until the whole
appliation is ready for that, right?
I prefer to have the AST requeue the $io_perform or $qio. Let the
mainline dequeue and process the arriving messages.
Post by Jan-Erik Söderholm
Post by Stephen Hoffman
The AST can arrive between pretty much any two hardware instructions
within any code sequence, or is best assumed to arrive at the least
opportune moment. Including within an unaligned variable read, or
within a multi-part update operation such as an un-interlocked queue
update.
My thought was to only queue an QIO when I know the application is ready.
You're seemingly trying to create a sync design with async tools.
Enqueue the pending work onto the queue and $wake the mainline and let
it churn out dequeues and processing. The AST does is enqueue the
finished $io_perform or $qio onto the AST-to-mainline queue, tickle the
$wake for the mainline, deallocates a buffer from the free queue, and
re-queues the buffer and the $io_perform or $qio AST. This as this
style of async coding on OpenVMS best gets out of AST mode and back to
the mainline expeditiously.

if you want to do that style of sorta-kinda async coding that you seem
to be envisioning, queue the $io_perform or $qio and keep going on
whatever in the mainline, and then $synch on the event flag (EFN$C_ENF)
when the mainline has gotten as far as it can go without the completion.
Post by Jan-Erik Söderholm
Post by Stephen Hoffman
Interlocked bitflags or interlocked queues are commonly used to avoid
these races. There are other ways too, though these interlocked
operations tend to be fast and fairly lightweight. These were VAX
hardware instructions, and are now available as C built-ins and as
LIBRTL calls.  Calls to $SETAST can be used to brute-force block AST
activity.
For cases processing async I/O such as this, an app design maintaining
a set of two or sometimes three queues is fairly common. The mainline
hibernates, if it doesn't have something to do. One queue pre-populated
at startup and used as a free list of data structures available for
use, one queue of data structures from mainline to AST, and one for
structures AST to mainline. The interlocked queues avoid issues with
variable tearing, and with race conditions. The structures can also
contain the IOSB, the data buffer, the interlocked queue headers, and
whatever other data is required.
Make the number of buffers pre-allocated programmable, and add some
instrumentation for when the free list is exhausted. It's absolutely
possible to dynamically add some structures when the freel queue s
empty, at the cost of some added complexity.
Use two unidirectional mailboxes whenever mailbox message traffic is
bidirectional. One reader, one or more writers, for each of the two
mailboxes. Don't try to multiplex a mailbox. That way leads to gnarly.
Always have a scheduled timer AST or (locally preferable) have a
scheduled wakeup call operating in the background, triggering a routine
that processes the queues every ten or thirty or minute, on the off
chance an AST or event flag gets lost somewhere. This happens more
often than any of us would prefer, and the scheduled wakeup. This so
that the AST issues a $wake, and the mainline loops and does its
processing and eventually issues a $hiber when the work-pending queue
is empty. Once started, the mainline initializes the queues and queues
the ASTs, then hibernates. The ASTs arrive as the I/O completions
arrive, and each can trigger a wakeup call and can shuffle buffers
among the interlocked queues and can also re-queue the I/O operation
for the next I/O operation. And the scheduled wakeup call masks any
lost wakeup calls, at minimal cost. (Wakes are coalesced into one, and
I've worked with a few app designs where a wake was occasionally lost.)
For a few of these app cases I've used global sections for app control,
sometimes lock manager doorbell locks, sometimes controlled activity
through signals, sometimes a management mailbox pair, and it's often
possible to pass management commands into the app through the mailbox.
Most of the above I do not understand. But keep it in mind if there is
some scenario where it seems to fit in.
Like how OO changes perceptions/abstractions around how data and code
is packaged and accessed within an app, using ASTs is a different way
of thinking about program control.

See chapters 6 and 8 in the Programming Concepts manual for memory
considerations. I'd expect to get bit otherwise, and—having followed
the path you're on—what's biting will be hard to find.

While I'm thinking about it, add some embedded logging into the app,
particularly around the comms. Make sure it can be enabled dynamically,
if it's not defaulted to enabled.
Post by Jan-Erik Söderholm
Post by Stephen Hoffman
Protect the mailboxes against unauthorized access correctly, and there
can be protocol design cases where looking at the PID of the message
sender can be necessary.
All access to the mailbox (both "ends") are from our own code.
Yeah. I've heard that before. You still want to protect the mailboxes
against unauthorized access, etc. Even if it's just some sap having
gotten loose in production with a debug tool, or a wrong-tool-version.
Post by Jan-Erik Söderholm
Post by Stephen Hoffman
You will want to consider including some sort of a protocol version
within the mailbox message traffic too, as that can makes message
protocol upgrades a whole lot easier.
Good idea.
Post by Stephen Hoffman
These app designs pretty quickly become state machines, too. It can be
easier to start out with interlocked queues and state machine than to
try to retrofit this. This having retrofit more than a few state
machines into apps that got way too gnarly.
If there's any chance the other end of the connection is untrusted,
parsing gets vastly more difficult.
All access to the mailbox (both "ends") are from our own code.
I once assumed that was the case, too.
Post by Jan-Erik Söderholm
Post by Stephen Hoffman
COBOL will be more involved, as it doesn't do pointers at all well, and
the designs I tend to use are rather more dynamic.
Good for you. Our application build environment is Cobol based.
You had stated that you had C, and that you wanted an async design. C
handles tasks such as async network communications and dynamic memory
allocation rather better than does COBOL. COBOL just doesn't do dynamic
memory allocation all that well, prior to 2002.
--
Pure Personal Opinion | HoffmanLabs LLC
Hein RMS van den Heuvel
2021-09-24 14:48:55 UTC
Reply
Permalink
Post by Jan-Erik Söderholm
Hi.
http://computer-programming-forum.com/48-cobol/b75d8c5fdd43048e.htm
This does work fine as an example. But what are the options to get
some data back to the main program (called "x" in the example)
from the ast program (called "ast_routine" in the example)?
I have tried different versions of global, external and so on, but
no luck so far. How to get "x" and "ast_routine" to share some data?
Anything similar to an COMMON area in Fortran?
External should have worked - it applies to a whole 01 'record structure' and can have integers, number, text in any any grouping.

If you have access to a server with DECforms installed - or at least the HELP structure you can find a detailed COBOL + AST example in the files FORMS$EXAMPLE:forms$demo_timer*.COB
Post by Jan-Erik Söderholm
The idea is to have an AST routine that will read from a mailbox when
something is written to it. My idea was that the read of the mailbox
would be using an AST to avoid polling the mailbox.
This is to have a command input to detached processes to get them to
reload the config, repoen the log file, close and exit and so on.
You received a bunch of answers, mostly over the top - insque and the works.
Sure that allows (and is required) for a solid solution but adds no value here.

Just have the AST routing plunk a command in shared 'external' memory.
Initialize with 'moves spaces'.
Have the main loop test for non-spaces
If found - log, interpret, execute, and set back spaces.
In the AST routine you _might_ want test that the shared command buffer is indeed set to spaces before moving in a new command.

Hope this helps,
Hein
Andrew Commons
2021-09-29 09:12:20 UTC
Reply
Permalink
I did this many years ago in MACRO32.

The main program set up two queues:

(a) An empty work queue
(b) A buffer queue primed with some arbitrary number of buffers.

The queues were managed using INSQUE/REMQUE.

Main pulls a buffer from the buffer queue, QIOs the mailbox with AST
routine with queue headers as AST param, then $HIBERs.

On wake it pulls buffer from the work queue and processes it putting the
buffer on the end of the free queue when done. Loop until work is
empty then $HIBER.

The AST routine puts the filled buffer on the end of the work queue,
pulls a buffer from the free queue, QIOs the mailbox, $WAKE, and returns.

Volume was low so didn't have to worry about running out of buffers

The LIB$ routines give you access to the instructions so this should
be possible in COBOL.
Stephen Hoffman
2021-09-29 17:18:13 UTC
Reply
Permalink
Post by Andrew Commons
I did this many years ago in MACRO32.
...
The queues were managed using INSQUE/REMQUE.
INSQUE and REMQUE are interruptable. Best use equivalent the
interlocked queue operations INSQ*I and REMQ*I. Which are not.

I've used this AST design for SCADA work, and in various other
projects, and it has worked well. I'd use KP Threads now, but ASTs were
then what was.
--
Pure Personal Opinion | HoffmanLabs LLC
Andrew Commons
2021-09-30 01:01:44 UTC
Reply
Permalink
Post by Stephen Hoffman
INSQUE and REMQUE are interruptable. Best use equivalent the
interlocked queue operations INSQ*I and REMQ*I. Which are not.
The distinction between the instructions is the type of queue they handle.

From the manual:

"Both INSQUE and REMQUE are implemented as noninterruptible instructions."
Stephen Hoffman
2021-09-30 01:51:25 UTC
Reply
Permalink
Post by Andrew Commons
Post by Stephen Hoffman
INSQUE and REMQUE are interruptable. Best use equivalent the
interlocked queue operations INSQ*I and REMQ*I. Which are not.
The distinction between the instructions is the type of queue they handle.
"Both INSQUE and REMQUE are implemented as noninterruptible instructions."
Yeah, you're right. INSQUE and REMQUE are non-interruptible within the
context of a single processor. But they're concurrent within the
context of a multiprocessor. And with no visibility within the
multiprocessor memory caching. Which in aggregate leads to some
hard-to-debug surprises.

See chapters 5 and 6 for a start:
https://vmssoftware.com/docs/VSI_PROGRAM_CONCEPTS_VOL_I.pdf

Also scrounge up a copy of EL-00032-00 DEC Standard 32, and see section
3.8 (page 3-95ff) and chapter 7 (e.g. section 7.1.4, using interlocks
to prevent the corruption of shared data ):

http://www.bitsavers.org/pdf/dec/vax/archSpec/EL-00032-00-decStd32_Jan90.pdf


If your app code stays strictly on one processor and forever avoids
concurrent access to the structures within an SMP system, you can get
away with INSQUE and REMQUE.

Just as soon as the queue becomes shared across processors (KP threads,
multiprocessing), not so much.

I've chased enough of these sync bugs over the years that I'll usually
avoid REMQUE and INSQUE in preference for using INSQHI, INSQTI, REMQHI,
REMQTI, etc.

Another advantage of using INSQHI, INSQTI, REMQHI, REMQTI, etc, is
relative addressing, which means any process or global sections
involved can be mapped at different address ranges in different
processes. Which is really handy.
--
Pure Personal Opinion | HoffmanLabs LLC
Dave Froble
2021-09-30 02:33:50 UTC
Reply
Permalink
Post by Stephen Hoffman
Post by Andrew Commons
Post by Stephen Hoffman
INSQUE and REMQUE are interruptable. Best use equivalent the
interlocked queue operations INSQ*I and REMQ*I. Which are not.
The distinction between the instructions is the type of queue they handle.
"Both INSQUE and REMQUE are implemented as noninterruptible
instructions."
Yeah, you're right. INSQUE and REMQUE are non-interruptible within the
context of a single processor. But they're concurrent within the context
of a multiprocessor. And with no visibility within the multiprocessor
memory caching. Which in aggregate leads to some hard-to-debug surprises.
Yeah, multi-processors, and multi-cores, really changes the game. Some
concepts from the single CPU era just don't work too well anymore.
--
David Froble Tel: 724-529-0450
Dave Froble Enterprises, Inc. E-Mail: ***@tsoft-inc.com
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Lee Gleason
2021-09-30 02:43:42 UTC
Reply
Permalink
Post by Andrew Commons
Post by Stephen Hoffman
INSQUE and REMQUE are interruptable. Best use equivalent the
interlocked queue operations INSQ*I and REMQ*I. Which are not.
The distinction between the instructions is the type of queue they handle.
"Both INSQUE and REMQUE are implemented as noninterruptible instructions."
Perhaps he didn't mean non-interruptible - he meant that INSQUE and
REMQUE are not multiprocessor safe, and INSQ*I and REMQ*I are. BY
multiprocessor safe, I mean they can be used in a multiprocessor
environment without additional means of synchronization of access.

--
Lee K. Gleason N5ZMR
Control-G Consultants
***@comcast.net

Loading...