Getrlimit and Setrlimit functions
Every process has a set of resource limits, some of which can is queried and changed by the Getrlimit and Setrlimit Ons.
#include <sys/resource.h>
int getrlimit (int resource, struct rlimit *rlptr);
int setrlimit (int resource, struct const rlimit *rlptr);
These two functions are defined in the XSI option to the single UNIX specification.
Each call to this two functions specifies a single resource and a pointer to the
Following structure:
STRCT rlimit
{
rlimt_t rlimit_cur;
rlimt_t Rlimit_max;
}
Three rules govern the changing of the resource limits.
1.A process can change it soft limit to A value less than or equal to its hard limit.
2.A process can lower its hard limit to A value greater than or equal to its soft
Limit. This lowering of the hard limit are irreversible for normal users.
3.Only a superuser process can raise a hard limit.
An infinite limit are specified by the constant rlim_infinity.
#include "apue.h" #include <sys/resource.h> #define DOIT (name) pr_limits (#name, name) static void Pr_limits (char *
, int); int main (void) {#ifdef rlimit_as doit (rlimit_as) #endif doit (rlimit_core) doit (rlimit_cpu) doit (rlimit_d
ATA) doit (rlimit_fsize) #ifdef Rlimit_memlock doit (rlimit_memlock);
#endif #ifdef rlimit_msgqueue doit (rlimit_msgqueue);
#endif #ifdef Rlimit_nice doit (rlimit_nice);
#endif doit (rlimit_nofile);
#ifdef Rlimit_nproc doit (rlimit_nproc);
#endif #ifdef rlimit_npts doit (rlimit_npts);
#endif #ifdef Rlimit_rss doit (rlimit_rss);
#endif #ifdef rlimit_sbsize doit (rlimit_sbsize);
#endif #ifdef rlimit_sigpending doit (rlimit_sigpending);
#endif doit (rlimit_stack) #ifdef Rlimit_swap doit (rlimit_swap) #endif #ifdef rlimit_vmem doit (rlimit_vmem)
#endif return 0;
} static void Pr_limits (char *name,int Resource) {struct rlimit limit;
unsigned long long Lim; if (Getrlimit (ResoUrce,&limit) <0) Err_sys ("Getrlimit error for%s", name);
printf ("%-14s", name);
if (limit.rlim_cur==rlim_infinity) {printf ("(infinite)");
else {lim=limit.rlim_cur;
printf ("%10lld", Lim);
} if (limit.rlim_max==rlim_infinity) {printf ("(infinite)");
else {Lim=limit.rlim_max;
printf ("%10lld", Lim);
} putchar ((int) ' \ n '); }
Print the current resource limits
We ' ve used the ISO C string-creation operator (#) in the doit macro, to generate the string value for each Resou Rce name. When we say
Doit (rlimit_core);
The C preprocessor expands this into
Pr_limits ("Rlimit_core", Rlimit_core);
Process Control
Introduction
We now turn to the process control provided by the UNIX System. This is includes the creation of new processes, program execution, and process termination. We also look at the various IDs this are the property of the Process-real, effective, and saved; User and group Ids-and how they ' re affected by the process control primitives. Interpreter files and the system function are also covered. We conclude the chapter by looking in the process accounting provided by most UNIX systems. Process Identifiers
Every process has a unique process ID, a non-negative integer. Because the process ID is the ' only well-known identifier ' a process that's always unique, it is often used as a piece O f other identifiers, to guarantee uniqueness.
Although unique, process IDs are reused. As processes terminate, their IDs become candidates for reuse. Most UNIX Systems implement algorithms to delay reuse, however, so, newly created processes are assigned IDs different From those used by processes that terminated recently. This is prevents a new process from being mistaken for the previous process to have used the same ID.
There are some special processes, but the details differ from implementation to
implementation.
Process ID 0 is usually the scheduler process and is often known as the swapper. No program on disk corresponds to this process, which are part of the kernel and is known as a system process.
Process ID 1 is usually the INIT process and are invoked by the kernel in the end of the bootstrap procedure. The program file for this process was/etc/init in older versions of the UNIX System and is/sbin/init in newer versions. This process is responsible to bringing up a UNIX system after the kernel has been bootstrapped. Init usually reads the system-dependent initialization files-the/etc/rc* files Or/etc/inittab and the files in/etc/in It.d-and brings the system to a certain state, such as multiuser.
The init process never dies. It is a normal user process, not a system process within the kernel, like the swapper, although it does run with Superuser privileges.
In Mac OS X 10.4, the init process is replaced with the LAUNCHD process, which performs the same set of tasks as Init, BU T has expanded functionality.
Each UNIX System implementation has it own set of kernel processes that provide System services. On some virtual memory implementations to the UNIX System, Process ID 2 is the Pagedaemon. This process was responsible for supporting the paging of the virtual memory system.
#include <unistd.h>
pid_t getpid (void);
pid_t getppid (void);
uid_t getuid (void);
uid_t geteuid (void);
gid_t getgid (void);
gid_t getegid (void);
Fork Function
#include <unistd.h>
pid_t fork (void);
The new process created by fork was called the child process. This function is called once but returns twice. The only difference in the "returns is" that "return" in the "the" is 0, whereas the "return value" in the "parent is T His process ID of the new child. The reason the "child's process ID is returned" to "is" that a "process can have more than one child, and there is n o function that allows a process to obtain the process IDs of it children. The reason fork returns 0 to the ' the ' of the ' is ' a process can have only a single parent, and the child can always call GETP PID to obtain the process ID of it parent. (Process ID 0 is reserved the kernel, so it's not possible the process ID of "a child.")
Both the child and the parent continue executing with the instruction that follows
The call to fork. The child is a copy of the parent.
Modern implementations don ' t perform a complete copy of the parent ' s data, stack, and heap, since a fork is often followed by an exec. Instead, a technique called copy-on-write (COW) is used. These regions are are shared by the parent and the "child" and have their protection changed by the kernel to read-only. If either process tries to modify these regions, the kernel then makes a copy of this piece of memory only, typically a ' Page ' in a virtual memory system.
Variations of the fork function are provided by some platforms. All four platforms discussed into this book support the Vfork (2) variant of discussed in the next section.
#include "apue.h"
int globvar=6;
Char buf[]= "A write to stdout\n";
int main (void)
{
int var;
pid_t pid;
var=88;
if (Write (stdout_fileno,buf,sizeof (BUF)-1)!=sizeof (BUF)-1)
{
Err_sys ("write error");
}
printf ("Before fork\n");
if ((Pid==fork ()) <0)
{
Err_sys ("fork Error");
}
else if (pid==0)
{
globvar++;
var++;
}
else
{sleep
(2);
}
printf ("Pid=%ld, glob=%d, var=%d\n", (long) getpid (), globvar,var);
return 0;
}
Example of fork function
In general, we never know whether of the child starts executing before the parent, or vice versa. The order depends on the scheduling algorithm used by the kernel. If It's required the child and parent synchronize their actions, some form of interprocess communication is required.
The Write function is not buffered. Because write is called before the fork, its data are written once to standard output. The standard I/O library, however, is buffered. Standard output is line buffered if it's connected to a terminal device; Otherwise, it ' s fully buffered. File Sharing
The child ' s standard output is also redirected. Indeed, one characteristic of fork is-that-all file-descriptors that are the. We say ' duplicated ' because it ' s as if the DUP function had been for each called. The parent and the child share a file table entry for every open descriptor.
There are two normal cases for handling the descriptors after a fork.
1.The parent waits for the "child" to complete. In this case, the parent does is not need to does anything with its descriptors. When the "child terminates", any of the "shared descriptors" that "child" read from or wrote to would have their file offsets Updated accordingly.
2.Both the parent and the child go their own ways. Here, after the fork, the parent closes the descriptors, it doesn ' t need, and the child does the same thing. This is way, neither interferes with the other ' s open descriptors. This scenario was often found with network servers.
Besides the open files, numerous other properties of the "Parent are inherited by"
Child:real user ID, Real gro Up ID, effective user ID, and effective Group ID supplementary Group IDs Process Group ID session ID controlling terminal The Set-user-id and Set-group-id flags current working directory Root directory File mode creation Mask Signal mask and di Spositions the CLOSE-ON-EXEC flag for any open file descriptors environment attached shared memory segments memory mapping s Resource limits
The differences between the parent and child are the return values from fork are different. The process IDs are different. The two processes have different parent process ids:the Parent process ID of the child is the parent; The parent process ID of the parent doesn ' t change. The child's Tms_utime, Tms_stime, Tms_cutime, and tms_cstime values are set to 0 (this times are discussed in section 8.1 7). File locks set by the "parent are not inherited by the" child. Pending alarms are cleared for the child. The set of pending signals for the "the" Child is set to the empty set.
There are two uses for fork:
1.When a process wants to duplicate itself so, the parent and the child can all execute different sections of code at The same time. This is common to network servers-the parent waits for a service request from a client. When the request was arrives, the parent calls Fork and lets the child handle the request. The parent goes back to waiting for the next service request to arrive.
2.When a process wants to execute a different. This is common for shells. In this case, the child does a exec (which we describe in section 8.10) right after it returns from the fork.
The single UNIX specification does include spawn interfaces in the Advanced option group. These interfaces are are not intended to is replacements for fork and exec, however. They are intended to support systems, have difficulty implementing fork efficiently, especially systems without-hardwa Re support for memory management. vfork Function
The function vfork has the same calling sequence and same return values as fork, but the semantics of the two functions di Ffer.
The Vfork function originated with 2.9BSD. Some Consider the function a blemish, but all of the platforms covered in this book support it. In fact, the BSD developers removed it to the 4.4BSD release, but all the open source BSD distributions this derive from 4.4BSD added support for it their own releases. The Vfork function was marked as a obsolescent interface in Version 3 of the "the single UNIX specification and is removed en Tirely in Version 4. We include it for historical reasons only. Portable applications should it.
The Vfork function is intended to create a new process for the purpose of executing a new program (step 2 at the end O f the previous section), similar to the
method used by the Bare-bones shell from Figure 1.7. The Vfork function creates the new process, just like fork, without copying the "address" and "the" the "parent into" the child , as the child won ' t reference so address spaces; The child simply calls exec (or exit) right after the vfork. Instead, the child runs in the address space of the parent until it calls either exec or exit. This optimization are more efficient on some implementations of the UNIX System, but leads to undefined results if the Chil D modifies any data (except the variable used to hold the return value from vfork), makes function calls, or returns Witho UT calling exec or exit.
#include "apue.h"
int globvar=6;
Char buf[]= "A write to stdout\n";
int main (void)
{
int var;
pid_t pid;
var=88;
printf ("Before vfork\n");
if ((Pid==vfork ()) <0)
{
Err_sys ("Vfork error");
}
else if (pid==0)
{
globvar++;
var++;
return 0;
}
printf ("Pid=%ld, glob=%d, var=%d\n", (long) getpid (), globvar,var);
return 0;
}
Example of vfork function
_exit does not perform any flushing of standard I/O buffers. If We call exit instead, the results are indeterminate. Depending on the implementation of the standard I/O library, we might no difference in the output, or we might find th At the output from the "the" in the parent has disappeared.
If the child calls exit, the implementation flushes the standard I/O streams. If this is the ' only action ' taken by the library, then we would be no difference from the output generated if the child CAL LED _exit. If The implementation also closes the standard I/O streams, however, the memory representing the FILE object for the stand ARD output is cleared out. Because the child is borrowing the parent's address spaces, when the parent resumes and calls printf, no output would appear and printf would return−1. Note that the parent's Stdout_fileno is still valid, as the child gets a copy of the parent ' s file descriptor array.
Most modern implementations of Exit do not bother to close the streams. Because the "process is" about to exit, the kernel would close all the file descriptors open in the process. Closing them in the library simply adds overhead without any benefit.