HP C
Run-Time Library Reference Manual for OpenVMS Systems


Previous Contents Index

5.3 Synchronizing Processes

A child process is terminated when the parent process terminates. Therefore, the parent process must check the status of its child processes before exiting. This is done using the HP C RTL function wait .

5.4 Interprocess Communication

A channel through which parent and child processes communicate is called a pipe. Use the pipe function to create a pipe.

5.5 Program Examples

Example 5-1 shows the basic procedures for executing an image in a child process. The child process in Example 5-1 prints a message 10 times.

Example 5-1 Creating the Child Process

/*      chap_5_exec_image.c     */ 
 
/* This example creates the child process.  The only    */ 
/* functionality given to the child is the ability to   */ 
/* print a message 10 times.                            */ 
 
#include <climsgdef.h>  /* CLI status values  */ 
#include <stdio.h> 
#include <perror.h> 
#include <processes.h> 
#include <stdlib.h> 
 
static const char *child_name = "chap_5_exec_image_child.exe" ; 
 
main() 
{ 
   int status, 
       cstatus; 
 
   /* NOTE:                                            */ 
   /*    Any local automatic variables, even those     */ 
   /*    having the volatile attribute, may have       */ 
   /*    indeterminant values if they are modified     */ 
   /*    between the vfork() call and the matching     */ 
   /*    exec() call.                                  */ 
 
(1)   if ((status = vfork()) != 0) {   
       /* This is either an error or                   */ 
       /* the "second" vfork return, taking us "back"  */ 
       /* to parent mode.                              */ 
(3)       if (status < 0)   
            printf("Parent - Child process failed\n"); 
       else { 
            printf("Parent - Waiting for Child\n"); 
(4)            if ((status = wait(&cstatus)) == -1)  
               perror("Parent - Wait failed"); 
(5)            else if (cstatus == CLI$_IMAGEFNF)    
               printf("Parent - Child does not exist\n"); 
            else 
               printf("Parent - Child final status: %d\n", cstatus); 
        } 
    } 
(2)    else {  /* The FIRST Vfork return is zero, do the exec */ 
           printf("Parent - Starting Child\n"); 
           if ((status = execl(child_name, 0)) == -1) { 
               perror("Parent - Execl failed"); 
               exit(EXIT_FAILURE); 
         } 
    } 
} 
 
---------------------------------------------------------- 

/*      CHAP_5_EXEC_IMAGE_CHILD.C                    */ 
 
/* This is the child program that writes a message   */ 
/* through the parent to "stdout"                    */ 
 
#include <stdio.h> 
 
main() 
{ 
    int i; 
 
    for (i = 0; i < 10; i++) 
        printf("Child - executing\n"); 
    return (255) ;    /* Set an unusual success stat */ 
} 

Key to Example 5-1:

  1. The vfork function is called to set up the return address for the exec call.
    The vfork function is normally used in the expression of an if statement. This construct allows you to take advantage of the double return aspect of vfork , since one return value is 0 and the other is nonzero.
  2. A 0 return value is returned the first time vfork is called and the parent executes the else clause associated with the vfork call, which calls execl .
  3. A negative child process ID is returned when an exec function fails. The return value is checked for these conditions.
  4. The wait function is used to synchronize the parent and child processes.
  5. Since the exec functions can indicate success up to this point even if the image to be activated in the child does not exist, the parent checks the child's return status for the predefined status, CLI$_IMAGEFNF (file not found).

In Example 5-2, the parent passes arguments to the child process.

Example 5-2 Passing Arguments to the Child Process

/*       CHAP_5_CHILDARG.C                                           */ 
 
/* In this example, the arguments are placed in an array, gargv,     */ 
/* but they can be passed to the child explicitly as a zero-         */ 
/* terminated series of character strings. The child program in this */ 
/* example writes the arguments that have been passed it to stdout.  */ 
 
#include <climsgdef.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <perror.h> 
#include <processes.h> 
 
const char *child_name = "chap_5_childarg_child.exe" ; 
 
main() 
{ 
    int status, 
        cstatus; 
    char *gargv[] = 
    {"Child", "ARGC1", "ARGC2", "Parent", 0}; 
 
    if ((status = vfork()) != 0) { 
        if (status < -1) 
            printf("Parent - Child process failed\n"); 
        else { 
            printf("Parent - waiting for Child\n"); 
            if ((status = wait(&cstatus)) == -1) 
                perror("Parent - Wait failed"); 
            else if (cstatus == CLI$_IMAGEFNF) 
                printf("Parent - Child does not exist\n"); 
            else 
                printf("Parent - Child final status: %x\n", 
                       cstatus); 
        } 
    } 
    else { 
        printf("Parent - Starting Child\n"); 
        if ((status = execv(child_name, gargv)) == -1) { 
            perror("Parent - Exec failed"); 
            exit(EXIT_FAILURE); 
        } 
    } 
} 
 
