hp.com home products and services support and drivers solutions how to buy
cd-rom home
End of Jump to page title
HP OpenVMS systems
documentation

Jump to content


HP OpenVMS Programming Concepts Manual

HP OpenVMS Programming Concepts Manual


Previous Contents Index

4.8 Synchronizing Programs by Specifying a Time for Program Execution

You can synchronize timed program execution in the following ways:

4.8.1 Obtaining the System Time

The process control procedures that allow you to synchronize timed program execution require you to supply a system time value.

You can use either system services or RTL routines for obtaining and reading time. They are summarized in Table 4-10. With these routines, you can determine the system time, convert it to an external time, and pass a time back to the system. The system services use the operating system's default date format. With the RTL routines, you can use the default format or specify your own date format. However, if you are just using the time and date for program synchronization, using the operating system's default format is probably sufficient.

When using the RTL routines to change date/time formats, initialization routines are required. Refer to the HP OpenVMS RTL Library (LIB$) Manual for more information.

See Chapter 27 for a further discussion of using timing operations with the operating system.

Table 4-10 Time Manipulation System Services and Routines
Routine Description
SYS$GETTIM Obtains the current date and time in 64-bit binary format
SYS$NUMTIM Converts system date and time to numeric integer values
SYS$ASCTIM Converts an absolute or delta time from 64-bit system time format to an ASCII string
SYS$ASCUTC Converts an absolute time from 128-bit Coordinated Universal Time (UTC) format to an ASCII string
LIB$SYS_ASCTIM Converts binary time to an ASCII string
SYS$BINTIM Converts a date and time from ASCII to system format
SYS$BINUTC Converts an ASCII string to an absolute time value in the 128-bit UTC format
SYS$FAO Converts a binary value into an ASCII character string in decimal, hexadecimal, or octal notation and returns the character string in an output string
SYS$GETUTC Returns the current time in 128-bit UTC format
SYS$NUMUTC Converts an absolute 128-bit binary time into its numeric components. The numeric components are returned in local time
SYS$TIMCON Converts 128-bit UTC to 64-bit system format or 64-bit system format to 128-bit UTC based on the value of the convert flag
LIB$ADD_TIMES Adds two quadword times
LIB$CONVERT_DATE_STRING Converts an input date/time string to an operating system internal time
LIB$CVT_FROM_INTERNAL_TIME Converts internal time to external time
LIB$CVTF_FROM_INTERNAL_TIME Converts internal time to external time (F-floating value)
LIB$CVT_TO_INTERNAL_TIME Converts external time to internal time
LIB$CVTF_TO_INTERNAL_TIME Converts external time to internal time (F-floating value)
LIB$CVT_VECTIM Converts 7-word vector to internal time
LIB$DAY Obtains offset to current day from base time, in number of days
LIB$DATE_TIME Obtains the date and time in user-specified format
LIB$FORMAT_DATE_TIME Formats a date and/or time for output
LIB$FREE_DATE_TIME_CONTEXT Frees date/time context
LIB$GET_DATE_FORMAT Returns the user's specified date/time input format
LIB$GET_MAXIMUM_DATE_LENGTH Returns the maximum possible length of an output date/time string
LIB$GET_USERS_LANGUAGE Returns the user's selected langauge
LIB$INIT_DATE_TIME_CONTEXT Initializes the date/time context with a user-specified format
LIB$SUB_TIMES Subtracts two quadword times

4.8.1.1 Executing a Program at a Specified Time

To execute a program at a specified time, use LIB$SPAWN to create a process that executes a command procedure containing two commands---the DCL command WAIT and the command that invokes the desired program. Because you do not want the parent process to remain in hibernation until the process executes, execute the process concurrently.

You can also use the SYS$CREPRC system service to execute a program at a specified time. However, because a process created by SYS$CREPRC hibernates rather than terminates after executing the desired program, HP recommends you use the LIB$SPAWN routine unless you need a detached process.

