Mac OS X Internals: A Systems Approach

7.1. Processes: From Early UNIX to Mac OS X

The process abstraction has long been used to represent various activities in a computer system. In early UNIX, a process could be running a user program, or it could represent one or more flows of control in the kernelfor example, process 0 ran sched(), the process scheduler. The only way to create a new process in traditional UNIX was through the fork() system call, and the only way to run a new program within a process was through the exec() system call.

The Earliest fork() and exec() System Calls

The following are excerpts from the manual pages of the fork() and exec() system calls in First Edition Research UNIX (circa late 1971)[3]:

fork is the only way new processes are created. The new process's core image is a copy of that of the caller of fork; the only distinction is the return location of the fact that r0 in the old process contains the process ID of the new process.

exec overlays the calling process with the named file, then transfers to the beginning of the core image of the file. The first argument to exec is a pointer to the name of the file to be executed. The second is the address of a list of pointers to arguments to be passed to the file. . . . There can be no return from the file; the calling core image is lost.

[3] UNIX Programmers Manual, by K. Thompson and D. M. Ritchie (Bell Laboratories, 1971).

As compared to modern operating systems, early UNIX had a vastly simpler process abstraction. In fact, it wasn't until UNIX was rewritten in Cand ran on a PDP-11 with an MMUthat the UNIX kernel could have more than one process in memory at a time. Consider the proc structurea kernel-memory-resident process bookkeeping data structurefrom Third Edition Research UNIX (circa early 1973):

struct proc { char p_stat; /* (SSLEEP, SWAIT, SRUN, SIDL, SZOMB) */ char p_flag; /* (SLOAD, SSYS, SLOCK, SSWAP) */ char p_pri; /* current process priority */ char p_sig; /* most recent interrupt outstanding */ char p_ndis; /* index into priority "cookie" array */ char p_cook; /* cookie value */ int p_ttyp; /* controlling terminal */ int p_pid; /* process ID */ int p_ppid; /* parent process ID */ int p_addr; /* address of data segment, memory/disk */ int p_size; /* size of data segment in blocks */ int p_wchan; /* reason for sleeping */ int *p_textp; /* text segment statistics */ } proc[NPROC];

The value of NPROC, the number of entries in the process table, was set at compile timea typical value was 50. Besides program text and data, each process had kernel-mode stack and a data areathe user structure or the u-area. There could be only one current process.

7.1.1. Mac OS X Process Limits

As is the case with modern operating systems, the Mac OS X kernel has soft and hard limits on the number of processes allowed. The hard limit is either more than or equal to the soft limit. The hard limit is set at compile time and cannot be varied. The soft limit can be varied through the sysctl interface by setting the value of the kern.maxproc variable.

$ sysctl -a | grep proc kern.maxproc = 532 kern.maxfilesperproc = 10240 kern.maxprocperuid = 100 kern.aioprocmax = 16 kern.proc_low_pri_io = 0 ...

The hard limit is computed at compile time using the following formula:

// bsd/conf/param.c #define NPROC (20 + 16 * MAXUSERS) #define HNPROC (20 + 64 * MAXUSERS) int maxproc = NPROC; __private_extern__ int hard_maxproc = HNPROC; /* hardcoded limit */

The MAXUSERS value is defined per Table 71 in a configuration file in the BSD portion of the kernel. The standard Mac OS X kernel is compiled in a medium configuration, with MAXUSERS being 32. The corresponding values of NPROC and HNPROC are 532 and 2068, respectively.

Table 71. System Size Configuration

Configuration

Description

MAXUSERS

xlarge

Extra-large scale

64

large

Large scale

50

medium

Medium scale

32

small

Small scale

16

xsmall

Extra-small scale

8

bsmall

Special extra-small scale (such as for boot floppies)

2

However, the difference in the number of maximum processes allowed between early UNIX and Mac OS X is insignificant compared to the differences in the respective compositions of their process subsystems. Even though modern systems are expected to be considerably more complicated, it would not be much of an exaggeration to say that the term process has more connotations in Mac OS X than there were fields in the Third Edition UNIX process structure!

7.1.2. Mac OS X Execution Flavors

Code can execute in Mac OS X in several environments, where environments are differentiated based on one or more of the following: machine architecture, executable format, system mode (user or kernel), miscellaneous policies,[4] and so on. Each environment has its own flavor of execution. Here are examples of such environments:

[4] Examples of policies that affect program execution include those related to security and resource consumption.

  • The BSD, Mach, and I/O Kit portions of the kernel

  • The BSD user-space environment

  • The Carbon environment

  • The Classic environment

  • The Cocoa environment

  • The Java runtime environment

  • The Dashboard environment for running JavaScript-based widgets

  • The Rosetta binary translation environment that allows running PowerPC executables to run on x86-based Macintosh computers

Figure 71 shows a conceptual view of the process subsystem's composition in Mac OS X. Despite the presence of numerous process-like entities on Mac OS X, exactly one abstraction executes on a processor: the Mach thread. All other process-like entities are eventually layered atop Mach threads.

Figure 71. An overview of the Mac OS X process subsystem

Категории