HP OpenVMS Systems Documentation

Content starts here

OpenVMS Programming Concepts Manual


Previous Contents Index

In the following example, the program assigns a channel to the device specified by the logical name SYS$OUTPUT:



        int RetStat;
        unsigned short int IOchan;
        $DESCRIPTOR(DevNam,"SYS$OUTPUT");
   .
   .
   .
        RetStat = sys$assign( &DevNam,           /* Device name */
                             &IOchan,            /* Channel */
                             0, 0, 0);
        if ($!VMS_STATUS_SUCCESS( RetStat ))
           return RetStat;

For more information about channel assignment for I/O operations, see Chapter 23.

Setting Privileges

Set different privileges by defining the privilege list for the subprocess using the prvadr argument. This is particularly useful when you want to dedicate a subprocess to execute privileged or sensitive code. If you do not specify this argument, the privileges of the calling process are used. If you specify the prvadr argument, only the privileges specified in the bit mask are used; the privileges of the calling process are not used. For example, a creating process has the user privileges GROUP and TMPMBX. It creates a process, specifying the user privilege TMPMBX. The created process receives only the user privilege TMPMBX; it does not have the user privilege GROUP.

If you need to create a process that has a privilege that is not one of the privileges of your current process, you must have the user privilege SETPRV.

Symbols associated with privileges are defined by the $PRVDEF macro. Each symbol begins with PRV$M_ and identifies the bits in the bit mask that must be set to specify a given privilege. The following example shows the data definition for a bit mask specifying the GRPNAM and GROUP privileges:


   unsigned int PrivQuad[2] = { (PRV$M_GRPNAM | PRV$M_GROUP), 0};
   // OpenVMS Alpha could also use:  __int64 PrivQuad = PRV$M_GRPNAM | PRV$M_GROUP;

Setting Process Quotas

Set different process quotas by defining the quota list of system resources for the subprocess using the quota argument. This option can be useful when managing a subprocess to limit use of system resources (such as AST usage, I/O, CPU time, lock requests, and working set size and expansion). If you do not specify this argument, the system defines default quotas for the subprocess.

The following example shows how to construct the process quota array for the SYS$CREPRC call using Compaq C, and particularly how to avoid problems on OpenVMS Alpha due to the default use of member alignment. Without the nomember_alignment setting, there would be three pad bytes embedded within each element of the array, and SYS$CREPRC would not perform as expected.


#pragma environment save
#pragma nomember_alignment
    struct
        {
        unsigned char pql_code;
        unsigned long int pql_value;
        } pql[] =
            {
            {   PQL$_ASTLM,        600      },
            {   PQL$_BIOLM,        100      },
            {   PQL$_BYTLM,        131072   },
            {   PQL$_CPULM,        0        },
            {   PQL$_DIOLM,        100      },
            {   PQL$_FILLM,        50       },
            {   PQL$_PGFLQUOTA,    40960    },
            {   PQL$_PRCLM,        16       },
            {   PQL$_TQELM,        600      },
            {   PQL$_WSDEFAULT,    512      },
            {   PQL$_WSQUOTA,      2048     },
            {   PQL$_ENQLM,        600      },
            {   PQL$_WSEXTENT,     4096     },
            {   PQL$_JTQUOTA,      4096     },
            {   PQL$_LISTEND,      0        }
            };
#pragma environment restore

For more information about process quotas and process quota lists, see Section 2.6.

Setting the Subprocess Priority

Set the subprocess priority by setting the base execution priority with the baspri argument. If you do not set the subprocess priority, the priority defaults to 2 for VAX MACRO and VAX BLISS--32 and to 0 for all other languages. If you want a subprocess to have a higher priority than its creator, you must have the user privilege ALTPRI to raise the priority level.

Specifying Additional Processing Options

Enable and disable parent and subprocess wait mode, control process swapping, control process accounting, control process dump information, control authorization checks, and control working set adjustments using the stsflg argument. This argument defines the status flag, a set of bits that controls some execution characteristics of the created process, including resource wait mode and process swap mode.

Defining an Image for a Subprocess to Execute

When you call the SYS$CREPRC system service, use the image argument to provide the process with the name of an image to execute. For example, the following lines of C create a subprocess to execute the image named CARRIE.EXE:


        $DESCRIPTOR(image,"CARRIE");
   .
   .
   .
        RetStat = sys$creprc(0, &image, ...);

In this example, only a file name is specified; the service uses current disk and directory defaults, performs logical name translation, uses the default file type .EXE, and locates the most recent version of the image file. When the subprocess completes execution of the image, the subprocess is deleted. Process deletion is described in Chapter 4.

2.4.3.1 Disk and Directory Defaults for Created Processes

When you use the SYS$CREPRC system service to create a process to execute an image, the system locates the image file in the default device and directory of the created process. Any created process inherits the current default device and directory of its creator.

