SIMPLE SOLUTIONS

GETRLIMIT(2) - Linux manual

資源の制限を取得/設定する.

2015-01-22
GETRLIMIT(2) Linux Programmer's Manual GETRLIMIT(2)

getrlimit, setrlimit, prlimit - 資源の制限を取得/設定する

#include <sys/time.h> #include <sys/resource.h> 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); glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照): prlimit(): _GNU_SOURCE && _FILE_OFFSET_BITS == 64

getrlimit() と setrlimit() はそれぞれ資源 (resource) の制限 (limit) の設定と取得を行う。 各リソースには、それに対応するソフトリミッ トとハードリミットがあり、 rlimit 構造体で定義される: struct rlimit { rlim_t rlim_cur; /* ソフトリミット */ rlim_t rlim_max; /* ハードリミット (rlim_cur より小さくない) */ }; ソフトリミットは、カーネルが対応するリソースに対して課す制限値である。 ハードリミットはソフトリミットの上限として働く。 特権を持たないプロセスは、ソフトリミットの値を 0 からハードリミットの範囲に設定することと、 ハードリミットを下げることのみができる (一度下げたハードリミットは上げられない)。 特権プロセス (Linux では CAP_SYS_RESOURCE ケーパビリティ (capability) を持つプロセス) は ソフトリミットとハードリミットを自由に変更できる。 値 RLIM_INFINITY はリソースに制限がないことを表す (この値は getrlimit() が返す構造体と setrlimit() に渡す構造体の両方で使用される)。 resource 引き数は次のいずれか 1 つである。 RLIMIT_AS プロセスの仮想メモリー (アドレス空間) の最大サイズ (バイト単位)。 この制限は brk(2), mmap(2), mremap(2) の呼び出しに影響し、この制限を超えた場合は エラー ENOMEM で失敗する。 また自動的なスタック拡張にも失敗する (さらに sigaltstack(2) を使った代替スタックを利用可能にしていなかった場合には、 SIGSEGV を生成してそのプロセスを kill する)。 この値は long 型なので、32 ビットの long 型を持つマシンでは、 この制限は最大で 2 GiB になるか、この資源が無制限になる。 RLIMIT_CORE core ファイルの最大サイズ (core(5) 参照)。 0 の場合、core ファイルは生成されない。 0 以外の場合、このサイズより大きいダンプは切り詰められる。 RLIMIT_CPU CPU 時間の上限 (秒数)。プロセスがソフトリミットに達した場合に、 SIGXCPU シグナルを送る。このシグナルに対するデフォルトの動作は、 プロセスの終了である。ただし、シグナルをキャッチして、ハンドラーがメイン プログラムに制御を返すこともできる。プロセスが CPU 時間を使い続けた 場合は、ハードリミットに達するまで 1 秒毎にプロセスに SIGXCPU を送り、 ハードリミットに達すると SIGKILL を送る。 (ソフトリミットを超過したときの動作は、 Linux における動作である。ソフ トリミットを超えて CPU 時間を使い続けるプロセスの扱い方についての実装は 変化してきている。 このシグナルをキャッチする必要のある 移植性を考えた アプリケーションでは、 最初に SIGXCPU を受け取った時点で正しく終了 すべきである。) RLIMIT_DATA プロセスのデータセグメント (初期化されたデータ・初期化されていないデータ・ヒープ) の最大値。 このリミットは brk(2)sbrk(2) の呼び出しに影響する。 これらの関数は、このリソースのソフトリミットに達すると、 エラー ENOMEM で失敗する。 RLIMIT_FSIZE プロセスが作成できるファイルサイズの最大値。 このサイズを超えてファイルを拡張すると、 SIGXFSZ シグナルを送る。 デフォルトでは、このシグナルはプロセスを終了する。 プロセスをキャッチすることもできるが、 関連するシステムコール (write(2), trun‐ cate(2) など) はエラー EFBIG で失敗する。 RLIMIT_LOCKS (初期の Linux 2.4 のみ) このプロセスが実行できる flock(2) ロック数と fcntl(2) リース数の合計値を制限する。 RLIMIT_MEMLOCK RAM 内にロックできるメモリーの最大バイト数。 実際には、この制限はシステムページサイズの最も近い倍数に 切り捨てて丸められる。 この制限は mlock(2), mlockall(2), mmap(2) の MAP_LOCKED 操作に影響する。 Linux 2.6.9 以降では shmctl(2) SHM_LOCK 操作にも影響する。 この操作は呼び出し元プロセスの実 (real) ユーザー ID にロックされる 共有メモリーセグメント (shmget(2) を参照) の合計バイト数の最大値を設定する。 shm‐ ctl(2) SHM_LOCK によるロックは、 mlock(2), mlockall(2), mmap(2) の MAP_LOCKED によって確立されるプロセス毎のメモリーロックとは分けて数える。 1 つのプロセスはこの制限までのバイトをロックできる。 この制限には 2 つの種類がある。 2.6.9 より前の Linux カーネル では、 この制限は特権プロセスによってロックされるメモリーの合計を制御していた。 Linux 2.6.9 以降では、特権プロセスがロックするメモリーの合計に制限はなく、 代わりにこの制限は非特権プロセスがロックするメモリーの合計に 適用されるようになった。 RLIMIT_MSGQUEUE (Linux 2.6.8 以降) 呼び出し元プロセスの実ユーザー ID に対して、 POSIX メッセージキューのために確保できるバイト数の制限を指定する。 この制限は mq_open(3) に対して適用される。 ユーザーが作成した各々のメッセージキューのバイト数は 以下の式により計算され、(そのキューが削除されるまでの間) この制限の計算対象に含められる。 Linux 3.5 以降: bytes = attr.mq_maxmsg * sizeof(struct msg_msg) + min(attr.mq_maxmsg, MQ_PRIO_MAX) * sizeof(struct posix_msg_tree_node)+ /* オーバーヘッド分 */ attr.mq_maxmsg * attr.mq_msgsize; /* メッセージデータ分 */ Linux 3.4 以前: bytes = attr.mq_maxmsg * sizeof(struct msg_msg *) + /* オーバーヘッド分 */ attr.mq_maxmsg * attr.mq_msgsize; /* メッセージデータ分 */ ここで attr は mq_attr 構造体であり、 mq_open(3) の第 4 引き数として指定される。 また、構造体 msg_msg と posix_msg_tree_node はカーネル内部の構造体である。 上記の式での「オーバーヘッド」加算分は、実装において必要となるオーバーヘッドを考慮したものである。 また、これにより、ユーザーが長さ 0 のメッセージを無制限に作れないことが保証される (このようなメッセージであっても、 記録のためのオーバーヘッドでシステムメモリーを消費する)。 RLIMIT_NICE (Linux 2.6.12 以降, 下記の「バグ」の節も参照) setpriority(2)nice(2) を使って引き上げられるプロセスの nice 値の上限を指定する。 nice 値の実際の上限は 20 - rlim_cur で計算される (このような変な状況は、リソース制限値として負の数を指定できないため 発生する。通常、負の値は特別な意味を持っているからである。 例えば、通常は RLIM_INFINITY の値は -1 である)。 RLIMIT_NOFILE このプロセスがオープンできるファイルディスクリプター数の最大値より 1 大きい値を指定する。 (open(2), pipe(2), dup(2) などにより) この上限を超えようとした場合、エラー EMFILE が発生する (歴史的に、BSD ではこの上限は RLIMIT_OFILE という名前となっている)。 RLIMIT_NPROC 呼び出したプロセスの実ユーザー ID で作成できる最大プロセス数 (より正確には Linux ではスレッド数)。 この上限に達すると、 fork(2) はエラー EAGAIN で失敗する。 この上限値は、ケーパビリティ CAP_SYS_ADMIN か CAP_SYS_RESOURCE のどちらかを持つプロセスには適用されない。 RLIMIT_RSS プロセスの resident set (RAM 上に存在する仮想ページの数) の 上限を (ページ数で) 指定する。 この制限は 2.4.30 より前でしか影響がなく、 madvise(2) に MADV_WILLNEED を指定した関数コールにしか影響しない。 RLIMIT_RTPRIO (Linux 2.6.12 以降, バグの節も参照) sched_setscheduler(2)sched_setparam(2) を使って設定できる、そのプロセスのリアルタイム優先度の上限を指定する。 RLIMIT_RTTIME (Linux 2.6.25 以降) リアルタイムスケジューリング方針でスケジューリングされるプロセスが ブロッキング型のシステムコールを呼び出さずに消費することのできる CPU 時間の合計についての上限を (マイクロ秒単位で) 指定する。 この上限の目的のため、プロセスがブロッキング型のシステムコールを 呼び出す度に、消費された CPU 時間のカウントは 0 にリセットされる。 プロセスが CPU を使い続けようとしたが他のプロセスに置き換えられた (preempted) 場合や、そのプロセスのタイムスライスが満了した場合、 そのプロセスが sched_yield(2) を呼び出した場合は、CPU 時間のカウントはリセットされない。 ソフトリミットに達すると、そのプロセスに SIGXCPU シグナルが送られる。そのプロセスがこのシグナルを捕捉するか 無視して、CPU 時間を消費し続けた場合には、 ハードリミットに達するまで 1 秒に 1 回 SIGXCPU が生成され続けることになる。 ハードリミットに達した時点で、そのプロセスには SIGKILL シグナルが送られる。 この上限を意図的に使用するのは、暴走したリアルタイムプロセスを 停止して、システムが動かなくなるのを避ける場合である。 RLIMIT_SIGPENDING (Linux 2.6.8 以降) 呼び出し元プロセスの実ユーザー ID に対して キューに入れられるシグナルの 数の制限を指定する。この制限をチェックするため、標準シグナルとリアルタ イムシグナルの両方がカウントされる。しかし、この制限は sigqueue(3) に対してのみ適用され、 kill(2) 使うことで、そのプロセスに対してま だキューに入れられていない シグナルのインスタンスをキューに入れることが できる。 RLIMIT_STACK プロセススタックの最大サイズをバイト単位で指定する。 この上限に達すると、 SIGSEGV シグナルが生成される。 このシグナルを扱うためには、 プロセスは代りのシグナルスタック (sigaltstack(2)) を使用しなければならない。 Linux 2.6.23 以降では、この制限はプロセスのコマンドライン引き数と環境変数 に使用される空間の合計サイズの上限の決定にも使用される。詳細については execve(2) を参照。 prlimit() Linux 固有の prlimit() システムコールは、 setrlimit() と getrlimit の機能を合わせて拡張したものである。 このシステムコールを使って、任意のプロセスのリソース上限の設定と取得を行うことができる。 resource 引き数は setrlimit() や getrlimit() と同じ意味である。 new_limit 引き数が NULL 以外の場合、 new_limit が指す rlimit 構造体を使って resource のソフトリミットとハードリミットの新しい値が設定される。 old_limit 引き数が NULL 以外の場合、 prlimit() の呼び出しが成功すると、 resource の直前のソフトリミットとハードリミットが old_limit が指す rlimit 構造体に格納される。 pid 引き数は呼び出しの操作対象となるプロセス ID を指定する。 pid が 0 の場合、呼び出しは呼び出し元プロセスに対して適用される。 自分以外のプロセスのリソースの設定と取得を行うためには、 呼び出し元プロセスが CAP_SYS_RESOURCE ケーパビリティを持っているか、 対象となるプロセスの実ユーザー ID、 実効ユーザー ID、 保存 set-user-ID が呼び出し元プロセスの実ユーザー ID と一致し、 かつ、 対象となるプロセスの実グループ ID、 実効グループ ID、 保存 set-group-ID が呼び出し元プロセスの実グループ ID と一致していなければならない。

