Document revision date: 30 March 2001
[Compaq] [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]
[OpenVMS documentation]

OpenVMS Programming Concepts Manual


Previous Contents Index

27.3.3 Setting the Current Time with SYS$SETIME

The Set System Time (SYS$SETIME) system service allows a user with the operator (OPER) and logical I/O (LOG_IO) privileges to set the current system time. You can specify a new system time (using the timadr argument), or you can recalibrate the current system time using the processor's hardware time-of-year clock (omitting the timadr argument). If you specify a time, it must be an absolute time value; a delta time (negative) value is invalid.

The system time is set whenever the system is bootstrapped. Normally you do not need to change the system time between system bootstrap operations; however, in certain circumstances you may want to change the system time without rebooting. For example, you might specify a new system time to synchronize two processors, or to adjust for changes between standard time and Daylight Savings Time. Also, you may want to recalibrate the time to ensure that the system time matches the hardware clock time (the hardware clock is more accurate than the system clock).

The DCL command SET TIME calls the SYS$SETIME system service.

If a process issues a delta time request and then the system time is changed, the interval remaining for the request does not change; the request executes after the specified time has elapsed. If a process issues an absolute time request and the system time is changed, the request executes at the specified time, relative to the new system time.

The following example shows the effect of changing the system time on an existing timer request. In this example, two set timer requests are scheduled: one is to execute after a delta time of 5 minutes and the other specifies an absolute time of 9:00.


 
 
#include <stdio.h> 
#include <descrip.h> 
#include <ssdef.h> 
#include <stdlib.h> 
 
void gemini (int x); 
unsigned int status; 
 
/* Buffers to receive binary times */ 
struct { 
        unsigned int buff1, buff2; 
}abs_binary, delta_binary; 
 
 
main() { 
        $DESCRIPTOR(abs_time,"-- 19:37:00.00");         /* 9 am absolute time */ 
        $DESCRIPTOR(delta_time,"0 :00:30");             /* 5-min delta time */ 
 
        /* Convert ASCII absolute time to binary format */ 
        status = SYS$BINTIM( &abs_time,         /* ASCII absolute time */ 
                                &abs_binary);   /* Converted to binary */ 
 
        if (status == SS$_NORMAL) 
        { 
                status = SYS$SETIMR(0,          /* efn - event flag */ 
                                 &abs_binary,   /* daytim - expiration time */ 
                                 &gemini,       /* astadr - AST routine */ 
                                 1,             /* reqidt - timer request id */ 
                                 0);            /* flags */ 
                if (status == SS$_NORMAL) 
                        printf("Setting system timer A\n");                     
        }               
        else    
                LIB$SIGNAL( status ); 
 
        /* Convert ASCII delta time to binary format */ 
        status = SYS$BINTIM( &delta_time,               /* ASCII delta time */ 
                                &delta_binary);         /* Converted to binary */ 
        if (status == SS$_NORMAL) 
        { 
                printf("Converting delta time to binary format\n"); 
                status = SYS$SETIMR(0,          /* efn - event flag */ 
                                &delta_binary,  /* daytim - expiration time */ 
                                &gemini,        /* astadr - AST routine */ 
                                2,              /* reqidt - timer request id */ 
                                0);             /* flags */ 
 
                if (status == SS$_NORMAL) 
                        printf("Setting system timer B\n");                     
                else 
                        LIB$SIGNAL( status ); 
        } 
        else 
                        LIB$SIGNAL( status ); 
 
        status = SYS$HIBER(); 
} 
 
 
void gemini (int  reqidt) { 
 
        unsigned short outlen; 
        unsigned int cvtflg=1; 
        char timenow[12]; 
        char fao_str[80]; 
        $DESCRIPTOR(nowdesc, timenow); 
        $DESCRIPTOR(fao_in, "Request ID !UB answered at !AS"); 
        $DESCRIPTOR(fao_out, fao_str); 
 
/* Returns and converts the current time */ 
        status = SYS$ASCTIM( 0,         /* timlen - length of ASCII string */ 
                        &nowdesc,       /* timbuf - receives ASCII string */ 
                        0,              /* timadr - time value to convert */ 
                        cvtflg);        /* cvtflg - conversion flags */ 
        if ((status & 1) != 1) 
                LIB$SIGNAL( status ); 
 
/* Receives the formatted output string */ 
        status = SYS$FAO(&fao_in,       /* srcstr - control FAO string */ 
                        &outlen,        /* outlen - length in bytes */ 
                        &fao_out,       /* outbuf - output buffer */ 
                        reqidt,         /* p1 - param needed for 1st FAO dir */ 
                        &nowdesc);      /* p2 - param needed for 2nd FAO dir */ 
        if ((status & 1) != 1) 
                LIB$SIGNAL( status ); 
 
        status = LIB$PUT_OUTPUT( &fao_out ); 
 
        return;  
 
} 
 
 

