Document revision date: 19 July 1999
[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

5.7.2 Conditions Affecting AST Delivery

When a condition causes an AST to be delivered, the system may not be able to deliver the AST to the process immediately. An AST cannot be delivered under any of the following conditions:

If an AST cannot be delivered when the interrupt occurs, the AST is queued until the conditions disabling delivery are removed. Queued ASTs are ordered by the access mode from which they were declared, with those declared from more privileged access modes at the front of the queue. If more than one AST is queued for an access mode, the ASTs are delivered in the order in which they are queued.

5.7.3 Kernel Threads AST Delivery (Alpha Only)

On Alpha systems with the kernel threads implementation, ASTs are associated with the kernel thread that initiates them, though it is not required that they execute on the thread that initiates them. The use of the kernel thread's PID in the asynchronous system trap control block (ACB) identifies the initiating thread. Associating an ACB with its initiating thread is required; the arrival of an AST is often the event that allows a thread, waiting on a flag or resource, to be made computable.

An AST, for example, may set a flag or make a resource available, and when the AST is completed, the thread continues its execution in non-AST mode and rechecks the wait condition. If the wait condition is satisfied, the thread continues; if not, the thread goes back into the wait queue.

On the other hand, if an AST executes on a kernel thread other than the one that initiated it, then when the AST completes, the kernel thread that initiated the AST must be made computable to ensure that it rechecks a waiting condition that may now be satisfied.

The queuing and delivery mechanisms of ASTs makes a distinction between outer mode ASTs (user and supervisor modes), and inner mode ASTs (executive and kernel modes). This distinction is necessary because of the requirement to synchronize inner mode access.

With the kernel threads implementation, the standard process control block (PCB) AST queues now appear in the kernel thread block (KTB), so that each kernel thread may receive ASTs independently. These queues receive outer mode ASTs, which are delivered on the kernel thread that initiates them. The PCB has a new set of inner mode queues for inner mode ASTs which require the inner mode semaphore. With the creation of multiple kernel threads, inner mode ASTs are inserted in the PCB queues, and are delivered on whichever kernel thread holds the inner mode semaphore. Inner mode ASTs, which are explicitly declared as thread-safe, are inserted in the KTB queues, and are delivered on the kernel thread that initiates them.

If a thread manager declares a user AST callback, then user mode ASTs are delivered to the thread manager. The thread manager then is responsible for determining in what context the AST should be executed.

There are significant programming considerations to be understood when mixing DECthreads with ASTs. For information about using DECthreads with ASTs, see the Guide to DECthreads.

5.7.3.1 Outer Mode (User and Supervisor) Non-Serial Delivery of ASTs

Before kernel threads, AST routine code of a given mode has always been able to assume the following:

Further, before kernel threads, user mode code could safely access data that it knows is only used by other user mode, non-AST level routines without needing any synchronization mechanisms. The underlying assumption is that only one thread of user mode execution exists. If the current code stream is accessing the data, then by implication no other code stream can be accessing it.

After kernel threads, this assumed behavior of AST routines and user mode code is no longer valid. Multiple user-mode, non-AST level code streams can be executing at the same time. The use of any data that can be accessed by multiple user-mode code streams must be modified to become synchronized using the load-locked (LDx_L) and store-conditional (STx_C) instructions, or by using some other synchronization mechanism.

Kernel threads assumes that multiple threads of execution can be active at one time and includes outer mode ASTs. Within any given kernel thread, outer mode ASTs will still be delivered serially. Also, the kernel thread model allows any combination of multiple outer mode threads, or multiple outer mode ASTs. However, outer-mode AST routines, as well as non-AST outer-mode code, has to be aware that any data structure that can be accessed concurrently by outer-mode code, or by any other outer-mode AST must be protected by some form of synchronization.

Before kernel threads, same-mode ASTs executed in the order that they were queued. After kernel threads and within a single kernel thread, that still is true. However, it is not true process-wide. If two ACBs are queued to two different KTBs, whichever is scheduled first executes first. There is no attempt to schedule kernel threads in such a way to correctly order ASTs that have been queued to them. The ASTs execute in any order and can, in fact, execute concurrently.

5.7.3.2 Inner Mode (Executive and Kernel) AST Delivery

Before kernel threads, OpenVMS implemented AST preemptions in inner modes as follows:

After kernel threads, in contrast to the preceeding list, kernel threads delivers any non thread-safe inner mode ASTs to the kernel thread which already owns the semaphore. If no thread currently owns the semaphore when the AST is queued, then the semaphore is acquired in SCH$QAST, and the owner is set to the target kernel thread for that AST. Subsequently queued ASTs see that thread as the semaphore owner and are delivered to that thread. This allows the PALcode and the hardware architecture to process all the AST preemption and ordering rules.

5.8 ASTs and Process Wait States

A process in a wait state can be interrupted for the delivery of an AST and the execution of an AST service routine. When the AST service routine completes execution, the process is returned to the wait state, if the condition that caused the wait is still in effect.

With the exception of suspended waits (SUSP) and suspended outswapped waits (SUSPO), any wait states can be interrupted.

5.8.1 Event Flag Waits

If a process is waiting for an event flag and is interrupted by an AST, the wait state is restored following execution of the AST service routine. If the flag is set at completion of the AST service routine (for example, by completion of an I/O operation), then the process continues execution when the AST service routine completes.

Event flags are described in Section 16.6 in the Chapter 16 chapter.

5.8.2 Hibernation

A process can place itself in a wait state with the Hibernate (SYS$HIBER) system service. This state can be interrupted for the delivery of an AST. When the AST service routine completes execution, the process continues hibernation. The process can, however, "wake" itself in the AST service routine or be awakened by another process or as the result of a timer-scheduled wakeup request. Then, it continues execution when the AST service routine completes.

Process suspension is another form of wait; however, a suspended process cannot be interrupted by an AST. Process hibernation and suspension are described in the Chapter 3 chapter.

5.8.3 Resource Waits and Page Faults

When a process is executing an image, the system can place the process in a wait state until a required resource becomes available, or until a page in its virtual address space is paged into memory. These waits, which are generally transparent to the process, can also be interrupted for the delivery of an AST.

5.9 Examples of Using AST Services


The following is an example of a DEC Fortran program that finds the process identification (PID) number of any user working on a particular disk and delivers an AST to a local routine that notifies the user that the disk is coming down:
#1

 PROGRAM DISK_DOWN 
 ! Implicit none 
 ! Status variable 
 INTEGER STATUS 
 STRUCTURE /ITMLST/ 
  UNION 
   MAP 
    INTEGER*2 BUFLEN, 
 2            CODE 
    INTEGER*4 BUFADR, 
 2            RETLENADR 
   END MAP 
          MAP 
    INTEGER*4 END_LIST 
   END MAP 
  END UNION 
 END STRUCTURE 
 RECORD /ITMLST/ DVILIST(2), 
 2               JPILIST(2) 
 ! Information for GETDVI call 
 INTEGER PID_BUF, 
 2       PID_LEN 
 ! Information for GETJPI call 
 CHARACTER*7 TERM_NAME 
 INTEGER TERM_LEN 
 EXTERNAL DVI$_PID, 
 2        JPI$_TERMINAL 
 ! AST routine and flag 
 INTEGER AST_FLAG 
 PARAMETER (AST_FLAG = 2) 
 EXTERNAL NOTIFY_USER 
 
 INTEGER SYS$GETDVIW, 
 2       SYS$GETJPI, 
 2       SYS$WAITFR 
 
 ! Set up for SYS$GETDVI 
 DVILIST(1).BUFLEN = 4 
 DVILIST(1).CODE   = %LOC(DVI$_PID) 
 DVILIST(1).BUFADR = %LOC(PID_BUF) 
 DVILIST(1).RETLENADR = %LOC(PID_LEN) 
 DVILIST(2).END_LIST = 0 
 ! Find PID number of process using SYS$DRIVE0 
 STATUS = SYS$GETDVIW (, 
 2                     , 
 2                     '_MTA0:',       ! device 
 2                     DVILIST,        ! item list 
 2                     ,,,) 
 IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
 ! Get terminal name and fire AST 
 JPILIST(1).CODE = %LOC(JPI$_TERMINAL) 
 JPILIST(1).BUFLEN = 7 
 JPILIST(1).BUFADR = %LOC(TERM_NAME) 
 JPILIST(1).RETLENADR = %LOC(TERM_LEN) 
 JPILIST(2).END_LIST = 0 
 STATUS = SYS$GETJPI (, 
 2                    PID_BUF,         !process id 
 2                    , 
 2                    JPILIST,         !itemlist 
 2                    , 
 2                    NOTIFY_USER,     !AST 
 2                    TERM_NAME)       !AST arg 
 IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) 
 
 ! Ensure that AST was executed 
 STATUS = SYS$WAITFR(%VAL(AST_FLAG)) 
 IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) 
 END 
 
 
 SUBROUTINE NOTIFY_USER (TERM_STR) 
 ! AST routine that broadcasts a message to TERMINAL 
 ! Dummy argument 
 CHARACTER*(*) TERM_STR 
 CHARACTER*8 TERMINAL 
 INTEGER LENGTH 
 ! Status variable 
 INTEGER STATUS 
 CHARACTER*(*) MESSAGE 
 PARAMETER (MESSAGE = 
 2             'SYS$TAPE going down in 10 minutes') 
 ! Flag to indicate AST executed 
 INTEGER AST_FLAG 
 
 ! Declare system routines 
 INTRINSIC LEN 
 INTEGER  SYS$BRDCST, 
 2        SYS$SETEF 
 EXTERNAL SYS$BRDCST, 
 2        SYS$SETEF, 
 2        LIB$SIGNAL 
 ! Add underscore to device name 
 LENGTH = LEN (TERM_STR) 
 TERMINAL(2:LENGTH+1) = TERM_STR 
 TERMINAL(1:1) = '_' 
 
 ! Send message 
 STATUS = SYS$BRDCST(MESSAGE, 
 2                   TERMINAL(1:LENGTH+1)) 
 IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) 
 ! Set event flag 
 STATUS = SYS$SETEF (%VAL(AST_FLAG)) 
 IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) 
 END 
      

