Operating System - OpenVMS
1753448 Members
6115 Online
108794 Solutions
New Discussion юеВ

Re: 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