The following example shows the output received from the preceding program. Assume the program starts execution at 8:45. Seconds later, the system time is set to 9:15. The timer request that specified an absolute time of 9:00 executes immediately, because 9:00 has passed. The request that specified a delta time of 5 minutes times out at 9:20.


$ SHOW TIME
   30-DEC-1993 8:45:04.56                       +----------------------+ 
$ RUN SCORPIO                                   | operator sets system | 
<-----------------------------------------------| time to 9:15         | 
Request ID number 1 executed at 09:15:00.00     +----------------------+ 
Request ID number 2 executed at 09:20:00.02 
$

27.4 Routines Used for Timer Requests

This section presents information about setting and canceling timer requests, and scheduling and canceling wakeups. Since many applications require the scheduling of program activities based on clock time, the operating system allows an image to schedule events for a specific time of day or after a specified time interval. For example, you can use timer system services to schedule, convert, or cancel events. For example, you can use the timer system services to do the following:

Table 27-4 describes system services that set, cancel, and schedule timer requests.

Table 27-4 Timer System Services
Timer System Service Routine Function
SYS$SETIMR Sets the timer to expire at a specified time. This service sets a per-thread timer.
SYS$CANTIM Cancels all or a selected subset of the Set Timer requests previously issued by the current image executing in a process. This service cancels all timers associated with the process.
SYS$SCHDWK Schedules the awakening (restarting) of a kernel thread that has placed itself in a state of hibernation with the Hibernate (SYS$HIBER) service.
SYS$CANWAK Removes all scheduled wakeup requests for a process from the timer queue, including those made by the caller or by other processes. The Schedule Wakeup ($SCHDWK) service makes scheduled wakeup requests.

27.4.1 Setting Timer Requests with SYS$SETIMR

Timer requests made with the Set Timer (SYS$SETIMR) system service are queued; that is, they are ordered for processing according to their expiration times. The quota for timer queue entries (TQELM quota) controls the number of entries a process can have pending in this timer queue.

When you call the SYS$SETIMR system service, you can specify either an absolute time or a delta time value. Depending on how you want the request processed, you can specify either or both of the following:

Optionally, you can specify a request identification for the timer request. You can use this identification to cancel the request, if necessary. The request identification is also passed as the AST parameter to the AST service routine, if one is specified, so that the AST service routine can identify the timer request.

Example 27-2 and Example 27-3 show timer requests using event flags and ASTs, respectively. Event flags, event flag services, and ASTs are described in more detail in Chapter 8.

Example 27-2 Setting an Event Flag

#include <stdio.h> 
#include <ssdef.h> 
#include <descrip.h> 
 
/* Buffer to receive binary time */ 
struct { 
        unsigned int buff1, buff2; 
}b30sec; 
 