If a created process runs an image that is not in its default directory, you must identify the directory and, if necessary, the device in the file specification of the image to be run.

There is no way to define a default device or directory for the created process that is different from that of the creating process in a call to SYS$CREPRC. The created process can, however, define an equivalence for the logical device SYS$DISK by calling the Create Logical Name ($CRELNM) system service.

If the process is a subprocess, you, in the creating process, can define an equivalence name in the group logical name table, job logical name table, or any logical name table shared by the creating process and the subprocess. The created process then uses this logical name translation as its default directory. The created process can also set its own default directory by calling the OpenVMS RMS default directory system service, SYS$SETDDIR.

A process can create a process with a default directory that is different from its own by completing the following steps in the creating process:

  1. Make a call to SYS$SETDDIR to change its own default directory.
  2. Make a call to SYS$CREPRC to create the new process.
  3. Make a call to SYS$SETDDIR to change its own default directory back to the default directory it had before the first call to SYS$SETDDIR.

The creating process now has its original default directory. The new process has the different default directory that the creating process had when it created the new process. If the default device is to change, you must also redefine the SYS$DISK logical name. For details on how to call SYS$SETDDIR, see the OpenVMS System Services Reference Manual.

2.5 Creating a Detached Process

The creation of a detached process is primarily a task the operating system performs when you log in. In general, an application creates a detached process only when a program must continue executing after the parent process exits. To do this, you should use the SYS$CREPRC system service. You can also use detached processes to write to the terminal of another process by using the SYS$BREAKTHRU system service.

The IMPERSONATE privilege controls the ability to create a detached process with a UIC that is different from the UIC of the creating process. You can use the uic argument to the SYS$CREPRC system service to define whether a process is a subprocess or a detached process. The uic argument provides the created process with a user identification code (UIC). If you omit the uic argument, the SYS$CREPRC system service creates a subprocess that executes under the UIC of the creating process.

You can also create a detached process with the same UIC as the creating process by specifying the detach flag in the stsflg argument. You do not need the IMPERSONATE privilege to create a detached process with the same UIC as the creating process.

Examples of Creating a Detached Process

The following Fortran program segment creates a process that executes the image SYS$USER:[ACCOUNT]INCTAXES.EXE. INCTAXES reads input from the file TAXES.DAT and writes output to the file TAXES.RPT. (TAXES.DAT and TAXES.RPT are in the default directory on the default disk.) The last argument specifies that the created process is a detached process (the UIC defaults to that of the parent process). (The symbol PRC$M_DETACH is defined in the $PRCDEF module of the system macro library.)


EXTERNAL  PRC$M_DETACH

! Declare status and system routines
INTEGER STATUS,SYS$CREPRC
   .
   .
   .
STATUS = SYS$CREPRC (,
2                    'SYS$USER:[ACCOUNT]INCTAXES', ! Image
2                    'TAXES.DAT',                  ! SYS$INPUT
2                    'TAXES.RPT',                  ! SYS$OUTPUT
2                    ,,,,
2                    %VAL(4),                      ! Priority
2                    ,,
2                    %VAL(%LOC(PRC$M_DETACH)))     ! Detached

The following program segment creates a detached process to execute the DCL commands in the command file SYS$USER:[TEST]COMMANDS.COM. The system image SYS$SYSTEM:LOGINOUT.EXE is executed to include DCL in the created process. The DCL commands to be executed are specified in a command procedure that is passed to SYS$CREPRC as the input file. Output is written to the file SYS$USER:[TEST]OUTPUT.DAT.


   .
   .
   .
STATUS = SYS$CREPRC (,
2                    'SYS$SYSTEM:LOGINOUT',        ! Image
2                    'SYS$USER:[TEST]COMMANDS.COM',! SYS$INPUT
2                    'SYS$USER:[TEST]OUTPUT.DAT',  ! SYS$OUTPUT
2                    ,,,,
2                    %VAL(4),                      ! Priority
2                    ,,
2                    %VAL(%LOC(PRC$M_DETACH)))     ! Detached

2.6 Process Quota Lists

The SYS$CREPRC system service uses the quota argument to create a process quota list (PQL). Individual quota items such as paging file quota (PQL_PGFLQUOTA) and timer queue entry quota (PQL_TQELM) of the SYS$CREPRC system service make up the PQL. In allocating the PQL, SYS$CREPRC constructs a default PQL for the process being created, assigning it the default values for all individaul quota items. Default values are SYSGEN parameters and so can be changed from system to system. SYS$CREPRC then reads the specified quota list, if any is indicated, and updates the corresponding items in the default PQL. Any missing values are filled in from the default items (PQL_Dxxxxx) SYSGEN parameter, where xxxxx are the characters of the quota name that follow PQL$_ in the quota name. The PQL is then complete.