Example 4-14 executes a program at a specified delta time. The parent program prompts the user for a delta time, equates the delta time to the symbol EXECUTE_TIME, and then creates a subprocess to execute the command procedure LATER.COM. LATER.COM uses the symbol EXECUTE_TIME as the parameter for the WAIT command. (You might also allow the user to enter an absolute time and have your program change it to a delta time by subtracting the current time from the specified time. Chapter 27 discusses time manipulation.)

Example 4-14 Executing a Program Using Delta Time

! Delta time 
CHARACTER*17 TIME 
INTEGER LEN 
! Mask for LIB$SPAWN 
INTEGER*4 MASK 
 
! Declare status and library routine 
INTEGER STATUS, LIB$SPAWN 
 
! Get delta time 
STATUS = LIB$GET_INPUT (TIME, 
2                       'Time (delta): ', 
2                       LEN) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
! Equate symbol to TIME 
STATUS = LIB$SET_SYMBOL ('EXECUTE_TIME', 
2                        TIME(1:LEN)) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
! Set the mask and call LIB$SPAWN 
MASK = IBSET (MASK,0)            ! Execute subprocess concurrently 
STATUS = LIB$SPAWN('@LATER', 
2                  'DATA84.IN', 
2                  'DATA84.RPT', 
2                  MASK) 
 
END 

LATER.COM

$ WAIT 'EXECUTE_TIME' 
$ RUN SYS$DRIVE0:[USER.MATH]CALC                              
$ DELETE/SYMBOL EXECUTE_TIME 

4.8.1.2 Executing a Program at Timed Intervals

To execute a program at timed intervals, you can use either LIB$SPAWN or SYS$CREPRC.

Using LIB$SPAWN

Using 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. Because you do not want the parent process to remain in hibernation until the subprocess executes, execute the subprocess concurrently. See Section 4.8.1.1 for an example of LIB$SPAWN.

Using SYS$CREPRC

Using SYS$CREPRC, create a detached process to execute a program at timed intervals as follows:

  1. Create and hibernate a process---Use SYS$CREPRC to create a process that executes the desired program. Set the PRC$V_HIBER bit of the stsflg argument of the SYS$CREPRC system service to indicate that the created process should hibernate before executing the program.
  2. Schedule a wakeup call for the created subprocess---Use the SYS$SCHDWK system service to specify the time at which the system should wake up the subprocess, and a time interval at which the system should repeat the wakeup call.

Example 4-15 executes a program at timed intervals. The program creates a subprocess that immediately hibernates. (The identification number of the created subprocess is returned to the parent process so that it can be passed to SYS$SCHDWK.) The system wakes up the subprocess at 6:00 a.m. on the 23rd (month and year default to system month and year) and every 10 minutes thereafter.

Example 4-15 Executing a Program at Timed Intervals

! SYS$CREPRC options and values 
INTEGER OPTIONS 
EXTERNAL PRC$V_HIBER 
! ID of created subprocess 
INTEGER CR_ID 
! Binary times 
INTEGER TIME(2), 
2       INTERVAL(2) 
   .
   .
   .
! Set the PRC$V_HIBER bit in the OPTIONS mask and 
! create the process 
OPTIONS = IBSET (OPTIONS, %LOC(PRC$V_HIBER)) 
STATUS = SYS$CREPRC (CR_ID,         ! PID of created process 
2                    'CHECK',       ! Image 
2                    ,,,,, 
2                    'SLEEP',       ! Process name 
2                    %VAL(4),       ! Priority 
2                    ,, 
2                    %VAL(OPTIONS)) ! Hibernate 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
! Translate 6:00 a.m. (absolute time) to binary 
STATUS = SYS$BINTIM ('23-- 06:00:00.00', ! 6:00 a.m. 
2                    TIME) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
! Translate 10 minutes (delta time) to binary 
STATUS = SYS$BINTIM ('0 :10:00.00',      ! 10 minutes 
2                    INTERVAL) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
! Schedule wakeup calls 
STATUS = SYS$SCHDWK (CR_ID,         ! ID of created process 
2                    , 
2                    TIME,          ! Initial wakeup time 
2                    INTERVAL)      ! Repeat wakeup time 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
   .
   .
   .

4.8.2 Placing Entries in the System Timer Queue