main() { 
        
        unsigned int efn = 4,status; 
        $DESCRIPTOR(a30sec,"0 00:00:30.00"); 
 
/* Convert time to binary format */ 
        status = SYS$BINTIM( &a30sec, /* timbuf - ASCII time */ 
                             &b30sec);/* timadr - binary time */ 
        if ((status & 1) != 1) 
                LIB$SIGNAL( status ); 
        else 
                printf("Converting ASCII to binary time...\n"); 
 
/* Set timer to wait */ 
        status = SYS$SETIMR( efn, /* efn - event flag */ 
                          &b30sec,/* daytim - binary time */ 
                          0,      /* astadr - AST routine */ 
                          0,      /* reqidt - timer request */ 
                          0);     /* flags */        (1)
        if ((status & 1) != 1) 
                LIB$SIGNAL( status ); 
        else 
                printf("Request event flag be set in 30 seconds...\n"); 
 
/* Wait 30 seconds */ 
        status = SYS$WAITFR( efn );                         (2)
        if ((status & 1) != 1) 
                LIB$SIGNAL( status ); 
        else 
                printf("Timer expires...\n"); 
 
} 

  1. The call to SYS$SETIMR requests that event flag 4 be set in 30 seconds (expressed in the quadword B30SEC).
  2. The Wait for Single Event Flag (SYS$WAITFR) system service places the process in a wait state until the event flag is set. When the timer expires, the flag is set and the process continues execution.

Example 27-3 Specifying an AST Service Routine

#include <stdio.h> 
#include <descrip.h> 
 
#define NOON 12 
 
struct { 
        unsigned int buff1, buff2; 
}bnoon; 
 
/* Define the AST routine */ 
 
void astserv( int ); 
 
main() { 
        unsigned int status, reqidt=12; 
        $DESCRIPTOR(anoon,"-- 12:00:00.00"); 
 
/* Convert ASCII time to binary */ 
        status = SYS$BINTIM(&anoon,     /* timbuf - ASCII time */   (1)
                            &bnoon);    /* timadr - binary time buffer */ 
        if((status & 1) != 1) 
                LIB$SIGNAL( status ); 
        else 
                printf("Converting ASCII to binary...\n"); 
 
/* Set timer */ 
        status = SYS$SETIMR(0,                  /* efn - event flag */ (2)
                            &bnoon,             /* daytim - timer expiration */ 
                            &astserv,           /* astadr - AST routine */ 
                            reqidt,             /* reqidt - timer request id */ 
                            0);                 /* cvtflg - conversion flags */ 
        if((status & 1) != 1) 
                LIB$SIGNAL( status ); 
        else 
                printf("Setting timer expiration...\n"); 
 
        status = SYS$HIBER(); 
 
} 
 
void astserv( int astprm ) {                                     (3)
 
/* Do something if it's a "noon" request */ 
        if (astprm == NOON) 
                printf("This is a noon AST request\n"); 
        else 
                printf("Handling some other request\n"); 
 
        status = SYS$SCHDWK(0, /* pidadr - process id */ 
                        0);/* prcnam - process name */ 
 
        return; 
} 
 

  1. The call to SYS$BINTIM converts the ASCII string representing 12:00 noon to format. The value returned in BNOON is used as input to the SYS$SETIMR system service.
  2. The AST routine specified in the SYS$SETIMR request will be called when the timer expires, at 12:00 noon. The reqidt argument identifies the timer request. (This argument is passed as the AST parameter and is stored at offset 4 in the argument list. See Chapter 8.) The process continues execution; when the timer expires, it is interrupted by the delivery of the AST. Note that if the current time of day is past noon, the timer expires immediately.
  3. This AST service routine checks the parameter passed by the reqidt argument to determine whether it must service the 12:00 noon timer request or another type of request (identified by a different reqidt value). When the AST service routine completes, the process continues execution at the point of interruption.

27.4.2 Canceling a Timer Request with SYS$CANTIM

The Cancel Timer Request (SYS$CANTIM) system service cancels timer requests that have not been processed. The SYS$CANTIM system service removes the entries from the timer queue. Cancellation is based on the request identification given in the timer request. For example, to cancel the request illustrated in Example 27-3, you would use the following call to SYS$CANTIM:


        unsigned int status, reqidt=12; 
   .
   .
   .
        status = SYS$CANTIM( reqidt, 0); 

If you assign the same identification to more than one timer request, all requests with that identification are canceled. If you do not specify the reqidt argument, all your requests are canceled.

27.4.3 Scheduling Wakeups with SYS$WAKE

