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), truncate(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) を参照) の合計バイト数の最大値を設定する。 shmctl(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 ライブラリとカーネル ABI の違い
バージョン 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 より大きかった場合、 setrlimit() での 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), quotactl(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/ に書かれている。