成功した場合、これらのシステムコールは 0 を返す。 エラーの場合は -1 が返され、 errno が適切に設定される。

EFAULT 場所を指すポインター引き数がアクセス可能なアドレス空間外を指している。 EINVAL resource で指定された値が有効でない。 または、 setrlimit() や prlimit() で、 rlim->rlim_cur が rlim->rlim_max よりも大きかった。 EPERM 非特権プロセスがハードリミットを増やそうとした。 この操作には CAP_SYS_RESOURCE ケーパビリティが必要である。 EPERM 呼び出し元がハードリミット RLIMIT_NOFILE を /proc/sys/fs/nr_open (proc(5) 参照) で定義される最大値より大きな値に増やそうとした。 EPERM (prlimit()) 呼び出し元のプロセスが pid で指定されたプロセスの上限を設定する許可を持っていなかった。 ESRCH pid で指定された ID のプロセスが見つからなかった。

prlimit() システムコールは Linux 2.6.36 以降で利用できる。 ライブラリのサポートは glibc 2.13 以降で利用できる。

getrlimit(), setrlimit(): SVr4, 4.3BSD, POSIX.1-2001. prlimit(): Linux 固有。 RLIMIT_MEMLOCK と RLIMIT_NPROC は BSD から派生し、 POSIX.1-2001 には指定されていない。 これらは BSD 系と Linux に存在するが、他の実装は少ない。 RLIMIT_RSS は BSD から派生し、POSIX.1-2001 には指定されていない。 それにも関わらず多くの実装で存在する。 RLIMIT_MSGQUEUE, RLIMIT_NICE, RLIMIT_RTPRIO, RLIMIT_RTTIME, RLIMIT_SIGPENDING は Linux 固有のものである。

