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

The first CPU on the system corresponds to a cpu value of 0, the next CPU corresponds to a cpu value of 1, and so on. No assumptions should be made about particular CPUs being available, or the set of CPUs being contiguous, since CPUs can be taken offline dynamically or be otherwise absent. The constant CPU_SETSIZE (currently 1024) specifies a value one greater than the maximum CPU number that can be stored in cpu_set_t.

以下のマクロは 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;
        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 (int 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 プロジェクトのリリース 5.10 の一部である。プロジェクトの説明とバグ報告に関する情報は https://www.kernel.org/doc/man-pages/ に書かれている。