#include <sys/resource.h> int getrlimit(int resource, struct rlimit *rlptr); int setrlimit(int resource, const struct rlimit *rlptr); /* 返回值:若成功,都返回 0;否则,都返回非 0 */ struct rlimit{ rlim_t rlim_cur; // soft limit: current limit rlim_t rlim_max; // hard limit: maximum value for rlim_cur };
在更改资源限制时,须遵循下列 3 条规则。
(1)任何一个进程都可将一个软限制值更改为小于或等于其硬限制值。
(2)任何一个进程都可降低其硬限制值,但必须不小于其软限制值。这种降低对普通用户而言是不可逆的。
(3)只有超级用户进程可以提高硬限制值。
常量 RLIM_INFINITY 指定了一个无限量的限制。
下图显示了 resource 参数的可选值中哪些是由 Single UNIX Specification 定义以及常用UNIX 系统的支持情况。
其中各个值的说明如下。
* RLIMIT_AS:进程总的可用存储空间的最大长度(字节)。这影响到 sbrk 函数和 mmap 函数。
* RLIMIT_CORE:core 文件的最大字节数,若其值为 0 则阻止创建 core 文件。
* RLIMIT_CPU:CPU 时间的最大量值(秒),当超过此软限制时,向进程发送 SIGXCPU 信号。
* RLIMIT_DATA:数据段的最大字节长度。这是初始化数据、非初始化以及堆的总和。
* RLIMIT_FSIZE:可以创建的文件的最大字节长度。当超过此软限制时,则向该进程发送 SIGXFSZ 信号。
* RLIMIT_MEMLOCK:一个进程使用 mlock(2) 能够锁定在存储空间中的最大字节长度。
* RLIMIT_MSQQUEUE:进程为 POSIX 消息队列可分配的最大存储字节数。
* RLIMIT_NICE:为了影响进程的调度优先级,nice 值可设置的最大限制。
* RLIMIT_NOFILE:每个进程能打开的最多文件数。更改此限制将影响到 sysconf 函数在参数 _SC_OPEN_MAX 中返回的值。
* RLIMIT_NPROC:每个实际用户 ID 可拥有的最大子进程数。更改此限制将影响到 sysconf 函数在参数 _SC_CHILD_MAX 中返回的值。
* RLIMIT_NPTS:用户可同时打开的伪终端的最大数量。
* RLIMIT_RSS:最大驻内存集字节长度(resident set size in bytes,RSS)。如果可用的物理存储器非常少,则内核将从进程处取回超过 RSS 的部分。
* RLIMIT_SBSIZE:在任一给定时刻,一个用户可以占用的套接字缓冲区的最大长度(字节)。
* RLIMIT_SIGPENDING:一个进程可排队的信号最大数量。这个限制是 sigqueue 函数实施的。
* RLIMIT_STACK:栈的最大字节长度。
* RLIMIT_SWAP:用户可消耗的交换空间的最大字节数。
* RLIMIT_VMEM:RLIMIT_AS 的同义词。
资源限制影响到调用进程并由其子进程继承。这意味着,为了影响一个用户的所有后续进程,需要将资源限制的设置构造在 shell 中,比如 Bourne shell、GNU Bourne-again shell 和 Kom shell 就具有内置的 ulimit 命令,C shell 具有内置的 limit 命令。
下列程序打印由系统支持的所有资源当前的软限制和硬限制(注意,有些平台定义 rlim_t 为 unsigned long long 而非 unsigned long。有些限制作用于文件大小,因此 rlim_t 类型必须足够大才能表示文件大小限制。为了避免使用错误的格式说明而导致编译器警告,通常会首先把限制复制到 64 位整型,这样只需处理一种格式)。
#include <stdio.h> #include <stdlib.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_DATA); 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 exit(0); } static void pr_limits(char *name, int resource){ struct rlimit limit; unsigned long long lim; if(getrlimit(resource, &limit) < 0){ printf("getrlimit error for %s\n", name); return; } 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'); }
注意,在 doit 宏中使用了 ISO C 的字符串创建运算符“#”,以便为每个资源名产生字符串值。
Linux 系统上的运行结果如下。
$ ./resourceLimit.out RLIMIT_AS (infinite) (infinite) RLIMIT_CORE 0 (infinite) RLIMIT_CPU (infinite) (infinite) RLIMIT_DATA (infinite) (infinite) RLIMIT_FSIZE (infinite) (infinite) RLIMIT_MEMLOCK 65536 65536 RLIMIT_MSGQUEUE 819200 819200 RLIMIT_NICE 0 0 RLIMIT_NOFILE 65535 65535 RLIMIT_NPROC 1024 65535 RLIMIT_RSS (infinite) (infinite) RLIMIT_SIGPENDING 3810 3810 RLIMIT_STACK 10485760 (infinite)