Skip to the content of the web site.

fork() and exec()

fork()

As we have already seen in class, the fork() command makes a complete copy of the running process and the only way to differentiate the two is by looking at the returned value:

  • fork() returns the process identifier (pid) of the child process in the parent, and
  • fork() returns 0 in the child.

For example, the following program performs a simple fork. The return value of fork() is pid_t (defined in the library header file <sys/types.h>; however, below it is simply assigned and implicitly cast to an int.

#include <stdio.h>

/* This program forks and and the prints whether the process is
 *   - the child (the return value of fork() is 0), or
 *   - the parent (the return value of fork() is not zero)
 *
 * When this was run 100 times on the computer the author is
 * on, only twice did the parent process execute before the
 * child process executed.
 *
 * Note, if you juxtapose two strings, the compiler automatically
 * concatenates the two, e.g., "Hello " "world!"
 */

int main( void ) {
	int pid = fork();

	if ( pid == 0 ) {
		printf( "This is being printed from the child process\n" );
	} else {
		printf( "This is being printed in the parent process:\n"
		        " - the process identifier (pid) of the child is %d\n", pid );
	}

	return 0;
}

This program, when compiled and executed on this computer prints

% gcc fork.c
% ./a.out
This is being printed from the child process
This is being printed in the parent process:
 - the process identifier (pid) of the child is 24338
%

getpid()

Every process can query its own process identifier using the getpid().

#include <stdio.h>

/* This program demonstrates that the use of the getpid() function.
 *
 * When this was run 100 times on the computer the author is
 * on, only twice did the parent process execute before the
 * child process executed.
 *
 * Note, if you juxtapose two strings, the compiler automatically
 * concatenates the two, e.g., "Hello " "world!"
 *
 * The return value of fork() is actually pid_t ('pid' 't'ype).
 * When it is assigned to 'int pid', if the type is different, there
 * is an implicit cast; however, when we print the return value
 * of getpid(), it is necessary to explicitly cast it as an
 * integer.
 *
 * The type 'pid_t' is defined in the library header <sys/types.h>
 */

int main( void ) {
	printf( "The process identifier (pid) of the parent process is %d\n", (int)getpid() );

	int pid = fork();

	if ( pid == 0 ) {
		printf( "After the fork, the process identifier (pid) "
		        "of the child is %d\n", (int)getpid() );
	} else {
		printf( "After the fork, the process identifier (pid) "
		        "of the parent is still %d\n - fork() returned %d\n",
		        (int)getpid(), pid );
	}

	return 0;
}

When executed, this prints

% gcc getpid.c
% ./a.out 
The process identifier (pid) of the parent process is 25201
After the fork, the process identifier (pid) of the child is 25202
After the fork, the process identifier (pid) of the parent is still 25201
 - fork() returned 25202
% 

As you may guess, approximately 1000 processes were created by the operating system between the time that the source code for fork.c was executed and the time that getpid.c was executed.

The exec Family of Functions

There is a family of exec() functions, all of which have slightly different characteristics:

       int execl ( const char *path, const char *arg, ... );
       int execlp( const char *file, const char *arg, ... );
       int execle( const char *path, const char *arg, ..., char *const envp[] );
       int execv ( const char *path, char *const argv[] );
       int execvp( const char *file, char *const argv[] );
       int execve( const char *file, char *const argv[], char *const envp[] );

Each system call is the word exec followed by either l or v and then possibly followed by either e or p.

The first three have are of the form execl and accept a variable number of arguments. In order to use this feature, you must load the <stdarg.h> header file. Please see the example stdarg.c.

The latter three are of the form execv in which case the arguments are passed using an array of pointers to strings where the last entry is NULL. For example, you might have

       char *argv[] = {"Hello ", "world!", NULL};

If the name ends in either l or v, the program name must be given in full.

If the name is appended by a p, it will search for the file using the current environment variable PATH, which usually includes /bin/, /usr/bin/, etc.

Finally, if the name is appended by a e, one can include an array of strings indicating environment variables, each of the form "ENVVAR=value" and the array being null terminated. For example,

       char *envp[] = {"USER=dwharder", "HOME=/home/dwharder", NULL};

Combining fork() and exec

The following program uses both fork and exec. The function forks, and if it is the child process, it launches the find command with the argument ".".

#include <stdio.h>

/* This program forks and and the prints whether the process is
 *   - the child (the return value of fork() is 0), or
 *   - the parent (the return value of fork() is not zero)
 *
 * When this was run 100 times on the computer the author is
 * on, only twice did the parent process execute before the
 * child process executed.
 *
 * Note, if you juxtapose two strings, the compiler automatically
 * concatenates the two, e.g., "Hello " "world!"
 */

int main( void ) {
	char *argv[3] = {"Command-line", ".", NULL};

	int pid = fork();

	if ( pid == 0 ) {
		execvp( "find", argv );
	}

	/* Put the parent to sleep for 2 seconds--let the child finished executing */
	wait( 2 );

	printf( "Finished executing the parent process\n"
	        " - the child won't get here--you will only see this once\n" );

	return 0;
}

The output of this, when compiled, is

% gcc exec.c 
% ./a.out 
.
./index.html
./a.out
./exec.c
./src
./src/stdarg.c
./src/getpid.c
./src/fork.c
./primary.0.html
./content.html
Finished executing the parent process
 - the child won't get here--you will only see this once
% 

For further reading, please see Chapter 3 of the on-line text Advanced Linux Programming.