CPU_SET(3)

名前
CPU_SET, CPU_CLR, CPU_ISSET, CPU_ZERO, CPU_COUNT, CPU_AND, CPU_OR, CPU_XOR, CPU_EQUAL, CPU_ALLOC, CPU_ALLOC_SIZE, CPU_FREE, CPU_SET_S, CPU_CLR_S, CPU_ISSET_S, CPU_ZERO_S, CPU_COUNT_S, CPU_AND_S, CPU_OR_S, CPU_XOR_S, CPU_EQUAL_S - CPU 集合を操作するためのマクロ

書式
#define _GNU_SOURCE             /* feature_test_macros(7) 参照 */
#include <sched.h>

void CPU_ZERO(cpu_set_t *set);

void CPU_SET(int cpu, cpu_set_t *set);
void CPU_CLR(int cpu, cpu_set_t *set);
int  CPU_ISSET(int cpu, cpu_set_t *set);

int  CPU_COUNT(cpu_set_t *set);

void CPU_AND(cpu_set_t *destset,
             cpu_set_t *srcset1, cpu_set_t *srcset2);
void CPU_OR(cpu_set_t *destset,
             cpu_set_t *srcset1, cpu_set_t *srcset2);
void CPU_XOR(cpu_set_t *destset,
             cpu_set_t *srcset1, cpu_set_t *srcset2);

int  CPU_EQUAL(cpu_set_t *set1, cpu_set_t *set2);

cpu_set_t *CPU_ALLOC(int num_cpus);
void CPU_FREE(cpu_set_t *set);
size_t CPU_ALLOC_SIZE(int num_cpus);

void CPU_ZERO_S(size_t setsize, cpu_set_t *set);

void CPU_SET_S(int cpu, size_t setsize, cpu_set_t *set);
void CPU_CLR_S(int cpu, size_t setsize, cpu_set_t *set);
int  CPU_ISSET_S(int cpu, size_t setsize, cpu_set_t *set);

int  CPU_COUNT_S(size_t setsize, cpu_set_t *set);

void CPU_AND_S(size_t setsize, cpu_set_t *destset,
             cpu_set_t *srcset1, cpu_set_t *srcset2);
void CPU_OR_S(size_t setsize, cpu_set_t *destset,
             cpu_set_t *srcset1, cpu_set_t *srcset2);
void CPU_XOR_S(size_t setsize, cpu_set_t *destset,
             cpu_set_t *srcset1, cpu_set_t *srcset2);

int  CPU_EQUAL_S(size_t setsize, cpu_set_t *set1, cpu_set_t *set2);

説明
cpu_set_t データ構造体は CPU 集合を表現している。 CPU 集合は sched_setaffinity(2) や同様のインタフェースで使用されている。 cpu_set_t データ型はビット集合として実装されている。 しかし、 データ構造体はその実装を意識せずに扱うものとされており、 CPU 集合のすべての操作は、 このページで説明されているマクロを通して行うべきである。 以下のマクロが CPU 集合 set を操作するために提供されている。

CPU_ZERO()
    set をクリアする。 集合には何も CPU が含まれない状態となる。

CPU_SET()
    set に cpu を追加する。

CPU_CLR()
    set から cpu を削除する。

CPU_ISSET()
    CPU cpu が set のメンバーであるかを検査する。

CPU_COUNT()
    set に含まれる CPU 数を返す。

cpu 引き数が指定する場合、 その引き数は副作用を伴うべきではない。 上記のマクロは引き数を複数回評価する可能性があるからである。

そのシステムで利用可能な最初の CPU が cpu 値 0 に対応し、 次の CPU が cpu 値 1 に対応し、 以降も同様である。 定数 CPU_SETSIZE (現在のところ 1024) は cpu_set_t に格納できる最大 CPU 数よりも大きな値である。 以下のマクロは CPU 集合どうしの論理操作を行う。

CPU_AND()
    集合 srcset1 と srcset2 の積集合を destset に格納する (元の集合のいずれかが destset として使用される場合もある)。

CPU_OR()
    集合 srcset1 と srcset2 の和集合を destset に格納する (元の集合のいずれかが destset として使用される場合もある)。

CPU_XOR()
    集合 srcset1 と srcset2 の XOR を destset に格納する (元の集合のいずれかが destset として使用される場合もある)。 XOR とは、 srcset1 か srcset2 のいずれかに含まれるが、両方には含まれない集合のことである。

CPU_EQUAL()
    二つの CPU 集合が全く同じ CPU を含んでいるかを検査する。

  動的に大きさが決まる CPU 集合
いくつかのアプリケーションでは CPU 集合の大きさを動的に決める能力 (例えば、 標準の cpu_set_t データ型で定義されたよりも大きい集合を割り当てるなど) が必要となることがあるため、 現在 glibc はこれに対応するためにいくつかのマクロを提供している。 以下のマクロを使うと CPU 集合の割り当てと解放ができる。