Example 27-2 shows a process placing itself in a wait state using the SYS$SETIMR and SYS$WAITFR services. A process can also make itself inactive by hibernating. A process hibernates by issuing the Hibernate (SYS$HIBER) system service. Hibernation is reversed by a wakeup request, which can be put into effect immediately with the SYS$WAKE system service or scheduled with the Schedule Wakeup (SYS$SCHDWK) system service. For more information about the SYS$HIBER and SYS$WAKE system services, see Chapter 4.

The following example shows a process scheduling a wakeup for itself prior to hibernating:


#include <stdio.h> 
#include <descrip.h> 
 
struct { 
        unsigned int buff1, buff2; 
}btensec; 
 
main() { 
 
        unsigned int status; 
        $DESCRIPTOR(atensec,"0 00:00:10.00"); 
 
/* Convert time */ 
        status = SYS$BINTIM(&atensec, /* timbuf - ASCII time */ 
                            &btensec);/* timadr - binary time */ 
        if ((status & 1 ) != 1) 
                LIB$SIGNAL( status ); 
 
/* Schedule wakeup */ 
        status = SYS$SCHDWK(0, /* pidadr - process id */ 
                            0, /* prcnam - process name */ 
                            &btensec, /* daytim - wake up time */ 
                            0); /* reptim - repeat interval */ 
        if ((status & 1 ) != 1) 
                LIB$SIGNAL( status ); 
 
/* Sleep ten seconds */ 
        status = SYS$HIBER(); 
        if ((status & 1 ) != 1) 
                LIB$SIGNAL( status ); 
} 

Note that a suitably privileged process can wake or schedule a wakeup request for another process; thus, cooperating processes can synchronize activity using hibernation and scheduled wakeups. Moreover, when you use the SYS$SCHDWK system service in a program, you can specify that the wakeup request be repeated at fixed time intervals. See Chapter 4 for more information on hibernation and wakeup.

27.4.4 Canceling a Scheduled Wakeup with SYS$CANWAK

You can cancel scheduled wakeup requests that are pending but have not yet been processed with the Cancel Wakeup (SYS$CANWAK) system service. This service cancels a wakeup request for a specific kernel thread, if a process ID is specified. If a process name is specified, then the initial thread's wakeup request is canceled.

The following example shows the scheduling of wakeup requests for the process CYGNUS and the subsequent cancellation of the wakeups. The SYS$SCHDWK system service in this example specifies a delta time of 1 minute and an interval time of 1 minute; the wakeup is repeated every minute until the requests are canceled.


#include <stdio.h> 
#include <descrip.h> 
 
/* Buffer to hold one minute */ 
 
struct { 
        unsigned int buff1, buff2; 
}interval; 
 
main() { 
 
        unsigned int status; 
        $DESCRIPTOR(one_min,"0 00:01:00.00");  /* One minute delta */ 
        $DESCRIPTOR(cygnus, "CYGNUS");          /* Process name */ 
 
/* Convert time to binary */ 
        status = SYS$BINTIM(&one_min,   /* timbuf - ASCII delta time */ 
                           &interval);  /* timadr - Buffer to hold binary time */ 
        if((status & 1) != 1) 
                LIB$SIGNAL( status ); 
        else 
                printf("Converting time to binary format...\n"); 
 
/* Schedule wakeup */   
        status = SYS$SCHDWK(0,          /* pidadr - process id */ 
                            &cygnus,    /* prcnam - process name */ 
                            &interval,  /* daytim - time to be awakened */ 
                            &interval); /* reptim - repeat interval */ 
        if((status & 1) != 1) 
                LIB$SIGNAL( status ); 
        } 
        else 
                printf("Scheduling wakeup...\n"); 
 
        /* Cancel wakeups */ 
        status = SYS$CANWAK(0,                  /* pidadr - process id */ 
                            &cygnus);           /* prcnam - process name */ 
 
} 

27.4.5 Executing a Program at Timed Intervals