fork(2) で作成された作成された子プロセスは、 親プロセスのリソース制限を継承する。 execve(2) の前後でリソース制限は保存される。 リソースのソフトリミットをそのプロセスが現在のリソース使用量より小さい値に設定することはできる (但し、そのプロセスはそれ以降そのリソースの使用量を増やすことができなくなる)。 シェルのリソース制限は、シェルの組み込みコマンドである ulimit (csh(1) では limit ) を使って設定することができる。 このシェルのリソース制限は、コマンドを実行してシェルが生成するプロセス に引き継がれる。 Linux 2.6.24 以降では、 プロセスのリソース上限は /proc/[pid]/limits で知ることができる。 proc(5) 参照。 古いシステムでは、 setrlimit() と同様の目的を持つ関数 vlimit() が提供されていた。 後方互換性のため、glibc でも vlimit() を提供している。 全ての新しいアプリケーションでは、 setrlimit() を使用すべきである。 C ラ バージョン 2.13 以降では、 glibc の getrlimit() と setrlimit() のラッパー関数はもはや対応するシステムコールを呼び出さず、 代わりに「バグ」の節で説明されている理由から prlimit() を利用している。

以前の Linux カーネルでは、プロセスがソフトまたはハード RLIMIT_CPU リミットに達した場合に送られる SIGXCPU と SIGKILL シグナルが、本来送られるべき時点の 1 (CPU) 秒後に送られてしまう。 これはカーネル 2.6.8 で修正された。 2.6.17 より前の 2.6.x カーネルでは、 RLIMIT_CPU リミットが 0 の場合、 (RLIM_INFINITY と同じように) 「制限なし」と間違って解釈されていた。 Linux 2.6.17 以降では、リミットを 0 に設定した場合にも 効果を持つようになっているが、実際にはリミットの値は 1 秒となる。 カーネル 2.6.12 には、 RLIMIT_RTPRIO が動作しないというバグがある。この問題はカーネル 2.6.13 で修正されている。 カーネル 2.6.12 では、 getpriority(2) と RLIMIT_NICE が返す優先度の範囲が一つずれていた。このため、nice 値の実際の上限が 19 - rlim_cur になってしまうという影響があった。これはカーネル 2.6.13 で修正された。 Linux 2.6.12 以降では、 プロセスがその RLIMIT_CPU ソフトリミットに達し、 SIGXCPU に対してシグナルハンドラーが設定されている場合、 シグナルハンドラーを起動するだけでなく、 カーネルは 1 秒間ソフトリミットを増やす。 そのプロセスが CPU 時間を消費し続けている限り、 ハードリミットに達するまで、この動作が繰り返される。 ハードリミットに達すると、その時点でプロセスは kill される。 他の実装では、上記のような RLIMIT_CPU ソフトリミットの変更は行われず、 おそらく Linux の動作は標準に準拠していない。 移植性が必要なアプリケーションではこの Linux 固有の動作を前提にするのは避けるべきである。 Linux 固有の上限 RLIMIT_RTTIME でも、 ソフトリミットに達した場合に同じ動作となる。 2.4.22 より前のカーネルでは、 rlim->rlim_cur が rlim->rlim_max より大きかった場合、 setr‐ limit() での EINVAL エラーを検出できない。 32 ビ glibc の getrlimit() と setrlimit() ラッパー関数は、32 ビットプラットフォームであっても 64 ビットの rlim_t データ型を使用する。 しかし、 getrlimit() と setrlimit() システムコールで使用される rlim_t データ型は (32 ビットの) unsigned long である。 さらに、 2.6.36 より前の Linux では、 カーネルは 32 ビットプラットフォームではリソース上限を unsigned long として表現している。 しかしながら、 32 ビットデータ型は十分な大きさではない。 ここで最も関係がある上限値は RLIMIT_FSIZE である。 この上限はファイルサイズの最大値であり、実用性の面からは、 この上限をファイルオフセットを表現するのに使用されている型、 つまり 64 ビットの off_t (_FILE_OFFSET_BITS=64 でコンパイルしたプログラムの場合)、 と同じ幅を持つ型、を使って表現すべきである。 カーネルのこの制限に対する対策として、 プログラムがリソース上限を 32 ビットの unsigned long で表現できる値よりも大きな値に設定しようとした際には、 glibc の setrlimit() ラッパー関数はこの上限値を黙って RLIM_INFINITY に変換していた。 言い換えると、指定されたリソース上限値は黙って無視されていた。 この問題は Linux 2.6.36 での以下の主な変更により解決された。 * 32 ビットプラットフォームであっても 64 ビットを使用するリソース上限の新しいカーネルでの表現方法の追加。 * リソース上限の引き数として 64 ビット値を取る prlimit() システムコールの追加。 バージョン 2.13 以降の glibc では、 getrlimit() と setrlimit() システムコールの制限に対する回避手段として、 setrlimit() と getrlimit() を prlimit() を呼び出すラッパー関数として実装している。

