Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!husc6!rutgers!labrea!aurora!ames!hc!beta!cmcl2!brl-adm!adm!KLH@SRI-NIC.arpa From: KLH@SRI-NIC.arpa (Ken Harrenstien) Newsgroups: comp.unix.wizards Subject: Combined fork/exec Message-ID: <9424@brl-adm.ARPA> Date: Mon, 21-Sep-87 23:28:09 EDT Article-I.D.: brl-adm.9424 Posted: Mon Sep 21 23:28:09 1987 Date-Received: Thu, 24-Sep-87 00:41:56 EDT Sender: news@brl-adm.ARPA Lines: 83 The discussion on combining the functions of fork() and exec() is rather interesting, as I recently implemented a forkexec() call for the TOPS-20 C implementation that we distribute (KCC). Perhaps the following description will provide additional food for thought. As background, I should explain that at SRI-NIC we create (and sometimes import) a lot of software which we try to make portable between TOPS-20 and 4.3BSD UNIX. Not all of these programs use (or can use) just the portable C functions, so we have implemented a large number of the 4.3 system calls, including fork, vfork, and exec. The problem with fork(), or even vfork(), is the usual one. If the intention of v/fork() really is to create another instance of the same program, then the time needed to copy the entire process image (even mapping it with vfork takes time) is justifiable. But in most cases, the fork() is followed almost immediately by an exec(), and the time consumed is just so much useless overhead. I believe vfork() was primarily created as a means of reducing this overhead, but it seems more like a failure of nerve -- it doesn't go far enough to help either process creation or process mapping. On TOPS-20, the most efficient way of forking off a new program is to first create an (empty) inferior fork, and then map the program file into that subfork. Other systems have similar mechanisms which likewise disagree with the fork/exec model. While I think that each system should provide as fine-grained access as possible to such functions (the pt_xxx calls in a recent message are an example), it's unlikely that any particular system would be able to easily support all of these specific things. Accordingly, for maximum portability we have to combine existing functions rather than fragment them; by using a different new function for each desired overall combination of operations, we can leave it up to the implementation to perform the combined function most efficiently. Hence, I created forkexec() to combine fork() and exec() and whatever related operations seem necessary. To avoid namespace problems, there is just this single new call; to specify a variety of desired operations, flags are used; to ensure future upwards compatibility, the only argument is a structure pointer. Because all of its generic operations can be performed with UNIX primitives, it is portable to UNIX without requiring kernel changes. And meanwhile, on systems like TOPS-20, programs which previously suffered with fork() now enjoy vastly improved performance. ################################# Synopsis: #include int forkexec(fxp) /* Returns 0 on success, -1 if failure */ struct frkxec *fxp; Partial contents of : struct frkxec { int fx_flags; /* Flag args to forkexec() */ char *fx_name; /* Program name */ char **fx_argv; /* Argument vector (if any) */ char **fx_envp; /* Environment vector (if any) */ int fx_pid; /* PID of created subfork (if won) */ int fx_waitres; /* wait() result if FX_WAIT was set */ int fx_fdin; /* FX_FDMAP: New std input fd unless -1 */ int fx_fdout; /* FX_FDMAP: New std output fd unless -1 */ ... /* Other stuff depending on flag options */ }; /* forkexec() flags */ #define FX_NOFORK 01 /* Do chain (exec), not subfork */ #define FX_PGMSRCH 02 /* Do shell-search for program name */ #define FX_FDMAP 04 /* Map standard I/O FDs from fdin, fdout */ #define FX_WAIT 010 /* Wait for subfork to finish */ ... /* Other flag options for PC setting, etc. */ ... /* FX_T20_xxx flags exist for T20-specific capabilities. */ ################################# These operations are not meant to represent everything that forkexec() could be used for; they are just the ones that I found most immediately useful, and obviously many others could be added. Note that if UNIX primitives were being used, most of the structure specifies actions that should take place in the child after a fork() is done, such as FX_FDMAP to redefine the standard input and output for the new process. The only exception is FX_WAIT, which is very convenient and happens to be much easier to do on TOPS-20 while still in the context of forkexec(). But I didn't want to call it forkexecwait()... -------