[FreeBSD] Kernel Services and Process Management

2024. 5. 1. 04:49ComputerScience/FreeBSD

 

 

 

Kernel Services 

  • The boundary between the kernel- and user-level code is enforced by hardware-protection facilities provided by the underlying hardware. The kernel operates in a separate address space that is inaccessible to user processes. Privileged operations—such as starting I/O and halting the central processing unit (CPU)—are available to only the kernel. Applications request services from the kernel with system calls.
  • System calls are used to cause the kernel to execute complicated operations, such as writing data to secondary storage, and simple operations, such as returning the current time of day. All system calls appear synchronous to applications: An application does not run while the kernel performs the actions associated with a system call.
  • The kernel may finish some operations associated with a system call after it has returned. For example, a write system call will copy the data to be written from the user process to a kernel buffer while the process waits, but it will usually return from the system call before the kernel buffer is written to the disk.
  • A system call usually is implemented as a hardware trap that changes the CPU’s execution mode and the current address-space mapping. Parameters supplied by users in system calls are validated by the kernel before being used. Such checking ensures the integrity of the system. All parameters passed into the kernel are copied into the kernel’s address space to ensure that validated parameters are not changed as a side effect of the system call.
  • System-call results are returned by the kernel, either in hardware registers or by their values being copied to user-specified memory addresses. Like parameters passed into the kernel, addresses used for the return of results must be validated to ensure that they are part of an application’s address space.
  • If the kernel encounters an error while processing a system call, it returns an error code to the user. For the C programming language, this error code is stored in the global variable errno, and the function that executed the system call returns the value -1.
  • User applications and the kernel operate independently of each other. FreeBSD does not store I/O control blocks or other operating-system-related data structures in the application’s address space. Each user-level application is provided an independent address space in which it executes.
  • The kernel makes most state changes—such as suspending a process while another is running—invisible to the processes involved.

 

 

 

Process Management

  • FreeBSD supports a multitasking environment. Each task or thread of execution is termed a process. In FreeBSD, the process context consists of user-level state, including the contents of its address space and the run-time environment, and kernel-level state, which includes scheduling parameters, resource controls, and identification information. The context includes everything used by the kernel in providing services for the process. Users can create processes, control the processes’ execution, and receive notification when the processes’ execution status changes.
  • Every process is assigned a unique value, termed a process identifier (PID). This value is used by the kernel to identify a process when reporting status changes to a user, and by a user when referencing a process in a system call.
  • The kernel creates a process by duplicating the context of another process. The new process is termed a child process of the original parent process. The context duplicated in process creation includes both the user-level execution state of the process and the process’s system state managed by the kernel.

 

 

 

 

 

  • A process may create a new process that is a copy of the original by using the fork system call. The fork call returns twice: once in the parent process, where the return value is the process identifier of the child, and once in the child process, where the return value is 0. The parent–child relationship induces a hierarchical structure on the set of processes in the system. The new process shares all its parent’s resources, such as file descriptors, signal-handling status, and memory layout.
  • Although there are occasions when the new process is intended to be a copy of the parent, the loading and execution of a different program is a more useful and typical action. A process can overlay itself with the memory image of another program, passing to the newly created image a set of parameters, using the system call execve. One parameter is the name of a file whose contents are in a format recognized by the system—either a binary-executable file or a file that causes the execution of a specified interpreter program to interpret its contents.
  • A process may terminate by executing an exit system call, sending 8 bits of exit status to its parent.
  • If a process wants to communicate more than a single byte of information with its parent, it must either set up an interprocess-communication(IPC) channel using pipes or sockets, or use an intermediate file. 
  • A process can suspend execution until any of its child processes terminate using the wait system call, which returns the PID and exit status of the terminated child process. A parent process can arrange to be notified by a signal when a child process exits or terminates abnormally. Using the wait4 system call, the parent can retrieve information about the event that caused termination of the child process and about resources consumed by the process during its lifetime.
  • If a process is orphaned because its parent exits before it is finished, then the kernel arranges for the child’s exit status to be passed back to a special system process, init. 

 

  • Processes are scheduled for execution according to a process-priority parameter. Under the default timesharing scheduler, this priority is managed by a kernel-based scheduling algorithm. Users can influence the scheduling of a process by specifying a parameter (nice) that weights the overall scheduling priority but are still obligated to share the underlying CPU resources according to the kernel’s scheduling policy. FreeBSD also has a real-time scheduler. Processes running under the real-time scheduler manage their own priority, which is not changed by the kernel.
  • The kernel will run the highest priority real-time process to the exclusion of all other processes. Thus, real-time processes are not obliged to share the underlying CPU resources.

 

 

 