The following is an example of a C program setting up an AST.

2.


#module SETAST "SRH X1.0-000" 
#pragma builtins 
 
/* 
** COPYRIGHT (c) 1992 BY 
** DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS. 
** ALL RIGHTS RESERVED. 
** 
** THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED 
** ONLY  IN  ACCORDANCE  WITH  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE 
** INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR  ANY  OTHER 
** COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY 
** OTHER PERSON.  NO TITLE TO AND  OWNERSHIP OF THE  SOFTWARE IS  HEREBY 
** TRANSFERRED. 
** 
** THE INFORMATION IN THIS SOFTWARE IS  SUBJECT TO CHANGE WITHOUT NOTICE 
** AND  SHOULD  NOT  BE  CONSTRUED  AS A COMMITMENT BY DIGITAL EQUIPMENT 
** CORPORATION. 
** 
** DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE  OR  RELIABILITY OF ITS 
** SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. 
*/ 
 
/* 
**++ 
**  Facility: 
** 
** Examples 
** 
**  Version: V1.0 
** 
**  Abstract: 
** 
** Example of working with the $SETAST call and ASTs. 
** 
**  Author: 
** Steve Hoffman 
** 
**  Creation Date:  1-Jan-1990 
** 
**  Modification History: 
**-- 
*/ 
/* 
 *  AST and $SETAST demo 
 *  raise the AST shields 
 *  request an AST, parameter is 1 
 *  request an AST, parameter is 2 
 *  lower the shields 
 *  <bing1><bing2> 
 */ 