-------------------------------------------------------- 
/*       CHAP_5_CHILDARG_CHILD.C                      */ 
 
/* This is a child program that echos its arguments   */ 
 
#include <stdio.h> 
 
main(argc, argv) 
    int argc; 
    char *argv[]; 
{ 
    int i; 
 
    printf("Program name: %s\n", argv[0]); 
 
    for (i = 1; i < argc; i++) 
        printf("Argument %d: %s\n", i, argv[i]); 
    return(255) ; 
} 

Example 5-3 shows how to use the wait function to check the final status of multiple children being run simultaneously.

Example 5-3 Checking the Status of Child Processes

/*        CHAP_5_CHECK_STAT.C                                   */ 
 
/* In this example 5 child processes are started.  The wait()   */ 
/* function is placed in a separate for loop so that it is      */ 
/* called once for each child. If wait() were called within     */ 
/* the first for loop, the parent would wait for one child to   */ 
/* terminate before executing the next child. If there were     */ 
/* only one wait request, any child still running when the      */ 
/* parent exits would terminate prematurely.                    */ 
 
#include <climsgdef.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <perror.h> 
#include <processes.h> 
 
const char *child_name = "chap_5_check_stat_child.exe" ; 
 
main() 
{ 
    int status, 
        cstatus, 
        i; 
 
    for (i = 0; i < 5; i++) { 
        if ((status = vfork()) == 0) { 
            printf("Parent - Starting Child %d\n", i); 
            if ((status = execl(child_name, 0)) == -1) { 
                perror("Parent - Exec failed"); 
                exit(EXIT_FAILURE); 
            } 
        } 
        else if (status < -1) 
            printf("Parent - Child process failed\n"); 
    } 
 
    printf("Parent - Waiting for children\n"); 
 
    for (i = 0; i < 5; i++) { 
        if ((status = wait(&cstatus)) == -1) 
            perror("Parent - Wait failed"); 
        else if (cstatus == CLI$_IMAGEFNF) 
            printf("Parent - Child does not exist\n"); 
        else 
            printf("Parent - Child %X final status: %d\n", 
                   status, cstatus); 
    } 
} 

Example 5-4 shows how to use the pipe and dup2 functions to communicate between a parent and child process through specific file descriptors. The #define preprocessor directive defines the preprocessor constants inpipe and outpipe as the names of file descriptors 11 and 12.

Example 5-4 Communicating Through a Pipe

/*        CHAP_5_PIPE.C                                         */ 
 
/* In this example, the parent writes a string to the pipe for  */ 
/* the child to read.  The child then writes the string back    */ 
/* to the pipe for the parent to read.  The wait function is    */ 
/* called before the parent reads the string that the child has */ 
/* passed back through the pipe.  Otherwise, the reads and      */ 
/* writes will not be synchronized.                             */ 
 
#include <perror.h> 
#include <climsgdef.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <processes.h> 
#include <unixio.h> 
 
#define inpipe 11 
#define outpipe 12 
 
const char *child_name = "chap_5_pipe_child.exe" ; 
 
main() 
{ 
    int pipes[2]; 
    int mode, 
        status, 
        cstatus, 
        len; 
    char *outbuf, 
        *inbuf; 
 
    if ((outbuf = malloc(512)) == 0) { 
        printf("Parent - Outbuf allocation failed\n"); 
        exit(EXIT_FAILURE); 
    } 
 
    if ((inbuf = malloc(512)) == 0) { 
        printf("Parent - Inbuf allocation failed\n"); 
        exit(EXIT_FAILURE); 
    } 
    if (pipe(pipes) == -1) { 
        printf("Parent - Pipe allocation failed\n"); 
        exit(EXIT_FAILURE); 
    } 
 
    dup2(pipes[0], inpipe); 
    dup2(pipes[1], outpipe); 
    strcpy(outbuf, "This is a test of two-way pipes.\n"); 
 
    status = vfork(); 
 
    switch (status) { 
    case 0: 
        printf("Parent - Starting child\n"); 
        if ((status = execl(child_name, 0)) == -1) { 
            printf("Parent - Exec failed"); 
            exit(EXIT_FAILURE); 
        } 
        break; 
 
    case -1: 
        printf("Parent - Child process failed\n"); 
        break; 
 
    default: 
        printf("Parent - Writing to child\n"); 
  
        if (write(outpipe, outbuf, strlen(outbuf) + 1) == -1) { 
            perror("Parent - Write failed"); 
            exit(EXIT_FAILURE); 
        } 
        else { 
            if ((status = wait(&cstatus)) == -1) 
                perror("Parent - Wait failed"); 
 
            if (cstatus == CLI$_IMAGEFNF) 
                printf("Parent - Child does not exist\n"); 
            else { 
                printf("Parent - Reading from child\n"); 
                if ((len = read(inpipe, inbuf, 512)) <= 0) { 
                    perror("Parent - Read failed"); 
                    exit(EXIT_FAILURE); 
                } 
                else { 
                    printf("Parent: %s\n", inbuf); 
                    printf("Parent - Child final status: %d\n", 
                            cstatus); 
                } 
            } 
        } 
        break; 
    } 
}  
 
