Operating System - OpenVMS
1828032 Members
1658 Online
109973 Solutions
New Discussion

AST routine and C language va_count, va_start, va_end, etc

 
Mark Daniel_2
Frequent Advisor

AST routine and C language va_count, va_start, va_end, etc

This is a copy of a post I have made on c.o.v.
(I hope the ITRC interface doesn't mangle it too much. I guess I'll see in a moment. Hmmm, in the preview it's not too bad - no monospace, which makes code examples difficult. Here goes.)

> I would like to use the C langauge va_count() in a function to distinguish between direct and AST use of the function. For example:
>
> myFunction (int a1, int, a2, int a3) {
> int argcount;
> va_count (argcnt)
> if (argcnt == 3) {
> /* direct call behaviour */
> }
> else {
> /* AST call behaviour */
> }
> }
>
> The idea being with all direct calls three arguments are always supplied but with an AST only the one (the user parameter).
>
> Is this usage of va_count() valid? TIA.

I have subsequently discovered that va_count() often reports an argument count of 4 (for the above example). That is, it often reports the maximum number of arguments ever directly called plus one (I've checked through the code for obvious call error). This is always in user AST delivery mode and the only explanation that springs to mind is when an AST routine calls it directly. I cannot explain the four arguments otherwise.

Can anyone offer an explanation for this behaviour or describe how va_count() works (for the Alpha platform in this case if that is relevant - I see the macro uses a builtin)? TIA.

PS. Any opinions on whether the HP ITRC fora are better than c.o.v. for technical queries? ("duck and cover")
14 REPLIES 14
Hein van den Heuvel
Honored Contributor

Re: AST routine and C language va_count, va_start, va_end, etc

Hmmm,

Best I know, and confirmed by the OpenVMS Programming concepts in chapter: "8.7.1 The AST Service Routine" an AST routine is called with 5 arguments: AST Parameter, R0, R1, PC, PS

Why don't you do your self a favour and create a minor shell say my_function_ast which calls my_function, either just passing on the ast argument or that argument and two recognizable other arguments to indicate the context.

Btw.. I always test this stuff with SYS$DCLAST.

hth,
Hein.

Mark Daniel_2
Frequent Advisor

Re: AST routine and C language va_count, va_start, va_end, etc

(Muses: hmmm, taking a while to get used to this ITRC interface.)

>Best I know, and confirmed by the OpenVMS
>Programming concepts in chapter: "8.7.1 The
>AST Service Routine" an AST routine is called
>with 5 arguments: AST Parameter, R0, R1, PC,
>PS

va_count() usually only indicates 1 with an AST (and 3 directly, and sometimes 3+1 with the AST) for the example. I'm assuming the register arguments are 'internal' to the VMS calling standard (I'm no internals expert).

>Why don't you do your self a favour and
>create a minor shell say my_function_ast
>which calls my_function, either just passing
>on the ast argument or that argument and two
>recognizable other arguments to indicate the
>context.

This has been suggested to me before. I could. It seems like unnecessary clutter though (the OCD in me) if the context can be recognised by something intrinsic (like the call stack) rather than something extrinsic like a flag. The is also the (small) consideration of the extra layer of overhead (one function calling another). VMS has enough layering.

>Btw.. I always test this stuff with SYS$DCLAST.

This (real, not example) routine is called directly from within another AST routine and then by AST so the libary routines for detecting and controlling AST mode are not appropriate here. Everything's happening in a single kernel thread at user mode AST. It's network I/O where the routine can be called to initiate the I/O and then continue it over multiple chunks (due in part to the 65k $QIO limit). The approach I'm trying to use here just seems very elegant for such a general purpose ... 'n' parameters to initiate, 1 (or whatever) to continue the I/O.
Robert Gezelter
Honored Contributor

Re: AST routine and C language va_count, va_start, va_end, etc

Mark,

Before this goes too far, how about everybody check and report which version of the compiler they are using.

I don't have a citation handy, but I seem to recall something about argument counts that I encountered recently. My vague recollection is that it involved variable length parameter lists, not the difference between AST and process level.

- Bob Gezelter, http://www.rlgsc.com
Mark Daniel_2
Frequent Advisor

Re: AST routine and C language va_count, va_start, va_end, etc

Compaq C V6.5-001 on OpenVMS Alpha V7.3-2

I can imagine the counting mechanism being modified between releases but if I pass six arguments to a function in V5.n I'd hope it would tell me there were six and that I wouldn't need to change the constant from four to eight when I updated to V6.n :-)
Bojan Nemec
Honored Contributor

