每个进程都用一组资源限制值,它们可以用来限制进程能够消耗的各种系统资源。
从2.6.24开始,Linux特有的proc/PID/limits 文件可以用来查看任意进程的所有资源限制。这个文件由相应进程的真实用户 ID 所拥有,并且只有进程 ID 为用户 ID 的进程(或特权进程)才能够读取这个文件。
getrlimit()和 setrlimit()系统调用允许一个进程可以读取和修改自己的资源限制
NAME
getrlimit, setrlimit, prlimit - get/set resource limits
SYNOPSIS
#include
#include
int getrlimit(int resource, struct rlimit *rlim);
int setrlimit(int resource, const struct rlimit *rlim);
int prlimit(pid_t pid, int resource, const struct rlimit *new_limit,
struct rlimit *old_limit);
RETURN VALUE
On success, these system calls return 0. On error, -1 is returned, and errno is set appropriately.
resource参数标识出了需要读取或者修改的资源限制。
rlim参数用来返回限制值(getrlimit())或指定新的资源限制值((setrlimit()),它是一个指向包含两个字段的结构的指针。
struct rlimit {
rlim_t rlim_cur; /* Soft limit */
rlim_t rlim_max; /* Hard limit (ceiling for rlim_cur) */
};
这两个字段对应于一种资源的两个关联限制:软限制(rlim_cur)和硬限制(rlim_max)。(rlim_t 数据类型是一个整数类型。基于这个原因,在打印 rlim_t 值时,最好转换成 long long 并使用%lld printf()修饰符。)
在大多数情况下,特权进程和非特权进程在使用资源时都会受到限制。通过 fork()创建的子进程会继承这些限制并且在 exec()调用之间不得到保持。
resource有如下取值:
RLIMIT_AS
RLIMIT_CORE
RLIMIT_CPU
RLIMIT_DATA
RLIMIT_FSIZE
RLIMIT_MEMLOCK
RLIMIT_MSGQUEUE
RLIMIT_NICE
RLIMIT_NOFILE
RLIMIT_NPROC
RLIMIT_RSS
RLIMIT_RTPRIO
RLIMIT_RTTIME
RLIMIT_SBSIZE
RLIMIT_SIGPENDING
- 一个进程可排队的信号最大数量制(Linux 特有的,自 Linux 2.6.8 起)
- 试图(sigqueue())超出这个限制会得到 EAGAIN错误。
- RLIMIT_SIGPENDING 只影响调用进程。这个用户下的其他进程不会受到影响,除非它们也设置或继承了这个限制
RLIMIT_STACK
RLIMIT_VMEN
看个例子:下面调用了setrlimit()来设置一个用户能够创建的进程数量的软限制和硬限制(RLIMIT_NPROC)同时使用了 printRlimit()来输出变更之前和之后的资源限制,最后根据资源限制创建了尽可能多的进程
#include
#include
#include
#include
#include
int /* Print 'msg' followed by limits for 'resource' */
printRlimit(const char *msg, int resource)
{
struct rlimit rlim;
if (getrlimit(resource, &rlim) == -1)
return -1;
printf("%s soft=", msg);
if (rlim.rlim_cur == RLIM_INFINITY)
printf("infinite");
#ifdef RLIM_SAVED_CUR /* Not defined on some implementations */
else if (rlim.rlim_cur == RLIM_SAVED_CUR)
printf("unrepresentable");
#endif
else
printf("%lld", (long long) rlim.rlim_cur);
printf("; hard=");
if (rlim.rlim_max == RLIM_INFINITY)
printf("infinite\n");
#ifdef RLIM_SAVED_MAX /* Not defined on some implementations */
else if (rlim.rlim_max == RLIM_SAVED_MAX)
printf("unrepresentable");
#endif
else
printf("%lld\n", (long long) rlim.rlim_max);
return 0;
}
int main(int argc, char *argv[])
{
struct rlimit rl;
int j;
pid_t childPid;
if (argc < 2 || argc > 3 || strcmp(argv[1], "--help") == 0){
printf("%s soft-limit [hard-limit]\n", argv[0]);
exit(EXIT_FAILURE);
}
printRlimit("Initial maximum process limits: ", RLIMIT_NPROC);
/* Set new process limits (hard == soft if not specified) */
rl.rlim_cur = (argv[1][0] == 'i') ? RLIM_INFINITY : atoi(argv[1]); // "soft-limit"
rl.rlim_max = (argc == 2) ? rl.rlim_cur :
(argv[2][0] == 'i') ? RLIM_INFINITY : atoi(argv[2]); // "hard-limit"
if (setrlimit(RLIMIT_NPROC, &rl) == -1){
perror("setrlimit");
exit(EXIT_FAILURE);
}
printRlimit("New maximum process limits: ", RLIMIT_NPROC);
/* Create as many children as possible */
for (j = 1; ; j++) {
switch (childPid = fork()) {
case -1:
perror("fork error ");
exit(EXIT_FAILURE);
case 0:
_exit(EXIT_SUCCESS); /* Child */
default: /* Parent: display message about each new child
and let the resulting zombies accumulate */
printf("Child %d (PID=%ld) started\n", j, (long) childPid);
break;
}
}
}
获取进程默认可以打开的最大文件描述符数
#include
#include
#include
#include
#ifdef OPEN_MAX
static long openmax = OPEN_MAX
#else
static long openmax = 0;
#endif
/*
if OPEN_MAX is indeterminate, this might be inadequate
*/
#define OPEN_MAX_GUESS 256
long open_max(void)
{
if(openmax == 0){
errno = 0;
if((openmax = sysconf(_SC_OPEN_MAX)) < 0){
if(errno == 0)
openmax = OPEN_MAX_GUESS; //it's indeterminate,return -1 and not change errno
else
perror("sysconf error for _SC_OPEN_MAX");//_SC_OPEN_MAX is invalid,errno is set EINVAL
}
}
return(openmax);
}
int main(void){
printf("open max:%ld\n",open_max());
}
获取进程默认可以打开的最大文件描述符数
#include
#include
#include
#include
#include
long get_open_max(void){
struct rlimit rl;
const char *myname = "acl_open_limit";
int rlim_cur = -1;
if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
rlim_cur = getdtablesize();
printf("%s(%d): getrlimit error: %s, use: %d",
myname, __LINE__, strerror(errno), rlim_cur);
return rlim_cur;
}
return rl.rlim_cur; // 软限制
}
int main(void){
printf("open max:%ld\n" , get_open_max());
}
getdtablesize()函数等效于带有RLIMIT_NOFILE选项的getrlimit()。
保留此功能是出于历史原因。它是Single UNIX Specification,版本2中的Legacy Feature的一部分,但已被撤回,不作为Single UNIX Specification,版本3的一部分得到支持。新应用程序应使用getrlimit()而不是getdtablesize()。
如果有必要在为Single UNIX规范版本3编写的应用程序中继续使用此功能,请在包含任何标准系统头之前定义功能测试宏_UNIX03_WITHDRAWN。该宏公开了在单一UNIX规范版本3中删除的所有接口和符号。
设置进程默认可以打开的最大文件描述符数
#include
#include
#include
#include
#include
int acl_set_limit(int limit){
const char *myname = "acl_open_limit";
int rlim_cur = -1;
struct rlimit rl;
if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
rlim_cur = getdtablesize();
printf("%s(%d): getrlimit error: %s, use: %d",
myname, __LINE__, strerror(errno), rlim_cur);
return rlim_cur;
}
if (rl.rlim_max <= 0){
rl.rlim_max = 204800;
}
rlim_cur = (int) rl.rlim_cur;
if (limit > 0) {
if (limit > (int) rl.rlim_max){
rl.rlim_cur = rl.rlim_max;
}else{
rl.rlim_cur = limit;
}
if (setrlimit(RLIMIT_NOFILE, &rl) < 0) { // 修改的是软限制而不是硬限制
printf("%s(%d): setrlimit error: %s, limit: %d,"
" curr: %d", myname, __LINE__,
strerror(errno), limit, rlim_cur);
return rlim_cur;
}
else{
return (int) rl.rlim_cur;
}
} else if (rl.rlim_max > rl.rlim_cur) {
rlim_cur = (int) rl.rlim_cur;
rl.rlim_cur = rl.rlim_max;
if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
printf("%s(%d): setrlimit error: %s,"
" cur: %d, max: %d", myname, __LINE__,
strerror(errno), (int) rl.rlim_cur,
(int) rl.rlim_max);
return rlim_cur;
}
return (int) rl.rlim_cur;
} else{
return (int) rl.rlim_cur;
}
}
下面程序可以查询当前系统支持的所有资源当前的软限制与硬限制
#include "apue.h"
#include
#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)
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');
}
https://www.yingsoo.com/news/servers/60515.html