The SYS$CREPRC service next reads the PQL, comparing each value against the corresponding minimum (PQL_Mxxxxx) SYSGEN parameter. If the SYSGEN parameter is greater than the resulting value, SYS$CREPRC replaces it with the SYSGEN value. Thus no process on the system has a quota value lower than the minimum (PQL_Mxxxxx) SYSGEN parameter. Since all PQL individual quota items are dynamic, you can change the values in SYSGEN.

The SYS$CREPRC service also determines what kind of process the PQL belongs to, whether batch, interactive, or detached. If it is a batch or interactive process, the process derives all its quotas from the user authorization file (UAF) and completely overwrites the PQL. These quotas are unaffected by the default (PQL_Dxxxxx) SYSGEN parameters, but are affected by the minimum (PQL_Mxxxxx) values. If the process is a detached process, it determines what items have been passed in the quota list and only then overwrites these items in the PQL. SYS$CREPRC never reads the PQL it is creating until it has completed it and then goes to the final pass making sure its values are greater than the minimum (PQL_Mxxxxx) values.

With subprocesses some quotas are pooled, for instance, PQL_PGFLQUOTA and PQL_TQELM. SYS$CREPRC establishes pooled quotas when it creates a detached process, and they are shared by that process and all its descendent subprocesses. All the related processes report the same quota as they are accessing a common location in the job information block (JIB).

To determine the maximum virtual page count of the paging file quota of a process, use the JPI$_PGFLQUOTA item code of the SYS$GETJPI system service. The JPI$_PGFLQUOTA on VAX systems returns the longword integer value of the paging file quota in pages; on Alpha systems, it returns the longword integer value of the paging file quota in pagelets.

To determine the remaining paging file quota of the process, use the JPI$_PAGFILCNT item code of the SYS$GETJPI system service. The JPI$_PAGFILCNT on VAX systems returns the longword integer value of the paging file quota in pages; on Alpha systems, it returns the longword integer value of the paging file quota in pagelets.

For a complete description of quotas, see the OpenVMS System Services Reference Manual: A--GETUAI.

2.7 Debugging a Subprocess or a Detached Process

You have several ways to debug a subprocess or a detached process including the following:

  • Using DBG$ logical names
  • Using the workstation device (see Section 2.4.3)
  • Using a DECwindows DECterm display

DBG$ Logical Names

You can allow a program to be debugged within a subprocess or a detached process by using DBG$INPUT and DBG$OUTPUT. To allow debug operations with DBG$INPUT and DBG$OUTPUT, equate the subprocess logical names DBG$INPUT and DBG$OUTPUT to the terminal. When the subprocess executes the program, which has been compiled and linked with the debugger, the debugger reads input from DBG$INPUT and writes output to DBG$OUTPUT.