Re: AST routine and C language va_count, va_start, va_end, etc

Mark,

I try to compile yours example (Alpha VMS 7.2 , C 6.4) with the /LIS/MACRO/NOOPTIMIZE qualifiers. First the routine homes the the argument count, this is done by

AND R25, 255, R25
...
STL R25, 8(FP)

Note that R25 is the argument count register in the alpha VMS calling standard and 255 is the maximum number of arguments. After that the arguments are homed. va_count macro does this:

LDL R0, 8(FP)
STL R0, argcnt

Ok, this is done when you use the /NOOPTIMIZE. With /OPTIMIZE this is optimized but works in a similar way.

When you call the function regulary (myFunction (1,2,3)) you receive 3 for the argcnt. If you use it as an AST routine (for example: sys$setimr (0,&tim,myFunction,0,0)) you receive 5 for the argcnt. If the function is called from another AST routine you will receive 3 (this is the same as calling the function from a non AST function).

If you dont receive these results, it is possible that you somehow rewrite the contents of the stack. Please check the OpenVMS Programming Concepts Manual - Common Mistakes in Asynchronous Programming

http://h71000.www7.hp.com/doc/731FINAL/5841/5841pro_024.html#mistakes_programming

for common mistakes.

Bojan
Mark Daniel_2
Frequent Advisor

Re: AST routine and C language va_count, va_start, va_end, etc

Bojan's test-case got me reappraising. I inserted some more debug points into the code and this is what these have told me. All counts are from va_count() and all are being performed in user-mode AST delivery.

A direct call of the function gives me the expected argument count, 4 in the actual code.

An AST delivery from a completing $QIO gives me a count of 1, again what I'd expect for the single parameter an AST delivery allows, the user data.

An AST delivery from a $DCLAST gives an argument count of 5, with the first the expected AST user data, the second 0x00000001, the third 0x812C8AC0, the fourth 0x80001934, and I don't have the fifth. Under some circumstances the code intercepts the AST delivery from a $QIO, postprocesses it, and then $DCLASTs to the final AST target.

This last one tends to line up with what might be expected from the description in 8.7.1 or Programming Concepts. It begs the question though of why the difference? I (perhaps mis) understood that an AST was an AST was an AST regardless of the source.

If there is a difference in the mechansim or behaviour between services such as $QIO and $DCLAST can someone provide a pointer to the documentation?

Or is this an artifact of the va_count() mechanism?
John Gillings
Honored Contributor

Re: AST routine and C language va_count, va_start, va_end, etc

Hi Mark,

Isn't this exactly what the routine LIB$AST_IN_PROG is for? No arguments just returns a boolean. TRUE if executing at AST level, FALSE otherwise (no point complaining that LIB$ routines are non-portable! ;-)

There's been some discussion in OpenVMS engineering about the "standard" arguments delivered to an AST, with the conclusion that they're not always relevant, useful, or easy to make consistent across all architectures. You may find that, apart from arg 1 (userarg), the number of AST arguments and their semantics might vary between architectures.

On the other hand, I'm quite confident that LIB$AST_IN_PROG will work correctly in all circumstances.
A crucible of informative mistakes
Mark Daniel_2
Frequent Advisor

Re: AST routine and C language va_count, va_start, va_end, etc

Hi John,

good to see your script. Hoping things have settled out for you a little more these days.