main() 
    { 
    int retstat = 0; 
    int bogus(); 
    int SYS$SETAST(); 
    int SYS$DCLAST(); 
 
    printf("\ndisabling\n"); 
    /* 
     * $SETAST() returns SS$_WASSET and SS$_WASCLR depending 
     * on the previous setting of the AST shield.  Watch out, 
     * SS$_WASSET looks like a SUCCESSFUL SS$_ACCVIO.  (ie: 
     * a debug EXAMINE/COND shows SS$_WASSET as the error 
     * %SYSTEM-S-ACCVIO.  *Real* ACCVIO's never have the "-S-" 
     *  code!) 
     */ 
    retstat = SYS$SETAST( 0 ); 
    printf("\n  disable/ was: %d\n", retstat ); 
 
    retstat = SYS$DCLAST( bogus, 1, 0 ); 
    retstat = SYS$DCLAST( bogus, 2, 0 ); 
    printf("\ndclast %x\n", retstat ); 
 
    printf("\nenabling\n" ); 
    retstat = SYS$SETAST( 1 ); 
 
    /* 
     *  and, since we just lowered the shields, the ASTs should hit 
     *  in here somewhere.... 
     */ 
    printf("\n  enable/ was: %d\n", retstat ); 
 
    return( 1 ); 
    }; 
 
/* 
 *  and, here's the entire, sophisticated, twisted AST code... 
 */ 
