System Interface Guide

Functions

The functions listed in Table 3-1 are used to control user processes:

Table 3-1 Process Functions

Function Name 

Purpose 

fork

Create a new process 

exec

execl

execv

execle

execve

execlp

execvp

Execute a program 

 

 

 

 

exit

_exit

Terminate a process 

wait

Wait for a child process to stop or terminate 

dladdr

Translate address to symbolic information 

dlclose

Close a shared object 

dlerror

Get diagnostic information 

dlopen

Open a shared object 

dlsym

Get the address of a symbol in a shared object 

setuid

setgid

Set user and group IDs 

setpgrp

Set process group ID 

chdir

fchdir

Change working directory 

chroot

Change root directory 

nice

Change priority of a process 

getcontext

setcontext

Get and set current user context 

getgroups

setgroups

Get or set supplementary group access list IDs 

getpid

getpgrp

getppid

getpgid

Get process, process group, and parent process IDs 

 

 

getuid

geteuid

getgid

getegid

Get real user, effective user, real group, and effective group IDs 

 

 

pause

Suspend process until signal 

priocntl

Control process scheduler  

setpgid

Set process group ID 

setsid

Set session ID 

waitid

Wait for a child process to change state 

Spawning New Processes

fork(2)

The fork call creates a new process that is an exact copy of the calling process. The new process is the child process; the old process is the parent process. The child gets a new, unique process ID. The fork function returns a 0 to the child process and the child's process ID to the parent. The returned value is how a forked program determines whether it is the parent process or the child process.

The new process created by the fork or exec function inherits all open file descriptors from the parent including the three standard files: stdin, stdout, and stderr. When the parent has buffered output that should appear before output from the child, the buffers must be flushed before the fork.

The following code is an example of a call to fork and the subsequent actions:


	pid_t		pid;

 	pid = fork;
 	switch (pid) {
 		case -1:			/* fork failed */
 			perror ("fork");
 			exit (1);
 		case 0:			/* in new child process */
 			printf ("In child, my pid is: %d\n", getpid(); );
 			do_child_stuff();
 			exit (0);
 		default:			/* in parent, pid contains PID of child */
 			printf ("In parent, my pid is %d, my child is %d\n", getpid(), pid);
 			break;
 	}

 	/* Parent process code */
 	...

If the parent and the child process both read input from a stream, whatever is read by one process is lost to the other. So, once something has been delivered from the input buffer to a process, the buffer pointer has moved on.


Note -

An obsolete practice is to use fork() and exec() to start another executable, then wait for the new process to die. In effect, a second process is created to perform a subroutine call. It is much more efficient to use dlopen(), dlsym(), and dlclose() as described in "Runtime Linking " to make a subroutine temporarily resident in memory.


exec(2)

exec is the name of a family of functions that includes execl, execv, execle, execve, execlp, and execvp. All load a new process over the calling process, but with different ways of pulling together and presenting the arguments of the function. For example, execl could be used like this


	execl("/usr/bin/prog2", "prog2", progarg1, progarg2, (char (*)0));

The execl argument list is:

/usr/bin/prog2

The path name of the new program file. 

prog2

The name the new process gets in its argv[0].

progarg1, progarg2

The arguments to prog2 as char (*)s.

(char (*)0)

A null char pointer to mark the end of the arguments. 

See execl(2) for more details.

There is no return from a successful execution of any variation of exec(); the new process overlays the process that calls exec. The new process also takes over the process ID and other attributes of the old process. If a call to exec fails, control is returned to the calling program with a return value of -1. You can check errno to learn why it failed.

Runtime Linking

An application can extend its address space during execution by binding to additional shared objects. There are several advantages in this delayed binding of shared objects:

Process Scheduling

The UNIX system scheduler determines when processes run. It maintains process priorities based on configuration parameters, process behavior, and user requests. It uses these priorities to assign processes to the CPU.

Scheduler functions give users varying degrees of control over the order in which certain processes run and the amount of time each process may use the CPU before another process gets a chance.

By default, the scheduler uses a time-sharing policy. A time-sharing policy adjusts process priorities dynamically in an attempt to give good response time to interactive processes and good throughput to CPU-intensive processes.

The scheduler also provides an alternate real-time scheduling policy. Real-time scheduling allows users to set fixed priorities--priorities that the system does not change. The highest priority real-time user process always gets the CPU as soon as it can be run, even if other system processes are also eligible to be run. A program can therefore specify the exact order in which processes run. You can also write a program so that its real-time processes have a guaranteed response time from the system.

For most Solaris 2.x system environments, the default scheduler configuration works well and no real-time processes are needed: administrators need not change configuration parameters and users need not change scheduler properties of their processes. However, for some programs with strict timing constraints, real-time processes are the only way to guarantee that the timing requirements are met.

For more information, see priocntl(1), priocntl(2) and dispadmin(1M) of the man Pages(2): System Calls. For a fuller discussion of this subject, see Chapter 4, Process Scheduler ."