When you use the system timer queue, you use the timer expiration to signal when a routine is to be executed. It allows the caller to request a timer that will activate sometime in the future. The timer is requested for the calling kernel thread. When the timer activates, the event is reported to that thread. It does not affect any other thread in the process.

For the actual signal, you can use an event flag or AST. With this method, you do not need a separate process to control program execution. However, you do use up your process's quotas for ASTs and timer queue requests.

Use the system service SYS$SETIMR to place a request in the system timer queue. The format of this service is as follows:

SYS$SETIMR ([efn] ,daytim ,[astadr] ,[reqidt] ,[flags])

Specifying the Starting Time

Specify the absolute or delta time at which you want the program to begin execution using the daytim argument. Use the SYS$BINTIM system service to convert an ASCII time to the binary system format required for this argument.

Signaling Timer Expiration

Once the system has reached this time, the timer expires. To signal timer expiration, set an event flag in the efn argument or specify an AST routine to be executed in the astadr argument. Refer to Section 6.8 and Chapter 8 for more information about using event flags and ASTs.

How Timer Requests Are Identified

The reqidt argument identifies each system time request uniquely. Then, if you need to cancel a request, you can refer to each request separately.

To cancel a timer request, use the SYS$CANTIM system service.

4.9 Controlling Kernel Threads and Process Execution

You can control kernel threads and process execution in the following ways:

4.9.1 Process Hibernation and Suspension

There are two ways to halt the execution of a kernel thread or process temporarily:

The kernel thread can continue execution normally only after a corresponding Wake from Hibernation (SYS$WAKE) system service (if it is hibernating), or after a Resume Process (SYS$RESUME) system service, if it is suspended.

Suspending or hibernating a kernel thread puts it into a dormant state; the thread is not deleted.

A process in hibernation can control itself; a process in suspension requires another process to control it. Table 4-11 compares hibernating and suspended processes.

Table 4-11 Process Hibernation and Suspension
Hibernation Suspension
Can cause only self to hibernate. Can suspend self or another process, depending on privilege; suspends all threads associated with the specified process.
Reversed by SYS$WAKE/SYS$SCHDWK system service. Reversed by SYS$RESUME system service.
Interruptible; can receive ASTs. Noninterruptible; cannot receive ASTs 1.
Can wake self. Cannot cause self to resume.
Can schedule wake up at an absolute time or at a fixed time interval. Cannot schedule resumption.


1If a process is suspended in kernel mode (a hard suspension), it cannot receive any ASTs. If a process is suspended at supervisor mode (a soft suspension), it can receive executive or kernel mode ASTs. See the description of SYS$SUSPND in the HP OpenVMS System Services Reference Manual: GETUTC--Z.

Table 4-12 summarizes the system services and routines that can place a process in or remove a process from hibernation or suspension.

Table 4-12 System Services and Routines Used for Hibernation and Suspension
Routine Function
Hibernating Processes
SYS$HIBER Places the requesting kernel thread in the hibernation state. An AST can be delivered to the thread while it is hibernating. The service puts only the calling thread into HIB; no other thread is affected.
SYS$WAKE Resumes execution of a kernel thread in hibernation. This service wakes all hibernating kernel threads in a process regardless of the caller. Any thread that is not hibernating when the service is called is marked wake pending. Because of the wake pending, the next call to SYS$HIBER completes immediately and the thread does not hibernate. Premature wakeups must be handled in the code.
SYS$SCHDWK Resumes execution of a kernel thread in hibernation at a specified time. This service schedules a wakeup request for a thread that is about to call SYS$HIBER. The wakeup affects only the requesting thread; any other hibernating kernel threads are not affected.
LIB$WAIT Uses the services SYS$SCHDWK and SYS$HIBER.
SYS$CANWAK Cancels a scheduled wakeup issued by SYS$SCHDWK. Unless called with a specific timer request ID, this service cancels all timers for all threads in the process regardless of the calling thread.
Suspended Kernel Threads and Processes
SYS$SUSPEND Puts in a suspended state all threads associated with the specified process.
SYS$RESUME Puts in an execution state all threads of the specified process.

