This appendix describes the libcpuset C programming application programming interface (API) functions and covers the following topics:
In order to provide for the convenient and robust extensibility of this cpuset API over time, the following function enables dynamically obtaining pointers for optional functions by name, at runtime:
void *cpuset_function(const char * function_name) |
It returns a function pointer or NULL if function name is not recognized.
For maximum portability, you should not reference any optional cpuset function by explicit name.
However, if you presume that an optional function will always be available on the target systems of interest, you might decide to explicitly reference it by name, in order to improve the clarity and simplicity of the software in question.
Also to support robust extensibility, flags and integer option values have names dynamically resolved at runtime, not via preprocessor macros.
Some functions in Advanced Cpuset Library Functions are marked [optional]. (see “Advanced Cpuset Library Functions”). They are not available in all implementations of libcpuset. Additional [optional] cpuset_* functions may also be added in the future. Functions that are not marked [optional] are available on all implementations of libcpuset.so and can be called directly without using cpuset_function (). However, any of them can also be called indirectly via cpuset_function().
To safely invoke an optional function, such as for example cpuset_migrate(), use the following call sequence:
/* fp has function signature of pointer to cpuset_migrate() */ int (*fp)(struct cpuset *fromcp, struct cpuset *tocp, pid_t pid); fp = cpuset_function("cpuset_migrate"); if (fp) { fp( ... ); } else { puts ("cpuset migration not supported"); } |
If you invoke an [optional] function directly, your resulting program will not be able to link with any version of libcpuset.so that does not define that particular function.
The basic cpuset API provides functions usable from a C program for the processor and memory placement within a cpuset.
These functions enable an application to place various threads of its execution on specific CPUs within its current cpuset and perform related functions, such as, asking how large the current cpuset is and on which CPU within the current cpuset a thread is currently executing.
These functions do not provide the full power of the advanced cpuset API, but they are easier to use, and provide some common needs of multithreaded applications.
Unlike the rest of this document, the functions described in this section use cpuset relative numbering. In a cpuset of N CPUs, the relative cpu numbers range from zero to N - 1.
Memory placement is done automatically, preferring the node local to the requested CPU. Threads may only be placed on a single CPU. This avoids the need to allocate and free the bitmasks required to specify a set of serveral CPUs. These functions do not support creating or removing cpusets, only the placement of threads within an existing cpuset. This avoids the need to explicitly allocate and free cpuset structures. Operations only apply to the current thread, avoiding the need to pass the process ID of the thread to be affected.
If more powerful capabilities are needed, use the Advanced Cpuset library functions (see “Advanced Cpuset Library Functions”). These basic functions do not provide any essential new capability. They are implemented using the advanced function and are fully interoperable with them.
On error, these routines return -1 and set errno. If invoked on an operating system kernel that does not support cpusets, errno is set to ENOSYS. If invoked on a system that supports cpusets, but when the cpuset file system is not currently mounted at /dev/cpuset, the errno is set to ENODEV.
The following inclusion and linkage provides access to the cpuset API from C code:
#include <cpuset.h> /* link with -lcpuset */ |
The following functions are supported in the basic cpuset C API:
cpuset_pin | Pins the current thread to a CPU, preferring local memory | |
cpuset_size | Returns the number of CPUs that are in the current tasks cpuset | |
cpuset_where | Returns on which CPU in current tasks cpuset did the task most recently execute | |
cpuset_unpin | Removes the affect of cpuset_pin, lets the task have run of its entire cpuset |
int cpuset_pin(int relcpu);
Pins the current task to execute only on the CPU relcpu, which is a relative CPU number within the current cpuset of that task. Also, automatically pins the memory allowed to be used by the current task to prefer the memory on that same node (as determined by the cpuset_cpu2node function), but to allow any memory in the cpuset if no free memory is readily available on the same node.
Return 0 on success, -1 on error. Errors include relcpu being too large (greater than cpuset_size() - 1). They also include running on a system that does not support cpusets (ENOSYS) and running when the cpuset file system is not mounted at /dev/cpuset (ENODEV).
int cpuset_size();
Returns the number of CPUs in the current tasks cpuset. The relative CPU numbers that are passed to the cpuset_pin function and that are returned by the cpuset_where function, must be between 0 and N - 1 inclusive, where N is the value returned by cpuset_size.
Returns -1 and sets errno on error. Errors include running on a system that does not support cpusets (ENOSYS) and running when the cpuset file system is not mounted at /dev/cpuset (ENODEV).
int cpuset_where();
Returns the CPU number, relative to the current tasks cpuset, of the CPU on which the current task most recently executed. If a task is allowed to execute on more than one CPU, then there is no guarantee that the task is still executing on the CPU returned by cpuset_where, by the time that the user code obtains the return value.
Returns -1 and sets errno on error. Errors include running on a system that does not support cpusets (ENOSYS) and running when the cpuset file system is not mounted at /dev/cpuset (ENODEV).
int cpuset_unpin();
Remove the CPU and Memory pinning affects of any previous cpuset_pin call, allowing the current task to execute on any CPU in its current cpuset and to allocate memory on any memory node in its current cpuset. Return -1 on error, 0 on success.
Returns -1 and sets errno on error. Errors include running on a system that does not support cpusets (ENOSYS) and running when the cpuset file system is not mounted at /dev/cpuset (ENODEV).
The advanced cpuset API provides functions usable from a C language application for managing cpusets on a system-wide basis.
These functions primarily deal with the following three entities:
struct cpuset * structure
system cpusets
tasks
The struct cpuset * structure provides a transient in-memory structure used to build up a description of an existing or desired cpuset. These structures can be allocated, freed, queried, and modified.
Actual kernel cpusets are created under the /dev/cpuset directory, which is the usual mount point of the kernel's virtual cpuset filesystem. These cpusets are visible to all tasks in the system, and persist until the system is rebooted or until the cpuset is explicitly deleted. These cpusets can be created, deleted, queried, modified, listed, and examined.
Every task (also known as a process) is bound to exactly one cpuset at a time. You can list which tasks are bound to a given cpuset, and to which cpuset a given task is bound. You can change to which cpuset a task is bound.
The primary attributes of a cpuset are its lists of CPUs and memory nodes. The scheduling affinity for each task, whether set by default or explicitly by the sched_setaffinity() system call, is constrained to those CPUs that are available in that tasks cpuset. The NUMA memory placement for each task, whether set by default or explicitly by the mbind() system call, is constrained to those memory nodes that are available in that tasks cpuset. This provides the essential purpose of cpusets - to constrain the CPU and Memory usage of tasks to specified subsets of the system.
The other essential attribute of a cpuset is its pathname beneath /dev/cpuset. All tasks bound to the same cpuset pathname can be managed as a unit, and this hierarchical name space describes the nested resource management and hierarchical permission space supported by cpusets. Also, this hierarchy is used to enforce strict exclusion, using the following rules:
A cpuset may only be marked strictly exclusive for CPU or memory if its parent is also.
A cpuset may not make any CPUs or memory nodes available that are not also available in its parent.
If a cpuset is exclusive for CPU or memory, it may not overlap CPUs or memory with any of its siblings.
The combination of these rules enables checking for strict exclusion just by making various checks on the parent, siblings, and existing child cpusets of the cpuset being changed, without having to check all cpusets in the system.
On error, some of these routines return -1 or NULL and set errno. If one of the routines below that requires cpuset kernel support or the cpuset file system mounted is invoked on an operating system kernel that does not support cpusets, then that routine returns failure and errno is set to ENOSYS. If invoked on a system that supports cpusets, but when the cpuset file system is not currently mounted at /dev/cpuset, it returns failure and errno is set to ENODEV.
The following inclusion and linkage provides access to the cpuset API from C code:
#include <bitmask.h> #include <cpuset.h> /* link with -lcpuset */ |
The following functions are supported in the advanced cpuset C API:
Allocate and free struct cpuset * structure
cpuset_alloc - Returns handle to newly allocated struct cpuset * structure
cpuset_free - Discards no longer needed struct cpuset * structure
Lengths of CPUs and memory nodes bitmasks - needed to allocate bitmasks
cpuset_cpus_nbits - Number of bits needed for a CPU bitmask on current system
cpuset_mems_nbits - Number of bits needed for a memory bitmask on current system
Set various attributes of a struct cpuset * Structure
cpuset_setcpus - Specifies CPUs in cpuset
cpuset_setmems - Specifies memory nodes in cpuset
cpuset_set_iopt - Specifies an integer value option of cpuset
cpuset_set_sopt - [optional] Specifies a string value option of cpuset
Query various attributes of a struct cpuset * Structure
cpuset_getcpus - Queries CPUs in cpuset
cpuset_getmems - Queries memory nodes in cpuset
cpuset_cpus_weight - Number of CPUs in a cpuset
cpuset_mems_weight - Number of memory nodes in a cpuset
cpuset_get_iopt - Query an integer value option of cpuse
cpuset_set_sopt - [optional] Species a string value option of cpuset
Local CPUs and memory nodes
cpuset_localcpus - Queries the CPUs local to specified memory nodes
cpuset_localmems - Queries the memory nodes local to specified CPUs
cpuset_cpumemdist - [optional] Hardware distance from CPU to memory node
cpuset_cpu2node - Returns number of memory node closed to specified CPU
cpuset_addr2node - Return number of memory node holding page at specified address.
Create, delete, query, modify, list, and examine cpusets
cpuset_create - Creates a named cpuset as specified by struct cpuset * structure
cpuset_delete - Deletes the specified cpuset (if empty)
cpuset_query - Sets the struct cpuset structure to settings of specified cpuset
cpuset_modify - Modifies the settings of a cpuset to those specified in a struct cpuset structure
cpuset_getcpusetpath - Gets path of a tasks (0 for current) cpuset
cpuset_cpusetofpid - Sets the struct cpuset structure to settings of cpuset of specified task
cpuset_mountpoint - Returns path at which cpuset filesystem is mounted
cpuset_collides_exclusive - [optional] True, if it would collide an exclusive
List tasks (pids) currently attached to a cpuset
cpuset_init_pidlist - Initializes a list of tasks (pids) attached to a cpuset
cpuset_pidlist_length - Returns number of elements in a list of pid
cpuset_get_pidlist - Returns i'th element of a list of pids
cpuset_free_pidlist - Deallocates a list of pids
Attach tasks to cpusets
cpuset_move - Moves task (0 for current) to a cpuset
cpuset_move_all - Moves all tasks in a list of pids to a cpuset
cpuset_migrate - [optional] Moves a task and its memory to a cpuset
cpuset_migrate_all - [optional] Moves all tasks with memory in a list of pids to a cpuset
cpuset_reattach - Rebinds cpus_allowed of each task in a cpuset after changing its cpus
Determine memory pressure
cpuset_open_memory_pressure - [optional] Opens handle to read memory_pressure
cpuset_read_memory_pressure - [optional] Reads cpuset current memory_pressure
cpuset_close_memory_pressure - [optional] Closes handle to read memory_pressure
Map between cpuset relative and system-wide CPU and memory node numbers
cpuset_c_rel_to_sys_cpu - Maps cpuset relative CPU number to system wide number
cpuset_c_sys_to_rel_cpu - Maps system-wide CPU number to cpuset relative number
cpuset_c_rel_to_sys_mem - Maps cpuset relative memory node number to system wide number
cpuset_c_sys_to_rel_mem - Maps system-wide memory node number to cpuset relative number
cpuset_p_rel_to_sys_cpu - Maps task cpuset relative CPU number to system wide number
cpuset_p_sys_to_rel_cpu - Maps system-wide CPU number to task cpuset relative number
cpuset_p_rel_to_sys_mem - Maps task cpuset relative memory node number to system-wide number
cpuset_p_sys_to_rel_mem - Maps system-wide memory node number to task cpuset relative number
Placement operations for detecting cpuset migration
cpuset_get_placement - [optional] Returns the current placement of task pid
cpuset_equal_placement - [optional] True, if two placements are equal
cpuset_free_placement - [optional] Free placement
Bind to a CPU or memory node within the current cpuset
cpuset_cpubind - Binds to a single CPU within a cpuset (uses sched_setaffinity(2))
cpuset_latestcpu - Most recent CPU on which a task has executed
cpuset_membind - Binds to a single memory node within a cpuset (uses set_mempolicy(2))
Export cpuset settings to a regular file and import them from a regular file
cpuset_export - Exports cpuset settings to a text file
cpuset_import - Imports cpuset settings from a text file
Support calls to [optional] cpuset_* API routines
cpuset_function - Returns pointer to a libcpuset.so function, or NULL
Cpuset Library Functions Calling Sequence
A typical calling sequence would use the above functions in the following order to create a new cpuset named "xyz" and attach itself to it, as follows:
struct cpuset *cp = cpuset_alloc(); various cpuset_set*(cp, ...) calls cpuset_create(cp, "xyz"); cpuset_free(cp); cpuset_move(0, "xyz"); |
Note: Some functions are marked [optional]. For an explanation, see “Extensible Application Programming Interface”. |
struct cpuset *cpuset_alloc();
Creates, initializes, and returns a handle to a struct cpuset structure, that is an opaque data structure used to describe a cpuset.
After obtaining a struct cpuset handle with this call, you can use the various cpuset_set() methods to specify which CPUs and memory nodes are in the cpuset and other attributes. Then, you can create such a cpuset with the cpuset_create() call and free cpuset handles with the cpuset_free() call.
The cpuset_alloc function returns a zero pointer (NULL) and sets errno in the event that malloc (3) fails. See the malloc(3) man page for possible values of errno (ENOMEM being the most likely).
The cpuset_alloc() call applies a hidden undefined mark to each attribute of the allocated struct cpuset. Calls to the various cpuset_set*() routines mark the attribute being set as defined. Calls to cpuset_create () and cpuset_modify() only set the attributes of the cpuset marked defined. This is primarily noticable when creating a cpuset. Code in the kernel sets some attributes of new cpusets, such as memory_spread_page, memory_spread_slab , and notify_on_release, by default to the value inherited from their parent. Unless the application using libcpuset explicitly overrides the setting of these attributes in the struct cpuset, between the calls to cpuset_alloc() and cpuset_create (), the kernel default settings will prevail. These hidden marks have no noticeable affect when modifying an existing cpuset using the sequence of calls cpuset_alloc(), cpuset_query (), and cpuset_modify(), because the cpuset_query() call sets all attributes and marks them defined, while reading the attributes from the cpuset.
struct cpuset *cpuset_alloc();
Frees the memory associated with a struct cpuset handle, that must have been returned by a previous cpuset_alloc() call. If cp is NULL, no operation is performed.
int cpuset_cpus_nbits();
Return the number of bits in a CPU bitmask on current system. Useful when using bitmask_alloc() call to allocate a CPU mask. Some other routines below return cpuset_cpus_nbits () as an out-of-bounds indicator.
int cpuset_mems_nbits();
Returns the number of bits in a memory node bitmask on current system. Useful when using a bitmask_alloc() call to allocate a memory mode mask. Some other routines below return cpuset_mems_nbits() as an out-of-bounds indicator.
int cpuset_setcpus(struct cpuset *cp, const struct bitmask *cpus);
Given a bitmask of CPUs, the cpuset_setcpus () call sets the specified cpuset cp to include exactly those CPUs.
Returns 0 on success, else -1 on error, setting errno. This routine can fail if malloc(3) fails. See the malloc(3) man page for possible values of errno (ENOMEM being the most likely).
void cpuset_setmems(struct cpuset *cp, const struct bitmask *mems);
Given a bitmask of memory nodes, the cpuset_setmems() call sets the specified cpuset cp to include exactly those memory nodes.
Returns 0 on success, else -1 on error, setting errno. This routine can fail if malloc(3) fails. See the malloc(3) man page for possible values of errno (ENOMEM being the most likely).
int cpuset_set_iopt(struct cpuset *cp, const char *optionname, int value);
Sets cpuset integer valued option optionname to specified integer value. Returns 0 if optionname is recognized and value is an allowed value for that option. Returns -1 if optionname is recognized, but value is not allowed. Returns -2 if optionname is not recognized. Boolean options accept any non-zero value as equivalent to a value of one (1).
The following optionname values are recognized:
cpu_exclusive - Sibling cpusets not allowed to overlap cpus (see “Exclusive Cpusets” in Chapter 2)
mem_exclusive - Sibling cpusets not allowed to overlap mems (see “Exclusive Cpusets” in Chapter 2)
notify_on_release - Invokes /sbin/cpuset_release_agent when cpuset released (see “Notify on Release Flag” in Chapter 2)
memory_migrate - Causes memory pages to migrate to new mems (see “Memory Migration” in Chapter 2)
memory_spread_page - Causes kernel buffer (page) cache to spread over cpuset (see “Memory Spread” in Chapter 2)
memory_spread_slab - Causes kernel file I/O data (directory and inode slab caches) to spread over cpuset (see “Memory Spread” in Chapter 2)
int cpuset_set_sopt(struct cpuset *cp, const char *optionname, const char *value);
Sets cpuset string valued option optionname to specified string value.
Returns 0 if optionname is recognized and value is an allowed value for that option. Returns -1 if optionname is recognized, but value is not allowed. Returns -2 if optionname is not recognized.
This is an [optional] function. Use the cpuset_function () to invoke it, as follows:
/* fp has function signature of pointer to cpuset_set_sopt() */ int (*fp)(struct cpuset *cp, const char *optionname, const char *value); fp = cpuset_function("cpuset_set_sopt"); if (fp) { fp( ... ); } else { puts ("cpuset_set_sopt not supported"); } |
int cpuset_getcpus(const struct cpuset *cp, struct bitmask *cpus);
Queries CPUs in cpuset cp, by writing them to the bitmask cpus. Pass cp == NULL to query the current tasks cpuset.
If the memory nodes have not been set in cpuset cp, then no operation is performed, -1 is returned, and errno is set to EINVAL.
Returns 0 on success, else -1 on error, setting errno. This routine can fail if malloc(3) fails. See the malloc(3) man page for possible values of errno (ENOMEM being the most likely).
int cpuset_getmems(const struct cpuset *cp, struct bitmask *mems);
Queries memory nodes in cpuset cp, by writing them to the bitmask mems. Pass cp == NULL to query the current tasks cpuset.
If the memory nodes have not been set in cpuset cp, then no operation is performed, -1 is returned, and errno is set to EINVAL.
Returns 0 on success, else -1 on error, setting errno. This routine can fail if malloc(3) fails. See the malloc(3) man page for possible values of errno (ENOMEM being the most likely).
int cpuset_cpus_weight(const struct cpuset *cp);
Queries the number of CPUs in cpuset cp. Pass cp == NULL to query the current tasks cpuset.
If the CPUs have not been set in cpuset cp, then zero(0) is returned.
int cpuset_mems_weight(const struct cpuset *cp);
Queries the number of memory nodes in cpuset cp. Pass cp == NULL to query the current tasks cpuset.
If the memory nodes have not been set in cpuset cp, then zero (0) is returned.
int cpuset_get_iopt(const struct cpuset *cp, const char *optionname);
Queries the value of integer option optionname in cpuset cp.
Returns value of optionname is recognized, else returns -1. Integer values in an uninitialized cpuset have value 0.The following optionname values are recognized:
cpu_exclusive - Sibling cpusets not allowed to overlap cpus (see “Exclusive Cpusets” in Chapter 2)
mem_exclusive - Sibling cpusets not allowed to overlap mems (see “Exclusive Cpusets” in Chapter 2)
notify_on_release - Invokes /sbin/cpuset_release_agent when cpuset released (see “Notify on Release Flag” in Chapter 2)
memory_migrate - Causes memory pages to migrate to new mems (see “Memory Migration” in Chapter 2)
memory_spread_page - Causes kernel buffer (page) cache to spread over cpuset (see “Memory Spread” in Chapter 2)
memory_spread_slab - Causes kernel file I/O data (directory and inode slab caches) to spread over cpuset (see “Memory Spread” in Chapter 2)
const char *cpuset_get_sopt(const struct cpuset *cp, const char *optionname);
Queries the value of string option optionname in cpuset cp.
Returns pointer to value of optionname is recognized, else returns NULL. String values in an uninitialized cpuset have value NULL.
This is an [optional] function. Use cpuset_function() to invoke it, as follows:
/* fp has function signature of pointer to cpuset_get_sopt() */ int (*fp)(struct cpuset *cp, const char *optionname); fp = cpuset_function("cpuset_get_sopt"); if (fp) { fp( ... ); } else { puts ("cpuset_get_sopt not supported"); } |
int cpuset_localcpus(const struct bitmask *mems, struct bitmask *cpus);
Queries the CPUs local to specified memory nodes mems, by writing them to the bitmask cpus.
Returns 0 on success, -1 on error, setting errno.
int cpuset_localmems(const struct bitmask *cpus, struct bitmask *mems);
Queries the memory nodes local to specified CPUs cpus, by writing them to the bitmask mems.
Returns 0 on success, -1 on error, setting errno.
unsigned int cpuset_cpumemdist(int cpu, int mem);
Distance between hardware CPU cpu and memory node mem, on a scale which has the closest distance of a CPU to its local memory valued at ten (10), and other distances more or less proportional. Distance is a rough metric of the bandwidth and delay combined, where a higher distance means lower bandwidth and longer delays.
If either cpu or mem is not known to the current system, or if any internal error occurs while evaluating this distance, or if a node has no CPUs nor memory (I/O only), then the distance returned is UCHAR_MAX (from limits.h ).
These distances are obtained from the systems ACPI SLIT table, and should conform to: System Locality Information Table Interface Specification Version 1.0, July 26, 2003
This is an [optional] function. Use cpuset_function() to invoke it.
int cpuset_cpu2node(int cpu);
Returns number of memory node closest to CPU cpu. For NUMA architectures (as of this writing), this commonly would be the number of the node on which cpu is located. If an architecture did not have memory on the same node as a CPU, it would be the node number of the memory node closest to or preferred by that cpu.
int cpuset_create(const char *cpusetpath, const struct *cp);
Creates a cpuset at the specified cpusetpath , as described in the provided struct cpuset *cp structure. The parent cpuset of that pathname must already exist. The parameter cp refers to a handle obtained from a cpuset_alloc() call. If the parameter cpusetpath starts with a slash (/) character, this a path relative to /dev/cpuset, otherwise, it is relative to the current tasks cpuset.
The default behaviour of the libcpuset routine cpuset_create() has changed in the following way. In previous versions of SGI ProPack, the cpuset attributes memory_spread_page , memory_spread_slab, and notify_on_release in the newly created cpuset would default to the value zero (0) for off, regardless of the setting of these attributes in the parent cpuset. In this version of SGI ProPack, these attributes are inherited from the parent cpuset, unless explicitly set otherwise in the cpuset creation code.
Returns 0 on success, else -1 on error, setting errno.
This routine can fail if malloc(3) fails. See the malloc(3) man page for possible values of errno (ENOMEM being the most likely).
int cpuset_delete(const char *cpusetpath);
Deletes a cpuset at the specified cpusetpath . The cpuset of that pathname must already exist, be empty (no child cpusets) and be unused (no using tasks).
If the parameter cpusetpath starts with a slash (/) character, this a path relative to /dev/cpuset, otherwise, it is relative to the current tasks cpuset.
Returns 0 on success, else -1 on error, setting errno.
int cpuset_query(struct cpuset *cp, const char *cpusetpath);
Set struct cpuset structure to settings of cpuset at specified path cpusetpath. struct cpuset *cp must have been returned by a previous cpuset_alloc() call. Any previous settings of cp are lost.
If the parameter cpusetpath starts with a slash (/) character, this a path relative to /dev/cpuset, otherwise, it is relative to the current tasks cpuset.
Returns 0 on success, or -1 on error, setting errno. Errors include cpusetpath not referencing a valid cpuset path relative to /dev/cpuset, or the current task lacking permission to query that cpuset.
int cpuset_modify(const char *cpusetpath, const struct *cp);
Modify the cpuset at the specified cpusetpath , as described in the provided struct cpuset *cp. The cpuset at that pathname must already exist. The parameter cp refers to a handle obtained from a cpuset_alloc () call.
If the parameter cpusetpath starts with a slash (/) character, this a path relative to /dev/cpuset, otherwise, it is relative to the current tasks cpuset.
Returns 0 on success, else -1 on error, setting errno.
char *cpuset_getcpusetpath(pid_t pid, char *buf, size_t size);
The cpuset_getcpusetpath() function copies an absolute pathname of the cpuset to which task of process ID pid is attached, to the array pointed to by buf, which is of length size. Use pid == 0 for the current process.
The provided path is relative to the cpuset file system mount point.
If the cpuset path name would require a buffer longer than size elements, NULL is returned, and errno is set to ERANGE an application should check for this error, and allocate a larger buffer if necessary.
Returns NULL on failure with errno set accordingly, and buf on success. The contents of buf are undefined on error.
ERRORS are, as follows:
EACCES | Permission to read or search a component of the file name was denied. | |
EFAULT | buf points to a bad address. | |
ESRCH | The pid does not exist. | |
E2BIG | Larger buffer needed. | |
ENOSYS | Kernel does not support cpusets. |
int cpuset_cpusetofpid(struct cpuset *cp, int pid);
Set struct cpuset to settings of cpuset to which specified task pid is attached. struct cpuset *cp must have been returned by a previous cpuset_alloc() call. Any previous settings of cp are lost.
Returns 0 on success, or -1 on error, setting errno.
ERRORS are, as follows:
EACCES | Permission to read or search a component of the file name was denied. | |
EFAULT | buf points to a bad address. | |
ESRCH | The pid does not exist. | |
ERANGE | Larger buffer needed. | |
ENOSYS | Kernel does not support cpusets. |
int cpuset_cpusetofpid(struct cpuset *cp, int pid);
Sets the struct cpuset structure to settings of cpuset to which specified task pid is attached. struct cpuset *cp must have been returned by a previous cpuset_alloc() call. Any previous settings of cp are lost.
Returns 0 on success, or -1 on error, setting errno.
ERRORS are, as follows:
EACCES | Permission to read or search a component of the file name was denied. | |
EFAULT | buf points to a bad address. | |
ESRCH | The pid does not exist. | |
ERANGE | Larger buffer needed. | |
ENOSYS | Kernel does not support cpusets. |
const char *cpuset_mountpoint();
Returns the filesystem path at which the cpuset file system is mounted. The current implementation of this routine returns /dev/cpuset, or the string [cpuset filesystem not mounted] if the cpuset file system is not mounted, or the string [cpuset filesystem not supported] if the system does not support cpusets.
In general, if the first character of the return string is a slash (/), the result is the mount point of the cpuset file system; otherwise, the result is an error message string.
This is an [optional] function. Use cpuset_function to invoke it.
int cpuset_collides_exclusive(const char *cpusetpath, const struct *cp);
Returns true (1) if cpuset cp would collide with any sibling of the cpuset at cpusetpath due to overlap of cpu_exclusive cpus or mem_exclusive mems. Return false (0) if no collision, or for any error.
The cpuset_create function fails with errno == EINVAL if the requested cpuset would overlap with any sibling, where either one is cpu_exclusive or mem_exclusive. This is a common, and not obvious error. cpuset_collides_exclusive() checks for this particular case, so that code creating cpusets can better identify the situation, perhaps to issue a more informative error message.
Can also be used to diagnose cpuset_modify failures. This routine ignores any existing cpuset with the same path as the given cpusetpath, and only looks for exclusive collisions with sibling cpusets of that path.
In case of any error, returns (0) -- does not collide. Presumably, any actual attempt to create or modify a cpuset will encounter the same error, and report it usefully.
This routine is not particularly efficient; most likely code creating or modifying a cpuset will want to try the operation first, and then if that fails with errno EINVAL, perhaps call this routine to determine if an exclusive cpuset collision caused the error.
This is an [optional] function. Use cpuset_function to invoke it.
struct cpuset_pidlist *cpuset_init_pidlist(const char *cpusetpath, int recursiveflag);
Initializes and returns a list of tasks ( pids) attached to cpuset cpusetpath. If recursiveflag is zero, include only the tasks directly in that cpuset, otherwise, include all tasks in that cpuset or any descendant thereof.
Beware that tasks can come and go from a cpuset, after this call is made.
If the parameter cpusetpath starts with a slash (/) character, then this a path relative to /dev/cpuset, otherwise, it is relative to the current tasks cpuset.
On error, return NULL and set errno.
int cpuset_pidlist_length(const struct cpuset_pidlist *pl);
pid_t cpuset_get_pidlist(const struct cpuset_pidlist *pl, int i);
Return the i'th element of a cpuset_pidlist. The elements of a cpuset_pidlist of length N are numbered 0 through N-1. Return (pid_t)-1 for any other index i.
void cpuset_freepidlist(struct cpuset_pidlist *pl);
int cpuset_move(pid_t p, const char *cpusetpath);
Moves the task whose process ID is p to cpuset cpusetpath.
If pid is zero, then the current task is moved. If the parameter cpusetpath starts with a slash (/) character, this a path relative to /dev/cpuset, otherwise, it is relative to the current tasks cpuset.
Returns 0 on success, else -1 on error, setting errno.
int cpuset_move_all(struct cpuset_pid_list *pl, const char *cpusetpath);
Moves all tasks in list pl to cpuset cpusetpath.
If the parameter cpusetpath starts with a slash (/) character, this a path relative to /dev/cpuset, otherwise, it is relative to the current tasks cpuset.
Returns 0 on success, else -1 on error, setting errno.
The cpuset_move_all() routine now returns an error if it was unable to move all the tasks requested.
int cpuset_move_cpuset_tasks(const char *fromrelpath, const char *torelpath); |
Move all tasks in cpuset fromrelpath to cpuset torelpath. This may race with tasks being added to or forking into fromrelpath. Loop repeatedly, reading the task's file of cpuset fromrelpath and writing any task PIDs found there to the task's file of cpuset torelpath, up to ten attempts, or until the task's file of cpuset fromrelpath is empty, or until the cpuset fromrelpath is no longer present.
Returns 0 with errno == 0 if able to empty the task's file of cpuset fromrelpath. Of course, it is still possible that some independent task could add another task to cpuset fromrelpath at the same time that such a successful result is being returned. Therefore, there can be no guarantee that a successful return means that fromrelpath is still empty of tasks.
The cpuset fromrelpath might disappear during this operation, perhaps because it has notify_on_release flag set and was automatically removed as soon as its last task was detached from it. Consider a missing fromrelpath to be a successful move.
If called with fromrelpath and torelpath pathnames that evaluate to the same cpuset, then treat this as if cpuset_reattach() was called, rebinding each task in this cpuset one time, and return success or failure depending on the return of that cpuset_reattach() call.
On failure, returns -1, setting errno.
ERRORS are, as follows:
EACCES search permission denied on intervening directory
ENOTEMPTY tasks remain after multiple attempts to move them
EMFILE too many open files
ENODEV /dev/cpuset not mounted
ENOENT component of cpuset path does not exist
ENOMEM out of memory
ENOSYS kernel does not support cpusets
ENOTDIR component of cpuset path is not a directory
EPERM lacked permission to read cpusets or files therein
This is an [optional] function. Use cpuset_function to invoke it.
int cpuset_migrate(pid_t pid, const char *cpusetpath);
Migrates the task whose process ID is p to cpuset cpusetpath, moving its currently allocated memory to nodes in that cpuset, if not already there. If pid is zero, then the current task is migrated.
If the parameter cpusetpath starts with a slash (/) character, this a path relative to /dev/cpuset, otherwise, it is relative to the current tasks cpuset. For more information, see “Memory Migration” in Chapter 2.
Returns 0 on success, else -1 on error, setting errno.
This is an [optional] function. Use cpuset_function() to invoke it.
int cpuset_migrate_all(struct cpuset_pid_list *pl, const char *cpusetpath);
Moves all tasks in list pl to cpuset cpusetpath, moving their currently allocated memory to nodes in that cpuset, if not already there.
If the parameter cpusetpath starts with a slash (/) character, this a path relative to /dev/cpuset, otherwise, it is relative to the current tasks cpuset.
This is an [optional] function. Use cpuset_function() to invoke it.
int cpuset_reattach(const char *cpusetpath);
Reattaches all tasks in cpuset cpusetpath to itself. This additional step is necessary anytime that the cpus of a cpuset have been changed, in order to rebind the cpus_allowed of each task in the cpuset to the new value. This routine writes the pid of each task currently attached to the named cpuset to the tasks file of that cpuset. If additional tasks are being spawned too rapidly into the cpuset at the same time, there is an unavoidable race condition, and some tasks may be missed.
If the parameter cpusetpath starts with a slash (/) character, this a path relative to /dev/cpuset, otherwise, it is relative to the current tasks cpuset. Returns 0 on success, else -1 on error, setting errno.
int cpuset_open_memory_pressure(const char *cpusetpath);
Opens a file descriptor from which to read the memory_pressure of the cpuset cpusetpath.
If the cpusetpath parameter starts with a slash (/) character, this a path relative to /dev/cpuset; otherwise, it is relative to the current tasks cpuset.
By default, computation by the kernel of memory_pressure is disabled. Set the memory_pressure_enabled flag in the top cpuset to enable it.
For more information, see “Memory Pressure of a Cpuset” in Chapter 2.
This is an [optional] function. Use the cpuset_function to invoke it.
int cpuset_read_memory_pressure(int fd);
Reads and return the current memory_pressure of the cpuset for which file descriptor fd was opened using the cpuset_open_memory_pressure function.
Uses the system call pread(2). On success, returns a non-negative number, as described in “Memory Pressure of a Cpuset” in Chapter 2. On failure, returns -1 and sets errno.
By default, computation by the kernel of memory_pressure is disabled. Set the memory_pressure_enabled flag in the top cpuset to enable it.
For more information, see “Memory Pressure of a Cpuset” in Chapter 2.
This is an [optional] function. Use the cpuset_function to invoke it.
void cpuset_close_memory_pressure(int fd);
Closes the file descriptor fd which was opened using the cpuset_open_memory_pressure function.
If fd is not a valid open file descriptor, this call does nothing. No error is returned in any case.
By default, computation by the kernel of memory_pressure is disabled. Set the memory_pressure_enabled flag in the top cpuset to enable it.
For more information, see “Memory Pressure of a Cpuset” in Chapter 2.
This is an [optional] function. Use the cpuset_function to invoke it.
int cpuset_c_rel_to_sys_cpu(const struct cpuset *cp, int cpu);
Returns the system-wide CPU number that is used by the cpu-th CPU of the specified cpuset cp. Returns result of cpuset_cpus_nbits() if cpu is not in the range [0, bitmask_weight(cpuset_getcpus(cp))].
int cpuset_c_sys_to_rel_cpu(const struct cpuset *cp, int cpu);
Returns the cpu-th CPU of the specified cpuset cp that is used by the system-wide CPU number. Returns result of cpuset_cpus_nbits() if bitmask_isbitset(cpuset_getcpus(cp), cpu) is false.
int cpuset_c_rel_to_sys_mem(const struct cpuset *cp, int mem);
Returns the system-wide memory node number that is used by the mem-th memory node of the specified cpuset cp . Returns result of cpuset_mems_nbits() if mem is not in the range [0, bitmask_weight(cpuset_getmems(cp))) . Note that this is a left closed, right open interval. The set of points in the interval [a, b) is the set of all points x such that a <= x < b.
int cpuset_c_sys_to_rel_mem(const struct cpuset *cp, int mem);
Returns the mem-th memory node of the specified cpuset cp that is used by the system-wide memory node number. Returns result of cpuset_mems_nbits() if bitmask_isbitset(cpuset_getmems(cp), mem) is false.
int cpuset_p_rel_to_sys_cpu(pid_t pid, int cpu);
Returns the system-wide CPU number that is used by the cpu-th CPU of the cpuset to which task pid is attached. Returns result of cpuset_cpus_nbits() if that cpuset does not encompass that relative cpu number.
int cpuset_p_sys_to_rel_cpu(pid_t pid, int cpu);
Returns the cpu-th CPU of the cpuset to which task pid is attached that is used by the system-wide CPU number. Returns result of cpuset_cpus_nbits() if that cpuset does not encompass that system-wide cpu number.
int cpuset_p_rel_to_sys_mem(pid_t pid, int mem);
Returns the system-wide memory node number that is used by the mem-th memory node of the cpuset to which task pid is attached. Returns result of cpuset_mems_nbits () if that cpuset does not encompass that relative memory node number.
int cpuset_p_sys_to_rel_mem(pid_t pid, int mem);
Returns the mem-th memory node of the cpuset to which task pid is attached that is used by the system-wide memory node number. Returns result of cpuset_mems_nbits () if that cpuset does not encompass that system-wide memory node.
cpuset_get_placement(pid) - [optional Return current placement of task pid]
This function returns an opaque struct placement * pointer. The results of calling cpuset_get_placement twice at different points in a program can be compared using cpuset_equal_placement to determine if the specified task has had its cpuset CPU and memory placement modified between those two cpuset_get_placement calls.
When finished with a struct placement * pointer, free it by calling cpuset_free_placement.
This is an [optional] function. Use the cpuset_function to invoke it.
cpuset_equal_placement(plc1, plc2) - [optional] True if two placements equal
This function compares two struct placement * pointers, returned by two separate calls to cpuset_get_placement . This is done to determine if the specified task has had its cpuset CPU and memory placement modified between those two cpuset_get_placement calls.
When finished with a struct placement * pointer, free it by calling the cpuset_free_placement function.
Two struct placement * pointers will compare equal if they have the same CPU placement cpus, the same memory placement mems, and the same cpuset path.
This is an [optional] function. Use the cpuset_function to invoke it.
cpuset_free_placement(plc) - [optional] Free placement
Use this routine to free a struct placement * pointer returned by a previous call to the cpuset_get_placement function.
This is an [optional] function. Use the cpuset_function to invoke it.
int cpuset_cpubind(int cpu);
Binds the scheduling of the current task to CPU cpu, using the sched_setaffinity(2) system call.
Fails with a return of -1, and errno set to EINVAL, if cpu is not allowed in the current tasks cpuset.
The following code will bind the scheduling of a thread to the n-th CPU of the current cpuset:
/* * Confine current task to only run on the n-th CPU * of its current cpuset. If in a cpuset of N CPUs, * valid values for n are 0 .. N-1. */ cpuset_cpubind(cpuset_p_rel_to_sys_cpu(0, n)); |
int cpuset_latestcpu(pid_t pid);
Returns the most recent CPU on which the specified task pid executed. If pid is 0, examine current task.
The cpuset_latestcpu() call returns the number of the CPU on which the specified task pid most recently executed. If a process can be scheduled on two or more CPUs, the results of cpuset_lastcpu() may become invalid even before the query returns to the invoking user code.
The last used CPU is visible for a given pid as field #39 (starting with #1) in the file /proc/pid/stat. Currently, this file has 41 fields, so it is the 3rd to the last field.
int cpuset_membind(int mem);
Binds the memory allocation of the current task to memory node mem, using the set_mempolicy (2) system call with a policy of MPOL_BIND.
Fails with a return of -1, and errno set to EINVAL, if mem is not allowed in the current tasks cpuset.
The following code will bind the memory allocation of a thread to the n-th memory node of the current cpuset:
/* * Confine current task to only allocate memory on * n-th Node of its current cpuset. If in a cpuset * of N Memory Nodes, valid values for n are 0 .. N-1. */ cpuset_membind(cpuset_p_rel_to_sys_mem(0, n)); |
int cpuset_nuke(const char *cpusetpath, unsigned int seconds); |
Remove a cpuset, including killing tasks in it, and removing any descendent cpusets and killing their tasks.
Tasks can take a long time (minutes on some configurations) to exit. Loop up to seconds seconds, trying to kill them.
The following steps are taken to remove a cpuset:
First, kills all the PIDs, looping until there are no more PIDs in this cpuset or below or until the seconds timeout limit is exceeded.
Second, remove that cpuset, and any child cpusets it has, starting from the lowest level leaf node cpusets and working back upwards.
Third, if by this point the original cpuset is gone, return success.
If the timeout is exceeded, and tasks still exist, fail with errno == ETIME.
This routine sleeps a variable amount of time. After the first attempt to kill all the tasks in the cpuset or its descendents, it sleeps one second, the next time it sleeps two seconds, increasing one second each loop up to a maximum of ten seconds. If more loops past ten seconds are required to kill all the tasks, it sleeps ten seconds each subsequent loop. In any case, before the last loop, it sleeps however many seconds remain of the original timeout seconds requested. The total time of all sleeps will be no more than the requested seconds.
If the cpuset started out empty of any tasks, or if the passed in seconds was zero, this routine will return quickly, having not slept at all. Otherwise, this routine will at a minimum send a SIGKILL signal to all the tasks in this cpuset subtree, then sleep one second, before looking to see if any tasks remain. If tasks remain in the cpuset subtree, and a longer seconds timeout was requested (more than one), it will continue to kill remaining tasks and sleep, in a loop, for as long as time and tasks remain.
int cpuset_export(const struct cpuset *cp, char *buf, int buflen);
Writes the settings of cpuset cp to file. If no file exists at the path specified by file, create one. If a file already exists there, overwrite it.
Returns -1 and sets errno on error. Upon successful return, returns the number of characters printed (not including the trailing '0' used to end output to strings). The function cpuset_export does not write more than size bytes (including the trailing '0'). If the output was truncated due to this limit, the return value is the number of characters (not including the trailing '0') which would have been written to the final string if enough space had been available. Thus, a return value of size or more means that the output was truncated.
For details of the format required for exported cpuset file, see “Cpuset Text Format” in Chapter 2.
int cpuset_import(struct cpuset *cp, const char *file, int *errlinenum_ptr, char *errmsg_bufptr, int errmsg_buflen);
Reads the settings of cpuset cp from file. If no file exists at the path specified by file, create one. If a file already exists there, overwrite it.
struct cpuset *cp must have been returned by a previous cpuset_alloc() call. Any previous settings of cp are lost.
Returns 0 on success, or -1 on error, setting errno. Errors include file not referencing a readable file.
If parsing errors are encountered reading the file and if errlinenum_ptr is not NULL, the number of the first line (numbers start with one) with an error is written to *errlinenum_ptr. If an error occurs on the open and errlinenum_ptr is not NULL, zero is written to *errlinenum_ptr.
If parsing errors are encountered reading the file and if errmsg_bufptr is not NULL, it is presumed to point to a character buffer of at least errmsg_buflen characters and a nul-terminated error message is written to *errmsg_bufptr, providing a human readable error message explaining the error message in more detail. Currently, the possible error messages are, as follows:
"Token 'CPU' requires list"
"Token 'MEM' requires list"
"Invalid list format: %s"
"Unrecognized token: %s"
"Insufficient memory"
cpuset_function(const char *function_name);
Returns pointer to the named libcpuset.so function, or NULL. For base functions that are in all implementations of libcpuset, there is no particular value in using cpuset_function() to obtain a pointer to the function dynamically. But for [optional] cpuset functions, the use of cpuset_function () enables dynamically adapting to runtime environments that may or may not support that function.
int cpuset_version(); |
Version (simple integer) of the cpuset library (libcpuset ). The version number returned by cpuset_version() is incremented anytime that any changes or additions are made to its API or behaviour. Other mechanims are provided to maintain full upward compatibility with this libraries API. This cpuset_version() call is intended to provide a fallback mechanism in case an application needs to distinguish between two previous versions of this library.
This is an [optional] function. Use cpuset_function to invoke it.
The functions described in this section are used to transverse a cpuset hierarchy.
struct cpuset_fts_tree *cpuset_fts_open(const char *cpusetpath); |
Opens a cpuset hierarchy. Returns a pointer to a cpuset_fts_tree structure, which can be used to traverse all cpusets below the specified cpuset cpusetpath.
If the parameter cpusetpath starts with a slash (/) character, then this path is relative to /dev/cpuset, otherwise, it is relative to the current tasks cpuset.
The cpuset_fts_open routine is implemented internally using the fts(3) library routines for traversing a file hierarchy. The entire cpuset subtree below cpusetpath is traversed as part of the cpuset_fts_open() call, and all cpuset state and directory stat information is captured at that time. The other cpuset_fts_* routines just access this captured state. Any changes to the traversed cpusets made after the return of the cpuset_fts_open() call will not be visible via the returned cpuset_fts_tree structure.
Internally, the fts(3) options FTS_NOCHDIR and FTS_XDEV are used, to avoid changing the invoking tasks current directory, and to avoid descending into any other file systems mounted below /dev/cpuset. The order in which cpusets will be returned by the cpuset_fts_read routine corresponds to the fts pre-order (FTS_D) visitation order. The internal fts scan by cpuset_fts_open ignores the post-order (FTS_DP) results.
Because the cpuset_fts_open() call collects all the information at once from an entire cpuset subtree, a simple error return would not provide sufficient information as to what failed, and on what cpuset in the subtree. So, except for malloc(3) failures, errors are captured in the list of entries.
See cpuset_fts_get_info for details of the information field.
This is an [optional] function. Use cpuset_function to invoke it.
const struct cpuset_fts_entry *cpuset_fts_read(struct cpuset_fts_tree *cs_tree); |
Returns next cs_entry in cpuset_fts_tree cs_tree obtained from an cpuset_fts_open() call. One cs_entry is returned for each cpuset directory that was found in the subtree scanned by the cpuset_fts_open () call. Use the info field obtained from a cpuset_fts_get_info () call to determine which fields of a particular cs_entry are valid, and which fields contain error information or are not valid.
This is an [optional] function. Use cpuset_function to invoke it.
void cpuset_fts_reverse(struct cpuset_fts_tree *cs_tree); |
Reverse order of cs_entry's in the cpuset_fts_tree cs_tree obtained from a cpuset_fts_open () call.
An open cpuset_fts_tree stores a list of cs_entry cpuset entries, in pre-order, meaning that a series of cpuset_fts_read() calls will always return a parent cpuset before any of its child cpusets. Following a cpuset_fts_reverse () call, the order of cpuset entries is reversed, putting it in post-order, so that a series of cpuset_fts_read() calls will always return any children cpusets before their parent cpuset. A second cpuset_fts_reverse() call would put the list back in pre-order again.
To avoid exposing confusing inner details of the implementation across the API, a cpuset_fts_rewind() call is always automatically performed on a cpuset_fts_tree whenever cpuset_fts_reverse() is called on it.
This is an [optional] function. Use cpuset_function to invoke it.
void cpuset_fts_rewind(struct cpuset_fts_tree *cs_tree); |
Rewind a cpuset tree cs_tree obtained from a cpuset_fts_open() call, so that subsequent cpuset_fts_read () calls start from the beginning again.
This is an [optional] function. Use cpuset_function to invoke it.
const char *cpuset_fts_get_path(const struct cpuset_fts_entry *cs_entry); |
Return the cpuset path, relative to /dev/cpuset, as null-terminated string, of a cs_entry obtained from a cpuset_fts_read() call.
The results of this call are valid for all cs_entry's returned from cpuset_fts_read() calls, regardless of the value returned by cpuset_fts_get_info() for that cs_entry.
This is an [optional] function. Use cpuset_function to invoke it.
const struct stat *cpuset_fts_get_stat(const struct cpuset_fts_entry *cs_entry); |
Return pointer to stat(2) information about the cpuset directory of a cs_entry obtained from a cpuset_fts_read() call.
The results of this call are valid for all cs_entry's returned from cpuset_fts_read() calls, regardless of the value returned by cpuset_fts_get_info() for that cs_entry, except in the cases that:
The information field returned by cpuset_fts_get_info contains CPUSET_FTS_ERR_DNR, in which case, a directory in the path to the cpuset could not be read and this call will return a NULL pointer.
The information field returned by cpuset_fts_get_info contains CPUSET_FTS_ERR_STAT, in which case a stat(2) failed on this cpuset directory and this call will return a pointer to a struct stat containing all zeros.
This is an [optional] function. Use cpuset_function to invoke it.
const struct cpuset *cpuset_fts_get_cpuset(const struct cpuset_fts_entry *cs_entry); |
Return the struct cpuset pointer of a cs_entry obtained from a cpuset_fts_read() call. The struct cpuset so referenced describes the cpuset represented by one directory in the cpuset hierarchy, and can be used with various other calls in this library.
The results of this call are only valid for a cs_entry if the cpuset_fts_get_info() call returns CPUSET_FTS_CPUSET for the information field of a cs_entry . If the info field contained CPUSET_FTS_ERR_CPUSET , then cpuset_fts_get_cpuset returns a pointer to a struct cpuset that is all zeros. If the information field contains any other CPUSET_FTS_ERR_* value, then cpuset_fts_get_cpuset returns a NULL pointer.
This is an [optional] function. Use cpuset_function to invoke it.
int cpuset_fts_get_errno(const struct cpuset_fts_entry *cs_entry); |
Returns the error field of a cs_entry obtained from a cpuset_fts_read() call.
If this information field has one of the following CPUSET_FTS_ERR_* values, it indicates which operation failed, the error field (returned by cpuset_fts_get_errno) captures the failing errno value for that operation, the path field (returned by cpuset_fts_get_path) indicates which cpuset failed, and some of the other entry fields may not be valid, depending on the value. If an entry has the value CPUSET_FTS_CPUSET for its information field, then the error field will have the value 0, and the other fields will be contain valid information about that cpuset.
Information field values are, as follows:
CPUSET_FTS_ERR_DNR = 0: Error - couldn't read directory CPUSET_FTS_ERR_STAT = 1: Error - couldn't stat directory CPUSET_FTS_ERR_CPUSET = 2: Error - cpuset_query failed CPUSET_FTS_CPUSET = 3: Valid cpuset |
The above information field values are defined using an anonymous enum in the cpuset.h header file. If it necessary to maintain source code compatibility with earlier versions of the cpuset.h header file lacking the above CPUSET_FTS_* values, one can conditionally check that the C preprocessor symbol CPUSET_FTS_INFO_VALUES_DEFINED is not defined and provide alternative coding for that case.
This is an [optional] function. Use cpuset_function to invoke it.