To execute a program at timed intervals, you can use either the LIB$SPAWN routine or the SYS$CREPRC system service. With LIB$SPAWN, you can create a subprocess that executes a command procedure containing three commands: the DCL command WAIT, the command that invokes the desired program, and a GOTO command that directs control back to the WAIT command. To prevent the parent process from remaining in hibernation until the subprocess executes, you should execute the subprocess concurrently; that is, you should specify CLI$M_NOWAIT.

For more information about using LIB$SPAWN and SYS$CREPRC, see Chapter 4.

27.5 Routines Used for Timer Statistics

This section presents information about the LIB$INIT_TIMER, LIB$SHOW_TIMER, LIB$STAT_TIMER, and LIB$FREE_TIMER routines. By calling these run-time library routines, you can collect the following timer statistics from the system:

Following are descriptions of each routine:

You must invoke LIB$INIT_TIMER to allocate storage for the timer. You should invoke LIB$FREE_TIMER before you exit from your program unit. In between, you can invoke LIB$SHOW_TIMER or LIB$STAT_TIMER, or both, as often as you want. Example 27-4 invokes LIB$SHOW_TIMER and uses a user-written subprogram either to display the statistics or to write them to a file.

Example 27-4 Displaying and Writing Timer Statistics

   .
   .
   .
! Timer arguments 
INTEGER*4 TIMER_ADDR, 
2         TIMER_DATA, 
2         TIMER_ROUTINE 
EXTERNAL  TIMER_ROUTINE 
! Declare library procedures as functions 
INTEGER*4 LIB$INIT_TIMER, 
2         LIB$SHOW_TIMER 
EXTERNAL  LIB$INIT_TIMER, 
2         LIB$SHOW_TIMER 
! Work variables 
CHARACTER*5 REQUEST 
INTEGER*4   STATUS 
! User request - either WRITE or FILE 
INTEGER*4   WRITE, 
2           FILE 
PARAMETER  (WRITE = 1, 
2           FILE = 2) 
! Get user request 
WRITE (UNIT=*, FMT='($,A)') ' Request: ' 
ACCEPT *, REQUEST 
IF (REQUEST .EQ. 'WRITE') TIMER_DATA = WRITE 
IF (REQUEST .EQ. 'FILE') TIMER_DATA = FILE 
! Set timer 
STATUS = LIB$INIT_TIMER (TIMER_ADDR) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
   .
   .
   .
! Get statistics 
STATUS = LIB$SHOW_TIMER (TIMER_ADDR,, 
2                        TIMER_ROUTINE, 
2                        TIMER_DATA) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
   .
   .
   .
! Free timer 
STATUS = LIB$FREE_TIMER (TIMER_ADDR) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
   .
   .
   .
INTEGER FUNCTION TIMER_ROUTINE (STATS, 
2                               TIMER_DATA) 
! Dummy arguments 
CHARACTER*(*) STATS 
INTEGER TIMER_DATA 
! Logical unit number for file 
INTEGER STATS_FILE 
! User request 
INTEGER WRITE, 
2       FILE 
PARAMETER (WRITE = 1, 
2          FILE = 2) 
! Return code 
INTEGER SUCCESS, 
2       FAILURE 
PARAMETER (SUCCESS = 1, 
2          FAILURE = 0) 
! Set return status to success 
TIMER_ROUTINE = SUCCESS 
! Write statistics or file them in STATS.DAT 
IF (TIMER_DATA .EQ. WRITE) THEN 
  TYPE *, STATS 
ELSE IF (TIMER_DATA .EQ. FILE) THEN 
  CALL LIB$GET_LUN (STATS_FILE) 
  OPEN (UNIT=STATS_FILE, 
2       FILE='STATS.DAT') 
  WRITE (UNIT=STATS_FILE, 
2        FMT='(A)') STATS 
ELSE 
  TIMER_ROUTINE = FAILURE 
END IF 
END 

You can use the SYS$GETSYI system service to obtain more detailed system information about boot time, the cluster, processor type, emulated instructions, nodes, paging files, swapping files, and hardware and software versions. With SYS$GETQUI and LIB$GETQUI, you can obtain queue information.


Previous Next Contents Index

  [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]  
  privacy and legal statement  
5841PRO_073.HTML