>This (real, not example) routine is called
>directly from within another AST routine and
>then by AST so the libary routines for
>detecting and controlling AST mode are not
>appropriate here.

>All counts are from va_count() and all are
>being performed in user-mode AST delivery.

It's *all* happening at AST delivery level. So LIB$AST_IN_PROG would always return TRUE.

>You may find that, apart from arg 1
>(userarg), the number of AST arguments and
>their semantics might vary between
>architectures.

Well that's fairly definitive (in a politician's 'yes' sort of way). Is this caution documented?

What about va_count()? It doesn't really provide the number of function arguments? I guess what 'function arguments' means needs to be defined. I mean it to be the number of native integers (longs or quads I guess) passed to and available for use by the function (this is much the same as the C RTL description). The size doesn't really matter because va_count() tells you how many 'units' of the architecture's call.

If va_count() is unreliable is there another (relatively straight-foward) mechanism I could use in C?

TIA.
John Gillings
Honored Contributor

Re: AST routine and C language va_count, va_start, va_end, etc

Mark,

Having read more of the discussion...

The "standard" 5 AST arguments are (UserArg, R0, R1, PC, PSL) all passed by immediate value. This always made sense on VAX, and that's what you'll get everytime from all possible sources of ASTs. But the meaning got a bit blurred on Alpha, and there are some places where the extra arguments aren't passed (as you've discovered), and other places where they're passed, but aren't actually "correct". Since R0,R1,PC and PSL are all volatile and unpredictable objects, it's difficult to imagine a user program that could depend on "correct" values for all 5 arguments. How would you know? (though perhaps you're presenting one here?).

The arguments are even more meaningless on IA64, and engineering have been debating what to do with them. Why go to the trouble of synthesising a plausible PC when no one can/will ever use it? The extra arguments may be omitted entirely, or passed as zeros. It's also possible that an AST might be invoked with more than 5 arguments. I don't think you can depend on counting arguments as a mechanism for detecting an AST.

I'm not sure I understand your comment:

"is called directly from within another AST routine and then by AST so the libary routines for detecting and controlling AST mode are not appropriate here."

Why not? Why don't you think it will work? LIB$AST_IN_PROG doesn't just mean "was this routine called as an AST" - it means "am I executing at AST level". It's also written so it works in inner mode. A bit surprising for an RTL routine, but it's there in the source.

If you don't want to call a LIBRTL routine, will a system service do? Call SYS$GETJPIW against yourself, requesting JPI$_ASTACT, then interpret the returned bit mask. When in user mode, LIB$AST_IN_PROG uses a shortcut to invoke $GETJPI without a context switch.

The nice thing about using LIB$AST_IN_PROG or $GETJPI to detect AST mode is if you find a case that doesn't work, we can elevate it to engineering and get it fixed. Making assumptions about counting arguments won't hold much weight with engineering. Sorry!
A crucible of informative mistakes
Mark Daniel_2
Frequent Advisor

Re: AST routine and C language va_count, va_start, va_end, etc

Now we're getting closer. Thanks John. I think I've been won-over from c.o.v. (which I did not use as much as would have liked because I can't shake the impression it's basically noise).

My understanding was/is flawed.

>I don't think you can depend on counting
>arguments as a mechanism for detecting an AST.