bogus( astprm ) 
int astprm; 
    { 
    printf("\nAST tripped.  ast parameter was 0x%x\n\n", astprm); 
    return( 1 ); 
    }; 
 


Chapter 6
System Time Operations

This chapter describes the types of system time operations performed by the operating system. It contains the following sections:

Section 6.1 describes the system time format.

Section 6.2 describes time conversion and date/time manipulation.

Section 6.3 describes how to get the current date and time and set the current time.

Section 6.4 describes how to set and cancel timer requests and how to schedule and cancel wakeups.

Section 6.5 describes using run-time library (RTL) routines to collect timer statistics.

Section 6.6 describes using date/time formatting routines.

Section 6.7 describes the Coordinated Universal Time (UTC) system.

6.1 System Time Format

The operating system maintains the current date and time in 64-bit format. The time value is a binary number in 100-nanosecond (ns) units offset from the system base date and time, which is 00:00 o'clock, November 17, 1858 (the Smithsonian base date and time for the astronomic calendar). Time values must be passed to or returned from system services as the address of a quadword containing the time in 64-bit format. A time value can be expressed as either of the following:

If you specify 0 as the address of a time value, the operating system supplies the current date and time.

6.1.1 Absolute Time Format

The operating system uses the following format for absolute time. The full date and time require a character string of 23 characters. The punctuation is required.

dd-MMM-yyyy hh:mm:ss.cc 

dd Day of the month (2 characters)
MMM Month (first 3 characters of the month in uppercase)
yyyy Year (4 characters)
hh Hours of the day in 24-hour format (2 characters)
mm Minutes (2 characters)
ss.cc Seconds and hundredths of a second (5 characters)

6.1.2 Delta Time Format

The operating system uses the following format for delta time. The full date and time require a character string of 16 characters. The punctuation is required.

dddd hh:mm:ss.cc 

dddd Day of the month (4 characters)
hh Hour of the day (2 characters)
mm Minutes (2 characters)
ss.cc Seconds and hundredths of a second (5 characters)

A delta time is maintained as an integer value representing an amount of time in 100-ns units.

6.2 Time Conversion and Date/Time Manipulation

This section presents information about time conversion and date/time manipulation features, and the routines available to implement them.

6.2.1 Time Conversion Routines

Since the timer system services require you to specify the time in a 64-bit format, you can use time conversion run-time library and system service routines to work with time in a different format. Run-time library and system services do the following:

Table 6-1 shows time conversion run-time and system service routines.

Table 6-1 Time Conversion Routines and System Services
Routine Function
Time Conversion Run-Time Library (LIB$) Routines
LIB$CONVERT_DATE_STRING Converts an input date/time string to an operating system internal time.
LIB$CVT_FROM_INTERNAL_TIME Converts an operating system standard internal binary time value to an external integer value. The value is converted according to a selected unit of time operation.
LIB$CVTF_FROM_INTERNAL_TIME Converts an operating system standard internal binary time to an external F-floating point value. The value is converted according to a selected unit of time operation.
LIB$CVT_TO_INTERNAL_TIME Converts an external integer time value to an operating system standard internal binary time value. The value is converted according to a selected unit of time operation.
LIB$CVTF_TO_INTERNAL_TIME Converts an F-floating-point time value to an internal binary time value.
LIB$CVT_VECTIM Converts a seven-word array (as returned by the SYS$NUMTIM system service) to an operating system standard format internal time.
LIB$FORMAT_DATE_TIME Allows you to select at run time a specific output language and format for a date or time, or both.
LIB$SYS_ASCTIM Provides a simplified interface between higher-level languages and the $ASCTIM system service.
Time Conversion System Service Routines
SYS$ASCTIM Converts an absolute or delta time from 64-bit binary time format to an ASCII string.
SYS$ASCUTC Converts an absolute time from 128-bit Coordinated Universal Time (UTC) format to an ASCII string.
SYS$BINTIM Converts an ASCII string to an absolute or delta time value in a binary time 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$NUMTIM Converts an absolute or delta time from 64-bit system time format to binary integer date and time values.
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.

You can use the SYS$GETTIM system service to get the current time in internal format, or you can use SYS$BINTIM to convert a formatted time to an internal time, as shown in Section 6.3.2. You can also use the LIB$DATE_TIME routine to obtain the time, LIB$CVT_FROM_INTERNAL_TIME to convert an internal time to an external time, and LIB$CVT_TO_INTERNAL to convert from an external time to an internal time.


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_014.HTML