以下のプログラムに prlimit() の使用例を示す。 #define _GNU_SOURCE #define _FILE_OFFSET_BITS 64 #include <stdio.h> #include <time.h> #include <stdlib.h> #include <unistd.h> #include <sys/resource.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) int main(int argc, char *argv[]) { struct rlimit old, new; struct rlimit *newp; pid_t pid; if (!(argc == 2 || argc == 4)) { fprintf(stderr, "Usage: %s <pid> [<new-soft-limit> " "<new-hard-limit>]\n", argv[0]); exit(EXIT_FAILURE); } pid = atoi(argv[1]); /* PID of target process */ newp = NULL; if (argc == 4) { new.rlim_cur = atoi(argv[2]); new.rlim_max = atoi(argv[3]); newp = &new; } /* Set CPU time limit of target process; retrieve and display previous limit */ if (prlimit(pid, RLIMIT_CPU, newp, &old) == -1) errExit("prlimit-1"); printf("Previous limits: soft=%lld; hard=%lld\n", (long long) old.rlim_cur, (long long) old.rlim_max); /* Retrieve and display new CPU time limit */ if (prlimit(pid, RLIMIT_CPU, NULL, &old) == -1) errExit("prlimit-2"); printf("New limits: soft=%lld; hard=%lld\n", (long long) old.rlim_cur, (long long) old.rlim_max); exit(EXIT_FAILURE); }

prlimit(1), dup(2), fcntl(2), fork(2), getrusage(2), mlock(2), mmap(2), open(2), quo‐ tactl(2), sbrk(2), shmctl(2), malloc(3), sigqueue(3), ulimit(3), core(5), capabilities(7), signal(7)

この man ページは Linux man-pages プロジェクトのリリース 3.79 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。
Linux 2015-01-22 GETRLIMIT(2)
getrlimit(2).txt (日本語 / Japanese)
Index English version of getrlimit(2)
Go top