In order for a process to perform whatever task it is instructed to perform, it may need to write data to a file, send data to a printer, or display data to a screen. A process may need input from the user via the keyboard or input from a file. Processes can also use other processes, such as a subroutine, as a resource. Subroutines, files, semaphores, mutexes , keyboards, and display screens are all examples of resources that can be utilized by a process. A resource is anything used by a process at any given time as a source of data, a means to process, compute, or display data or information. In order for a process to access a resource, it must first make a request to the operating system. If the resource is available, the operating system allows the process to use the resource. The process uses the resource, then releases it so it will be available to other processes. If the resource is not available, the request is denied and the process must wait. When the resource becomes available, the process is awakened. This is the basic approach to resource allocation. Figure 3-11 shows a resource allocation graph, which shows which processes hold resources and which processes are requesting resources. In Figure 3-11, process B makes a request for resource 2, which is held by process C. Process C makes a request for resource 3, which is held by process D. Figure 3-11. A resource-allocation graph that shows which processes hold resources and which processes are requesting resources.
When more than one request to access a resource is granted, the resource is sharable , which is shown in Figure 3-11 as well. Process A shares resource 1 with process D. A resource may allow many processes concurrent access or may only allow one process limited time before allowing another process access. An example of this type of shared resource is the processor. A process is assigned a processor for a short interval and then another process is assigned the processor. When only one request to access a resource is granted at a time and that occurs after the resource has been released by another process, the resource is unshared and the process has exclusive access to the resource. In a multiprocessor environment, it is important to know whether a shared resource can be accessed simultaneously or by only one process at a time in order to avoid some of the pitfalls inherent in concurrency. Some resources can be changed or modified by a process. Other resources will not allow a process to change it. The behavior of shared modifiable or unmodifiable resources is determined by the resource type.
3.8.1 Types of ResourcesThere are three basic types of resources: hardware, data, and software. Hardware resources are physical devices connected to the computer. Examples of hardware resources are processors, main memory, and all other I/O devices including printers, hard disk, tape, and zip drives , monitors , keyboards, sound, network, graphic cards, and modems. All these devices can be shared by several processes. Some hardware resources are preempted to allow different processes access. For example, a processor is preempted to allow different processes time to run. RAM is another example of a shared, preemptible resource. When a process is not executing, some of the physical page frames it occupies may be swapped out to secondary storage in order for another process to be swapped in to occupy those now-available page frames. A range of memory can only be occupied by the page frames of one process at any given time. An example of a shared, nonpreemptible resource is a printer. When a printer is shared, the jobs sent to the printer by each process is stored in a queue. Each job is printed to completion before another job starts. The printer is not preempted by any waiting printer jobs unless the current job is canceled . Data resources such as objects; system data such as environment variables, files, and handles, and globally defined variables such as semaphores and mutexes are all resources shared and modified by processes. Regular files and files associated with physical devices such as the printer can be opened in such a manner, restricting the type of access processes have to that file. Processes may be granted only read or write access, or read/write access. A child process inherits the parent process's resources and access rights to those resources existing at the time the child's process was created. The child process can advance the file pointer, close, modify, or overwrite the contents of a file opened by the parent. Shared memory and files with write permission require their access to be synchronized. Shared data such as semaphores or mutexes can be used to synchronize access to other shared data resources. Shared libraries are examples of software resources . Shared libraries provide a common set of services or functions to processes. Processes can also share applications, programs, and utilities. In such a case, only one copy of the program(s) code is brought into memory. There will be separate copies of the data, one for each user (process). Program code that is not changed (also called reentrant ) can be accessed by several processes simultaneously. 3.8.2 POSIX Functions to Set Resource LimitsPOSIX defines functions that restrict a process's ability to use certain resources. The operating system sets limitations on a process's ability to utilize system resources. These resource limits affect the following:
The operating system sets a hard limit on resource usage by a process. The process can set or change the soft limit of its resources but its value should not exceed the hard limit set by the operating system. A process can lower its hard limit but this value should be greater than or equal to the soft limit. When a process lowers its hard limit, it is irreversible. Only processes with special privileges can raise their hard limit.
The setrlimit() function is used to set limits on the consumption of specified resources. This function can set both hard and soft limits. The parameter resource represents the resource type. Table 3-6 lists the values for resource with a brief description. The soft and hard limits of the specified resource are represented by the rlp parameter. The rlp parameter points to a struct rlimit that contains two objects of type rlim_t : struct rlimit { rlim_t rlim_cur; rlim_t rlim_max; }; rlim_t is an unsigned integer type. rlim_cur contains the current or soft limit. rlim_max contains the maximum or hard limit. rlim_cur and rlim_max can be assigned any value. They can also be assigned these symbolic constants defined in the header <sys/resource.h> :
The soft or hard limit can be set to RLIM_INFINITY , which means the resource is unlimited. Table 3-6. Values for resource
The getrlimit() returns the soft and hard limit of the specified resource in the rlp object. Both functions return if successful and -1 if unsuccessful . Example 3.4 contains an example of a process setting the soft limit for file size in bytes. Example 3.4 Using setrlimit() to set the soft limit for file size.#include <sys/resource.h> //... struct rlimit R_limit; struct rlimit R_limit_values; //... R_limit.rlim_cur = 2000; R_limit.rlim_max = RLIM_SAVED_MAX; setrlimit(RLIMIT_FSIZE,&R_limit); getrlimit(RLIMIT_FSIZE,&R_limit_values); cout << "file size soft limit: " << R_limit_values.rlim_cur << endl; //... In Example 3.4, the file size soft limit is set to 2000 bytes and the hard limit is set to the hard limit maximum. R_limit and the RLIMIT_FSIZE are passed to the setrlimit() function. getrlimit() are passed RLIMIT_FSIZE and R_limit_value . The soft value is sent to cout . The getrusage() function returns information about the measures of resources used by the calling process. It also returns information about the terminated child process the calling process is waiting for. The parameter who can have these values: RUSAGE_SELF RUSAGE_CHILDREN If the value for who is RUSAGE_SELF , then the information returned will pertain to the calling process. If the value for who is RUSAGE_CHILDREN , then the information returned is pertaining to the calling process's children. If the calling process did not wait for its children, then the information pertaining to the child process is discarded. The information is returned in the r_usage . r_usage points to a struct rusage that contains information listed and described in Table 3-7. If the function is successful, it returns , if unsuccessful, it returns -1 . |