Document revision date: 30 March 2001

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

- Schedule the setting of an event flag or the queuing of an asynchronous system trap (AST) for the current process, or cancel a pending request that has not yet been processed
- Schedule a wakeup request for a hibernating process, or cancel a pending wakeup request that has not yet been processed
- Set or recalibrate the current system time, if the caller has the proper user privileges

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:

- The number of an event flag to be set when the time expires. If you do not specify an event flag, the system sets event flag 0.
- The address of an AST service routine to be executed when the time expires.

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:

- Elapsed time---Actual time that has passed since setting a timer
- CPU time---CPU time that has passed since setting a timer
- Buffered I/O---Number of buffered I/O operations that have occurred since setting a timer
- Direct I/O---Number of direct I/O operations that have occurred since setting a timer
- Page faults---Number of page faults that have occurred since setting a timer

Following are descriptions of each routine:

- LIB$INIT_TIMER---Allocates and initializes space for collecting the statistics. You should specify the handle-adr argument as a variable with a value of 0 to ensure the modularity of your program. When you specify the argument, the system collects the information in a specially allocated area in dynamic storage. This prevents conflicts with other timers used by the application.
- LIB$SHOW_TIMER---Obtains one or all of five statistics (elapsed time, CPU time, buffered I/O, direct I/O, and page faults); the statistics are formatted for output. The handle-adr argument must be the same value as specified for LIB$INIT_TIMER (do not modify this variable). Specify the code argument to obtain one particular statistic rather than all the statistics.
  You can let the system write the statistics to SYS$OUTPUT (the default), or you can process the statistics with your own routine. To process the statistics yourself, specify the name of your routine in the action-rtn argument. You can pass one argument to your routine by naming it in the user-arg argument. If you use your own routine, it must be written as an integer function and return an error code (return a value of 1 for success). This error code becomes the error code returned by LIB$SHOW_TIMER. Two arguments are passed to your routine: the first is a passed-length character string containing the formatted statistics, and the second is the value of the fourth argument (if any) specified to LIB$SHOW_TIMER.
- LIB$STAT_TIMER---Obtains one of five unformatted statistics. Specify the statistic you want in the code argument. Specify a storage area for the statistic in value. The handle-adr argument must be the same value as you specified for LIB$INIT_TIMER.
- LIB$FREE_TIMER---Ensures the modularity of your program. Invoke this procedure when you are done with the timer. The value in the handle-adr argument must be the same as that specified for LIB$INIT_TIMER.

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

| privacy and legal statement |
5841PRO_073.HTML