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]
3 REPLIES 3
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".