Signals

  • The system defines a set of signals that may be delivered to a process. Signals in FreeBSD are modeled after hardware interrupts. A process may specify a user-level subroutine to be a handler to which a signal should be delivered. When a signal is generated, it is blocked from further occurrence while it is being caught by the handler. Catching a signal involves saving the current process context and building a new one in which to run the handler.
  • The signal is then delivered to the handler, which can either abort the process or return to the executing process (perhaps after setting a global variable). If the handler returns, the signal is unblocked and can be generated (and caught) again.
  • Alternatively, a process may specify that a signal is to be ignored or that a default action, as determined by the kernel, is to be taken. The default action of certain signals is to terminate the process. This termination may be accompanied by creation of a core file that contains the current memory image of the process for use in postmortem debugging. Some signals cannot be caught or ignored. These signals include SIGKILL, which kills runaway processes, and the job-control signal SIGSTOP.
  • A process may choose to have signals delivered on a special stack so that sophisticated software stack manipulations are possible. For example, a language supporting co-routines needs to provide a stack for each co-routine. The language run-time system can allocate these stacks by dividing up the single stack provided by FreeBSD. If the kernel does not support a separate signal stack, the space allocated for each co-routine must be expanded by the amount of space required to catch a signal.
  • All signals have the same priority. If multiple signals are pending simultaneously, the order in which signals are delivered to a process is implementation specific. Signal handlers execute with the signal that caused their invocation to be blocked, but other signals may yet occur. Mechanisms are provided so that processes can protect critical sections of code against the occurrence of specified signals.

 

 

 

Process Groups and Sessions

  • Processes are organized into process groups. Process groups are used to control access to terminals and to provide a means of distributing signals to collections of related processes. A process inherits its process group from its parent process. Mechanisms are provided by the kernel to allow a process to alter its process group or the process group of its descendants. Creating a new process group is easy; the value of a new process group is ordinarily the process identifier of the creating process.
  • The group of processes in a process group is sometimes referred to as a job and is manipulated by high-level system software, such as the shell. A common kind of job created by a shell is a pipeline of several processes connected by pipes, such that the output of the first process is the input of the second, the output of the second is the input of the third, and so forth. The shell creates such a job by forking a process for each stage of the pipeline, and then putting all those processes into a separate process group.
  • A user process can send a signal to each process in a process group as well as to a single process. A process in a specific process group may receive software interrupts affecting the group, causing the group to suspend or resume execution, or to be interrupted or terminated.
  • A terminal (or more commonly a software emulation of a terminal called a pseudo-terminal) has a process-group identifier assigned to it. This identifier is normally set to the identifier of a process group associated with the terminal. A job-control shell may create several process groups associated with the same terminal; the terminal is the controlling terminal for each process in these groups. A process may read from a descriptor for its controlling terminal only if the terminal’s process-group identifier matches that of the process. If the identifiers do not match, the process will be blocked if it attempts to read from the terminal. By changing the process-group identifier of the terminal, a shell can arbitrate a terminal among several different jobs. This arbitration is called job control with process groups.
  • Just as a set of related processes can be collected into a process group, a set of process groups can be collected into a session. The main uses for sessions are to create an isolated environment for a daemon process and its children, and to collect a user’s login shell and the jobs that that shell spawns.