If you are executing the subprocess concurrently, you should restrict debugging to the program in the subprocess. The debugger prompt DBG> should enable you to differentiate between input required by the parent process and input required by the subprocess. However, each time the debugger displays information, you must press the Return key to display the DBG> prompt. (By pressing the Return key, you actually write to the parent process, which has regained control of the terminal following the subprocess's writing to the terminal. Writing to the parent process allows the subprocess to regain control of the terminal.)

DECwindows DECterm Display

If you have DECwindows installed, you can use display for debugging a subprocess or detached process. The following debugging example with DECterm shows how to create a DECterm display, and pass it into the SYS$CREPRC call for use with an application that is built using the OpenVMS Debugger:


#pragma module  CREATE_DECTERM

#include <descrip.h>
#include <lib$routines.h>
#include <pqldef.h>
#include <prcdef.h>
#include <ssdef.h>
#include <starlet.h>
#include <stsdef.h>

// Comment syntax used here assumes Compaq C compiler support (eg: V6.2)

// To build and run:
//    $ cc CREATE_DECTERM
//    $ link CREATE_DECTERM,sys$input/option
//    sys$share:DECW$TERMINALSHR.EXE/share
//    $ run CREATE_DECTERM

// This routine is not declared in a currently-available library
extern int decw$term_port(void *,...);


main( void )
  {
  int RetStat;
  int StsFlg;
  int DbgTermLen = 0;
#define DBGTERMBUFLEN 50
  char DbgTermBuf[DBGTERMBUFLEN];
  $DESCRIPTOR( Customization,
"DECW$TERMINAL.iconName:\tDebugging Session\n\
DECW$TERMINAL.title:\tDebugging Session" );
  $DESCRIPTOR( Command, "SYS$SYSDEVICE:[HOFFMAN]DEBUG_IMAGE.EXE" );
  struct dsc$descriptor DbgTerm;

  DbgTerm.dsc$w_length  = DBGTERMBUFLEN;
  DbgTerm.dsc$b_dtype   = DSC$K_DTYPE_T;
  DbgTerm.dsc$b_class   = DSC$K_CLASS_S;
  DbgTerm.dsc$a_pointer = DbgTermBuf;

  // Request creation of a DECterm display
  RetStat = decw$term_port(
            0,              // display (use default)
            0,              // setup file (use default)
            &Customization, // customization
            &DbgTerm,       // resulting device name
            &DbgTermLen,    // resulting device name length
            0,              // controller (use default)
            0,              // char buffer (use default)
            0 );            // char change buffer (default)
  if ( !$VMS_STATUS_SUCCESS (RetStat ))
    lib$signal( RetStat );

  DbgTerm.dsc$w_length  = DbgTermLen;

  // Create the process as detached.
  StsFlg = PRC$M_DETACH;

  // Now create the process
  RetStat = sys$creprc(
            0,              // PID
            &Command,       // Image to invoke
            &DbgTerm,       // Input
            &DbgTerm,       // Output
            0, 0, 0, 0, 0, 0, 0,
            StsFlg );       // Process creation flags
  if ( !$VMS_STATUS_SUCCESS( RetStat ))
    lib$signal( RetStat );

  return SS$_NORMAL;
  }

2.8 Kernel Threads and the Kernel Threads Process Structure (Alpha Only)

This section defines and describes some advantages of using kernel threads. It also describes some kernel threads features and type of model, as well as the design changes made to the OpenVMS operating system.

Note

For information about the concepts and implementation of user threads with Compaq POSIX Threads Library, see the Guide to the POSIX Threads Library.

2.8.1 Definition and Advantages of Kernel Threads

A thread is a single, sequential flow of execution within a process's address space. A single process contains an address space wherein either a single thread or multiple threads execute concurrently. Programs typically have a single flow of execution and therefore a single thread; whereas multithreaded programs have multiple points of execution at any one time.

By using threads as a programming model, you can gain the following advantages:

  • More modular code design
  • Simpler application design and maintenance
  • The potential to run independent flows of execution in parallel on multiple CPUs
  • The potential to make better use of available CPU resources through parallel execution

2.8.2 Kernel Threads Features

With kernel threads, the OpenVMS operating system implements the following two features:

  • Multiple execution contexts within a process
  • Efficient use of the OpenVMS and POSIX Threads Library schedulers

2.8.2.1 Multiple Execution Contexts Within a Process

Before the implementation of kernel threads, the scheduling model for the OpenVMS operating system was per process. The only scheduling context was the process itself, that is, only one execution context per process. Since a threaded application could create thousands of threads, many of these threads could potentially be executing at the same time. But because OpenVMS processes had only a single execution context, in effect, only one of those application threads was running at any one time. If this multithreaded application was running on a multiprocessor system, the application could not make use of more than a single CPU.

After the implementation of kernel threads, the scheduling model allows for multiple execution contexts within a process; that is, more than one application thread can be executing concurrently. These execution contexts are called kernel threads. Kernel threads allow a multithreaded application to have a thread executing on every CPU in a multiprocessor system. Kernel threads, therefore, allow a threaded application to take advantage of multiple CPUs in a symmetric multiprocessing (SMP) system.

In the initial release of kernel threads, OpenVMS allowed a maximum of 16 kernel threads per process. This enabled an application to have threads executing on up to 16 CPUs at one time. With OpenVMS Alpha Version 7.2, the number of kernel threads that can be created per-process increased to 256. The maximum value for the MULTITHREAD system parameter has also increased to 256.

2.8.2.2 Efficient Use of the OpenVMS and POSIX Threads Library Schedulers

The user mode thread manager schedules individual user mode application threads. On OpenVMS, POSIX Threads Library is the user mode threading package of choice. Before the implementation of kernel threads, POSIX Threads Library multiplexed user mode threads on the single OpenVMS execution context---the process. POSIX Threads Library implemented parts of its scheduling by using a periodic timer. When the AST executed and the thread manager gained control, the thread manager could then select a new application thread for execution. But because the thread manager could not detect that a thread had entered an OpenVMS wait state, the entire application blocked until that periodic AST was delivered. That resulted in a delay until the thread manager regained control and could schedule another thread. Once the thread manager gained control, it could schedule a previously preempted thread unaware that the thread was in a wait state. The lack of integration between the OpenVMS and POSIX Threads Library schedulers could result in wasted CPU resources.

After the implementation of kernel threads, the scheduling model provides for scheduler callbacks, which is not the default. A scheduler callback is an upcall from the OpenVMS scheduler to the thread manager whenever a thread changes state. This upcall allows the OpenVMS scheduler to inform the thread manager that the current thread is stalled and that another thread should be scheduled. Upcalls also inform the thread manager that an event a thread is waiting on has completed. With kernel threads, the two schedulers are better integrated, minimizing application thread scheduling delays.


Previous Next Contents Index