4.9.1.1 Using Process Hibernation

The hibernate/wake mechanism provides an efficient way to prepare an image for execution and then to place it in a wait state until it is needed.

If you create a subprocess that must execute the same function repeatedly and must execute immediately when it is needed, you could use the SYS$HIBER and SYS$WAKE system services, as shown in the following example:


/* Process TAURUS */ 
 
#include <stdio.h> 
#include <descrip.h> 
 
main() { 
 
        unsigned int status; 
        $DESCRIPTOR(prcnam,"ORION");                
        $DESCRIPTOR(image,"COMPUTE.EXE"); 
 
/* Create ORION */                      
        status = SYS$CREPRC(0,                (1)        /* Process id */ 
                            &image,                       /* Image */ 
                            0, 0, 0, 0, 0, 
                            &prcnam,                      /* Process name */ 
                            0, 0, 0, 0); 
        if ((status & 1) != 1) 
                LIB$SIGNAL(status); 
   .
   .
   .
/* Wake ORION */ 
        status = SYS$WAKE(0, &prcnam);          (2)
        if ((status & 1) != 1) 
                LIB$SIGNAL(status); 
   .
   .
   .
/* Wake ORION again */ 
        status = SYS$WAKE(0, &prcnam); 
        if ((status & 1) != 1) 
                LIB$SIGNAL(status); 
   .
   .
   .
} 
 
/* Process ORION and image COMPUTE */ 
 
#include <stdio.h> 
#include <ssdef.h> 
   .
   .
   .
sleep: 
        status = SYS$HIBER();                  (3)
        if ((status & 1) != 1) 
                LIB$SIGNAL(status); 
   .
   .
   .
        goto sleep; 
} 

  1. Process TAURUS creates the process ORION, specifying the descriptor for the image named COMPUTE.
  2. At an appropriate time, TAURUS issues a SYS$WAKE request for ORION. ORION continues execution following the SYS$HIBER service call. When it finishes its job, ORION loops back to repeat the SYS$HIBER call and to wait for another wakeup.
  3. The image COMPUTE is initialized, and ORION issues the SYS$HIBER system service.

The Schedule Wakeup (SYS$SCHDWK) system service, a variation of the SYS$WAKE system service, schedules a wakeup for a hibernating process at a fixed time or at an elapsed (delta) time interval. Using the SYS$SCHDWK service, a process can schedule a wakeup for itself before issuing a SYS$HIBER call. For an example of how to use the SYS$SCHDWK system service, see Chapter 27.

Hibernating processes can be interrupted by asynchronous system traps (ASTs), as long as AST delivery is enabled. The process can call SYS$WAKE on its own behalf in the AST service routine, and continue execution following the execution of the AST service routine. For a description of ASTs and how to use them, see Chapter 8.

4.9.1.2 Using Alternative Methods of Hibernation

You can use two additional methods to cause a process to hibernate:

When you use the SYS$CREPRC system service, the creating process can control when to wake the created process. When you use the RUN command, its qualifiers control when to wake the process.

If you use the /INTERVAL qualifier and the image to be executed does not call the SYS$HIBER system service, the image is placed in a state of hibernation whenever it issues a return instruction (RET). Each time the image is awakened, it begins executing at its entry point. If the image does call SYS$HIBER, each time it is awakened it begins executing at either the point following the call to SYS$HIBER or at its entry point (if it last issued a RET instruction).

If wakeup requests are scheduled at time intervals, the image can be terminated with the Delete Process (SYS$DELPRC) or Force Exit (SYS$FORCEX) system service, or from the command level with the STOP command. The SYS$DELPRC and SYS$FORCEX system services are described in Section 4.9.3.4 and in Section 4.9.4. The RUN and STOP commands are described in the HP OpenVMS DCL Dictionary.

These methods allow you to write programs that can be executed once, on request, or cyclically. If an image is executed more than once in this manner, normal image activation and termination services are not performed on the second and subsequent calls to the image. Note that the program must ensure both the integrity of data areas that are modified during its execution and the status of opened files.


Previous Next Contents Index