CPU_ALLOC()
    0 から num_cpus-1 までの範囲の CPU を保持するのに十分な大きさの CPU 集合を割り当てる。

CPU_ALLOC_SIZE()
    0 から num_cpus-1 までの範囲の CPU を保持するのに必要な CPU 集合の大きさをバイト数で返す。 このマクロが返す値は、 後述の CPU_*_S() マクロの setsize 引き数として使用できる。

CPU_FREE()
    以前に CPU_ALLOC() で割り当てられた CPU 集合を解放する。

名前が "_S" で終わるマクロは "_S" なしの同じ名前のマクロと同等である。 これらのマクロは "_S" なしのものと同じ動作をするが、 動的に割り当てられた、 大きさが setsize バイトの CPU 集合に対して操作を行う点が異なる。

返り値
CPU_ISSET() と CPU_ISSET_S() は、 cpu が set に含まれていれば 0 以外を返し、含まれない場合 0 を返す。 CPU_COUNT() と CPU_COUNT_S() は set に含まれる CPU 数を返す。 CPU_EQUAL() と CPU_EQUAL_S() は、 二つの CPU 集合が等しければ 0 以外を返し、 等しくない場合 0 を返す。 CPU_ALLOC() は成功するとポインタを返し、 失敗すると NULL を返す (エラーは malloc(3) と同じである)。 CPU_ALLOC_SIZE() は指定された大きさの CPU 集合を格納するのに必要なバイト数を返す。 他の関数は値を返さない。

バージョン
マクロ CPU_ZERO(), CPU_SET(), CPU_CLR(), CPU_ISSET() は glibc 2.3.3 で追加された。 CPU_COUNT() は glibc 2.6 で初めて登場した。 CPU_AND(), CPU_OR(), CPU_XOR(), CPU_EQUAL(), CPU_ALLOC(), CPU_ALLOC_SIZE(), CPU_FREE(), CPU_ZERO_S(), CPU_SET_S(), CPU_CLR_S(), CPU_ISSET_S(), CPU_AND_S(), CPU_OR_S(), CPU_XOR_S(), CPU_EQUAL_S() は glibc 2.7 で初めて登場した。

準拠
これらのインタフェースは Linux 固有である。

注意
CPU 集合を複製するには、 memcpy(3) を使用する。 CPU 集合はロングワード単位に割り当てられるビット集合なので、 動的に割り当てられた CPU 集合の実際の CPU 数は sizeof(unsigned long) の次の倍数に切り上げられることになる。 アプリケーションは、 これらの余分なビットの内容は不定と考えるべきである。 名前は似ているが、 定数 CPU_SETSIZE は cpu_set_t データ型に含まれる CPU 数 (つまり、事実上ビット集合内のビットカウント) を示すのに対して、 マクロ CPU_*_S() の setsize 引き数はバイト単位のサイズである点に注意すること。 「書式」に書かれている引き数と返り値のデータ型は、それぞれの場合でどんな型が期待されるかのヒントである。 しかしながら、 これらのインタフェースはマクロとして実装されているため、 このヒントを守らなかった場合に、 コンパイラが必ずしも全ての型エラーを捕捉できるとは限らない。

バグ
glibc 2.8 以前の 32 ビットプラットフォームでは、 CPU_ALLOC() は必要な空間の割り当てを二度行い、 CPU_ALLOC_SIZE() は本来あるべき値の二倍の値を返す。 このバグはプログラムの動作には影響を与えないはずだが、 無駄にメモリを消費し、 動的に割り当てられた CPU 集合に対して操作を行うマクロの動作の効率が下がる結果となる。 これらのバグは glibc 2.9 で修正された。

例
以下のプログラムは、動的に割り当てた CPU 集合に対していくつかのマクロを使用する例を示している。
#define _GNU_SOURCE
#include <sched.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
int
main(int argc, char *argv[])
{
    cpu_set_t *cpusetp;
    size_t size;
    int num_cpus, cpu;
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <num-cpus>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    num_cpus = atoi(argv[1]);
    cpusetp = CPU_ALLOC(num_cpus);
    if (cpusetp == NULL) {
        perror("CPU_ALLOC");
        exit(EXIT_FAILURE);
    }
    size = CPU_ALLOC_SIZE(num_cpus);
    CPU_ZERO_S(size, cpusetp);
    for (cpu = 0; cpu < num_cpus; cpu += 2)
        CPU_SET_S(cpu, size, cpusetp);
    printf("CPU_COUNT() of set:    %d\n", CPU_COUNT_S(size, cpusetp));
    CPU_FREE(cpusetp);
    exit(EXIT_SUCCESS);
}

関連項目
sched_setaffinity(2), pthread_attr_setaffinity_np(3), pthread_setaffinity_np(3), cpuset(7)

この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.54 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。