[an error occurred while processing this directive]

HP OpenVMS Systems Documentation

Content starts here

HP OpenVMS Programming Concepts Manual


Previous Contents Index

This procedure is illustrated in the following example:


#include <descrip.h>
#include <dvidef.h>
#include <efndef.h>
#include <lib$routines.h>
#include <ssdef.h>
#include <starlet.h>
#include <stdio.h>
#include <stsdef.h>
// Comment syntax used here assumes compiler support
main()
  {
#define MAXTERMLEN   64
#define MAXITMLST 3
  char TermName[MAXTERMLEN];
  int BasPri = 4;
  int RetStat;
  int TermLen;
  unsigned short int IOSB[4];


  // ItemList data structures used to acquire device name
  int i;
  struct
    {
    unsigned short int BufLen;
    unsigned short int ItmCod;
    void *BufAdr;
    void *BufRLA;
    } ItmLst[MAXITMLST];



  // Descriptors for sys$getdviw call
  $DESCRIPTOR( SysInput, "SYS$INPUT" );


  // Descriptors for sys$creprc call
  $DESCRIPTOR( ImageDesc,"SYS$SYSTEM:LOGINOUT.EXE");
  struct dsc$descriptor TermDesc =
    { MAXTERMLEN, DSC$K_DTYPE_T, DSC$K_CLASS_S, TermName };


  // Assign values to the item list
  i = 0;
  ItmLst[i].BufLen   = MAXTERMLEN;
  ItmLst[i].ItmCod   = DVI$_DEVNAM;
  ItmLst[i].BufAdr   = &TermName;
  ItmLst[i++].BufRLA = &TermLen;
  ItmLst[i].BufLen   = 0;
  ItmLst[i].ItmCod   = 0;
  ItmLst[i].BufAdr   = NULL;
  ItmLst[i++].BufRLA = NULL;


  // Acquire the terminal device name
  RetStat = sys$getdviw(
                     EFN$C_ENF,     // no event flag needed here
                     0,             // Channel (not needed here)
                     &SysInput,     // Device Name
                     ItmLst,        // item list
                     IOSB,          // Address of I/O Status Block
                     0,0,0);
  if (!$VMS_STATUS_SUCCESS( RetStat ))
    lib$signal( RetStat );
  if (!$VMS_STATUS_SUCCESS( IOSB[0] ))
    lib$signal( IOSB[0] );


  // Create the subprocess
  RetStat = sys$creprc(
                     0,
                     &ImageDesc,    // The image to be run
                     &TermDesc,     // Input (SYS$INPUT device)
                     &TermDesc,     // Output (SYS$OUTPUT device)
                     &TermDesc,     // Error (SYS$ERROR device)
                     0,0,0,
                     &BasPri,       // Process base priority
                     0,0,0);
  if (!$VMS_STATUS_SUCCESS( RetStat ))
    lib$signal( RetStat );


  return SS$_NORMAL;
  }

In this example, the subprocess executes, and the logical names SYS$INPUT, SYS$OUTPUT, and SYS$ERROR are equated to the device name of the logical input device of the creating process. The subprocess can then do one of the following:

  • Use OpenVMS RMS to open the device for reading or writing, or both.
  • Use the Assign I/O Channel (SYS$ASSIGN) system service to assign an I/O channel to the device for input/output operations.

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};
// 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 HP 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 MACRO and BLISS 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.4.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 HP 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 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. If you specify a uic argument with the same UIC as the creating process, the system service creates a detached process with the same UIC as 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. The IMPERSONATE privilege controls the ability to create a detached process with a UIC that is different from the UIC of 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 individual 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.

The SYS$CREPRC service also determines what kind of process is being created --- 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 makes sure the PQL values are greater than the minimum (PQL_Mxxxxx) values.

With subprocesses, some quotas are pooled, such as 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 descendant subprocesses. All the related processes report the same quota because 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 and I64 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 and I64 systems, it returns the longword integer value of the paging file quota in pagelets.

For a complete description of quotas, refer to the HP 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 the kept debugger configuration
  • Using DBG$ logical names
  • Using the workstation device (see Section 2.4.4)
  • Using a DECwindows DECterm display

See Chapter 9 in the HP OpenVMS Debugger Manual for more details on debugging subprocesses and detached processes.

Kept Debugger

With the kept debugger configuration, you start the debugger user interface using the DCL command DEBUG/KEEP.

At the DBG> prompt, you then issue either the RUN or the CONNECT command, depending on whether or not the program you want to debug is already running.

If the program is not running, use the debugger's RUN command to start the program in a subprocess.

If the program is running, use the debugger's CONNECT command to interrupt a running program and bring it under debug control. CONNECT can be used to attach to a program running in a subprocess or to attach to a program running in a detached process. Detached processes must meet both of the following requirements:

  • The detached process UIC must be in the same group as your process.
  • The detached process must have a CLI mapped.

The second requirement effectively means that the program must have been started with a command similar to:


$ RUN/DETACH/INPUT=xxx.com SYS$SYSTEM:LOGINOUT

where xxx.com is a command procedure that starts the program with /NODEBUG.

After you have started or connected to the program, the remainder of the debugging session is the same as a normal debugger session.

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>



// 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 and I64 Only)

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

Note

For information about the concepts and implementation of user threads with HP POSIX Threads Library, refer to 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


Previous Next Contents Index