|
OpenVMS Programming Concepts Manual
4.7.2.5 LDR$UNLOAD_IMAGE (Alpha Only)
The following is a description of the callable interface to
LDR$UNLOAD_IMAGE.
LDR$UNLOAD_IMAGE
Unloads a removable executive image. This routine is called to unload
an execlet. All resources are returned.
Module
SYSLDR_DYN
Format
LDR$UNLOAD_IMAGE filename ,ref_handle
Arguments
filename
OpenVMS usage |
character string |
type |
character string |
access |
read only |
mechanism |
by descriptor |
The longword address of a character string descriptor containing the
file name of the executive image to be unloaded. The file name must be
supplied exactly as it was supplied to LDR$LOAD_IMAGE when the
executive image was loaded.
ref_handle
OpenVMS usage |
address |
type |
longword (signed) |
access |
read only |
mechanism |
by reference |
The longword address of the reference handle containing the
three-longword block returned by LDR$LOAD_IMAGE when the executive
image was loaded.
Context
LDR$UNLOAD_IMAGE must be called in kernel mode.
RETURNS
OpenVMS usage |
cond_value |
type |
longword (unsigned) |
access |
write only |
mechanism |
by value |
Status indicating the success or failure of the operation.
Return Values
SS$_INSFARG
|
LDR$UNLOAD_IMAGE was not called with two parameters.
|
SS$_BADPARAMS
|
Reference handle data inconsistent with LDRIMG block that matches the
name in the first argument.
|
LOADER$_MARKUNL
|
A call was made to the LDR$UNLOAD_IMAGE routine to unload a removable
executive image that already has an outstanding unload request against
it.
|
SS$_NOPRIV
|
LDR$UNLOAD_IMAGE was not called in kernel mode.
|
SS$_NORMAL
|
Executive image was successfully removed from the system.
|
LOADER$_NOT_UNL
|
A call was made to LDR$UNLOAD_IMAGE to unload an executive image that
is not loaded or that was not loaded with the LDR$V_UNL flag bit set.
|
LOADER$_UNL_PEN
|
A call was made to LDR$UNLOAD_IMAGE to unload an executive image that
is in use. The image is marked to be unloaded later.
|
Description
LDR$UNLOAD_IMAGE removes an executive image from system space and
returns all memory resources allocated when the image was loaded.
Images can only be removed if they were originally loaded with the bit
LDR$V_UNL set in the input flags to LDR$LOAD_IMAGE.
4.8 Synchronizing Programs by Specifying a Time for Program Execution
You can synchronize timed program execution in the following ways:
- Executing a program at a specific time
- Executing a program at timed intervals
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 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,
Compaq 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:
- 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.
- 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.6 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:
- Suspending a process---All kernel threads associated with the
specified process are suspended.
- Hibernating a process---Only the calling kernel thread is
hibernated.
- Stopping a process---All kernel threads associated with the
specified process are stopped.
- Resuming a process---All kernel threads associated with the
specified process are resumed.
- Exiting an image---All kernel threads associated with the specified
process are exited.
- Deleting a process---All kernel threads associated with the
specified process are deleted, and then the process is deleted.
4.9.1 Process Hibernation and Suspension
There are two ways to halt the execution of a kernel thread or process
temporarily:
- Hibernation---Performed by the Hibernate (SYS$HIBER) system
service, which affects the calling kernel thread.
- Suspension---Performed by the Suspend Process (SYS$SUSPND) system
service, which affects all of the kernel threads associated with the
specified process.
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 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;
}
|
|