I saw one user argument available to and delivered by an AST. I confirmed this experimentally (using $QIO). Then it seemed to break (I realize now with $DCLAST). It appears va_count() was never designed with ASTs in mind, which are an internal mechanism and vary over time, architecture and circumstance (I know you'll cut me off when I start to babble here :-)

>I'm not sure I understand your comment:
>
>"is called directly from within another AST
>routine and then by AST so the libary
>routines for detecting and controlling AST
>mode are not appropriate here."

I am still not explaining myself well enough!
(The VMS community should be thankful I'm not a technical writer.)

Nothing is happening in non-AST delivery mode. $HIBER has been invoked (now inside a loop, perhaps you remember my spurious wakes when using $GRANTID? :-) All processing is event-driven. Nothing happens outside of AST delivery routines. All efforts to detect AST mode would return TRUE and even I can perform that code optimisation ;-)

If va_count() cannot be used in an AST context, or it's an inappropriate usage, perhaps that should be documented (to discourage the particularly bloody-minded amongst us)?
Robert Gezelter
Honored Contributor

Re: AST routine and C language va_count, va_start, va_end, etc

John,

I would tend to agree with Mark. While I have always (25 years) written code only using the AST parameter (the first parameter), I intensely dislike features that have very small differences.

Thinking "off the cuff", the different architectural behavior is less troubling than the different source (e.g., QIO, DCLAST, etc.). The uniformity of the AST interface is a great benefit when implementing code and avoiding subtle errors. However, I can make a case that even the architectural bugs detract from the technical cleanliness of the implementation.

If anybody wants to discuss this offline, I would be happy to do so.

- Bob Gezelter, http://www.rlgsc.com
Hein van den Heuvel
Honored Contributor

Re: AST routine and C language va_count, va_start, va_end, etc

So can we then agree that the AST state is irrelevant?
Now then, why would you want to associate an important application state with a largerly irrelevant 'circumstance' through an unclear and possibly unsupported mechanism? You inidicated that would be in a desire to 'save' an entry point name, where the additinal entrypoint would make your code easier to understand and debug. Hmmm...

Your AST argument is the address of a control block / state block is it not?
If it is not, then make it one!
Make your two additional optional/continuation arguments, fields in the control block pointed to by the ast param. Clear them in the initial call setting of the chain of event. Pass the data for the chained events in those fields instead of through arguments. Further clarify that mechanisme with a (redundant) state/phase flag, for example a 'first_part' and 'last_part' flag. (both present for a single short message).

or

stick with the 'wasted words' plan of the one (or two) additions routine name:
your_routine_initial and your_routine
or
your_routine_init_entry, your_routine_cont_entry and your_routine

hth,
Hein.
Mark Daniel_2
Frequent Advisor

Re: AST routine and C language va_count, va_start, va_end, etc

>So can we then agree that the AST state is
>irrelevant?

Always was (as I understand your reference to it). It was always executing in AST delivery.

>Now then, why would you want to associate an
>important application state with a largerly
>irrelevant 'circumstance' through an unclear
>and possibly unsupported mechanism? You
>inidicated that would be in a desire to
>'save' an entry point name, where the
>additinal entrypoint would make your code
>easier to understand and debug. Hmmm...

I must be careful not just to become argumentative over this point (an often counter-productive character trait of mine).

But ... I have a preference for intrinsic mechanisms; extrinsic, such as flags, are always vulnerable to program error. For instance, in a 'normal' program why would you ever use a flag to indicate AST delivery when you have a perfectly valid mechanism for detecting that mode of program execution flow, LIB$AST_IN_PROG, et.al. (except perhaps for efficiency considerations - still that'd be the trade-off).

I saw an opportunity to improve the elegance of my code (at least in my perhaps limited appreciation) by using a mechanism I perceived to be external to my programmatic contrivance. John Gillings explained why that is not the case. Though the variable number of AST parameters is not obvious to the average VMS punter, whether it's one, five or some other magic number.

>Your AST argument is the address of a
>control block / state block is it not?
8< snip 8<

Yes. That and more.

>stick with the 'wasted words' plan of the
>one (or two) additions routine name:
>your_routine_initial and your_routine
8< snip 8<

Historically this has been my approach.

blah_blah()
blah_blah_AST()

Apparently it will be my future history as well (with apologies to Hari Seldon).

My Grandmother used to say, "You can learn something everyday ... if you're not very careful!"

Thankyou for your input to the thread Hein.
Mark Daniel_2
Frequent Advisor

Re: AST routine and C language va_count, va_start, va_end, etc

The consensus is that argument counting is simplistic, not representative of how ASTs are really delivered, and just plain unreliable. I've revised my approach.