Kernel Process Tables
The process is truly the king of the HP-UX operating system, the primary entity managed by the kernel. In general, the prime directive for the HP-UX kernel is to level the playing field and make sure every process thread gets a chance to run.
The Process Table
Threads are the schedulable entity, but it is the venerable process that owns resources (at least as long as it is active). As such, the process table (see Figure 3-12) is the starting point for all process and thread management-related activities in the kernel. HP-UX 11.i features a dynamic process table. Entries are created as needed by allocating memory from a kernel memory arena and adding it to the linked list of active processes. The beginning of the process list is pointed to by the kernel pointer proc_list*.
Figure 3-12. Kernel Process Tables
Prior to the HP-UX 11.i release, the process table was a fixed-length table initialized at system boot, pointed to by the kernel pointer proc*, and defined in size by the tunable kernel parameter nproc. The original nproc parameter has been maintained through the current release for a couple of reasons. There are several static kernel tables that are sized directly in proportion to the process table. While the process table is now dynamic, not all related structures have made this change. It is reasonable to assume that in future releases this may not continue to be an issue, but for now nproc needs to be declared. This parameter also serves as a maximum limit for the growth of a system's process table.
Process management starts by using the phash[x] to locate a specific entry in the process table. Once we have located the appropriate proc structure, we follow its pointers to other key kernel tables.
The kthread Table
kthread structures are also dynamically allocated from a kernel memory arena and linked onto a list of active kthreads. In addition, all kthread structures belonging to a single process are linked together and to the parent process proc structure. Such threads are commonly called siblings. The process table has a pointer to the first and last of its sibling threads and maintains a count of how many it has spawned.
Prior to HP-UX 11.i, the kthread table was also a static array allocated at system boot and sized by the kernel parameter kthreadNTHREAD.
The vas and pregion Tables
In the grand scheme of things, a pregion contains the address offset and size of a process's logical region, access identifier information, and a type designator that specifies the usage mode. The pregion also maps a process's logical region into the system's VAS and creates a linked list of a process's virtual memory elements. When a process causes a page fault (requests access to a virtual page that is not currently memory-resident), the fault handler must search the process's linked list of pregions to determine which kernel region contains the necessary data for obtaining the faulting page. These structures and the underlying kernel region structures are the backbone of memory fault handling and have been optimized for function and efficiency. In addition to keeping track of its threads, a process table must also provide a map to each of the memory regions it will require for execution. To this end, a structure called a vas is created and linked to the proc of the process. The vas is the nexus of a linked list of pregion structures connected by a skip list. Each pregion links the process and its threads to a kernel-managed region structure. The pregion-to-region abstraction layer facilitates the mapping of shared objects by the kernel.
Process File Descriptors
All sibling threads share access to any file that has been opened in the name of its parent process. Each open() system call results in an entry in the process's file descriptor table. The size of this table is controlled by the kernel-tunable parameter nfile and prevents unlimited opens by a runaway thread.
All I/O is file I/O, and as such the file descriptor table represents the process's gateway to the "real world." File descriptors are required for each read and write operation. For example, consider the shell's default STDIN, STDOUT, and STDERR descriptors. As is the case with the shell, multiple file descriptors may point to the same file path, some for reading and some for writing.
The uarea Structure
An additional structure being introduced here is the uarea. The uarea is implemented as a kernel memory region, and unlike the other regions mapped in the parent process's pregion chain, access to the uarea is private to a single kthread. If there are multiple siblings, then there is an equal number of uarea pregions linked to the process's vas. An interesting note is that the uarea is mapped into a process's vas but never directly accessed by a user thread. The kernel has exclusive usage rights and stores the threads register image, known as a process control block (PCB) prior to a context switch-out. It then loads the next thread on the run queue's PCB from its uarea prior to switching it in.