C++ Network Programming, Volume I: Mastering Complexity with ACE and Patterns

I l @ ve RuBoard

Motivation

Operating systems provide a variety of methods for setting the properties of newly-created processes. A new process's properties affect its relationship to other processes and its execution environment. Some of the common properties include

  • Program image. Which program should the new process execute?

  • Open I/O handles. Should the child process inherit open I/O handles or other OS objects? Should it close some or all of its inherited open handles?

  • Access to display. Should the child process have access to a terminal or to the user 's display?

  • Working directory. Should the child process run in the same directory as its parent or in a different directory?

  • Process relationship. Should the child process run in the background as an independent daemon or as part of a related group ?

  • Security attributes. Should the child process's security attributes or default file protection settings be changed to expand or restrict its abilities ?

These alternatives involve capabilities and APIs that are often unportable, even across similar platforms. A great deal of experience and platform-specific knowledge is needed to assure that each application's process properties are expressed correctly. The ACE_Process_Options class captures this knowledge portably.

Class Capabilities

The ACE_Process_Options class unifies how process properties are communicated to the ACE_Process and ACE_Process_Manager classes, which use these properties to select and influence the underlying OS process creation and environment mechanisms. ACE_Process_Options provides the following capabilities:

  • It enables an application to specify desired process control information.

  • It allows process control items to be expanded as platforms change.

  • It provides a decoupling mechanism that enables ACE to offer these capabilities without varying the process creation interface.

The interface of the ACE_Process_Options class is shown in Figure 8.3 and its key platform-independent methods are outlined in the following table:

Method Description
command_line() Uses a printf-style format string to specify the command and its arguments to use when starting a new program in the spawned process.
setenv () Specifies environment variables to be added to the environment in the spawned process.
working_directory() Specifies a new directory that the spawned process will change to before starting a new program image.
set_handles() Sets specific file handles that the spawned process will use for its STDIN, STDOUT, and STDERR.
pass_handle() Indicates a handle that should be passed to the spawned process.
Figure 8.3. The ACE_Process_Options Class Diagram

Section 8.2 on page 161 explained why ACE_Process offers

  1. Methods that are portable to all operating systems that support processes

  2. Methods that work only on certain platforms

The ACE_Process_Options class also uses this approach. Its methods listed above offer a portable set of properties for all multiprocess platforms. The methods listed below access platform-specific properties:

Method Description
creation_flags() Specifies whether or not to run a new program image in the spawned process (POSIX).
avoid_zombies() Allows ACE_Process to take steps to ensure that the spawned process does not end up a zombie ( defunct ) process when it exits (POSIX).

setruid() seteuid()

Set the real and effective user ID, respectively, for the spawned process (POSIX).
set_process_attributes() Allows access to process attribute settings for the spawned process (Win32).

These methods allow multiprocessing applications to take advantage of nonportable capabilities, without having to rewrite process property management code for each platform.

Example

This section generalizes the example code from Section 8.2 as follows :

  • It uses the WORKING_DIR environment variable to set the program's working directory, which is where the factorial.log file resides.

  • It passes the program name to child processes via an environment variable.

  • It prints diagnostic messages to the factorial.log file that contain the program name and process ID.

#include "ace/OS.h" #include "ace/ACE.h" #include "ace/Process.h" int main (int argc, char *argv[]) { ACE_Process_Options options; FILE *fp = 0; char *n_env = 0; int n; if (argc == 1) { // Top-level process. n_env = ACE _OS::getenv ("FACTORIAL"); n = n_env == 0 ? 0 : atoi (n_env); options.command_line ("%s %d", argv[0], n == 0 ? 10 : n); const char *working_dir = ACE_OS::getenv ("WORKING_DIR"); if (working_dir) options.working_directory (working_dir); fp = fopen ("factorial.log", "a"); options.setenv ("PROGRAM=%s", ACE::basename (argv[0])); } else { fp = fopen ("factorial.log", "a"); if (atoi (argv[l]) == 1) { fprintf (fp, "[%s%d]: base case\n", ACE_OS::getenv ("PROGRAM"), ACE_OS::getpid ()); fclose (fp); return 1; // Base case. } else { n = atoi (argv[1]); options.command_line ("%s %d", argv[0], n - 1); } } ACE_Process child; child.spawn (options); // Make the ''recursive'' call. child.wait (); int factorial = n * child.exit_code (); // Compute n factorial. fprintf (fp, "[%s %d] : %d! == %d\n", ACE_OS::getenv ("PROGRAM"), ACE_OS::getpid (), n, factorial); fclose (fp); return factorial; }

Although the system functions called by the ACE_Process_Options and ACE_Process code vary considerably for different OS platforms, such as Win32 and POSIX, the code above will compile and run portably and correctly on all of them.

I l @ ve RuBoard

Категории