Operating System - OpenVMS
cancel
Showing results for 
Search instead for 
Did you mean: 

"Odd" DEC C Compiler Behaviour, or "vaguely expected"? (OVMS/VAX v6.2, DEC C v5.5-002)

 
Mark_Corcoran
Frequent Advisor

"Odd" DEC C Compiler Behaviour, or "vaguely expected"? (OVMS/VAX v6.2, DEC C v5.5-002)

I made some code changes to add new functionality that would alert us to someone resting a heavy object on a VT terminal on the shop floor (the process normally only reads a manual-override serial number, and when input is received from the VT, it causes a $CANCEL to be issued for any in-flight communications with the PLC;  leaving a heavy object on the VT keyboard causes all communications with the PLC to stop working until the object is removed).

The change involved detecting excessive input within a threshold time period, then generating an OPCOM message to suitable-enabled terminals and generation of an email message.

After this, it would enter a guard/backoff period where a $QIO to read from the terminal would not be issued ($SETIMR to set a timer to expire after the guard period, then the AST service routine would clear a flag that an outer level routine relied on, reset the count of input from the terminal, then call $WAKE so that the outer level routine would carry on after the $HIBER that it issued).

I found that the process was remaining in a $HIBER state, and I thought that perhaps the delta timer I specified was incorrect (extracting a per-process user-configurable value, using $BINTIM to convert, checking if it is an absolute/delta time, then using LIB$SUB_TIMES to compare it against minimum & maximum values, and doing the same again for a system-wide value if a per-process value isn't specified).

I eventually determined that no timer was being set in the first place, and it all came down to the way that the parameters for $SETIMR were passed (and not checking the return status as there was no expectation that the values passed to it were invalid).

The call to $SETIMR was in the following form:
SYS$SETIMR(0, delta_time_variable, ast_service_routine, 0, 0) ;

When I did eventually check the return status, it was 12 decimal - SS$_ACCVIO

I looked at other code that I knew worked (because I have seen those timers been set to wait whilst an SS$_ABORT or SS$_HANGUP has occurred, to prevent the process thrashing in an infinite I/O loop when the target port or server of the LAT port is not reachable or set to Access: Remote), and I couldn't understand how it was working.


A comparison of the CC /LIST /MACHINE_CODE=INTERSPERSED between the two revealed a difference, and some time later I realised that the bigger difference was how the quadword was defined.

In the working code, it was stored as unsigned int delta_time_variable[2], whereas in non-working code, it was this:

typedef struct quadword_struct
{
   unsigned long int hi_part ;
   unsigned long int lo_part ;
} QUADWORD ;

QUADWORD delta_time_variable ;


A small reproducer (TEST.C) follows:


#include <descrip>
#include <stdio>
#include <starlet>

typedef struct quadword_struct
{
   unsigned long int hi_part ;
   unsigned long int lo_part ;
} QUADWORD ;


void timer_function(void) ;


int main(int argc, char *argv[])
{
   int result ;
   unsigned long int bintim1[2] ;
   QUADWORD bintim2 ;
   $DESCRIPTOR(delta_desc, "0 00:05:00.00") ;

   /*
        Forward declaration of system services in starlet are
        in lower case; use upper case here and get a
        %CC-I-IMPLICITFUNC informational on compilation...
   */
   sys$bintim(&delta_desc, &bintim1) ;
   sys$bintim(&delta_desc, &bintim2) ;
   result = sys$setimr(0, bintim1, timer_function, 0, 0) ;
   printf("\nResult of $SETIMR #1=%d", result) ;
   result = sys$setimr(0, bintim2, timer_function, 0, 0) ;
   printf("\nResult of $SETIMR #2=%d", result) ;
   result = sys$setimr(0, &bintim2, timer_function, 0, 0) ;
   printf("\nResult of $SETIMR #3=%d", result) ;
   return (1) ;
}


void timer_function(void)
{
   printf("\nTimer has expired") ;
}

$ CC TEST.C /LIST /MACHINE=INTER
$ LINK TEST.OBJ
$ RUN TEST

Result of $SETIMR #1=1
Result of $SETIMR #2=12
Result of $SETIMR #3=1

Extrapolating the Macro-32 for the $SETIMR calls from the .LIS file:

result = sys$setimr(0, bintim1, timer_function, 0, 0) ;
              7E 7C 00B4 clrq -(sp)
 58 00000000* EF DE 00B6 moval TIMER_FUNCTION,r8
              58 DD 00BD pushl r8
           F0 AD 9F 00BF pushab -16(fp)
              00 DD 00C2 pushl #0
 57 00000000* EF DE 00C4 moval SYS$SETIMR,r7
           67 05 FB 00CB calls #5,(r7)

result = sys$setimr(0, bintim2, timer_function, 0, 0) ;
              7E 7C 00DE clrq -(sp)
              58 DD 00E0 pushl r8
           5E 08 C2 00E2 subl2 #8,sp
     6E E8 AD 08 28 00E5 movc3 #8,-24(fp),(sp)
              00 DD 00EA pushl #0
           67 06 FB 00EC calls #6,(r7)

result = sys$setimr(0, &bintim2, timer_function, 0, 0) ;
              7E 7C 00F8 clrq -(sp)
              58 DD 00FA pushl r8
           E8 AD 9F 00FC pushab -24(fp)
              00 DD 00FF pushl #0
           67 05 FB 0101 calls #5,(r7)

I generally strive to avoid Macro-32 where possible (other than writing some code to jump over other instructions and use PATCH to modify an executable, it's been "some time" since I last used Macro-32 / Macro-11, and even then I wasn't regularly programming in it).

So, my Macro-32 might be a little rusty, but the P1/first argument to the generated CALLS instruction appears to be the number of arguments, and in the failing $SETIMR call, the C compiler has added an extra parameter beyond that accepted by $SETIMR (though I suspect it is the SUBL2 or MOVC3 that helps trigger the SS$_ACCVIO when an attempt is made to dereference the address placed on the stack).

Is it just me, or does this behaviour seem odd (yes, I know, you get what you deserve if you don't test return status and don't prefix the variable name with the ampersand)?

On a related note, when I was writing the code, I had got it into my head from somewhere that the top bit of the quadword would indicate whether or not a time was a delta time (the docs say that delta times are negative, but it seems that the top longword is set to %XFFFFFFFF, which is what I'm checking to see if the user-configurable threshold & backoff time values are absolute (after all, don't want to set a timer that expires in 10 years'time)).

Is there a pictorial explanation of the bit fields of a quadword time somewhere? (I have looked in the programming concepts manuals, and a scanned (non-searchable) copy of the IDS book, and nothing readily stands out)

Or perhaps an alternative way of determining if a binary quadword time is a delta time beyond comparing the high word with FFFFFFFF?

 

Mark

[Formerly appearing as woeisme]
6 REPLIES 6
Steven Schweda
Honored Contributor

Re: "Odd" DEC C Compiler Behaviour, or "vaguely expected"? (OVMS/VAX v6.2, DEC C

> [...] does this behaviour seem odd [...]

   I've managed to avoid even looking at VAX Macro for decades.

> [...] I had got it into my head from somewhere that the top bit of the
> quadword would indicate whether or not a time was a delta time [...]

   Perhaps from the HELP?:

         [...] The daytim argument is the 64-
         bit address (on Alpha and Integrity server systems) of a quadword
         time value. A positive time value specifies an absolute time
         at which the timer expires; a negative time value specifies an
         offset (delta time) from the current time.

> [...] it seems that the top longword is set to %XFFFFFFFF, [...]

   "seems"?  "top longword"?

   printf( "\n bt2.hi = 0x%08x, bt2.lo = 0x%08x.\n",
    bintim2.hi_part, bintim2.lo_part);

 bt2.hi = 0x4d2fa200, bt2.lo = 0xffffffff.

   These systems are little-endian, you know.  I'd expect the "lo" part
to come first.

> Is there a pictorial explanation of the bit fields of a quadword time
> somewhere? [...]

   "bit fields"?  What's to picture?  It's the number of ticks of some
size (100ns?) since some epoch or other, isn't it?

      https://en.wikipedia.org/wiki/OpenVMS#Timekeeping

> [...] comparing the high word with FFFFFFFF?

   I'd look at the sign bit, not all 32 bits.

H.Becker
Honored Contributor

Re: "Odd" DEC C Compiler Behaviour, or "vaguely expected"? (OVMS/VAX v6.2, DEC C

The daytim argument is quadword, read only, by (64-bit) reference. As the MACRO32 code shows, bintim1 is passed as address (pushab -16(fp)), where bintim2 is passed as quadword (movc3 #8,-24(fp),(sp)). Simply said, you have to use "sys$setimr(0, &bintim2, timer_function, 0, 0) ;"

Steven Schweda
Honored Contributor

Re: "Odd" DEC C Compiler Behaviour, or "vaguely expected"? (OVMS/VAX v6.2, DEC C

   And, speaking of bit fields...

> result = sys$setimr(0, bintim1, timer_function, 0, 0) ;
> printf("\nResult of $SETIMR #1=%d", result) ;

   "%d"?  A VMS status code, which actually has bit fields, would be a
good place for a format like, say, "%%x%08x".

Mark_Corcoran
Frequent Advisor

Re: "Odd" DEC C Compiler Behaviour, or "vaguely expected"? (OVMS/VAX v6.2, DEC C

>Simply said, you have to use "sys$setimr(0, &bintim2, timer_function, 0, 0) ;"
Indeed.  The post was more concerned with the compiler specifying a parameter count that exceeded the number of parameters that $SETIMR accepts.

After increasing the number of longwords in the QUADWORD structure to 3, the compiler increased the parameter count to 2 more than the maximum number of parameters accepted by $SETIMR.

I see what it's doing, though I don't necessarily agree with that part of its behaviour when the ampersand is omitted.

[Formerly appearing as woeisme]
Mark_Corcoran
Frequent Advisor

Re: "Odd" DEC C Compiler Behaviour, or "vaguely expected"? (OVMS/VAX v6.2, DEC C

>> [...] it seems that the top longword is set to %XFFFFFFFF, [...]
> "seems"?

> "top longword"?

>"bit fields"? What's to picture?

This is not Usenet in the early 1990s, I'm not posting from AOL.COM, and I'm not a NOOB that hasn't undertaken any research before posting my query.

There are a number of posts to this forum by one-time posters, who are often new to OpenVMS (as a result of development/coding being outsourced & offshored).

They often do themselves no favours by not adequately describing the background, context, versions of software, commands issued or exact error messages received.

You frequently respond to them in the same truculent/sardonic/snide manner.

Do you really feel that this is acceptable behaviour in a public electronic forum? Or the workplace?

Prospective employers and customers (in the context of offering consulting services) can and do search out postings to social media & other forums before making decisions, so aside from putting off the thinner-skinned posters and lurkers, you're likely not doing yourself any favours.


>> [...] it seems that the top longword is set to %XFFFFFFFF, [...]
> "seems"?
Given that I hadn't performed a $BINTIM for all ~86.4bn delta time values (and then examined the resulting quadword value), I didn't consider it acceptable to state that it is always set to FFFFFFFF.

> "top longword"?
Because I had (wrongly) effectively assumed Big-Endian (because I had long since forgotten; maybe your memory is perfect - mine, alas, is not).

>And, speaking of bit fields...
>"%d"? A VMS status code, which actually has bit fields, would be a good place for a format like, say, "%%x%08x".
>>A small reproducer (TEST.C) follows:
Let me rephrase. A small reproducer created solely for the purpose of exhibiting the problem, not an excerpt which is extracted from the actual production code.

For the purposes of the test reproducer, having the returned condition value displayed in decimal or hexadecimal is neither here nor there:

$ EXIT 12
%SYSTEM-F-ACCVIO, access violation, reason mask=00, virtual address=0000000C, PC=0000000C, PSL=00000000

$ EXIT %X0000000C
%SYSTEM-F-ACCVIO, access violation, reason mask=00, virtual address=0000000C, PC=0000000C, PSL=00000000


Consequently, in the context of the test reproducer, I really don't care about the control bits, the facility number bits, the message number bits, or the severity bits.

In actual production code, I do however tend to output it as an 8-character hexadecimal string with a %X prefix.

But thank you for taking the time to critique.




[Formerly appearing as woeisme]
H.Becker
Honored Contributor

Re: "Odd" DEC C Compiler Behaviour, or "vaguely expected"? (OVMS/VAX v6.2, DEC C


@Mark_Corcoran wrote:

>Simply said, you have to use "sys$setimr(0, &bintim2, timer_function, 0, 0) ;"
Indeed.  The post was more concerned with the compiler specifying a parameter count that exceeded the number of parameters that $SETIMR accepts.

After increasing the number of longwords in the QUADWORD structure to 3, the compiler increased the parameter count to 2 more than the maximum number of parameters accepted by $SETIMR.

I see what it's doing, though I don't necessarily agree with that part of its behaviour when the ampersand is omitted.


That's the way how structures are passed by value.

And it is an effect of having/using no real prototypes. In a current starlet.h (unless __NEW_STARLET is defined) there is int sys$setimr(__unknown_params); where __unknown_params is "#define"d as nothing. Whether you can define/use the new starlet feature in your environment, I don't know. If it is defined, in a current environment you will see %CC-E-NOCONVERT, In this statement, "bintim2" is of type "struct quadword_struct", and cannot be converted to "long pointer to struct _generic_64". along with other warnings.