------------------------------------------------------------------ 
/*        CHAP_5_PIPE_CHILD.C                                   */ 
 
/* This is a child program which reads from a pipe and writes   */ 
/* the received message back to its parent.                     */ 
 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
 
#define inpipe 11 
#define outpipe 12 
 
main() 
{ 
    char *buffer; 
    int len; 
 
    if ((buffer = malloc(512)) == 0) { 
        perror("Child - Buffer allocation failed\n"); 
        exit(EXIT_FAILURE); 
    } 
 
    printf("Child - Reading from parent\n"); 
    if ((len = read(inpipe, buffer, 512)) <= 0) { 
        perror("Child - Read failed"); 
        exit(EXIT_FAILURE); 
    } 
    else { 
        printf("Child: %s\n", buffer); 
        printf("Child - Writing to parent\n"); 
        if (write(outpipe, buffer, strlen(buffer) + 1) == -1) { 
            perror("Child - Write failed"); 
            exit(EXIT_FAILURE); 
        } 
    } 
    exit(EXIT_SUCCESS); 
} 


Chapter 6
Curses Screen Management Functions and Macros

This chapter describes the screen management routines available with HP C for OpenVMS Systems.

The OpenVMS Curses screen management package is supported on all OpenVMS systems.

On OpenVMS Alpha systems, two screen management packages are supported: OpenVMS Curses and a more UNIX compatible package based on the Berkeley Standard Distribution (BSD) Curses software.1 Section 6.1 for more information.

Furthermore, the HP C RTL offers a Curses package based on the 4.4BSD Berkeley Software Distribution. Documentation on the 4.4BSD Curses package can be found in Screen Updating and Cursor Movement Optimization: A Library Package, by Kenneth C.R.C. Arnold.

The functions and macros in the OpenVMS and BSD-based Curses packages are nearly the same. Most differences between them are called out in this chapter. Otherwise, this chapter makes no distinction between the two Curses packages, and refers to "Curses" or the "Curses functions and macros."

Note

1 Copyright (c) 1981 Regents of the University of California.

6.1 Using the BSD-Based Curses Package (ALPHA ONLY)

The <curses.h> header file required to use the BSD-based Curses implementation is provided with the HP C compiler on OpenVMS Alpha systems.

Existing programs are not affected by the BSD-based Curses functions because the OpenVMS Curses functions are still available as the default Curses package. (Note that is a change from previous versions of HP C, where BSD-based Curses was the default.)

To get the the 4.4BSD Curses implementation, you must compile modules that include <curses.h> with the following qualifier:

/DEFINE=_BSD44_CURSES

The BSD-based Curses functions do not provide the support required to call the OpenVMS SMG$ routines with the pasteboard and keyboard allocated by the Curses functions. Consequently, Curses programs that rely on calling SMG$ entry points, as well as Curses functions, must continue to use the OpenVMS Curses implementation.

The BSD-based Curses implementation is not interoperable with the old implementation. Attempts to mix calls to the new functions and the old functions will result in incorrect output displayed on the screen and could result in an exception from an SMG$ routine.

6.2 Curses Overview

Curses, the HP C Screen Management Package, is composed of HP C RTL functions and macros that create and modify defined sections of the terminal screen and optimize cursor movement. Using the screen management package, you can develop a user interface that is both visually attractive and user-friendly. Curses is terminal-independent and provides simplified terminal screen formatting and efficient cursor movement.

Most Curses functions and macros are listed in pairs where the first routine is a macro and the second is a function beginning with the prefix "w," for "window." These prefixes are delimited by brackets ([ ]). For example, [w]addstr designates the addstr macro and the waddstr function. The macros default to the window stdscr ; the functions accept a specified window as an argument.

To access the Curses functions and macros, include the <curses.h> header file.

The terminal-independent Screen Management Software, which is part of the OpenVMS RTL, is used to implement Curses. For portability purposes, most functions and macros are designed to perform in a manner similar to other C implementations. However, the Curses routines depend on the OpenVMS system and its Screen Management Software, so performance of some functions and macros could differ slightly from those of other implementations.

Some functions and macros available on other systems are not available with the HP C RTL Curses package.

Some functions, such as [w]clrattr , [w]insstr , mv[w]insstr , and [w]setattr are specific to HP C for OpenVMS Systems and are not portable.

Table 6-1 lists all of the Curses functions and macros found in the HP C RTL. For more detailed information on each function and macro, see the Reference Section.

Table 6-1 Curses Functions and Macros
Function or Macro Description
[w]addch Adds a character to the window at the current position of the cursor.
[w]addstr Adds a string to the window at the current position of the cursor.
box Draws a box around the window.
[w]clear Erases the contents of the specified window and resets the cursor to coordinates (0,0).
clearok Sets the clear flag for the window.
[w]clrattr Deactivates the video display attribute within the window.
[w]clrtobot Erases the contents of the window from the current position of the cursor to the bottom of the window.
[w]clrtoeol Erases the contents of the window from the current cursor position to the end of the line on the specified window.
[no]crmode Sets and unsets the terminal from cbreak mode.
[w]delch Deletes the character on the specified window at the current position of the cursor.
[w]deleteln Deletes the line at the current position of the cursor.
delwin Deletes the specified window from memory.
[no]echo Sets the terminal so that characters may or may not be echoed on the terminal screen.
endwin Clears the terminal screen and frees any virtual memory allocated to Curses data structures.
[w]erase Erases the window by painting it with blanks.
[w]getch Gets a character from the terminal screen and echoes it on the specified window.
[w]getstr Gets a string from the terminal screen, stores it in a character variable, and echoes it on the specified window.
getyx Puts the (y,x) coordinates of the current cursor position on the window in the variables y and x.
[w]inch Returns the character at the current cursor position on the specified window without making changes to the window.
initscr Initializes the terminal-type data and all screen functions.
[w]insch Inserts a character at the current cursor position in the specified window.
[w]insertln Inserts a line above the line containing the current cursor position.
[w]insstr Inserts a string at the current cursor position on the specified window.
leaveok Leaves the cursor at the current coordinates after an update to the window.
longname Assigns the full terminal name to a character name that must be large enough to hold the character string.
[w]move Changes the current cursor position on the specified window.
mv[w]addch Moves the cursor and adds a character to the specified window.
mv[w]addstr Moves the cursor and adds a string to the specified window.
mvcur Moves the terminal's cursor.
mv[w]delch Moves the cursor and deletes a character on the specified window.
mv[w]getch Moves the cursor, gets a character from the terminal screen, and echoes it on the specified window.
mv[w]getstr Moves the cursor, gets a string from the terminal screen, stores it in a variable, and echoes it on the specified window.
mv[w]inch Moves the cursor and returns the character on the specified window without making changes to the window.
mv[w]insch Moves the cursor and inserts a character in the specified window.
mv[w]insstr Moves the cursor and inserts a string in the specified window.
mvwin Moves the starting position of the window to the specified coordinates.
newwin Creates a new window with lines and columns starting at the coordinates on the terminal screen.
[no]nl Provided only for UNIX software compatibility and has no functionality in the OpenVMS environment.
overlay Writes the contents of one window that will fit over the contents of another window, beginning at the starting coordinates of both windows.
overwrite Writes the contents of one window, insofar as it will fit, over the contents of another window beginning at the starting coordinates of both windows.
[w]printw Performs a printf on the window starting at the current position of the cursor.
[no]raw Provided only for UNIX software compatibility and has no functionality in the OpenVMS environment.
[w]refresh Repaints the specified window on the terminal screen.
[w]scanw Performs a scanf on the window.
scroll Moves all the lines on the window up one line.
scrollok Sets the scroll flag for the specified window.
[w]setattr Activates the video display attribute within the window.
[w]standend Deactivates the boldface attribute for the specified window.
[w]standout Activates the boldface attribute of the specified window.
subwin Creates a new subwindow with lines and columns starting at the coordinates on the terminal screen.
touchwin Places the most recently edited version of the specified window on the terminal screen.
wrapok OpenVMS Curses only. Allows the wrapping of a word from the right border of the window to the beginning of the next line.


Previous Next Contents Index