1f08c3bdfSopenharmony_ci/* 2f08c3bdfSopenharmony_ci * cpuset user library implementation. 3f08c3bdfSopenharmony_ci * 4f08c3bdfSopenharmony_ci * Copyright (c) 2006-2007 Silicon Graphics, Inc. All rights reserved. 5f08c3bdfSopenharmony_ci * 6f08c3bdfSopenharmony_ci * Paul Jackson <pj@sgi.com> 7f08c3bdfSopenharmony_ci */ 8f08c3bdfSopenharmony_ci 9f08c3bdfSopenharmony_ci/* 10f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or modify 11f08c3bdfSopenharmony_ci * it under the terms of the GNU Lesser General Public License as published by 12f08c3bdfSopenharmony_ci * the Free Software Foundation; either version 2.1 of the License, or 13f08c3bdfSopenharmony_ci * (at your option) any later version. 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * This program is distributed in the hope that it will be useful, 16f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 17f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18f08c3bdfSopenharmony_ci * GNU Lesser General Public License for more details. 19f08c3bdfSopenharmony_ci * 20f08c3bdfSopenharmony_ci * You should have received a copy of the GNU Lesser General Public License 21f08c3bdfSopenharmony_ci * along with this program; if not, write to the Free Software 22f08c3bdfSopenharmony_ci * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23f08c3bdfSopenharmony_ci */ 24f08c3bdfSopenharmony_ci 25f08c3bdfSopenharmony_ci#define _GNU_SOURCE /* need to see pread() and syscall() */ 26f08c3bdfSopenharmony_ci#include <unistd.h> 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_ci#include <ctype.h> 29f08c3bdfSopenharmony_ci#include <dirent.h> 30f08c3bdfSopenharmony_ci#include <errno.h> 31f08c3bdfSopenharmony_ci#include <fcntl.h> 32f08c3bdfSopenharmony_ci#include <fts.h> 33f08c3bdfSopenharmony_ci#include <limits.h> 34f08c3bdfSopenharmony_ci#include <signal.h> 35f08c3bdfSopenharmony_ci#include <stdint.h> 36f08c3bdfSopenharmony_ci#include <stdio.h> 37f08c3bdfSopenharmony_ci#include <stdlib.h> 38f08c3bdfSopenharmony_ci#include <string.h> 39f08c3bdfSopenharmony_ci#include <sys/stat.h> 40f08c3bdfSopenharmony_ci#include <sys/syscall.h> 41f08c3bdfSopenharmony_ci#include <sys/types.h> 42f08c3bdfSopenharmony_ci#include <time.h> 43f08c3bdfSopenharmony_ci#include <utime.h> 44f08c3bdfSopenharmony_ci#include <sys/utsname.h> /* for cpuset_would_crash_kernel() */ 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_ci#include "bitmask.h" 47f08c3bdfSopenharmony_ci#include "cpuset.h" 48f08c3bdfSopenharmony_ci#include "common.h" 49f08c3bdfSopenharmony_ci#include "test.h" 50f08c3bdfSopenharmony_ci#include "lapi/syscalls.h" 51f08c3bdfSopenharmony_ci#include "config.h" 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_ci#if HAVE_LINUX_MEMPOLICY_H 54f08c3bdfSopenharmony_ci#include <linux/mempolicy.h> 55f08c3bdfSopenharmony_ci 56f08c3bdfSopenharmony_ci/* Bump version, and update Change History, when libcpuset API changes */ 57f08c3bdfSopenharmony_ci#define CPUSET_VERSION 3 58f08c3bdfSopenharmony_ci 59f08c3bdfSopenharmony_ci/* 60f08c3bdfSopenharmony_ci * For a history of what changed in each version, see the "Change 61f08c3bdfSopenharmony_ci * History" section, at the end of the libcpuset master document. 62f08c3bdfSopenharmony_ci */ 63f08c3bdfSopenharmony_ci 64f08c3bdfSopenharmony_ciint cpuset_version(void) 65f08c3bdfSopenharmony_ci{ 66f08c3bdfSopenharmony_ci return CPUSET_VERSION; 67f08c3bdfSopenharmony_ci} 68f08c3bdfSopenharmony_ci 69f08c3bdfSopenharmony_cistruct cpuset { 70f08c3bdfSopenharmony_ci struct bitmask *cpus; 71f08c3bdfSopenharmony_ci struct bitmask *mems; 72f08c3bdfSopenharmony_ci char cpu_exclusive; 73f08c3bdfSopenharmony_ci char mem_exclusive; 74f08c3bdfSopenharmony_ci char mem_hardwall; 75f08c3bdfSopenharmony_ci char notify_on_release; 76f08c3bdfSopenharmony_ci char memory_migrate; 77f08c3bdfSopenharmony_ci char memory_pressure_enabled; 78f08c3bdfSopenharmony_ci char memory_spread_page; 79f08c3bdfSopenharmony_ci char memory_spread_slab; 80f08c3bdfSopenharmony_ci char sched_load_balance; 81f08c3bdfSopenharmony_ci int sched_relax_domain_level; 82f08c3bdfSopenharmony_ci 83f08c3bdfSopenharmony_ci /* 84f08c3bdfSopenharmony_ci * Each field 'x' above gets an 'x_valid' field below. 85f08c3bdfSopenharmony_ci * The apply_cpuset_settings() will only set those fields whose 86f08c3bdfSopenharmony_ci * corresponding *_valid flags are set. The cpuset_alloc() 87f08c3bdfSopenharmony_ci * routine clears these flags as part of the clear in calloc(), 88f08c3bdfSopenharmony_ci * and the various cpuset_set*() routines set these flags when 89f08c3bdfSopenharmony_ci * setting the corresponding value. 90f08c3bdfSopenharmony_ci * 91f08c3bdfSopenharmony_ci * The purpose of these valid fields is to ensure that when 92f08c3bdfSopenharmony_ci * we create a new cpuset, we don't accidentally overwrite 93f08c3bdfSopenharmony_ci * some non-zero kernel default, such as an inherited 94f08c3bdfSopenharmony_ci * memory_spread_* flag, just because the user application 95f08c3bdfSopenharmony_ci * code didn't override the default zero settings resulting 96f08c3bdfSopenharmony_ci * from the calloc() call in cpuset_alloc(). 97f08c3bdfSopenharmony_ci * 98f08c3bdfSopenharmony_ci * The choice of 'char' for the type of the flags above, 99f08c3bdfSopenharmony_ci * but a bitfield for the flags below, is somewhat capricious. 100f08c3bdfSopenharmony_ci */ 101f08c3bdfSopenharmony_ci unsigned cpus_valid:1; 102f08c3bdfSopenharmony_ci unsigned mems_valid:1; 103f08c3bdfSopenharmony_ci unsigned cpu_exclusive_valid:1; 104f08c3bdfSopenharmony_ci unsigned mem_exclusive_valid:1; 105f08c3bdfSopenharmony_ci unsigned mem_hardwall_valid:1; 106f08c3bdfSopenharmony_ci unsigned notify_on_release_valid:1; 107f08c3bdfSopenharmony_ci unsigned memory_migrate_valid:1; 108f08c3bdfSopenharmony_ci unsigned memory_pressure_enabled_valid:1; 109f08c3bdfSopenharmony_ci unsigned memory_spread_page_valid:1; 110f08c3bdfSopenharmony_ci unsigned memory_spread_slab_valid:1; 111f08c3bdfSopenharmony_ci unsigned sched_load_balance_valid:1; 112f08c3bdfSopenharmony_ci unsigned sched_relax_domain_level_valid:1; 113f08c3bdfSopenharmony_ci 114f08c3bdfSopenharmony_ci /* 115f08c3bdfSopenharmony_ci * if the relative variable was modified, use following flags 116f08c3bdfSopenharmony_ci * to put a mark 117f08c3bdfSopenharmony_ci */ 118f08c3bdfSopenharmony_ci unsigned cpus_dirty:1; 119f08c3bdfSopenharmony_ci unsigned mems_dirty:1; 120f08c3bdfSopenharmony_ci unsigned cpu_exclusive_dirty:1; 121f08c3bdfSopenharmony_ci unsigned mem_exclusive_dirty:1; 122f08c3bdfSopenharmony_ci unsigned mem_hardwall_dirty:1; 123f08c3bdfSopenharmony_ci unsigned notify_on_release_dirty:1; 124f08c3bdfSopenharmony_ci unsigned memory_migrate_dirty:1; 125f08c3bdfSopenharmony_ci unsigned memory_pressure_enabled_dirty:1; 126f08c3bdfSopenharmony_ci unsigned memory_spread_page_dirty:1; 127f08c3bdfSopenharmony_ci unsigned memory_spread_slab_dirty:1; 128f08c3bdfSopenharmony_ci unsigned sched_load_balance_dirty:1; 129f08c3bdfSopenharmony_ci unsigned sched_relax_domain_level_dirty:1; 130f08c3bdfSopenharmony_ci}; 131f08c3bdfSopenharmony_ci 132f08c3bdfSopenharmony_ci/* Presumed cpuset file system mount point */ 133f08c3bdfSopenharmony_cistatic const char *cpusetmnt = "/dev/cpuset"; 134f08c3bdfSopenharmony_ci 135f08c3bdfSopenharmony_ci/* Stashed copy of cpunodemap[], mapping each cpu to its node. */ 136f08c3bdfSopenharmony_cistatic const char *mapfile = "/var/run/cpunodemap"; 137f08c3bdfSopenharmony_ci 138f08c3bdfSopenharmony_ci/* The primary source for the cpunodemap[] is available below here. */ 139f08c3bdfSopenharmony_cistatic const char *sysdevices = "/sys/devices/system"; 140f08c3bdfSopenharmony_ci 141f08c3bdfSopenharmony_ci/* small buffer size - for reading boolean flags or map file (1 or 2 ints) */ 142f08c3bdfSopenharmony_ci#define SMALL_BUFSZ 16 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_ci/* 145f08c3bdfSopenharmony_ci * The 'mask_size_file' is used to ferrit out the kernel cpumask_t 146f08c3bdfSopenharmony_ci * and nodemask_t sizes. The lines in this file that begin with the 147f08c3bdfSopenharmony_ci * strings 'cpumask_prefix' and 'nodemask_prefix' display a cpumask 148f08c3bdfSopenharmony_ci * and nodemask string, respectively. The lengths of these strings 149f08c3bdfSopenharmony_ci * reflect the kernel's internal cpumask_t and nodemask_t sizes, 150f08c3bdfSopenharmony_ci * which sizes are needed to correctly call the sched_setaffinity 151f08c3bdfSopenharmony_ci * and set_mempolicy system calls, and to size user level 152f08c3bdfSopenharmony_ci * bitmasks to match the kernels. 153f08c3bdfSopenharmony_ci */ 154f08c3bdfSopenharmony_ci 155f08c3bdfSopenharmony_cistatic const char *mask_size_file = "/proc/self/status"; 156f08c3bdfSopenharmony_cistatic const char *cpumask_prefix = "Cpus_allowed:\t"; 157f08c3bdfSopenharmony_cistatic const char *nodemask_prefix = "Mems_allowed:\t"; 158f08c3bdfSopenharmony_ci 159f08c3bdfSopenharmony_ci/* 160f08c3bdfSopenharmony_ci * Sizes of kernel cpumask_t and nodemask_t bitmaps, in bits. 161f08c3bdfSopenharmony_ci * 162f08c3bdfSopenharmony_ci * The first time we need these, we parse the Cpus_allowed and 163f08c3bdfSopenharmony_ci * Mems_allowed lines from mask_size_file ("/proc/self/status"). 164f08c3bdfSopenharmony_ci */ 165f08c3bdfSopenharmony_ci 166f08c3bdfSopenharmony_cistatic int cpumask_sz; 167f08c3bdfSopenharmony_cistatic int nodemask_sz; 168f08c3bdfSopenharmony_ci 169f08c3bdfSopenharmony_ci/* 170f08c3bdfSopenharmony_ci * These defaults only kick in if we fail to size the kernel 171f08c3bdfSopenharmony_ci * cpumask and nodemask by reading the Cpus_allowed and 172f08c3bdfSopenharmony_ci * Mems_allowed fields from the /proc/self/status file. 173f08c3bdfSopenharmony_ci */ 174f08c3bdfSopenharmony_ci 175f08c3bdfSopenharmony_ci#define DEFCPUBITS (512) 176f08c3bdfSopenharmony_ci#define DEFNODEBITS (DEFCPUBITS/2) 177f08c3bdfSopenharmony_ci 178f08c3bdfSopenharmony_ci/* 179f08c3bdfSopenharmony_ci * Arch-neutral API for obtaining NUMA distances between CPUs 180f08c3bdfSopenharmony_ci * and Memory Nodes, via the files: 181f08c3bdfSopenharmony_ci * /sys/devices/system/node/nodeN/distance 182f08c3bdfSopenharmony_ci * which have lines such as: 183f08c3bdfSopenharmony_ci * 46 66 10 20 184f08c3bdfSopenharmony_ci * which say that for cpu on node N (from the path above), the 185f08c3bdfSopenharmony_ci * distance to nodes 0, 1, 2, and 3 are 44, 66, 10, and 20, 186f08c3bdfSopenharmony_ci * respectively. 187f08c3bdfSopenharmony_ci */ 188f08c3bdfSopenharmony_ci 189f08c3bdfSopenharmony_cistatic const char *distance_directory = "/sys/devices/system/node"; 190f08c3bdfSopenharmony_ci 191f08c3bdfSopenharmony_ci/* 192f08c3bdfSopenharmony_ci * Someday, we should disable, then later discard, the SN code 193f08c3bdfSopenharmony_ci * marked ALTERNATE_SN_DISTMAP. 194f08c3bdfSopenharmony_ci */ 195f08c3bdfSopenharmony_ci 196f08c3bdfSopenharmony_ci#define ALTERNATE_SN_DISTMAP 1 197f08c3bdfSopenharmony_ci#ifdef ALTERNATE_SN_DISTMAP 198f08c3bdfSopenharmony_ci 199f08c3bdfSopenharmony_ci/* 200f08c3bdfSopenharmony_ci * Alternative SN (SGI ia64) architecture specific API for obtaining 201f08c3bdfSopenharmony_ci * NUMA distances between CPUs and Memory Nodes is via the file 202f08c3bdfSopenharmony_ci * /proc/sgi_sn/sn_topology, which has lines such as: 203f08c3bdfSopenharmony_ci * 204f08c3bdfSopenharmony_ci * node 2 001c14#0 local asic SHub_1.1, nasid 0x4, dist 46:66:10:20 205f08c3bdfSopenharmony_ci * 206f08c3bdfSopenharmony_ci * which says that for each CPU on node 2, the distance to nodes 207f08c3bdfSopenharmony_ci * 0, 1, 2 and 3 are 46, 66, 10 and 20, respectively. 208f08c3bdfSopenharmony_ci * 209f08c3bdfSopenharmony_ci * This file has other lines as well, which start with other 210f08c3bdfSopenharmony_ci * keywords than "node". Ignore these other lines. 211f08c3bdfSopenharmony_ci */ 212f08c3bdfSopenharmony_ci 213f08c3bdfSopenharmony_cistatic const char *sn_topology = "/proc/sgi_sn/sn_topology"; 214f08c3bdfSopenharmony_cistatic const char *sn_top_node_prefix = "node "; 215f08c3bdfSopenharmony_ci 216f08c3bdfSopenharmony_ci#endif 217f08c3bdfSopenharmony_ci 218f08c3bdfSopenharmony_ci/* 219f08c3bdfSopenharmony_ci * Check that cpusets supported, /dev/cpuset mounted. 220f08c3bdfSopenharmony_ci * If ok, return 0. 221f08c3bdfSopenharmony_ci * If not, return -1 and set errno: 222f08c3bdfSopenharmony_ci * ENOSYS - kernel doesn't support cpusets 223f08c3bdfSopenharmony_ci * ENODEV - /dev/cpuset not mounted 224f08c3bdfSopenharmony_ci */ 225f08c3bdfSopenharmony_ci 226f08c3bdfSopenharmony_cistatic enum { 227f08c3bdfSopenharmony_ci check_notdone, 228f08c3bdfSopenharmony_ci check_enosys, 229f08c3bdfSopenharmony_ci check_enodev, 230f08c3bdfSopenharmony_ci check_ok 231f08c3bdfSopenharmony_ci} check_state = check_notdone; 232f08c3bdfSopenharmony_ci 233f08c3bdfSopenharmony_cistatic int check(void) 234f08c3bdfSopenharmony_ci{ 235f08c3bdfSopenharmony_ci if (check_state == check_notdone) { 236f08c3bdfSopenharmony_ci struct stat statbuf; 237f08c3bdfSopenharmony_ci 238f08c3bdfSopenharmony_ci if (stat("/proc/self/cpuset", &statbuf) < 0) { 239f08c3bdfSopenharmony_ci check_state = check_enosys; 240f08c3bdfSopenharmony_ci goto done; 241f08c3bdfSopenharmony_ci } 242f08c3bdfSopenharmony_ci 243f08c3bdfSopenharmony_ci if (stat("/dev/cpuset/tasks", &statbuf) < 0) { 244f08c3bdfSopenharmony_ci check_state = check_enodev; 245f08c3bdfSopenharmony_ci goto done; 246f08c3bdfSopenharmony_ci } 247f08c3bdfSopenharmony_ci 248f08c3bdfSopenharmony_ci check_state = check_ok; 249f08c3bdfSopenharmony_ci } 250f08c3bdfSopenharmony_cidone: 251f08c3bdfSopenharmony_ci switch (check_state) { 252f08c3bdfSopenharmony_ci case check_enosys: 253f08c3bdfSopenharmony_ci errno = ENOSYS; 254f08c3bdfSopenharmony_ci return -1; 255f08c3bdfSopenharmony_ci case check_enodev: 256f08c3bdfSopenharmony_ci errno = ENODEV; 257f08c3bdfSopenharmony_ci return -1; 258f08c3bdfSopenharmony_ci default: 259f08c3bdfSopenharmony_ci break; 260f08c3bdfSopenharmony_ci } 261f08c3bdfSopenharmony_ci return 0; 262f08c3bdfSopenharmony_ci} 263f08c3bdfSopenharmony_ci 264f08c3bdfSopenharmony_cistatic void chomp(char *s) 265f08c3bdfSopenharmony_ci{ 266f08c3bdfSopenharmony_ci char *t; 267f08c3bdfSopenharmony_ci 268f08c3bdfSopenharmony_ci for (t = s + strlen(s) - 1; t >= s; t--) { 269f08c3bdfSopenharmony_ci if (*t == '\n' || *t == '\r') 270f08c3bdfSopenharmony_ci *t = '\0'; 271f08c3bdfSopenharmony_ci else 272f08c3bdfSopenharmony_ci break; 273f08c3bdfSopenharmony_ci } 274f08c3bdfSopenharmony_ci} 275f08c3bdfSopenharmony_ci 276f08c3bdfSopenharmony_ci/* 277f08c3bdfSopenharmony_ci * Determine number of bytes in a seekable open file, without 278f08c3bdfSopenharmony_ci * assuming that stat(2) on that file has a useful size. 279f08c3bdfSopenharmony_ci * Has side affect of leaving the file rewound to the beginnning. 280f08c3bdfSopenharmony_ci */ 281f08c3bdfSopenharmony_cistatic int filesize(FILE * fp) 282f08c3bdfSopenharmony_ci{ 283f08c3bdfSopenharmony_ci int sz = 0; 284f08c3bdfSopenharmony_ci rewind(fp); 285f08c3bdfSopenharmony_ci while (fgetc(fp) != EOF) 286f08c3bdfSopenharmony_ci sz++; 287f08c3bdfSopenharmony_ci rewind(fp); 288f08c3bdfSopenharmony_ci return sz; 289f08c3bdfSopenharmony_ci} 290f08c3bdfSopenharmony_ci 291f08c3bdfSopenharmony_ci/* Are strings s1 and s2 equal? */ 292f08c3bdfSopenharmony_cistatic int streq(const char *s1, const char *s2) 293f08c3bdfSopenharmony_ci{ 294f08c3bdfSopenharmony_ci return strcmp(s1, s2) == 0; 295f08c3bdfSopenharmony_ci} 296f08c3bdfSopenharmony_ci 297f08c3bdfSopenharmony_ci/* Is string 'pre' a prefix of string 's'? */ 298f08c3bdfSopenharmony_cistatic int strprefix(const char *s, const char *pre) 299f08c3bdfSopenharmony_ci{ 300f08c3bdfSopenharmony_ci return strncmp(s, pre, strlen(pre)) == 0; 301f08c3bdfSopenharmony_ci} 302f08c3bdfSopenharmony_ci 303f08c3bdfSopenharmony_ci/* 304f08c3bdfSopenharmony_ci * char *flgets(char *buf, int buflen, FILE *fp) 305f08c3bdfSopenharmony_ci * 306f08c3bdfSopenharmony_ci * Obtain one line from input file fp. Copy up to first 307f08c3bdfSopenharmony_ci * buflen-1 chars of line into buffer buf, discarding any remainder 308f08c3bdfSopenharmony_ci * of line. Stop reading at newline, discarding newline. 309f08c3bdfSopenharmony_ci * Nul terminate result and return pointer to buffer buf 310f08c3bdfSopenharmony_ci * on success, or NULL if nothing more to read or failure. 311f08c3bdfSopenharmony_ci */ 312f08c3bdfSopenharmony_ci 313f08c3bdfSopenharmony_cistatic char *flgets(char *buf, int buflen, FILE * fp) 314f08c3bdfSopenharmony_ci{ 315f08c3bdfSopenharmony_ci int c = -1; 316f08c3bdfSopenharmony_ci char *bp; 317f08c3bdfSopenharmony_ci 318f08c3bdfSopenharmony_ci bp = buf; 319f08c3bdfSopenharmony_ci while ((--buflen > 0) && ((c = getc(fp)) >= 0)) { 320f08c3bdfSopenharmony_ci if (c == '\n') 321f08c3bdfSopenharmony_ci goto newline; 322f08c3bdfSopenharmony_ci *bp++ = c; 323f08c3bdfSopenharmony_ci } 324f08c3bdfSopenharmony_ci if ((c < 0) && (bp == buf)) 325f08c3bdfSopenharmony_ci return NULL; 326f08c3bdfSopenharmony_ci 327f08c3bdfSopenharmony_ci if (c > 0) { 328f08c3bdfSopenharmony_ci while ((c = getc(fp)) >= 0) { 329f08c3bdfSopenharmony_ci if (c == '\n') 330f08c3bdfSopenharmony_ci break; 331f08c3bdfSopenharmony_ci } 332f08c3bdfSopenharmony_ci } 333f08c3bdfSopenharmony_ci 334f08c3bdfSopenharmony_cinewline: 335f08c3bdfSopenharmony_ci *bp++ = '\0'; 336f08c3bdfSopenharmony_ci return buf; 337f08c3bdfSopenharmony_ci} 338f08c3bdfSopenharmony_ci 339f08c3bdfSopenharmony_ci/* 340f08c3bdfSopenharmony_ci * sgetc(const char *inputbuf, int *offsetptr) 341f08c3bdfSopenharmony_ci * 342f08c3bdfSopenharmony_ci * Return next char from nul-terminated input buffer inputbuf, 343f08c3bdfSopenharmony_ci * starting at offset *offsetptr. Increment *offsetptr. 344f08c3bdfSopenharmony_ci * If next char would be nul ('\0'), return EOF and don't 345f08c3bdfSopenharmony_ci * increment *offsetptr. 346f08c3bdfSopenharmony_ci */ 347f08c3bdfSopenharmony_ci 348f08c3bdfSopenharmony_cistatic int sgetc(const char *inputbuf, int *offsetptr) 349f08c3bdfSopenharmony_ci{ 350f08c3bdfSopenharmony_ci char c; 351f08c3bdfSopenharmony_ci 352f08c3bdfSopenharmony_ci if ((c = inputbuf[*offsetptr]) != 0) { 353f08c3bdfSopenharmony_ci *offsetptr = *offsetptr + 1; 354f08c3bdfSopenharmony_ci return c; 355f08c3bdfSopenharmony_ci } else { 356f08c3bdfSopenharmony_ci return EOF; 357f08c3bdfSopenharmony_ci } 358f08c3bdfSopenharmony_ci} 359f08c3bdfSopenharmony_ci 360f08c3bdfSopenharmony_ci/* 361f08c3bdfSopenharmony_ci * char *slgets(char *buf, int buflen, const char *inputbuf, int *offsetptr) 362f08c3bdfSopenharmony_ci * 363f08c3bdfSopenharmony_ci * Obtain next line from nul-terminated input buffer 'inputbuf', 364f08c3bdfSopenharmony_ci * starting at offset *offsetptr. Copy up to first buflen-1 365f08c3bdfSopenharmony_ci * chars of line into output buffer buf, discarding any remainder 366f08c3bdfSopenharmony_ci * of line. Stop reading at newline, discarding newline. 367f08c3bdfSopenharmony_ci * Nul terminate result and return pointer to output buffer 368f08c3bdfSopenharmony_ci * buf on success, or NULL if nothing more to read. 369f08c3bdfSopenharmony_ci */ 370f08c3bdfSopenharmony_ci 371f08c3bdfSopenharmony_cistatic char *slgets(char *buf, int buflen, const char *inputbuf, int *offsetptr) 372f08c3bdfSopenharmony_ci{ 373f08c3bdfSopenharmony_ci int c = -1; 374f08c3bdfSopenharmony_ci char *bp; 375f08c3bdfSopenharmony_ci 376f08c3bdfSopenharmony_ci bp = buf; 377f08c3bdfSopenharmony_ci while ((--buflen > 0) && ((c = sgetc(inputbuf, offsetptr)) >= 0)) { 378f08c3bdfSopenharmony_ci if (c == '\n') 379f08c3bdfSopenharmony_ci goto newline; 380f08c3bdfSopenharmony_ci *bp++ = c; 381f08c3bdfSopenharmony_ci } 382f08c3bdfSopenharmony_ci if ((c < 0) && (bp == buf)) 383f08c3bdfSopenharmony_ci return NULL; 384f08c3bdfSopenharmony_ci 385f08c3bdfSopenharmony_ci if (c > 0) { 386f08c3bdfSopenharmony_ci while ((c = sgetc(inputbuf, offsetptr)) >= 0) { 387f08c3bdfSopenharmony_ci if (c == '\n') 388f08c3bdfSopenharmony_ci break; 389f08c3bdfSopenharmony_ci } 390f08c3bdfSopenharmony_ci } 391f08c3bdfSopenharmony_ci 392f08c3bdfSopenharmony_cinewline: 393f08c3bdfSopenharmony_ci *bp++ = '\0'; 394f08c3bdfSopenharmony_ci return buf; 395f08c3bdfSopenharmony_ci} 396f08c3bdfSopenharmony_ci 397f08c3bdfSopenharmony_ci/* 398f08c3bdfSopenharmony_ci * time_t get_mtime(char *path) 399f08c3bdfSopenharmony_ci * 400f08c3bdfSopenharmony_ci * Return modtime of file at location path, else return 0. 401f08c3bdfSopenharmony_ci */ 402f08c3bdfSopenharmony_ci 403f08c3bdfSopenharmony_cistatic time_t get_mtime(const char *path) 404f08c3bdfSopenharmony_ci{ 405f08c3bdfSopenharmony_ci struct stat statbuf; 406f08c3bdfSopenharmony_ci 407f08c3bdfSopenharmony_ci if (stat(path, &statbuf) != 0) 408f08c3bdfSopenharmony_ci return 0; 409f08c3bdfSopenharmony_ci return statbuf.st_mtime; 410f08c3bdfSopenharmony_ci} 411f08c3bdfSopenharmony_ci 412f08c3bdfSopenharmony_ci/* 413f08c3bdfSopenharmony_ci * int set_mtime(const char *path, time_t mtime) 414f08c3bdfSopenharmony_ci * 415f08c3bdfSopenharmony_ci * Set modtime of file 'path' to 'mtime'. Return 0 on success, 416f08c3bdfSopenharmony_ci * or -1 on error, setting errno. 417f08c3bdfSopenharmony_ci */ 418f08c3bdfSopenharmony_ci 419f08c3bdfSopenharmony_cistatic int set_mtime(const char *path, time_t mtime) 420f08c3bdfSopenharmony_ci{ 421f08c3bdfSopenharmony_ci struct utimbuf times; 422f08c3bdfSopenharmony_ci 423f08c3bdfSopenharmony_ci times.actime = mtime; 424f08c3bdfSopenharmony_ci times.modtime = mtime; 425f08c3bdfSopenharmony_ci return utime(path, ×); 426f08c3bdfSopenharmony_ci} 427f08c3bdfSopenharmony_ci 428f08c3bdfSopenharmony_ci/* 429f08c3bdfSopenharmony_ci * True if two pathnames resolve to same file. 430f08c3bdfSopenharmony_ci * False if either path can not be stat'd, 431f08c3bdfSopenharmony_ci * or if the two paths resolve to a different file. 432f08c3bdfSopenharmony_ci */ 433f08c3bdfSopenharmony_ci 434f08c3bdfSopenharmony_cistatic int samefile(const char *path1, const char *path2) 435f08c3bdfSopenharmony_ci{ 436f08c3bdfSopenharmony_ci struct stat sb1, sb2; 437f08c3bdfSopenharmony_ci 438f08c3bdfSopenharmony_ci if (stat(path1, &sb1) != 0) 439f08c3bdfSopenharmony_ci return 0; 440f08c3bdfSopenharmony_ci if (stat(path2, &sb2) != 0) 441f08c3bdfSopenharmony_ci return 0; 442f08c3bdfSopenharmony_ci return sb1.st_ino == sb2.st_ino && sb1.st_dev == sb2.st_dev; 443f08c3bdfSopenharmony_ci} 444f08c3bdfSopenharmony_ci 445f08c3bdfSopenharmony_ci#define slash(c) (*(c) == '/') 446f08c3bdfSopenharmony_ci#define eocomp(c) (slash(c) || !*(c)) 447f08c3bdfSopenharmony_ci#define dot1(c) (*(c) == '.' && eocomp(c+1)) 448f08c3bdfSopenharmony_ci 449f08c3bdfSopenharmony_ci/* In place path compression. Remove extra dots and slashes. */ 450f08c3bdfSopenharmony_cistatic char *pathcomp(char *p) 451f08c3bdfSopenharmony_ci{ 452f08c3bdfSopenharmony_ci char *a = p; 453f08c3bdfSopenharmony_ci char *b = p; 454f08c3bdfSopenharmony_ci 455f08c3bdfSopenharmony_ci if (!p || !*p) 456f08c3bdfSopenharmony_ci return p; 457f08c3bdfSopenharmony_ci if (slash(p)) 458f08c3bdfSopenharmony_ci *b++ = *a++; 459f08c3bdfSopenharmony_ci for (;;) { 460f08c3bdfSopenharmony_ci if (slash(a)) 461f08c3bdfSopenharmony_ci while (slash(++a)) 462f08c3bdfSopenharmony_ci continue; 463f08c3bdfSopenharmony_ci if (!*a) { 464f08c3bdfSopenharmony_ci if (b == p) 465f08c3bdfSopenharmony_ci *b++ = '.'; 466f08c3bdfSopenharmony_ci *b = '\0'; 467f08c3bdfSopenharmony_ci return (p); 468f08c3bdfSopenharmony_ci } else if (dot1(a)) { 469f08c3bdfSopenharmony_ci a++; 470f08c3bdfSopenharmony_ci } else { 471f08c3bdfSopenharmony_ci if ((b != p) && !slash(b - 1)) 472f08c3bdfSopenharmony_ci *b++ = '/'; 473f08c3bdfSopenharmony_ci while (!eocomp(a)) 474f08c3bdfSopenharmony_ci *b++ = *a++; 475f08c3bdfSopenharmony_ci } 476f08c3bdfSopenharmony_ci } 477f08c3bdfSopenharmony_ci} 478f08c3bdfSopenharmony_ci 479f08c3bdfSopenharmony_ci#undef slash 480f08c3bdfSopenharmony_ci#undef eocomp 481f08c3bdfSopenharmony_ci#undef dot1 482f08c3bdfSopenharmony_ci 483f08c3bdfSopenharmony_ci/* 484f08c3bdfSopenharmony_ci * pathcat2(buf, buflen, name1, name2) 485f08c3bdfSopenharmony_ci * 486f08c3bdfSopenharmony_ci * Return buf, of length buflen, with name1/name2 stored in it. 487f08c3bdfSopenharmony_ci */ 488f08c3bdfSopenharmony_ci 489f08c3bdfSopenharmony_cistatic char *pathcat2(char *buf, int buflen, const char *name1, 490f08c3bdfSopenharmony_ci const char *name2) 491f08c3bdfSopenharmony_ci{ 492f08c3bdfSopenharmony_ci (void)snprintf(buf, buflen, "%s/%s", name1, name2); 493f08c3bdfSopenharmony_ci return pathcomp(buf); 494f08c3bdfSopenharmony_ci} 495f08c3bdfSopenharmony_ci 496f08c3bdfSopenharmony_ci/* 497f08c3bdfSopenharmony_ci * pathcat3(buf, buflen, name1, name2, name3) 498f08c3bdfSopenharmony_ci * 499f08c3bdfSopenharmony_ci * Return buf, of length buflen, with name1/name2/name3 stored in it. 500f08c3bdfSopenharmony_ci */ 501f08c3bdfSopenharmony_ci 502f08c3bdfSopenharmony_cistatic char *pathcat3(char *buf, int buflen, const char *name1, 503f08c3bdfSopenharmony_ci const char *name2, const char *name3) 504f08c3bdfSopenharmony_ci{ 505f08c3bdfSopenharmony_ci (void)snprintf(buf, buflen, "%s/%s/%s", name1, name2, name3); 506f08c3bdfSopenharmony_ci return pathcomp(buf); 507f08c3bdfSopenharmony_ci} 508f08c3bdfSopenharmony_ci 509f08c3bdfSopenharmony_ci/* 510f08c3bdfSopenharmony_ci * fullpath(buf, buflen, name) 511f08c3bdfSopenharmony_ci * 512f08c3bdfSopenharmony_ci * Put full path of cpuset 'name' in buffer 'buf'. If name 513f08c3bdfSopenharmony_ci * starts with a slash (``/``) character, then this a path 514f08c3bdfSopenharmony_ci * relative to ``/dev/cpuset``, otherwise it is relative to 515f08c3bdfSopenharmony_ci * the current tasks cpuset. Return 0 on success, else 516f08c3bdfSopenharmony_ci * -1 on error, setting errno. 517f08c3bdfSopenharmony_ci */ 518f08c3bdfSopenharmony_ci 519f08c3bdfSopenharmony_cistatic int fullpath(char *buf, int buflen, const char *name) 520f08c3bdfSopenharmony_ci{ 521f08c3bdfSopenharmony_ci int len; 522f08c3bdfSopenharmony_ci 523f08c3bdfSopenharmony_ci /* easy case */ 524f08c3bdfSopenharmony_ci if (*name == '/') { 525f08c3bdfSopenharmony_ci pathcat2(buf, buflen, cpusetmnt, name); 526f08c3bdfSopenharmony_ci pathcomp(buf); 527f08c3bdfSopenharmony_ci return 0; 528f08c3bdfSopenharmony_ci } 529f08c3bdfSopenharmony_ci 530f08c3bdfSopenharmony_ci /* hard case */ 531f08c3bdfSopenharmony_ci snprintf(buf, buflen, "%s/", cpusetmnt); 532f08c3bdfSopenharmony_ci len = strlen(buf); 533f08c3bdfSopenharmony_ci if (cpuset_getcpusetpath(0, buf + len, buflen - len) == NULL) 534f08c3bdfSopenharmony_ci return -1; 535f08c3bdfSopenharmony_ci if (strlen(buf) >= buflen - 1 - strlen(name)) { 536f08c3bdfSopenharmony_ci errno = E2BIG; 537f08c3bdfSopenharmony_ci return -1; 538f08c3bdfSopenharmony_ci } 539f08c3bdfSopenharmony_ci strcat(buf, "/"); 540f08c3bdfSopenharmony_ci strcat(buf, name); 541f08c3bdfSopenharmony_ci pathcomp(buf); 542f08c3bdfSopenharmony_ci return 0; 543f08c3bdfSopenharmony_ci} 544f08c3bdfSopenharmony_ci 545f08c3bdfSopenharmony_ci/* 546f08c3bdfSopenharmony_ci * fullpath2(buf, buflen, name1, name2) 547f08c3bdfSopenharmony_ci * 548f08c3bdfSopenharmony_ci * Like fullpath(), only concatenate two pathname components on end. 549f08c3bdfSopenharmony_ci */ 550f08c3bdfSopenharmony_ci 551f08c3bdfSopenharmony_cistatic int fullpath2(char *buf, int buflen, const char *name1, 552f08c3bdfSopenharmony_ci const char *name2) 553f08c3bdfSopenharmony_ci{ 554f08c3bdfSopenharmony_ci if (fullpath(buf, buflen, name1) < 0) 555f08c3bdfSopenharmony_ci return -1; 556f08c3bdfSopenharmony_ci if (strlen(buf) >= buflen - 1 - strlen(name2)) { 557f08c3bdfSopenharmony_ci errno = E2BIG; 558f08c3bdfSopenharmony_ci return -1; 559f08c3bdfSopenharmony_ci } 560f08c3bdfSopenharmony_ci strcat(buf, "/"); 561f08c3bdfSopenharmony_ci strcat(buf, name2); 562f08c3bdfSopenharmony_ci pathcomp(buf); 563f08c3bdfSopenharmony_ci return 0; 564f08c3bdfSopenharmony_ci} 565f08c3bdfSopenharmony_ci 566f08c3bdfSopenharmony_ci/* 567f08c3bdfSopenharmony_ci * Convert the string length of an ascii hex mask to the number 568f08c3bdfSopenharmony_ci * of bits represented by that mask. 569f08c3bdfSopenharmony_ci * 570f08c3bdfSopenharmony_ci * The cpumask and nodemask values in /proc/self/status are in an 571f08c3bdfSopenharmony_ci * ascii format that uses 9 characters for each 32 bits of mask. 572f08c3bdfSopenharmony_ci */ 573f08c3bdfSopenharmony_cistatic int s2nbits(const char *s) 574f08c3bdfSopenharmony_ci{ 575f08c3bdfSopenharmony_ci return strlen(s) * 32 / 9; 576f08c3bdfSopenharmony_ci} 577f08c3bdfSopenharmony_ci 578f08c3bdfSopenharmony_cistatic void update_mask_sizes(void) 579f08c3bdfSopenharmony_ci{ 580f08c3bdfSopenharmony_ci FILE *fp = NULL; 581f08c3bdfSopenharmony_ci char *buf = NULL; 582f08c3bdfSopenharmony_ci int fsize; 583f08c3bdfSopenharmony_ci 584f08c3bdfSopenharmony_ci if ((fp = fopen(mask_size_file, "r")) == NULL) 585f08c3bdfSopenharmony_ci goto done; 586f08c3bdfSopenharmony_ci fsize = filesize(fp); 587f08c3bdfSopenharmony_ci if ((buf = malloc(fsize)) == NULL) 588f08c3bdfSopenharmony_ci goto done; 589f08c3bdfSopenharmony_ci 590f08c3bdfSopenharmony_ci /* 591f08c3bdfSopenharmony_ci * Beware: mask sizing arithmetic is fussy. 592f08c3bdfSopenharmony_ci * The trailing newline left by fgets() is required. 593f08c3bdfSopenharmony_ci */ 594f08c3bdfSopenharmony_ci while (fgets(buf, fsize, fp)) { 595f08c3bdfSopenharmony_ci if (strprefix(buf, cpumask_prefix)) 596f08c3bdfSopenharmony_ci cpumask_sz = s2nbits(buf + strlen(cpumask_prefix)); 597f08c3bdfSopenharmony_ci if (strprefix(buf, nodemask_prefix)) 598f08c3bdfSopenharmony_ci nodemask_sz = s2nbits(buf + strlen(nodemask_prefix)); 599f08c3bdfSopenharmony_ci } 600f08c3bdfSopenharmony_cidone: 601f08c3bdfSopenharmony_ci free(buf); 602f08c3bdfSopenharmony_ci if (fp != NULL) 603f08c3bdfSopenharmony_ci fclose(fp); 604f08c3bdfSopenharmony_ci if (cpumask_sz == 0) 605f08c3bdfSopenharmony_ci cpumask_sz = DEFCPUBITS; 606f08c3bdfSopenharmony_ci if (nodemask_sz == 0) 607f08c3bdfSopenharmony_ci nodemask_sz = DEFNODEBITS; 608f08c3bdfSopenharmony_ci} 609f08c3bdfSopenharmony_ci 610f08c3bdfSopenharmony_ci/* Allocate a new struct cpuset */ 611f08c3bdfSopenharmony_cistruct cpuset *cpuset_alloc(void) 612f08c3bdfSopenharmony_ci{ 613f08c3bdfSopenharmony_ci struct cpuset *cp = NULL; 614f08c3bdfSopenharmony_ci int nbits; 615f08c3bdfSopenharmony_ci 616f08c3bdfSopenharmony_ci if ((cp = calloc(1, sizeof(struct cpuset))) == NULL) 617f08c3bdfSopenharmony_ci goto err; 618f08c3bdfSopenharmony_ci 619f08c3bdfSopenharmony_ci nbits = cpuset_cpus_nbits(); 620f08c3bdfSopenharmony_ci if ((cp->cpus = bitmask_alloc(nbits)) == NULL) 621f08c3bdfSopenharmony_ci goto err; 622f08c3bdfSopenharmony_ci 623f08c3bdfSopenharmony_ci nbits = cpuset_mems_nbits(); 624f08c3bdfSopenharmony_ci if ((cp->mems = bitmask_alloc(nbits)) == NULL) 625f08c3bdfSopenharmony_ci goto err; 626f08c3bdfSopenharmony_ci 627f08c3bdfSopenharmony_ci return cp; 628f08c3bdfSopenharmony_cierr: 629f08c3bdfSopenharmony_ci if (cp && cp->cpus) 630f08c3bdfSopenharmony_ci bitmask_free(cp->cpus); 631f08c3bdfSopenharmony_ci if (cp && cp->mems) 632f08c3bdfSopenharmony_ci bitmask_free(cp->mems); 633f08c3bdfSopenharmony_ci free(cp); 634f08c3bdfSopenharmony_ci return NULL; 635f08c3bdfSopenharmony_ci} 636f08c3bdfSopenharmony_ci 637f08c3bdfSopenharmony_ci/* Free struct cpuset *cp */ 638f08c3bdfSopenharmony_civoid cpuset_free(struct cpuset *cp) 639f08c3bdfSopenharmony_ci{ 640f08c3bdfSopenharmony_ci if (!cp) 641f08c3bdfSopenharmony_ci return; 642f08c3bdfSopenharmony_ci if (cp->cpus) 643f08c3bdfSopenharmony_ci bitmask_free(cp->cpus); 644f08c3bdfSopenharmony_ci if (cp->mems) 645f08c3bdfSopenharmony_ci bitmask_free(cp->mems); 646f08c3bdfSopenharmony_ci free(cp); 647f08c3bdfSopenharmony_ci} 648f08c3bdfSopenharmony_ci 649f08c3bdfSopenharmony_ci/* Number of bits in a CPU bitmask on current system */ 650f08c3bdfSopenharmony_ciint cpuset_cpus_nbits(void) 651f08c3bdfSopenharmony_ci{ 652f08c3bdfSopenharmony_ci if (cpumask_sz == 0) 653f08c3bdfSopenharmony_ci update_mask_sizes(); 654f08c3bdfSopenharmony_ci return cpumask_sz; 655f08c3bdfSopenharmony_ci} 656f08c3bdfSopenharmony_ci 657f08c3bdfSopenharmony_ci/* Number of bits in a Memory bitmask on current system */ 658f08c3bdfSopenharmony_ciint cpuset_mems_nbits(void) 659f08c3bdfSopenharmony_ci{ 660f08c3bdfSopenharmony_ci if (nodemask_sz == 0) 661f08c3bdfSopenharmony_ci update_mask_sizes(); 662f08c3bdfSopenharmony_ci return nodemask_sz; 663f08c3bdfSopenharmony_ci} 664f08c3bdfSopenharmony_ci 665f08c3bdfSopenharmony_ci/* Set CPUs in cpuset cp to bitmask cpus */ 666f08c3bdfSopenharmony_ciint cpuset_setcpus(struct cpuset *cp, const struct bitmask *cpus) 667f08c3bdfSopenharmony_ci{ 668f08c3bdfSopenharmony_ci if (cp->cpus) 669f08c3bdfSopenharmony_ci bitmask_free(cp->cpus); 670f08c3bdfSopenharmony_ci cp->cpus = bitmask_alloc(bitmask_nbits(cpus)); 671f08c3bdfSopenharmony_ci if (cp->cpus == NULL) 672f08c3bdfSopenharmony_ci return -1; 673f08c3bdfSopenharmony_ci bitmask_copy(cp->cpus, cpus); 674f08c3bdfSopenharmony_ci cp->cpus_valid = 1; 675f08c3bdfSopenharmony_ci cp->cpus_dirty = 1; 676f08c3bdfSopenharmony_ci return 0; 677f08c3bdfSopenharmony_ci} 678f08c3bdfSopenharmony_ci 679f08c3bdfSopenharmony_ci/* Set Memory Nodes in cpuset cp to bitmask mems */ 680f08c3bdfSopenharmony_ciint cpuset_setmems(struct cpuset *cp, const struct bitmask *mems) 681f08c3bdfSopenharmony_ci{ 682f08c3bdfSopenharmony_ci if (cp->mems) 683f08c3bdfSopenharmony_ci bitmask_free(cp->mems); 684f08c3bdfSopenharmony_ci cp->mems = bitmask_alloc(bitmask_nbits(mems)); 685f08c3bdfSopenharmony_ci if (cp->mems == NULL) 686f08c3bdfSopenharmony_ci return -1; 687f08c3bdfSopenharmony_ci bitmask_copy(cp->mems, mems); 688f08c3bdfSopenharmony_ci cp->mems_valid = 1; 689f08c3bdfSopenharmony_ci cp->mems_dirty = 1; 690f08c3bdfSopenharmony_ci return 0; 691f08c3bdfSopenharmony_ci} 692f08c3bdfSopenharmony_ci 693f08c3bdfSopenharmony_ci/* Set integer value optname of cpuset cp */ 694f08c3bdfSopenharmony_ciint cpuset_set_iopt(struct cpuset *cp, const char *optionname, int value) 695f08c3bdfSopenharmony_ci{ 696f08c3bdfSopenharmony_ci if (streq(optionname, "cpu_exclusive")) { 697f08c3bdfSopenharmony_ci cp->cpu_exclusive = ! !value; 698f08c3bdfSopenharmony_ci cp->cpu_exclusive_valid = 1; 699f08c3bdfSopenharmony_ci cp->cpu_exclusive_dirty = 1; 700f08c3bdfSopenharmony_ci } else if (streq(optionname, "mem_exclusive")) { 701f08c3bdfSopenharmony_ci cp->mem_exclusive = ! !value; 702f08c3bdfSopenharmony_ci cp->mem_exclusive_valid = 1; 703f08c3bdfSopenharmony_ci cp->mem_exclusive_dirty = 1; 704f08c3bdfSopenharmony_ci } else if (streq(optionname, "mem_hardwall")) { 705f08c3bdfSopenharmony_ci cp->mem_hardwall = ! !value; 706f08c3bdfSopenharmony_ci cp->mem_hardwall_valid = 1; 707f08c3bdfSopenharmony_ci cp->mem_hardwall_dirty = 1; 708f08c3bdfSopenharmony_ci } else if (streq(optionname, "notify_on_release")) { 709f08c3bdfSopenharmony_ci cp->notify_on_release = ! !value; 710f08c3bdfSopenharmony_ci cp->notify_on_release_valid = 1; 711f08c3bdfSopenharmony_ci cp->notify_on_release_dirty = 1; 712f08c3bdfSopenharmony_ci } else if (streq(optionname, "memory_pressure_enabled")) { 713f08c3bdfSopenharmony_ci cp->memory_pressure_enabled = ! !value; 714f08c3bdfSopenharmony_ci cp->memory_pressure_enabled_valid = 1; 715f08c3bdfSopenharmony_ci cp->memory_pressure_enabled_dirty = 1; 716f08c3bdfSopenharmony_ci } else if (streq(optionname, "memory_migrate")) { 717f08c3bdfSopenharmony_ci cp->memory_migrate = ! !value; 718f08c3bdfSopenharmony_ci cp->memory_migrate_valid = 1; 719f08c3bdfSopenharmony_ci cp->memory_migrate_dirty = 1; 720f08c3bdfSopenharmony_ci } else if (streq(optionname, "memory_spread_page")) { 721f08c3bdfSopenharmony_ci cp->memory_spread_page = ! !value; 722f08c3bdfSopenharmony_ci cp->memory_spread_page_valid = 1; 723f08c3bdfSopenharmony_ci cp->memory_spread_page_dirty = 1; 724f08c3bdfSopenharmony_ci } else if (streq(optionname, "memory_spread_slab")) { 725f08c3bdfSopenharmony_ci cp->memory_spread_slab = ! !value; 726f08c3bdfSopenharmony_ci cp->memory_spread_slab_valid = 1; 727f08c3bdfSopenharmony_ci cp->memory_spread_slab_dirty = 1; 728f08c3bdfSopenharmony_ci } else if (streq(optionname, "sched_load_balance")) { 729f08c3bdfSopenharmony_ci cp->sched_load_balance = ! !value; 730f08c3bdfSopenharmony_ci cp->sched_load_balance_valid = 1; 731f08c3bdfSopenharmony_ci cp->sched_load_balance_dirty = 1; 732f08c3bdfSopenharmony_ci } else if (streq(optionname, "sched_relax_domain_level")) { 733f08c3bdfSopenharmony_ci cp->sched_relax_domain_level = value; 734f08c3bdfSopenharmony_ci cp->sched_relax_domain_level_valid = 1; 735f08c3bdfSopenharmony_ci cp->sched_relax_domain_level_dirty = 1; 736f08c3bdfSopenharmony_ci } else 737f08c3bdfSopenharmony_ci return -2; /* optionname not recognized */ 738f08c3bdfSopenharmony_ci return 0; 739f08c3bdfSopenharmony_ci} 740f08c3bdfSopenharmony_ci 741f08c3bdfSopenharmony_ci/* [optional] Set string value optname */ 742f08c3bdfSopenharmony_ciint cpuset_set_sopt(UNUSED struct cpuset *cp, UNUSED const char *optionname, 743f08c3bdfSopenharmony_ci UNUSED const char *value) 744f08c3bdfSopenharmony_ci{ 745f08c3bdfSopenharmony_ci return -2; /* For now, all string options unrecognized */ 746f08c3bdfSopenharmony_ci} 747f08c3bdfSopenharmony_ci 748f08c3bdfSopenharmony_ci/* Return handle for reading memory_pressure. */ 749f08c3bdfSopenharmony_ciint cpuset_open_memory_pressure(const char *cpusetpath) 750f08c3bdfSopenharmony_ci{ 751f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 752f08c3bdfSopenharmony_ci 753f08c3bdfSopenharmony_ci fullpath2(buf, sizeof(buf), cpusetpath, "memory_pressure"); 754f08c3bdfSopenharmony_ci return open(buf, O_RDONLY); 755f08c3bdfSopenharmony_ci} 756f08c3bdfSopenharmony_ci 757f08c3bdfSopenharmony_ci/* Return current memory_pressure of cpuset. */ 758f08c3bdfSopenharmony_ciint cpuset_read_memory_pressure(int han) 759f08c3bdfSopenharmony_ci{ 760f08c3bdfSopenharmony_ci char buf[SMALL_BUFSZ]; 761f08c3bdfSopenharmony_ci 762f08c3bdfSopenharmony_ci if (pread(han, buf, sizeof(buf), 0L) < 0) 763f08c3bdfSopenharmony_ci return -1; 764f08c3bdfSopenharmony_ci return atoi(buf); 765f08c3bdfSopenharmony_ci} 766f08c3bdfSopenharmony_ci 767f08c3bdfSopenharmony_ci/* Close handle for reading memory pressure. */ 768f08c3bdfSopenharmony_civoid cpuset_close_memory_pressure(int han) 769f08c3bdfSopenharmony_ci{ 770f08c3bdfSopenharmony_ci close(han); 771f08c3bdfSopenharmony_ci} 772f08c3bdfSopenharmony_ci 773f08c3bdfSopenharmony_ci/* 774f08c3bdfSopenharmony_ci * Resolve cpuset pointer (to that of current task if cp == NULL). 775f08c3bdfSopenharmony_ci * 776f08c3bdfSopenharmony_ci * If cp not NULL, just return it. If cp is NULL, return pointer 777f08c3bdfSopenharmony_ci * to temporary cpuset for current task, and set *cp_tofree to 778f08c3bdfSopenharmony_ci * pointer to that same temporary cpuset, to be freed later. 779f08c3bdfSopenharmony_ci * 780f08c3bdfSopenharmony_ci * Return NULL and set errno on error. Errors can occur when 781f08c3bdfSopenharmony_ci * resolving the current tasks cpuset. 782f08c3bdfSopenharmony_ci */ 783f08c3bdfSopenharmony_cistatic const struct cpuset *resolve_cp(const struct cpuset *cp, 784f08c3bdfSopenharmony_ci struct cpuset **cp_tofree) 785f08c3bdfSopenharmony_ci{ 786f08c3bdfSopenharmony_ci const struct cpuset *rcp; 787f08c3bdfSopenharmony_ci 788f08c3bdfSopenharmony_ci if (cp) { 789f08c3bdfSopenharmony_ci rcp = cp; 790f08c3bdfSopenharmony_ci } else { 791f08c3bdfSopenharmony_ci struct cpuset *cp1 = cpuset_alloc(); 792f08c3bdfSopenharmony_ci if (cp1 == NULL) 793f08c3bdfSopenharmony_ci goto err; 794f08c3bdfSopenharmony_ci if (cpuset_cpusetofpid(cp1, 0) < 0) { 795f08c3bdfSopenharmony_ci cpuset_free(cp1); 796f08c3bdfSopenharmony_ci goto err; 797f08c3bdfSopenharmony_ci } 798f08c3bdfSopenharmony_ci *cp_tofree = cp1; 799f08c3bdfSopenharmony_ci rcp = cp1; 800f08c3bdfSopenharmony_ci } 801f08c3bdfSopenharmony_ci return rcp; 802f08c3bdfSopenharmony_cierr: 803f08c3bdfSopenharmony_ci return NULL; 804f08c3bdfSopenharmony_ci} 805f08c3bdfSopenharmony_ci 806f08c3bdfSopenharmony_ci/* Write CPUs in cpuset cp (current task if cp == NULL) to bitmask cpus */ 807f08c3bdfSopenharmony_ciint cpuset_getcpus(const struct cpuset *cp, struct bitmask *cpus) 808f08c3bdfSopenharmony_ci{ 809f08c3bdfSopenharmony_ci struct cpuset *cp_tofree = NULL; 810f08c3bdfSopenharmony_ci const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree); 811f08c3bdfSopenharmony_ci 812f08c3bdfSopenharmony_ci if (!cp1) 813f08c3bdfSopenharmony_ci goto err; 814f08c3bdfSopenharmony_ci if (cp1->cpus == NULL) { 815f08c3bdfSopenharmony_ci errno = EINVAL; 816f08c3bdfSopenharmony_ci goto err; 817f08c3bdfSopenharmony_ci } 818f08c3bdfSopenharmony_ci bitmask_copy(cpus, cp1->cpus); 819f08c3bdfSopenharmony_ci cpuset_free(cp_tofree); 820f08c3bdfSopenharmony_ci return 0; 821f08c3bdfSopenharmony_cierr: 822f08c3bdfSopenharmony_ci cpuset_free(cp_tofree); 823f08c3bdfSopenharmony_ci return -1; 824f08c3bdfSopenharmony_ci} 825f08c3bdfSopenharmony_ci 826f08c3bdfSopenharmony_ci/* Write Memory Nodes in cp (current task if cp == NULL) to bitmask mems */ 827f08c3bdfSopenharmony_ciint cpuset_getmems(const struct cpuset *cp, struct bitmask *mems) 828f08c3bdfSopenharmony_ci{ 829f08c3bdfSopenharmony_ci struct cpuset *cp_tofree = NULL; 830f08c3bdfSopenharmony_ci const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree); 831f08c3bdfSopenharmony_ci 832f08c3bdfSopenharmony_ci if (!cp1) 833f08c3bdfSopenharmony_ci goto err; 834f08c3bdfSopenharmony_ci if (cp1->mems == NULL) { 835f08c3bdfSopenharmony_ci errno = EINVAL; 836f08c3bdfSopenharmony_ci goto err; 837f08c3bdfSopenharmony_ci } 838f08c3bdfSopenharmony_ci bitmask_copy(mems, cp1->mems); 839f08c3bdfSopenharmony_ci cpuset_free(cp_tofree); 840f08c3bdfSopenharmony_ci return 0; 841f08c3bdfSopenharmony_cierr: 842f08c3bdfSopenharmony_ci cpuset_free(cp_tofree); 843f08c3bdfSopenharmony_ci return -1; 844f08c3bdfSopenharmony_ci} 845f08c3bdfSopenharmony_ci 846f08c3bdfSopenharmony_ci/* Return number of CPUs in cpuset cp (current task if cp == NULL) */ 847f08c3bdfSopenharmony_ciint cpuset_cpus_weight(const struct cpuset *cp) 848f08c3bdfSopenharmony_ci{ 849f08c3bdfSopenharmony_ci struct cpuset *cp_tofree = NULL; 850f08c3bdfSopenharmony_ci const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree); 851f08c3bdfSopenharmony_ci int w = -1; 852f08c3bdfSopenharmony_ci 853f08c3bdfSopenharmony_ci if (!cp1) 854f08c3bdfSopenharmony_ci goto err; 855f08c3bdfSopenharmony_ci if (cp1->cpus == NULL) { 856f08c3bdfSopenharmony_ci errno = EINVAL; 857f08c3bdfSopenharmony_ci goto err; 858f08c3bdfSopenharmony_ci } 859f08c3bdfSopenharmony_ci w = bitmask_weight(cp1->cpus); 860f08c3bdfSopenharmony_ci /* fall into ... */ 861f08c3bdfSopenharmony_cierr: 862f08c3bdfSopenharmony_ci cpuset_free(cp_tofree); 863f08c3bdfSopenharmony_ci return w; 864f08c3bdfSopenharmony_ci} 865f08c3bdfSopenharmony_ci 866f08c3bdfSopenharmony_ci/* Return number of Memory Nodes in cpuset cp (current task if cp == NULL) */ 867f08c3bdfSopenharmony_ciint cpuset_mems_weight(const struct cpuset *cp) 868f08c3bdfSopenharmony_ci{ 869f08c3bdfSopenharmony_ci struct cpuset *cp_tofree = NULL; 870f08c3bdfSopenharmony_ci const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree); 871f08c3bdfSopenharmony_ci int w = -1; 872f08c3bdfSopenharmony_ci 873f08c3bdfSopenharmony_ci if (!cp1) 874f08c3bdfSopenharmony_ci goto err; 875f08c3bdfSopenharmony_ci if (cp1->mems == NULL) { 876f08c3bdfSopenharmony_ci errno = EINVAL; 877f08c3bdfSopenharmony_ci goto err; 878f08c3bdfSopenharmony_ci } 879f08c3bdfSopenharmony_ci w = bitmask_weight(cp1->mems); 880f08c3bdfSopenharmony_ci /* fall into ... */ 881f08c3bdfSopenharmony_cierr: 882f08c3bdfSopenharmony_ci cpuset_free(cp_tofree); 883f08c3bdfSopenharmony_ci return w; 884f08c3bdfSopenharmony_ci} 885f08c3bdfSopenharmony_ci 886f08c3bdfSopenharmony_ci/* Return integer value of option optname in cp */ 887f08c3bdfSopenharmony_ciint cpuset_get_iopt(const struct cpuset *cp, const char *optionname) 888f08c3bdfSopenharmony_ci{ 889f08c3bdfSopenharmony_ci if (streq(optionname, "cpu_exclusive")) 890f08c3bdfSopenharmony_ci return cp->cpu_exclusive; 891f08c3bdfSopenharmony_ci else if (streq(optionname, "mem_exclusive")) 892f08c3bdfSopenharmony_ci return cp->mem_exclusive; 893f08c3bdfSopenharmony_ci else if (streq(optionname, "mem_hardwall")) 894f08c3bdfSopenharmony_ci return cp->mem_hardwall; 895f08c3bdfSopenharmony_ci else if (streq(optionname, "notify_on_release")) 896f08c3bdfSopenharmony_ci return cp->notify_on_release; 897f08c3bdfSopenharmony_ci else if (streq(optionname, "memory_pressure_enabled")) 898f08c3bdfSopenharmony_ci return cp->memory_pressure_enabled; 899f08c3bdfSopenharmony_ci else if (streq(optionname, "memory_migrate")) 900f08c3bdfSopenharmony_ci return cp->memory_migrate; 901f08c3bdfSopenharmony_ci else if (streq(optionname, "memory_spread_page")) 902f08c3bdfSopenharmony_ci return cp->memory_spread_page; 903f08c3bdfSopenharmony_ci else if (streq(optionname, "memory_spread_slab")) 904f08c3bdfSopenharmony_ci return cp->memory_spread_slab; 905f08c3bdfSopenharmony_ci else if (streq(optionname, "sched_load_balance")) 906f08c3bdfSopenharmony_ci return cp->sched_load_balance; 907f08c3bdfSopenharmony_ci else if (streq(optionname, "sched_relax_domain_level")) 908f08c3bdfSopenharmony_ci return cp->sched_relax_domain_level; 909f08c3bdfSopenharmony_ci else 910f08c3bdfSopenharmony_ci return -2; /* optionname not recognized */ 911f08c3bdfSopenharmony_ci} 912f08c3bdfSopenharmony_ci 913f08c3bdfSopenharmony_ci/* [optional] Return string value of optname */ 914f08c3bdfSopenharmony_ciconst char *cpuset_get_sopt(UNUSED const struct cpuset *cp, 915f08c3bdfSopenharmony_ci UNUSED const char *optionname) 916f08c3bdfSopenharmony_ci{ 917f08c3bdfSopenharmony_ci return NULL; /* For now, all string options unrecognized */ 918f08c3bdfSopenharmony_ci} 919f08c3bdfSopenharmony_ci 920f08c3bdfSopenharmony_cistatic int read_flag(const char *filepath, char *flagp) 921f08c3bdfSopenharmony_ci{ 922f08c3bdfSopenharmony_ci char buf[SMALL_BUFSZ]; /* buffer a "0" or "1" flag line */ 923f08c3bdfSopenharmony_ci int fd = -1; 924f08c3bdfSopenharmony_ci 925f08c3bdfSopenharmony_ci if ((fd = open(filepath, O_RDONLY)) < 0) 926f08c3bdfSopenharmony_ci goto err; 927f08c3bdfSopenharmony_ci if (read(fd, buf, sizeof(buf)) < 1) 928f08c3bdfSopenharmony_ci goto err; 929f08c3bdfSopenharmony_ci if (atoi(buf)) 930f08c3bdfSopenharmony_ci *flagp = 1; 931f08c3bdfSopenharmony_ci else 932f08c3bdfSopenharmony_ci *flagp = 0; 933f08c3bdfSopenharmony_ci close(fd); 934f08c3bdfSopenharmony_ci return 0; 935f08c3bdfSopenharmony_cierr: 936f08c3bdfSopenharmony_ci if (fd >= 0) 937f08c3bdfSopenharmony_ci close(fd); 938f08c3bdfSopenharmony_ci return -1; 939f08c3bdfSopenharmony_ci} 940f08c3bdfSopenharmony_ci 941f08c3bdfSopenharmony_cistatic int load_flag(const char *path, char *flagp, const char *flag) 942f08c3bdfSopenharmony_ci{ 943f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 944f08c3bdfSopenharmony_ci 945f08c3bdfSopenharmony_ci pathcat2(buf, sizeof(buf), path, flag); 946f08c3bdfSopenharmony_ci return read_flag(buf, flagp); 947f08c3bdfSopenharmony_ci} 948f08c3bdfSopenharmony_ci 949f08c3bdfSopenharmony_cistatic int read_number(const char *filepath, int *numberp) 950f08c3bdfSopenharmony_ci{ 951f08c3bdfSopenharmony_ci char buf[SMALL_BUFSZ]; 952f08c3bdfSopenharmony_ci int fd = -1; 953f08c3bdfSopenharmony_ci 954f08c3bdfSopenharmony_ci if ((fd = open(filepath, O_RDONLY)) < 0) 955f08c3bdfSopenharmony_ci goto err; 956f08c3bdfSopenharmony_ci if (read(fd, buf, sizeof(buf)) < 1) 957f08c3bdfSopenharmony_ci goto err; 958f08c3bdfSopenharmony_ci *numberp = atoi(buf); 959f08c3bdfSopenharmony_ci close(fd); 960f08c3bdfSopenharmony_ci return 0; 961f08c3bdfSopenharmony_cierr: 962f08c3bdfSopenharmony_ci if (fd >= 0) 963f08c3bdfSopenharmony_ci close(fd); 964f08c3bdfSopenharmony_ci return -1; 965f08c3bdfSopenharmony_ci} 966f08c3bdfSopenharmony_ci 967f08c3bdfSopenharmony_cistatic int load_number(const char *path, int *numberp, const char *file) 968f08c3bdfSopenharmony_ci{ 969f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 970f08c3bdfSopenharmony_ci 971f08c3bdfSopenharmony_ci pathcat2(buf, sizeof(buf), path, file); 972f08c3bdfSopenharmony_ci return read_number(buf, numberp); 973f08c3bdfSopenharmony_ci} 974f08c3bdfSopenharmony_ci 975f08c3bdfSopenharmony_cistatic int read_mask(const char *filepath, struct bitmask **bmpp, int nbits) 976f08c3bdfSopenharmony_ci{ 977f08c3bdfSopenharmony_ci FILE *fp = NULL; 978f08c3bdfSopenharmony_ci char *buf = NULL; 979f08c3bdfSopenharmony_ci int buflen; 980f08c3bdfSopenharmony_ci struct bitmask *bmp = NULL; 981f08c3bdfSopenharmony_ci 982f08c3bdfSopenharmony_ci if ((fp = fopen(filepath, "r")) == NULL) 983f08c3bdfSopenharmony_ci goto err; 984f08c3bdfSopenharmony_ci buflen = filesize(fp) + 1; /* + 1 for nul term */ 985f08c3bdfSopenharmony_ci if ((buf = malloc(buflen)) == NULL) 986f08c3bdfSopenharmony_ci goto err; 987f08c3bdfSopenharmony_ci if (flgets(buf, buflen, fp) == NULL) 988f08c3bdfSopenharmony_ci goto err; 989f08c3bdfSopenharmony_ci fclose(fp); 990f08c3bdfSopenharmony_ci fp = NULL; 991f08c3bdfSopenharmony_ci 992f08c3bdfSopenharmony_ci if ((bmp = bitmask_alloc(nbits)) == NULL) 993f08c3bdfSopenharmony_ci goto err; 994f08c3bdfSopenharmony_ci if (*buf && bitmask_parselist(buf, bmp) < 0) 995f08c3bdfSopenharmony_ci goto err; 996f08c3bdfSopenharmony_ci if (*bmpp) 997f08c3bdfSopenharmony_ci bitmask_free(*bmpp); 998f08c3bdfSopenharmony_ci *bmpp = bmp; 999f08c3bdfSopenharmony_ci free(buf); 1000f08c3bdfSopenharmony_ci buf = NULL; 1001f08c3bdfSopenharmony_ci return 0; 1002f08c3bdfSopenharmony_cierr: 1003f08c3bdfSopenharmony_ci if (buf != NULL) 1004f08c3bdfSopenharmony_ci free(buf); 1005f08c3bdfSopenharmony_ci if (fp != NULL) 1006f08c3bdfSopenharmony_ci fclose(fp); 1007f08c3bdfSopenharmony_ci if (bmp != NULL) 1008f08c3bdfSopenharmony_ci bitmask_free(bmp); 1009f08c3bdfSopenharmony_ci return -1; 1010f08c3bdfSopenharmony_ci} 1011f08c3bdfSopenharmony_ci 1012f08c3bdfSopenharmony_cistatic int load_mask(const char *path, struct bitmask **bmpp, 1013f08c3bdfSopenharmony_ci int nbits, const char *mask) 1014f08c3bdfSopenharmony_ci{ 1015f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 1016f08c3bdfSopenharmony_ci 1017f08c3bdfSopenharmony_ci pathcat2(buf, sizeof(buf), path, mask); 1018f08c3bdfSopenharmony_ci return read_mask(buf, bmpp, nbits); 1019f08c3bdfSopenharmony_ci} 1020f08c3bdfSopenharmony_ci 1021f08c3bdfSopenharmony_ci/* Write string to file at given filepath. Create or truncate file. */ 1022f08c3bdfSopenharmony_cistatic int write_string_file(const char *filepath, const char *str) 1023f08c3bdfSopenharmony_ci{ 1024f08c3bdfSopenharmony_ci int fd = -1; 1025f08c3bdfSopenharmony_ci 1026f08c3bdfSopenharmony_ci if ((fd = open(filepath, O_WRONLY | O_CREAT, 0644)) < 0) 1027f08c3bdfSopenharmony_ci goto err; 1028f08c3bdfSopenharmony_ci if (write(fd, str, strlen(str)) < 0) 1029f08c3bdfSopenharmony_ci goto err; 1030f08c3bdfSopenharmony_ci close(fd); 1031f08c3bdfSopenharmony_ci return 0; 1032f08c3bdfSopenharmony_cierr: 1033f08c3bdfSopenharmony_ci if (fd >= 0) 1034f08c3bdfSopenharmony_ci close(fd); 1035f08c3bdfSopenharmony_ci return -1; 1036f08c3bdfSopenharmony_ci} 1037f08c3bdfSopenharmony_ci 1038f08c3bdfSopenharmony_ci/* Size and allocate buffer. Write bitmask into it. Caller must free */ 1039f08c3bdfSopenharmony_cistatic char *sprint_mask_buf(const struct bitmask *bmp) 1040f08c3bdfSopenharmony_ci{ 1041f08c3bdfSopenharmony_ci char *buf = NULL; 1042f08c3bdfSopenharmony_ci int buflen; 1043f08c3bdfSopenharmony_ci char c; 1044f08c3bdfSopenharmony_ci 1045f08c3bdfSopenharmony_ci /* First bitmask_displaylist() call just to get the length */ 1046f08c3bdfSopenharmony_ci buflen = bitmask_displaylist(&c, 1, bmp) + 1; /* "+ 1" for nul */ 1047f08c3bdfSopenharmony_ci if ((buf = malloc(buflen)) == NULL) 1048f08c3bdfSopenharmony_ci return NULL; 1049f08c3bdfSopenharmony_ci bitmask_displaylist(buf, buflen, bmp); 1050f08c3bdfSopenharmony_ci return buf; 1051f08c3bdfSopenharmony_ci} 1052f08c3bdfSopenharmony_ci 1053f08c3bdfSopenharmony_cistatic int exists_flag(const char *path, const char *flag) 1054f08c3bdfSopenharmony_ci{ 1055f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 1056f08c3bdfSopenharmony_ci struct stat statbuf; 1057f08c3bdfSopenharmony_ci int rc; 1058f08c3bdfSopenharmony_ci 1059f08c3bdfSopenharmony_ci pathcat2(buf, sizeof(buf), path, flag); 1060f08c3bdfSopenharmony_ci rc = (stat(buf, &statbuf) == 0); 1061f08c3bdfSopenharmony_ci errno = 0; 1062f08c3bdfSopenharmony_ci return rc; 1063f08c3bdfSopenharmony_ci} 1064f08c3bdfSopenharmony_ci 1065f08c3bdfSopenharmony_cistatic int store_flag(const char *path, const char *flag, int val) 1066f08c3bdfSopenharmony_ci{ 1067f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 1068f08c3bdfSopenharmony_ci 1069f08c3bdfSopenharmony_ci pathcat2(buf, sizeof(buf), path, flag); 1070f08c3bdfSopenharmony_ci return write_string_file(buf, val ? "1" : "0"); 1071f08c3bdfSopenharmony_ci} 1072f08c3bdfSopenharmony_ci 1073f08c3bdfSopenharmony_cistatic int store_number(const char *path, const char *file, int val) 1074f08c3bdfSopenharmony_ci{ 1075f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 1076f08c3bdfSopenharmony_ci char data[SMALL_BUFSZ]; 1077f08c3bdfSopenharmony_ci 1078f08c3bdfSopenharmony_ci memset(data, 0, sizeof(data)); 1079f08c3bdfSopenharmony_ci pathcat2(buf, sizeof(buf), path, file); 1080f08c3bdfSopenharmony_ci snprintf(data, sizeof(data), "%d", val); 1081f08c3bdfSopenharmony_ci return write_string_file(buf, data); 1082f08c3bdfSopenharmony_ci} 1083f08c3bdfSopenharmony_ci 1084f08c3bdfSopenharmony_cistatic int store_mask(const char *path, const char *mask, 1085f08c3bdfSopenharmony_ci const struct bitmask *bmp) 1086f08c3bdfSopenharmony_ci{ 1087f08c3bdfSopenharmony_ci char maskpath[PATH_MAX]; 1088f08c3bdfSopenharmony_ci char *bp = NULL; 1089f08c3bdfSopenharmony_ci int rc; 1090f08c3bdfSopenharmony_ci 1091f08c3bdfSopenharmony_ci if (bmp == NULL) 1092f08c3bdfSopenharmony_ci return 0; 1093f08c3bdfSopenharmony_ci pathcat2(maskpath, sizeof(maskpath), path, mask); 1094f08c3bdfSopenharmony_ci if ((bp = sprint_mask_buf(bmp)) == NULL) 1095f08c3bdfSopenharmony_ci return -1; 1096f08c3bdfSopenharmony_ci rc = write_string_file(maskpath, bp); 1097f08c3bdfSopenharmony_ci free(bp); 1098f08c3bdfSopenharmony_ci return rc; 1099f08c3bdfSopenharmony_ci} 1100f08c3bdfSopenharmony_ci 1101f08c3bdfSopenharmony_ci/* 1102f08c3bdfSopenharmony_ci * Return 1 if 'cpu' is online, else 0 if offline. Tests the file 1103f08c3bdfSopenharmony_ci * /sys/devices/system/cpu/cpuN/online file for 0 or 1 contents 1104f08c3bdfSopenharmony_ci * were N == cpu number. 1105f08c3bdfSopenharmony_ci */ 1106f08c3bdfSopenharmony_ci 1107f08c3bdfSopenharmony_cichar cpu_online(unsigned int cpu) 1108f08c3bdfSopenharmony_ci{ 1109f08c3bdfSopenharmony_ci char online; 1110f08c3bdfSopenharmony_ci char cpupath[PATH_MAX]; 1111f08c3bdfSopenharmony_ci 1112f08c3bdfSopenharmony_ci (void)snprintf(cpupath, sizeof(cpupath), 1113f08c3bdfSopenharmony_ci "/sys/devices/system/cpu/cpu%d/online", cpu); 1114f08c3bdfSopenharmony_ci if (read_flag(cpupath, &online) < 0) 1115f08c3bdfSopenharmony_ci return 0; /* oops - guess that cpu's not there */ 1116f08c3bdfSopenharmony_ci return online; 1117f08c3bdfSopenharmony_ci} 1118f08c3bdfSopenharmony_ci 1119f08c3bdfSopenharmony_ci/* 1120f08c3bdfSopenharmony_ci * The cpunodemap maps each cpu in [0 ... cpuset_cpus_nbits()), 1121f08c3bdfSopenharmony_ci * to the node on which that cpu resides or cpuset_mems_nbits(). 1122f08c3bdfSopenharmony_ci * 1123f08c3bdfSopenharmony_ci * To avoid every user having to recalculate this relation 1124f08c3bdfSopenharmony_ci * from various clues in the sysfs file system (below the 1125f08c3bdfSopenharmony_ci * path /sys/devices/system) a copy of this map is kept at 1126f08c3bdfSopenharmony_ci * /var/run/cpunodemap. 1127f08c3bdfSopenharmony_ci * 1128f08c3bdfSopenharmony_ci * The system automatically cleans out files below 1129f08c3bdfSopenharmony_ci * /var/run on each system reboot (see the init script 1130f08c3bdfSopenharmony_ci * /etc/rc.d/boot.d/S*boot.localnet), so we don't have to worry 1131f08c3bdfSopenharmony_ci * about stale data in this file across reboots. If the file 1132f08c3bdfSopenharmony_ci * is missing, let the first process that needs it, and has 1133f08c3bdfSopenharmony_ci * permission to write in the /var/run directory, rebuild it. 1134f08c3bdfSopenharmony_ci * 1135f08c3bdfSopenharmony_ci * If using this cached data, remember the mtime of the mapfile 1136f08c3bdfSopenharmony_ci * the last time we read it in case something like a hotplug 1137f08c3bdfSopenharmony_ci * event results in the file being removed and rebuilt, so we 1138f08c3bdfSopenharmony_ci * can detect if we're using a stale cache, and need to reload. 1139f08c3bdfSopenharmony_ci * 1140f08c3bdfSopenharmony_ci * The mtime of this file is set to the time when we did 1141f08c3bdfSopenharmony_ci * the recalculation of the map, from the clues beneath 1142f08c3bdfSopenharmony_ci * /sys/devices/system. This is done so that a program 1143f08c3bdfSopenharmony_ci * won't see the mapfile it just wrote as being newer than what 1144f08c3bdfSopenharmony_ci * it just wrote out (store_map) and read the same map back in 1145f08c3bdfSopenharmony_ci * (load_file). 1146f08c3bdfSopenharmony_ci */ 1147f08c3bdfSopenharmony_ci 1148f08c3bdfSopenharmony_ci/* 1149f08c3bdfSopenharmony_ci * Hold flockfile(stdin) while using cpunodemap for posix thread safety. 1150f08c3bdfSopenharmony_ci * 1151f08c3bdfSopenharmony_ci * Note on locking and flockfile(FILE *): 1152f08c3bdfSopenharmony_ci * 1153f08c3bdfSopenharmony_ci * We use flockfile() and funlockfile() instead of directly 1154f08c3bdfSopenharmony_ci * calling pthread_mutex_lock and pthread_mutex_unlock on 1155f08c3bdfSopenharmony_ci * a pthread_mutex_t, because this avoids forcing the app 1156f08c3bdfSopenharmony_ci * to link with libpthread. The glibc implementation of 1157f08c3bdfSopenharmony_ci * flockfile/funlockfile will fall back to no-ops if libpthread 1158f08c3bdfSopenharmony_ci * doesn't happen to be linked. 1159f08c3bdfSopenharmony_ci * 1160f08c3bdfSopenharmony_ci * Since flockfile already has the moderately convoluted 1161f08c3bdfSopenharmony_ci * combination of weak and strong symbols required to accomplish 1162f08c3bdfSopenharmony_ci * this, it is easier to use flockfile() on some handy FILE * 1163f08c3bdfSopenharmony_ci * stream as a surrogate for pthread locking than it is to so 1164f08c3bdfSopenharmony_ci * re-invent that wheel. 1165f08c3bdfSopenharmony_ci * 1166f08c3bdfSopenharmony_ci * Forcing all apps that use cpusets to link with libpthread 1167f08c3bdfSopenharmony_ci * would force non-transparent initialization on apps that 1168f08c3bdfSopenharmony_ci * might not be prepared to handle it. 1169f08c3bdfSopenharmony_ci * 1170f08c3bdfSopenharmony_ci * The application using libcpuset should never notice this 1171f08c3bdfSopenharmony_ci * odd use of flockfile(), because we never return to the 1172f08c3bdfSopenharmony_ci * application from any libcpuset call with any such lock held. 1173f08c3bdfSopenharmony_ci * We just use this locking for guarding some non-atomic cached 1174f08c3bdfSopenharmony_ci * data updates and accesses, internal to some libcpuset calls. 1175f08c3bdfSopenharmony_ci * Also, flockfile() allows recursive nesting, so if the app 1176f08c3bdfSopenharmony_ci * calls libcpuset holding such a file lock, we won't deadlock 1177f08c3bdfSopenharmony_ci * if we go to acquire the same lock. We'll just get the lock 1178f08c3bdfSopenharmony_ci * and increment its counter while we hold it. 1179f08c3bdfSopenharmony_ci */ 1180f08c3bdfSopenharmony_ci 1181f08c3bdfSopenharmony_cistatic struct cpunodemap { 1182f08c3bdfSopenharmony_ci int *map; /* map[cpumask_sz]: maps cpu to its node */ 1183f08c3bdfSopenharmony_ci time_t mtime; /* modtime of mapfile when last read */ 1184f08c3bdfSopenharmony_ci} cpunodemap; 1185f08c3bdfSopenharmony_ci 1186f08c3bdfSopenharmony_ci/* 1187f08c3bdfSopenharmony_ci * rebuild_map() - Rebuild cpunodemap[] from scratch. 1188f08c3bdfSopenharmony_ci * 1189f08c3bdfSopenharmony_ci * Situation: 1190f08c3bdfSopenharmony_ci * Neither our in-memory cpunodemap[] array nor the 1191f08c3bdfSopenharmony_ci * cache of it in mapfile is current. 1192f08c3bdfSopenharmony_ci * Action: 1193f08c3bdfSopenharmony_ci * Rebuild it from first principles and the information 1194f08c3bdfSopenharmony_ci * available below /sys/devices/system. 1195f08c3bdfSopenharmony_ci */ 1196f08c3bdfSopenharmony_ci 1197f08c3bdfSopenharmony_cistatic void rebuild_map(void) 1198f08c3bdfSopenharmony_ci{ 1199f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 1200f08c3bdfSopenharmony_ci DIR *dir1, *dir2; 1201f08c3bdfSopenharmony_ci struct dirent *dent1, *dent2; 1202f08c3bdfSopenharmony_ci int ncpus = cpuset_cpus_nbits(); 1203f08c3bdfSopenharmony_ci int nmems = cpuset_mems_nbits(); 1204f08c3bdfSopenharmony_ci unsigned int cpu, mem; 1205f08c3bdfSopenharmony_ci 1206f08c3bdfSopenharmony_ci for (cpu = 0; cpu < (unsigned int)ncpus; cpu++) 1207f08c3bdfSopenharmony_ci cpunodemap.map[cpu] = -1; 1208f08c3bdfSopenharmony_ci pathcat2(buf, sizeof(buf), sysdevices, "node"); 1209f08c3bdfSopenharmony_ci if ((dir1 = opendir(buf)) == NULL) 1210f08c3bdfSopenharmony_ci return; 1211f08c3bdfSopenharmony_ci while ((dent1 = readdir(dir1)) != NULL) { 1212f08c3bdfSopenharmony_ci if (sscanf(dent1->d_name, "node%u", &mem) < 1) 1213f08c3bdfSopenharmony_ci continue; 1214f08c3bdfSopenharmony_ci pathcat3(buf, sizeof(buf), sysdevices, "node", dent1->d_name); 1215f08c3bdfSopenharmony_ci if ((dir2 = opendir(buf)) == NULL) 1216f08c3bdfSopenharmony_ci continue; 1217f08c3bdfSopenharmony_ci while ((dent2 = readdir(dir2)) != NULL) { 1218f08c3bdfSopenharmony_ci if (sscanf(dent2->d_name, "cpu%u", &cpu) < 1) 1219f08c3bdfSopenharmony_ci continue; 1220f08c3bdfSopenharmony_ci if (cpu >= (unsigned int)ncpus 1221f08c3bdfSopenharmony_ci || mem >= (unsigned int)nmems) 1222f08c3bdfSopenharmony_ci continue; 1223f08c3bdfSopenharmony_ci cpunodemap.map[cpu] = mem; 1224f08c3bdfSopenharmony_ci } 1225f08c3bdfSopenharmony_ci closedir(dir2); 1226f08c3bdfSopenharmony_ci } 1227f08c3bdfSopenharmony_ci closedir(dir1); 1228f08c3bdfSopenharmony_ci cpunodemap.mtime = time(0); 1229f08c3bdfSopenharmony_ci} 1230f08c3bdfSopenharmony_ci 1231f08c3bdfSopenharmony_ci/* 1232f08c3bdfSopenharmony_ci * load_map() - Load cpunodemap[] from mapfile. 1233f08c3bdfSopenharmony_ci * 1234f08c3bdfSopenharmony_ci * Situation: 1235f08c3bdfSopenharmony_ci * The cpunodemap in mapfile is more recent than 1236f08c3bdfSopenharmony_ci * what we have in the cpunodemap[] array. 1237f08c3bdfSopenharmony_ci * Action: 1238f08c3bdfSopenharmony_ci * Reload the cpunodemap[] array from the file. 1239f08c3bdfSopenharmony_ci */ 1240f08c3bdfSopenharmony_ci 1241f08c3bdfSopenharmony_cistatic void load_map(void) 1242f08c3bdfSopenharmony_ci{ 1243f08c3bdfSopenharmony_ci char buf[SMALL_BUFSZ]; /* buffer 1 line of mapfile */ 1244f08c3bdfSopenharmony_ci FILE *mapfp; /* File stream on mapfile */ 1245f08c3bdfSopenharmony_ci int ncpus = cpuset_cpus_nbits(); 1246f08c3bdfSopenharmony_ci int nmems = cpuset_mems_nbits(); 1247f08c3bdfSopenharmony_ci unsigned int cpu, mem; 1248f08c3bdfSopenharmony_ci 1249f08c3bdfSopenharmony_ci if ((cpunodemap.map = calloc(ncpus, sizeof(int))) == NULL) 1250f08c3bdfSopenharmony_ci return; 1251f08c3bdfSopenharmony_ci cpunodemap.mtime = get_mtime(mapfile); 1252f08c3bdfSopenharmony_ci if ((mapfp = fopen(mapfile, "r")) == NULL) 1253f08c3bdfSopenharmony_ci return; 1254f08c3bdfSopenharmony_ci for (cpu = 0; cpu < (unsigned int)ncpus; cpu++) 1255f08c3bdfSopenharmony_ci cpunodemap.map[cpu] = nmems; 1256f08c3bdfSopenharmony_ci while (flgets(buf, sizeof(buf), mapfp) != NULL) { 1257f08c3bdfSopenharmony_ci if (sscanf(buf, "%u %u", &cpu, &mem) < 2) 1258f08c3bdfSopenharmony_ci continue; 1259f08c3bdfSopenharmony_ci if (cpu >= (unsigned int)ncpus || mem >= (unsigned int)nmems) 1260f08c3bdfSopenharmony_ci continue; 1261f08c3bdfSopenharmony_ci cpunodemap.map[cpu] = mem; 1262f08c3bdfSopenharmony_ci } 1263f08c3bdfSopenharmony_ci fclose(mapfp); 1264f08c3bdfSopenharmony_ci} 1265f08c3bdfSopenharmony_ci 1266f08c3bdfSopenharmony_ci/* 1267f08c3bdfSopenharmony_ci * store_map() - Write cpunodemap[] out to mapfile. 1268f08c3bdfSopenharmony_ci * 1269f08c3bdfSopenharmony_ci * Situation: 1270f08c3bdfSopenharmony_ci * The cpunodemap in the cpunodemap[] array is 1271f08c3bdfSopenharmony_ci * more recent than the one in mapfile. 1272f08c3bdfSopenharmony_ci * Action: 1273f08c3bdfSopenharmony_ci * Write cpunodemap[] out to mapfile. 1274f08c3bdfSopenharmony_ci */ 1275f08c3bdfSopenharmony_ci 1276f08c3bdfSopenharmony_cistatic void store_map(void) 1277f08c3bdfSopenharmony_ci{ 1278f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 1279f08c3bdfSopenharmony_ci int fd = -1; 1280f08c3bdfSopenharmony_ci FILE *mapfp = NULL; 1281f08c3bdfSopenharmony_ci int ncpus = cpuset_cpus_nbits(); 1282f08c3bdfSopenharmony_ci int nmems = cpuset_mems_nbits(); 1283f08c3bdfSopenharmony_ci unsigned int cpu, mem; 1284f08c3bdfSopenharmony_ci 1285f08c3bdfSopenharmony_ci snprintf(buf, sizeof(buf), "%s.%s", mapfile, "XXXXXX"); 1286f08c3bdfSopenharmony_ci if ((fd = mkstemp(buf)) < 0) 1287f08c3bdfSopenharmony_ci goto err; 1288f08c3bdfSopenharmony_ci if ((mapfp = fdopen(fd, "w")) == NULL) 1289f08c3bdfSopenharmony_ci goto err; 1290f08c3bdfSopenharmony_ci for (cpu = 0; cpu < (unsigned int)ncpus; cpu++) { 1291f08c3bdfSopenharmony_ci mem = cpunodemap.map[cpu]; 1292f08c3bdfSopenharmony_ci if (mem < (unsigned int)nmems) 1293f08c3bdfSopenharmony_ci fprintf(mapfp, "%u %u\n", cpu, mem); 1294f08c3bdfSopenharmony_ci } 1295f08c3bdfSopenharmony_ci fclose(mapfp); 1296f08c3bdfSopenharmony_ci set_mtime(buf, cpunodemap.mtime); 1297f08c3bdfSopenharmony_ci if (rename(buf, mapfile) < 0) 1298f08c3bdfSopenharmony_ci goto err; 1299f08c3bdfSopenharmony_ci /* mkstemp() creates mode 0600 - change to world readable */ 1300f08c3bdfSopenharmony_ci (void)chmod(mapfile, 0444); 1301f08c3bdfSopenharmony_ci return; 1302f08c3bdfSopenharmony_cierr: 1303f08c3bdfSopenharmony_ci if (mapfp != NULL) { 1304f08c3bdfSopenharmony_ci fclose(mapfp); 1305f08c3bdfSopenharmony_ci fd = -1; 1306f08c3bdfSopenharmony_ci } 1307f08c3bdfSopenharmony_ci if (fd >= 0) 1308f08c3bdfSopenharmony_ci close(fd); 1309f08c3bdfSopenharmony_ci (void)unlink(buf); 1310f08c3bdfSopenharmony_ci} 1311f08c3bdfSopenharmony_ci 1312f08c3bdfSopenharmony_ci/* 1313f08c3bdfSopenharmony_ci * Load and gain thread safe access to the <cpu, node> map. 1314f08c3bdfSopenharmony_ci * 1315f08c3bdfSopenharmony_ci * Return 0 on success with flockfile(stdin) held. 1316f08c3bdfSopenharmony_ci * Each successful get_map() call must be matched with a 1317f08c3bdfSopenharmony_ci * following put_map() call to release the lock. 1318f08c3bdfSopenharmony_ci * 1319f08c3bdfSopenharmony_ci * On error, return -1 with errno set and no lock held. 1320f08c3bdfSopenharmony_ci */ 1321f08c3bdfSopenharmony_ci 1322f08c3bdfSopenharmony_cistatic int get_map(void) 1323f08c3bdfSopenharmony_ci{ 1324f08c3bdfSopenharmony_ci time_t file_mtime; 1325f08c3bdfSopenharmony_ci 1326f08c3bdfSopenharmony_ci flockfile(stdin); 1327f08c3bdfSopenharmony_ci 1328f08c3bdfSopenharmony_ci if (cpunodemap.map == NULL) { 1329f08c3bdfSopenharmony_ci cpunodemap.map = calloc(cpuset_cpus_nbits(), sizeof(int)); 1330f08c3bdfSopenharmony_ci if (cpunodemap.map == NULL) 1331f08c3bdfSopenharmony_ci goto err; 1332f08c3bdfSopenharmony_ci } 1333f08c3bdfSopenharmony_ci 1334f08c3bdfSopenharmony_ci /* If no one has a good cpunodemap, rebuild from scratch */ 1335f08c3bdfSopenharmony_ci file_mtime = get_mtime(mapfile); 1336f08c3bdfSopenharmony_ci if (cpunodemap.mtime == 0 && file_mtime == 0) 1337f08c3bdfSopenharmony_ci rebuild_map(); 1338f08c3bdfSopenharmony_ci 1339f08c3bdfSopenharmony_ci /* If either cpunodemap[] or mapfile newer, update other with it */ 1340f08c3bdfSopenharmony_ci file_mtime = get_mtime(mapfile); 1341f08c3bdfSopenharmony_ci if (cpunodemap.mtime < file_mtime) 1342f08c3bdfSopenharmony_ci load_map(); 1343f08c3bdfSopenharmony_ci else if (cpunodemap.mtime > file_mtime) 1344f08c3bdfSopenharmony_ci store_map(); 1345f08c3bdfSopenharmony_ci return 0; 1346f08c3bdfSopenharmony_cierr: 1347f08c3bdfSopenharmony_ci funlockfile(stdin); 1348f08c3bdfSopenharmony_ci return -1; 1349f08c3bdfSopenharmony_ci} 1350f08c3bdfSopenharmony_ci 1351f08c3bdfSopenharmony_cistatic void put_map(void) 1352f08c3bdfSopenharmony_ci{ 1353f08c3bdfSopenharmony_ci funlockfile(stdin); 1354f08c3bdfSopenharmony_ci} 1355f08c3bdfSopenharmony_ci 1356f08c3bdfSopenharmony_ci/* Set cpus to those local to Memory Nodes mems */ 1357f08c3bdfSopenharmony_ciint cpuset_localcpus(const struct bitmask *mems, struct bitmask *cpus) 1358f08c3bdfSopenharmony_ci{ 1359f08c3bdfSopenharmony_ci int ncpus = cpuset_cpus_nbits(); 1360f08c3bdfSopenharmony_ci unsigned int cpu; 1361f08c3bdfSopenharmony_ci 1362f08c3bdfSopenharmony_ci if (check() < 0) 1363f08c3bdfSopenharmony_ci return -1; 1364f08c3bdfSopenharmony_ci 1365f08c3bdfSopenharmony_ci get_map(); 1366f08c3bdfSopenharmony_ci bitmask_clearall(cpus); 1367f08c3bdfSopenharmony_ci for (cpu = 0; cpu < (unsigned int)ncpus; cpu++) { 1368f08c3bdfSopenharmony_ci if (bitmask_isbitset(mems, cpunodemap.map[cpu])) 1369f08c3bdfSopenharmony_ci bitmask_setbit(cpus, cpu); 1370f08c3bdfSopenharmony_ci } 1371f08c3bdfSopenharmony_ci put_map(); 1372f08c3bdfSopenharmony_ci return 0; 1373f08c3bdfSopenharmony_ci} 1374f08c3bdfSopenharmony_ci 1375f08c3bdfSopenharmony_ci/* Set mems to those local to CPUs cpus */ 1376f08c3bdfSopenharmony_ciint cpuset_localmems(const struct bitmask *cpus, struct bitmask *mems) 1377f08c3bdfSopenharmony_ci{ 1378f08c3bdfSopenharmony_ci int ncpus = cpuset_cpus_nbits(); 1379f08c3bdfSopenharmony_ci unsigned int cpu; 1380f08c3bdfSopenharmony_ci 1381f08c3bdfSopenharmony_ci if (check() < 0) 1382f08c3bdfSopenharmony_ci return -1; 1383f08c3bdfSopenharmony_ci 1384f08c3bdfSopenharmony_ci get_map(); 1385f08c3bdfSopenharmony_ci bitmask_clearall(mems); 1386f08c3bdfSopenharmony_ci for (cpu = 0; cpu < (unsigned int)ncpus; cpu++) { 1387f08c3bdfSopenharmony_ci if (bitmask_isbitset(cpus, cpu)) 1388f08c3bdfSopenharmony_ci bitmask_setbit(mems, cpunodemap.map[cpu]); 1389f08c3bdfSopenharmony_ci } 1390f08c3bdfSopenharmony_ci put_map(); 1391f08c3bdfSopenharmony_ci return 0; 1392f08c3bdfSopenharmony_ci} 1393f08c3bdfSopenharmony_ci 1394f08c3bdfSopenharmony_ci/* 1395f08c3bdfSopenharmony_ci * distmap[] 1396f08c3bdfSopenharmony_ci * 1397f08c3bdfSopenharmony_ci * Array of ints of size cpumask_sz by nodemask_sz. 1398f08c3bdfSopenharmony_ci * 1399f08c3bdfSopenharmony_ci * Element distmap[cpu][mem] is the distance between CPU cpu 1400f08c3bdfSopenharmony_ci * and Memory Node mem. Distances are weighted to roughly 1401f08c3bdfSopenharmony_ci * approximate the cost of memory references, and scaled so that 1402f08c3bdfSopenharmony_ci * the distance from a CPU to its local Memory Node is ten (10). 1403f08c3bdfSopenharmony_ci * 1404f08c3bdfSopenharmony_ci * The first call to cpuset_cpumemdist() builds this map, from 1405f08c3bdfSopenharmony_ci * whatever means the kernel provides to obtain these distances. 1406f08c3bdfSopenharmony_ci * 1407f08c3bdfSopenharmony_ci * These distances derive from ACPI SLIT table entries, which are 1408f08c3bdfSopenharmony_ci * eight bits in size. 1409f08c3bdfSopenharmony_ci * 1410f08c3bdfSopenharmony_ci * Hold flockfile(stdout) while using distmap for posix thread safety. 1411f08c3bdfSopenharmony_ci */ 1412f08c3bdfSopenharmony_ci 1413f08c3bdfSopenharmony_citypedef unsigned char distmap_entry_t; /* type of distmap[] entries */ 1414f08c3bdfSopenharmony_ci 1415f08c3bdfSopenharmony_cistatic distmap_entry_t *distmap; /* maps <cpu, mem> to distance */ 1416f08c3bdfSopenharmony_ci 1417f08c3bdfSopenharmony_ci#define DISTMAP_MAX UCHAR_MAX /* maximum value in distmap[] */ 1418f08c3bdfSopenharmony_ci 1419f08c3bdfSopenharmony_ci#define I(i,j) ((i) * nmems + (j)) /* 2-D array index simulation */ 1420f08c3bdfSopenharmony_ci 1421f08c3bdfSopenharmony_ci/* 1422f08c3bdfSopenharmony_ci * Parse arch neutral lines from 'distance' files of form: 1423f08c3bdfSopenharmony_ci * 1424f08c3bdfSopenharmony_ci * 46 66 10 20 1425f08c3bdfSopenharmony_ci * 1426f08c3bdfSopenharmony_ci * The lines contain a space separated list of distances, which is parsed 1427f08c3bdfSopenharmony_ci * into array dists[] of each nodes distance from the specified node. 1428f08c3bdfSopenharmony_ci * 1429f08c3bdfSopenharmony_ci * Result is placed in distmap[ncpus][nmems]: 1430f08c3bdfSopenharmony_ci * 1431f08c3bdfSopenharmony_ci * For each cpu c on node: 1432f08c3bdfSopenharmony_ci * For each node position n in list of distances: 1433f08c3bdfSopenharmony_ci * distmap[c][n] = dists[n] 1434f08c3bdfSopenharmony_ci */ 1435f08c3bdfSopenharmony_ci 1436f08c3bdfSopenharmony_cistatic int parse_distmap_line(unsigned int node, char *buf) 1437f08c3bdfSopenharmony_ci{ 1438f08c3bdfSopenharmony_ci char *p, *q; 1439f08c3bdfSopenharmony_ci int ncpus = cpuset_cpus_nbits(); 1440f08c3bdfSopenharmony_ci int nmems = cpuset_mems_nbits(); 1441f08c3bdfSopenharmony_ci unsigned int c, n; 1442f08c3bdfSopenharmony_ci distmap_entry_t *dists = NULL; 1443f08c3bdfSopenharmony_ci struct bitmask *cpus = NULL, *mems = NULL; 1444f08c3bdfSopenharmony_ci int ret = -1; 1445f08c3bdfSopenharmony_ci 1446f08c3bdfSopenharmony_ci p = buf; 1447f08c3bdfSopenharmony_ci if ((dists = calloc(nmems, sizeof(*dists))) == NULL) 1448f08c3bdfSopenharmony_ci goto err; 1449f08c3bdfSopenharmony_ci for (n = 0; n < (unsigned int)nmems; n++) 1450f08c3bdfSopenharmony_ci dists[n] = DISTMAP_MAX; 1451f08c3bdfSopenharmony_ci 1452f08c3bdfSopenharmony_ci for (n = 0; n < (unsigned int)nmems && *p; n++, p = q) { 1453f08c3bdfSopenharmony_ci unsigned int d; 1454f08c3bdfSopenharmony_ci 1455f08c3bdfSopenharmony_ci if ((p = strpbrk(p, "0123456789")) == NULL) 1456f08c3bdfSopenharmony_ci break; 1457f08c3bdfSopenharmony_ci d = strtoul(p, &q, 10); 1458f08c3bdfSopenharmony_ci if (p == q) 1459f08c3bdfSopenharmony_ci break; 1460f08c3bdfSopenharmony_ci if (d < DISTMAP_MAX) 1461f08c3bdfSopenharmony_ci dists[n] = (distmap_entry_t) d; 1462f08c3bdfSopenharmony_ci } 1463f08c3bdfSopenharmony_ci 1464f08c3bdfSopenharmony_ci if ((mems = bitmask_alloc(nmems)) == NULL) 1465f08c3bdfSopenharmony_ci goto err; 1466f08c3bdfSopenharmony_ci bitmask_setbit(mems, node); 1467f08c3bdfSopenharmony_ci 1468f08c3bdfSopenharmony_ci if ((cpus = bitmask_alloc(ncpus)) == NULL) 1469f08c3bdfSopenharmony_ci goto err; 1470f08c3bdfSopenharmony_ci cpuset_localcpus(mems, cpus); 1471f08c3bdfSopenharmony_ci 1472f08c3bdfSopenharmony_ci for (c = bitmask_first(cpus); c < (unsigned int)ncpus; 1473f08c3bdfSopenharmony_ci c = bitmask_next(cpus, c + 1)) 1474f08c3bdfSopenharmony_ci for (n = 0; n < (unsigned int)nmems; n++) 1475f08c3bdfSopenharmony_ci distmap[I(c, n)] = dists[n]; 1476f08c3bdfSopenharmony_ci ret = 0; 1477f08c3bdfSopenharmony_ci /* fall into ... */ 1478f08c3bdfSopenharmony_cierr: 1479f08c3bdfSopenharmony_ci bitmask_free(mems); 1480f08c3bdfSopenharmony_ci bitmask_free(cpus); 1481f08c3bdfSopenharmony_ci free(dists); 1482f08c3bdfSopenharmony_ci return ret; 1483f08c3bdfSopenharmony_ci} 1484f08c3bdfSopenharmony_ci 1485f08c3bdfSopenharmony_cistatic int parse_distance_file(unsigned int node, const char *path) 1486f08c3bdfSopenharmony_ci{ 1487f08c3bdfSopenharmony_ci FILE *fp; 1488f08c3bdfSopenharmony_ci char *buf = NULL; 1489f08c3bdfSopenharmony_ci int buflen; 1490f08c3bdfSopenharmony_ci 1491f08c3bdfSopenharmony_ci if ((fp = fopen(path, "r")) == NULL) 1492f08c3bdfSopenharmony_ci goto err; 1493f08c3bdfSopenharmony_ci 1494f08c3bdfSopenharmony_ci buflen = filesize(fp); 1495f08c3bdfSopenharmony_ci 1496f08c3bdfSopenharmony_ci if ((buf = malloc(buflen)) == NULL) 1497f08c3bdfSopenharmony_ci goto err; 1498f08c3bdfSopenharmony_ci 1499f08c3bdfSopenharmony_ci if (flgets(buf, buflen, fp) == NULL) 1500f08c3bdfSopenharmony_ci goto err; 1501f08c3bdfSopenharmony_ci 1502f08c3bdfSopenharmony_ci if (parse_distmap_line(node, buf) < 0) 1503f08c3bdfSopenharmony_ci goto err; 1504f08c3bdfSopenharmony_ci 1505f08c3bdfSopenharmony_ci free(buf); 1506f08c3bdfSopenharmony_ci fclose(fp); 1507f08c3bdfSopenharmony_ci return 0; 1508f08c3bdfSopenharmony_cierr: 1509f08c3bdfSopenharmony_ci free(buf); 1510f08c3bdfSopenharmony_ci if (fp) 1511f08c3bdfSopenharmony_ci fclose(fp); 1512f08c3bdfSopenharmony_ci return -1; 1513f08c3bdfSopenharmony_ci} 1514f08c3bdfSopenharmony_ci 1515f08c3bdfSopenharmony_cistatic void build_distmap(void) 1516f08c3bdfSopenharmony_ci{ 1517f08c3bdfSopenharmony_ci static int tried_before = 0; 1518f08c3bdfSopenharmony_ci int ncpus = cpuset_cpus_nbits(); 1519f08c3bdfSopenharmony_ci int nmems = cpuset_mems_nbits(); 1520f08c3bdfSopenharmony_ci int c, m; 1521f08c3bdfSopenharmony_ci DIR *dir = NULL; 1522f08c3bdfSopenharmony_ci struct dirent *dent; 1523f08c3bdfSopenharmony_ci 1524f08c3bdfSopenharmony_ci if (tried_before) 1525f08c3bdfSopenharmony_ci goto err; 1526f08c3bdfSopenharmony_ci tried_before = 1; 1527f08c3bdfSopenharmony_ci 1528f08c3bdfSopenharmony_ci if ((distmap = calloc(ncpus * nmems, sizeof(*distmap))) == NULL) 1529f08c3bdfSopenharmony_ci goto err; 1530f08c3bdfSopenharmony_ci 1531f08c3bdfSopenharmony_ci for (c = 0; c < ncpus; c++) 1532f08c3bdfSopenharmony_ci for (m = 0; m < nmems; m++) 1533f08c3bdfSopenharmony_ci distmap[I(c, m)] = DISTMAP_MAX; 1534f08c3bdfSopenharmony_ci 1535f08c3bdfSopenharmony_ci if ((dir = opendir(distance_directory)) == NULL) 1536f08c3bdfSopenharmony_ci goto err; 1537f08c3bdfSopenharmony_ci while ((dent = readdir(dir)) != NULL) { 1538f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 1539f08c3bdfSopenharmony_ci unsigned int node; 1540f08c3bdfSopenharmony_ci 1541f08c3bdfSopenharmony_ci if (sscanf(dent->d_name, "node%u", &node) < 1) 1542f08c3bdfSopenharmony_ci continue; 1543f08c3bdfSopenharmony_ci pathcat3(buf, sizeof(buf), distance_directory, dent->d_name, 1544f08c3bdfSopenharmony_ci "distance"); 1545f08c3bdfSopenharmony_ci if (parse_distance_file(node, buf) < 0) 1546f08c3bdfSopenharmony_ci goto err; 1547f08c3bdfSopenharmony_ci } 1548f08c3bdfSopenharmony_ci closedir(dir); 1549f08c3bdfSopenharmony_ci return; 1550f08c3bdfSopenharmony_cierr: 1551f08c3bdfSopenharmony_ci if (dir) 1552f08c3bdfSopenharmony_ci closedir(dir); 1553f08c3bdfSopenharmony_ci free(distmap); 1554f08c3bdfSopenharmony_ci distmap = NULL; 1555f08c3bdfSopenharmony_ci} 1556f08c3bdfSopenharmony_ci 1557f08c3bdfSopenharmony_ci#ifdef ALTERNATE_SN_DISTMAP 1558f08c3bdfSopenharmony_ci 1559f08c3bdfSopenharmony_ci/* 1560f08c3bdfSopenharmony_ci * Parse SN architecture specific line of form: 1561f08c3bdfSopenharmony_ci * 1562f08c3bdfSopenharmony_ci * node 3 001c14#1 local asic SHub_1.1, nasid 0x6, dist 66:46:20:10 1563f08c3bdfSopenharmony_ci * 1564f08c3bdfSopenharmony_ci * Second field is node number. The "dist" field is the colon separated list 1565f08c3bdfSopenharmony_ci * of distances, which is parsed into array dists[] of each nodes distance 1566f08c3bdfSopenharmony_ci * from that node. 1567f08c3bdfSopenharmony_ci * 1568f08c3bdfSopenharmony_ci * Result is placed in distmap[ncpus][nmems]: 1569f08c3bdfSopenharmony_ci * 1570f08c3bdfSopenharmony_ci * For each cpu c on that node: 1571f08c3bdfSopenharmony_ci * For each node position n in list of distances: 1572f08c3bdfSopenharmony_ci * distmap[c][n] = dists[n] 1573f08c3bdfSopenharmony_ci */ 1574f08c3bdfSopenharmony_ci 1575f08c3bdfSopenharmony_cistatic void parse_distmap_line_sn(char *buf) 1576f08c3bdfSopenharmony_ci{ 1577f08c3bdfSopenharmony_ci char *p, *pend, *q; 1578f08c3bdfSopenharmony_ci int ncpus = cpuset_cpus_nbits(); 1579f08c3bdfSopenharmony_ci int nmems = cpuset_mems_nbits(); 1580f08c3bdfSopenharmony_ci unsigned long c, n, node; 1581f08c3bdfSopenharmony_ci distmap_entry_t *dists = NULL; 1582f08c3bdfSopenharmony_ci struct bitmask *cpus = NULL, *mems = NULL; 1583f08c3bdfSopenharmony_ci 1584f08c3bdfSopenharmony_ci if ((p = strchr(buf, ' ')) == NULL) 1585f08c3bdfSopenharmony_ci goto err; 1586f08c3bdfSopenharmony_ci if ((node = strtoul(p, &q, 10)) >= (unsigned int)nmems) 1587f08c3bdfSopenharmony_ci goto err; 1588f08c3bdfSopenharmony_ci if ((p = strstr(q, " dist ")) == NULL) 1589f08c3bdfSopenharmony_ci goto err; 1590f08c3bdfSopenharmony_ci p += strlen(" dist "); 1591f08c3bdfSopenharmony_ci if ((pend = strchr(p, ' ')) != NULL) 1592f08c3bdfSopenharmony_ci *pend = '\0'; 1593f08c3bdfSopenharmony_ci if ((dists = calloc(nmems, sizeof(*dists))) == NULL) 1594f08c3bdfSopenharmony_ci goto err; 1595f08c3bdfSopenharmony_ci for (n = 0; n < (unsigned int)nmems; n++) 1596f08c3bdfSopenharmony_ci dists[n] = DISTMAP_MAX; 1597f08c3bdfSopenharmony_ci 1598f08c3bdfSopenharmony_ci for (n = 0; n < (unsigned int)nmems && *p; n++, p = q) { 1599f08c3bdfSopenharmony_ci unsigned long d; 1600f08c3bdfSopenharmony_ci 1601f08c3bdfSopenharmony_ci if ((p = strpbrk(p, "0123456789")) == NULL) 1602f08c3bdfSopenharmony_ci break; 1603f08c3bdfSopenharmony_ci d = strtoul(p, &q, 10); 1604f08c3bdfSopenharmony_ci if (p == q) 1605f08c3bdfSopenharmony_ci break; 1606f08c3bdfSopenharmony_ci if (d < DISTMAP_MAX) 1607f08c3bdfSopenharmony_ci dists[n] = (distmap_entry_t) d; 1608f08c3bdfSopenharmony_ci } 1609f08c3bdfSopenharmony_ci 1610f08c3bdfSopenharmony_ci if ((mems = bitmask_alloc(nmems)) == NULL) 1611f08c3bdfSopenharmony_ci goto err; 1612f08c3bdfSopenharmony_ci bitmask_setbit(mems, node); 1613f08c3bdfSopenharmony_ci 1614f08c3bdfSopenharmony_ci if ((cpus = bitmask_alloc(ncpus)) == NULL) 1615f08c3bdfSopenharmony_ci goto err; 1616f08c3bdfSopenharmony_ci cpuset_localcpus(mems, cpus); 1617f08c3bdfSopenharmony_ci 1618f08c3bdfSopenharmony_ci for (c = bitmask_first(cpus); c < (unsigned int)ncpus; 1619f08c3bdfSopenharmony_ci c = bitmask_next(cpus, c + 1)) 1620f08c3bdfSopenharmony_ci for (n = 0; n < (unsigned int)nmems; n++) 1621f08c3bdfSopenharmony_ci distmap[I(c, n)] = dists[n]; 1622f08c3bdfSopenharmony_ci /* fall into ... */ 1623f08c3bdfSopenharmony_cierr: 1624f08c3bdfSopenharmony_ci bitmask_free(mems); 1625f08c3bdfSopenharmony_ci bitmask_free(cpus); 1626f08c3bdfSopenharmony_ci free(dists); 1627f08c3bdfSopenharmony_ci} 1628f08c3bdfSopenharmony_ci 1629f08c3bdfSopenharmony_cistatic void build_distmap_sn(void) 1630f08c3bdfSopenharmony_ci{ 1631f08c3bdfSopenharmony_ci int ncpus = cpuset_cpus_nbits(); 1632f08c3bdfSopenharmony_ci int nmems = cpuset_mems_nbits(); 1633f08c3bdfSopenharmony_ci int c, m; 1634f08c3bdfSopenharmony_ci static int tried_before = 0; 1635f08c3bdfSopenharmony_ci FILE *fp = NULL; 1636f08c3bdfSopenharmony_ci char *buf = NULL; 1637f08c3bdfSopenharmony_ci int buflen; 1638f08c3bdfSopenharmony_ci 1639f08c3bdfSopenharmony_ci if (tried_before) 1640f08c3bdfSopenharmony_ci goto err; 1641f08c3bdfSopenharmony_ci tried_before = 1; 1642f08c3bdfSopenharmony_ci 1643f08c3bdfSopenharmony_ci if ((fp = fopen(sn_topology, "r")) == NULL) 1644f08c3bdfSopenharmony_ci goto err; 1645f08c3bdfSopenharmony_ci 1646f08c3bdfSopenharmony_ci if ((distmap = calloc(ncpus * nmems, sizeof(*distmap))) == NULL) 1647f08c3bdfSopenharmony_ci goto err; 1648f08c3bdfSopenharmony_ci 1649f08c3bdfSopenharmony_ci for (c = 0; c < ncpus; c++) 1650f08c3bdfSopenharmony_ci for (m = 0; m < nmems; m++) 1651f08c3bdfSopenharmony_ci distmap[I(c, m)] = DISTMAP_MAX; 1652f08c3bdfSopenharmony_ci 1653f08c3bdfSopenharmony_ci buflen = filesize(fp); 1654f08c3bdfSopenharmony_ci if ((buf = malloc(buflen)) == NULL) 1655f08c3bdfSopenharmony_ci goto err; 1656f08c3bdfSopenharmony_ci 1657f08c3bdfSopenharmony_ci while (flgets(buf, buflen, fp) != NULL) 1658f08c3bdfSopenharmony_ci if (strprefix(buf, sn_top_node_prefix)) 1659f08c3bdfSopenharmony_ci parse_distmap_line_sn(buf); 1660f08c3bdfSopenharmony_ci 1661f08c3bdfSopenharmony_ci free(buf); 1662f08c3bdfSopenharmony_ci fclose(fp); 1663f08c3bdfSopenharmony_ci return; 1664f08c3bdfSopenharmony_cierr: 1665f08c3bdfSopenharmony_ci free(buf); 1666f08c3bdfSopenharmony_ci free(distmap); 1667f08c3bdfSopenharmony_ci distmap = NULL; 1668f08c3bdfSopenharmony_ci if (fp) 1669f08c3bdfSopenharmony_ci fclose(fp); 1670f08c3bdfSopenharmony_ci} 1671f08c3bdfSopenharmony_ci 1672f08c3bdfSopenharmony_ci#endif 1673f08c3bdfSopenharmony_ci 1674f08c3bdfSopenharmony_ci/* [optional] Hardware distance from CPU to Memory Node */ 1675f08c3bdfSopenharmony_ciunsigned int cpuset_cpumemdist(int cpu, int mem) 1676f08c3bdfSopenharmony_ci{ 1677f08c3bdfSopenharmony_ci int ncpus = cpuset_cpus_nbits(); 1678f08c3bdfSopenharmony_ci int nmems = cpuset_mems_nbits(); 1679f08c3bdfSopenharmony_ci distmap_entry_t r = DISTMAP_MAX; 1680f08c3bdfSopenharmony_ci 1681f08c3bdfSopenharmony_ci flockfile(stdout); 1682f08c3bdfSopenharmony_ci 1683f08c3bdfSopenharmony_ci if (check() < 0) 1684f08c3bdfSopenharmony_ci goto err; 1685f08c3bdfSopenharmony_ci 1686f08c3bdfSopenharmony_ci if (distmap == NULL) 1687f08c3bdfSopenharmony_ci build_distmap(); 1688f08c3bdfSopenharmony_ci 1689f08c3bdfSopenharmony_ci#ifdef ALTERNATE_SN_DISTMAP 1690f08c3bdfSopenharmony_ci if (distmap == NULL) 1691f08c3bdfSopenharmony_ci build_distmap_sn(); 1692f08c3bdfSopenharmony_ci#endif 1693f08c3bdfSopenharmony_ci 1694f08c3bdfSopenharmony_ci if (distmap == NULL) 1695f08c3bdfSopenharmony_ci goto err; 1696f08c3bdfSopenharmony_ci 1697f08c3bdfSopenharmony_ci if (cpu < 0 || cpu >= ncpus || mem < 0 || mem >= nmems) 1698f08c3bdfSopenharmony_ci goto err; 1699f08c3bdfSopenharmony_ci 1700f08c3bdfSopenharmony_ci r = distmap[I(cpu, mem)]; 1701f08c3bdfSopenharmony_ci /* fall into ... */ 1702f08c3bdfSopenharmony_cierr: 1703f08c3bdfSopenharmony_ci funlockfile(stdout); 1704f08c3bdfSopenharmony_ci return r; 1705f08c3bdfSopenharmony_ci} 1706f08c3bdfSopenharmony_ci 1707f08c3bdfSopenharmony_ci/* [optional] Return Memory Node closest to cpu */ 1708f08c3bdfSopenharmony_ciint cpuset_cpu2node(int cpu) 1709f08c3bdfSopenharmony_ci{ 1710f08c3bdfSopenharmony_ci int ncpus = cpuset_cpus_nbits(); 1711f08c3bdfSopenharmony_ci int nmems = cpuset_mems_nbits(); 1712f08c3bdfSopenharmony_ci struct bitmask *cpus = NULL, *mems = NULL; 1713f08c3bdfSopenharmony_ci int r = -1; 1714f08c3bdfSopenharmony_ci 1715f08c3bdfSopenharmony_ci if (check() < 0) 1716f08c3bdfSopenharmony_ci goto err; 1717f08c3bdfSopenharmony_ci 1718f08c3bdfSopenharmony_ci if ((cpus = bitmask_alloc(ncpus)) == NULL) 1719f08c3bdfSopenharmony_ci goto err; 1720f08c3bdfSopenharmony_ci bitmask_setbit(cpus, cpu); 1721f08c3bdfSopenharmony_ci 1722f08c3bdfSopenharmony_ci if ((mems = bitmask_alloc(nmems)) == NULL) 1723f08c3bdfSopenharmony_ci goto err; 1724f08c3bdfSopenharmony_ci cpuset_localmems(cpus, mems); 1725f08c3bdfSopenharmony_ci r = bitmask_first(mems); 1726f08c3bdfSopenharmony_ci /* fall into ... */ 1727f08c3bdfSopenharmony_cierr: 1728f08c3bdfSopenharmony_ci bitmask_free(cpus); 1729f08c3bdfSopenharmony_ci bitmask_free(mems); 1730f08c3bdfSopenharmony_ci return r; 1731f08c3bdfSopenharmony_ci} 1732f08c3bdfSopenharmony_ci 1733f08c3bdfSopenharmony_cistatic int apply_cpuset_settings(const char *path, const struct cpuset *cp) 1734f08c3bdfSopenharmony_ci{ 1735f08c3bdfSopenharmony_ci if (cp->cpu_exclusive_valid && cp->cpu_exclusive_dirty) { 1736f08c3bdfSopenharmony_ci if (store_flag(path, "cpu_exclusive", cp->cpu_exclusive) < 0) 1737f08c3bdfSopenharmony_ci goto err; 1738f08c3bdfSopenharmony_ci } 1739f08c3bdfSopenharmony_ci 1740f08c3bdfSopenharmony_ci if (cp->mem_exclusive_valid && cp->mem_exclusive_dirty) { 1741f08c3bdfSopenharmony_ci if (store_flag(path, "mem_exclusive", cp->mem_exclusive) < 0) 1742f08c3bdfSopenharmony_ci goto err; 1743f08c3bdfSopenharmony_ci } 1744f08c3bdfSopenharmony_ci 1745f08c3bdfSopenharmony_ci if (cp->mem_hardwall_valid && cp->mem_hardwall_dirty) { 1746f08c3bdfSopenharmony_ci if (store_flag(path, "mem_hardwall", cp->mem_hardwall) < 0) 1747f08c3bdfSopenharmony_ci goto err; 1748f08c3bdfSopenharmony_ci } 1749f08c3bdfSopenharmony_ci 1750f08c3bdfSopenharmony_ci if (cp->notify_on_release_valid && cp->notify_on_release_dirty) { 1751f08c3bdfSopenharmony_ci if (store_flag(path, "notify_on_release", cp->notify_on_release) 1752f08c3bdfSopenharmony_ci < 0) 1753f08c3bdfSopenharmony_ci goto err; 1754f08c3bdfSopenharmony_ci } 1755f08c3bdfSopenharmony_ci 1756f08c3bdfSopenharmony_ci if (cp->memory_migrate_valid && 1757f08c3bdfSopenharmony_ci cp->memory_migrate_dirty && exists_flag(path, "memory_migrate")) { 1758f08c3bdfSopenharmony_ci if (store_flag(path, "memory_migrate", cp->memory_migrate) < 0) 1759f08c3bdfSopenharmony_ci goto err; 1760f08c3bdfSopenharmony_ci } 1761f08c3bdfSopenharmony_ci 1762f08c3bdfSopenharmony_ci if (cp->memory_pressure_enabled_valid && 1763f08c3bdfSopenharmony_ci cp->memory_pressure_enabled_dirty && 1764f08c3bdfSopenharmony_ci exists_flag(path, "memory_pressure_enabled")) { 1765f08c3bdfSopenharmony_ci if (store_flag 1766f08c3bdfSopenharmony_ci (path, "memory_pressure_enabled", 1767f08c3bdfSopenharmony_ci cp->memory_pressure_enabled) < 0) 1768f08c3bdfSopenharmony_ci goto err; 1769f08c3bdfSopenharmony_ci } 1770f08c3bdfSopenharmony_ci 1771f08c3bdfSopenharmony_ci if (cp->memory_spread_page_valid && 1772f08c3bdfSopenharmony_ci cp->memory_spread_page_dirty && 1773f08c3bdfSopenharmony_ci exists_flag(path, "memory_spread_page")) { 1774f08c3bdfSopenharmony_ci if (store_flag 1775f08c3bdfSopenharmony_ci (path, "memory_spread_page", cp->memory_spread_page) < 0) 1776f08c3bdfSopenharmony_ci goto err; 1777f08c3bdfSopenharmony_ci } 1778f08c3bdfSopenharmony_ci 1779f08c3bdfSopenharmony_ci if (cp->memory_spread_slab_valid && 1780f08c3bdfSopenharmony_ci cp->memory_spread_slab_dirty && 1781f08c3bdfSopenharmony_ci exists_flag(path, "memory_spread_slab")) { 1782f08c3bdfSopenharmony_ci if (store_flag 1783f08c3bdfSopenharmony_ci (path, "memory_spread_slab", cp->memory_spread_slab) < 0) 1784f08c3bdfSopenharmony_ci goto err; 1785f08c3bdfSopenharmony_ci } 1786f08c3bdfSopenharmony_ci 1787f08c3bdfSopenharmony_ci if (cp->sched_load_balance_valid && 1788f08c3bdfSopenharmony_ci cp->sched_load_balance_dirty && 1789f08c3bdfSopenharmony_ci exists_flag(path, "sched_load_balance")) { 1790f08c3bdfSopenharmony_ci if (store_flag 1791f08c3bdfSopenharmony_ci (path, "sched_load_balance", cp->sched_load_balance) < 0) 1792f08c3bdfSopenharmony_ci goto err; 1793f08c3bdfSopenharmony_ci } 1794f08c3bdfSopenharmony_ci 1795f08c3bdfSopenharmony_ci if (cp->sched_relax_domain_level_valid && 1796f08c3bdfSopenharmony_ci cp->sched_relax_domain_level_dirty && 1797f08c3bdfSopenharmony_ci exists_flag(path, "sched_relax_domain_level")) { 1798f08c3bdfSopenharmony_ci if (store_number 1799f08c3bdfSopenharmony_ci (path, "sched_relax_domain_level", 1800f08c3bdfSopenharmony_ci cp->sched_relax_domain_level) < 0) 1801f08c3bdfSopenharmony_ci goto err; 1802f08c3bdfSopenharmony_ci } 1803f08c3bdfSopenharmony_ci 1804f08c3bdfSopenharmony_ci if (cp->cpus_valid && cp->cpus_dirty) { 1805f08c3bdfSopenharmony_ci if (store_mask(path, "cpus", cp->cpus) < 0) 1806f08c3bdfSopenharmony_ci goto err; 1807f08c3bdfSopenharmony_ci } 1808f08c3bdfSopenharmony_ci 1809f08c3bdfSopenharmony_ci if (cp->mems_valid && cp->mems_dirty) { 1810f08c3bdfSopenharmony_ci if (store_mask(path, "mems", cp->mems) < 0) 1811f08c3bdfSopenharmony_ci goto err; 1812f08c3bdfSopenharmony_ci } 1813f08c3bdfSopenharmony_ci return 0; 1814f08c3bdfSopenharmony_cierr: 1815f08c3bdfSopenharmony_ci return -1; 1816f08c3bdfSopenharmony_ci} 1817f08c3bdfSopenharmony_ci 1818f08c3bdfSopenharmony_ci/* 1819f08c3bdfSopenharmony_ci * get_siblings() - helper routine for cpuset_would_crash_kernel(), below. 1820f08c3bdfSopenharmony_ci * 1821f08c3bdfSopenharmony_ci * Extract max value of any 'siblings' field in /proc/cpuinfo. 1822f08c3bdfSopenharmony_ci * Cache the result - only need to extract once in lifetime of task. 1823f08c3bdfSopenharmony_ci * 1824f08c3bdfSopenharmony_ci * The siblings field is the number of logical CPUs in a physical 1825f08c3bdfSopenharmony_ci * processor package. It is equal to the product of the number of 1826f08c3bdfSopenharmony_ci * cores in that package, times the number of hyper-threads per core. 1827f08c3bdfSopenharmony_ci * The bug that cpuset_would_crash_kernel() is detecting arises 1828f08c3bdfSopenharmony_ci * when a cpu_exclusive cpuset tries to include just some, not all, 1829f08c3bdfSopenharmony_ci * of the sibling logical CPUs available in a processor package. 1830f08c3bdfSopenharmony_ci * 1831f08c3bdfSopenharmony_ci * In the improbable case that a system has mixed values of siblings 1832f08c3bdfSopenharmony_ci * (some processor packages have more than others, perhaps due to 1833f08c3bdfSopenharmony_ci * partially enabling Hyper-Threading), we take the worse case value, 1834f08c3bdfSopenharmony_ci * the largest siblings value. This might be overkill. I don't know 1835f08c3bdfSopenharmony_ci * if this kernel bug considers each processor package's siblings 1836f08c3bdfSopenharmony_ci * separately or not. But it sure is easier this way ... 1837f08c3bdfSopenharmony_ci * 1838f08c3bdfSopenharmony_ci * This routine takes about 0.7 msecs on a 4 CPU 2.8 MHz Xeon, from 1839f08c3bdfSopenharmony_ci * open to close, the first time called. 1840f08c3bdfSopenharmony_ci */ 1841f08c3bdfSopenharmony_ci 1842f08c3bdfSopenharmony_cistatic int get_siblings(void) 1843f08c3bdfSopenharmony_ci{ 1844f08c3bdfSopenharmony_ci static int siblings; 1845f08c3bdfSopenharmony_ci char buf[32]; /* big enough for one 'siblings' line */ 1846f08c3bdfSopenharmony_ci FILE *fp; 1847f08c3bdfSopenharmony_ci 1848f08c3bdfSopenharmony_ci if (siblings) 1849f08c3bdfSopenharmony_ci return siblings; 1850f08c3bdfSopenharmony_ci 1851f08c3bdfSopenharmony_ci if ((fp = fopen("/proc/cpuinfo", "r")) == NULL) 1852f08c3bdfSopenharmony_ci return 4; /* wing it - /proc not mounted ? */ 1853f08c3bdfSopenharmony_ci while (flgets(buf, sizeof(buf), fp) != NULL) { 1854f08c3bdfSopenharmony_ci int s; 1855f08c3bdfSopenharmony_ci 1856f08c3bdfSopenharmony_ci if (sscanf(buf, "siblings : %d", &s) < 1) 1857f08c3bdfSopenharmony_ci continue; 1858f08c3bdfSopenharmony_ci if (s > siblings) 1859f08c3bdfSopenharmony_ci siblings = s; 1860f08c3bdfSopenharmony_ci } 1861f08c3bdfSopenharmony_ci fclose(fp); 1862f08c3bdfSopenharmony_ci if (siblings == 0) 1863f08c3bdfSopenharmony_ci siblings = 1; /* old kernel, no siblings, default to 1 */ 1864f08c3bdfSopenharmony_ci return siblings; 1865f08c3bdfSopenharmony_ci} 1866f08c3bdfSopenharmony_ci 1867f08c3bdfSopenharmony_ci/* 1868f08c3bdfSopenharmony_ci * Some 2.6.16 and 2.6.17 kernel versions have a bug in the dynamic 1869f08c3bdfSopenharmony_ci * scheduler domain code invoked for cpu_exclusive cpusets that causes 1870f08c3bdfSopenharmony_ci * the kernel to freeze, requiring a hardware reset. 1871f08c3bdfSopenharmony_ci * 1872f08c3bdfSopenharmony_ci * On kernels built with CONFIG_SCHED_MC enabled, if a 'cpu_exclusive' 1873f08c3bdfSopenharmony_ci * cpuset is defined where that cpusets 'cpus' are not on package 1874f08c3bdfSopenharmony_ci * boundaries then the kernel will freeze, usually as soon as this 1875f08c3bdfSopenharmony_ci * cpuset is created, requiring a hardware reset. 1876f08c3bdfSopenharmony_ci * 1877f08c3bdfSopenharmony_ci * A cpusets 'cpus' are not on package boundaries if the cpuset 1878f08c3bdfSopenharmony_ci * includes a proper non-empty subset (some, but not all) of the 1879f08c3bdfSopenharmony_ci * logical cpus on a processor package. This requires multiple 1880f08c3bdfSopenharmony_ci * logical CPUs per package, available with either Hyper-Thread or 1881f08c3bdfSopenharmony_ci * Multi-Core support. Without one of these features, there is only 1882f08c3bdfSopenharmony_ci * one logical CPU per physical package, and it's not possible to 1883f08c3bdfSopenharmony_ci * have a proper, non-empty subset of a set of cardinality one. 1884f08c3bdfSopenharmony_ci * 1885f08c3bdfSopenharmony_ci * SUSE SLES10 kernels, as first released, only enable CONFIG_SCHED_MC 1886f08c3bdfSopenharmony_ci * on i386 and x86_64 arch's. 1887f08c3bdfSopenharmony_ci * 1888f08c3bdfSopenharmony_ci * The objective of this routine cpuset_would_crash_kernel() is to 1889f08c3bdfSopenharmony_ci * determine if a proposed cpuset setting would crash the kernel due 1890f08c3bdfSopenharmony_ci * to this bug, so that the caller can avoid the crash. 1891f08c3bdfSopenharmony_ci * 1892f08c3bdfSopenharmony_ci * Ideally we'd check for exactly these conditions here, but computing 1893f08c3bdfSopenharmony_ci * the package (identified by the 'physical id' field of /proc/cpuinfo) 1894f08c3bdfSopenharmony_ci * of each cpu in a cpuset is more effort than it's worth here. 1895f08c3bdfSopenharmony_ci * 1896f08c3bdfSopenharmony_ci * Also there is no obvious way to identify exactly whether the kernel 1897f08c3bdfSopenharmony_ci * one is executing on has this bug, short of trying it, and seeing 1898f08c3bdfSopenharmony_ci * if the kernel just crashed. 1899f08c3bdfSopenharmony_ci * 1900f08c3bdfSopenharmony_ci * So for now, we look for a simpler set of conditions, that meets 1901f08c3bdfSopenharmony_ci * our immediate need - avoid this crash on SUSE SLES10 systems that 1902f08c3bdfSopenharmony_ci * are susceptible to it. We look for the kernel version 2.6.16.*, 1903f08c3bdfSopenharmony_ci * which is the base kernel of SUSE SLES10, and for i386 or x86_64 1904f08c3bdfSopenharmony_ci * processors, which had CONFIG_SCHED_MC enabled. 1905f08c3bdfSopenharmony_ci * 1906f08c3bdfSopenharmony_ci * If these simpler conditions are met, we further simplify the check, 1907f08c3bdfSopenharmony_ci * by presuming that the logical CPUs are numbered on processor 1908f08c3bdfSopenharmony_ci * package boundaries. If each package has S siblings, we assume 1909f08c3bdfSopenharmony_ci * that CPUs numbered N through N + S -1 are on the same package, 1910f08c3bdfSopenharmony_ci * for any CPU N such that N mod S == 0. 1911f08c3bdfSopenharmony_ci * 1912f08c3bdfSopenharmony_ci * Yes, this is a hack, focused on avoiding kernel freezes on 1913f08c3bdfSopenharmony_ci * susceptible SUSE SLES10 systems. 1914f08c3bdfSopenharmony_ci */ 1915f08c3bdfSopenharmony_ci 1916f08c3bdfSopenharmony_cistatic int cpuset_would_crash_kernel(const struct cpuset *cp) 1917f08c3bdfSopenharmony_ci{ 1918f08c3bdfSopenharmony_ci static int susceptible_system = -1; 1919f08c3bdfSopenharmony_ci 1920f08c3bdfSopenharmony_ci if (!cp->cpu_exclusive) 1921f08c3bdfSopenharmony_ci goto ok; 1922f08c3bdfSopenharmony_ci 1923f08c3bdfSopenharmony_ci if (susceptible_system == -1) { 1924f08c3bdfSopenharmony_ci struct utsname u; 1925f08c3bdfSopenharmony_ci int rel_2_6_16, arch_i386, arch_x86_64; 1926f08c3bdfSopenharmony_ci 1927f08c3bdfSopenharmony_ci if (uname(&u) < 0) 1928f08c3bdfSopenharmony_ci goto fail; 1929f08c3bdfSopenharmony_ci rel_2_6_16 = strprefix(u.release, "2.6.16."); 1930f08c3bdfSopenharmony_ci arch_i386 = streq(u.machine, "i386"); 1931f08c3bdfSopenharmony_ci arch_x86_64 = streq(u.machine, "x86_64"); 1932f08c3bdfSopenharmony_ci susceptible_system = rel_2_6_16 && (arch_i386 || arch_x86_64); 1933f08c3bdfSopenharmony_ci } 1934f08c3bdfSopenharmony_ci 1935f08c3bdfSopenharmony_ci if (susceptible_system) { 1936f08c3bdfSopenharmony_ci int ncpus = cpuset_cpus_nbits(); 1937f08c3bdfSopenharmony_ci int siblings = get_siblings(); 1938f08c3bdfSopenharmony_ci unsigned int cpu; 1939f08c3bdfSopenharmony_ci 1940f08c3bdfSopenharmony_ci for (cpu = 0; cpu < (unsigned int)ncpus; cpu += siblings) { 1941f08c3bdfSopenharmony_ci int s, num_set = 0; 1942f08c3bdfSopenharmony_ci 1943f08c3bdfSopenharmony_ci for (s = 0; s < siblings; s++) { 1944f08c3bdfSopenharmony_ci if (bitmask_isbitset(cp->cpus, cpu + s)) 1945f08c3bdfSopenharmony_ci num_set++; 1946f08c3bdfSopenharmony_ci } 1947f08c3bdfSopenharmony_ci 1948f08c3bdfSopenharmony_ci /* If none or all siblings set, we're still ok */ 1949f08c3bdfSopenharmony_ci if (num_set == 0 || num_set == siblings) 1950f08c3bdfSopenharmony_ci continue; 1951f08c3bdfSopenharmony_ci 1952f08c3bdfSopenharmony_ci /* Found one that would crash kernel. Fail. */ 1953f08c3bdfSopenharmony_ci errno = ENXIO; 1954f08c3bdfSopenharmony_ci goto fail; 1955f08c3bdfSopenharmony_ci } 1956f08c3bdfSopenharmony_ci } 1957f08c3bdfSopenharmony_ci /* If not susceptible, or if all ok, fall into "ok" ... */ 1958f08c3bdfSopenharmony_ciok: 1959f08c3bdfSopenharmony_ci return 0; /* would not crash */ 1960f08c3bdfSopenharmony_cifail: 1961f08c3bdfSopenharmony_ci return 1; /* would crash */ 1962f08c3bdfSopenharmony_ci} 1963f08c3bdfSopenharmony_ci 1964f08c3bdfSopenharmony_ci/* compare two cpuset and mark the dirty variable */ 1965f08c3bdfSopenharmony_cistatic void mark_dirty_variable(struct cpuset *cp1, const struct cpuset *cp2) 1966f08c3bdfSopenharmony_ci{ 1967f08c3bdfSopenharmony_ci if (cp1->cpu_exclusive_valid && 1968f08c3bdfSopenharmony_ci cp1->cpu_exclusive != cp2->cpu_exclusive) 1969f08c3bdfSopenharmony_ci cp1->cpu_exclusive_dirty = 1; 1970f08c3bdfSopenharmony_ci 1971f08c3bdfSopenharmony_ci if (cp1->mem_exclusive_valid && 1972f08c3bdfSopenharmony_ci cp1->mem_exclusive != cp2->mem_exclusive) 1973f08c3bdfSopenharmony_ci cp1->mem_exclusive_dirty = 1; 1974f08c3bdfSopenharmony_ci 1975f08c3bdfSopenharmony_ci if (cp1->mem_hardwall_valid && cp1->mem_hardwall != cp2->mem_hardwall) 1976f08c3bdfSopenharmony_ci cp1->mem_hardwall_dirty = 1; 1977f08c3bdfSopenharmony_ci 1978f08c3bdfSopenharmony_ci if (cp1->notify_on_release_valid && 1979f08c3bdfSopenharmony_ci cp1->notify_on_release != cp2->notify_on_release) 1980f08c3bdfSopenharmony_ci cp1->notify_on_release_dirty = 1; 1981f08c3bdfSopenharmony_ci 1982f08c3bdfSopenharmony_ci if (cp1->memory_migrate_valid && 1983f08c3bdfSopenharmony_ci cp1->memory_migrate != cp2->memory_migrate) 1984f08c3bdfSopenharmony_ci cp1->memory_migrate_dirty = 1; 1985f08c3bdfSopenharmony_ci 1986f08c3bdfSopenharmony_ci if (cp1->memory_pressure_enabled_valid && 1987f08c3bdfSopenharmony_ci cp1->memory_pressure_enabled != cp2->memory_pressure_enabled) 1988f08c3bdfSopenharmony_ci cp1->memory_pressure_enabled_dirty = 1; 1989f08c3bdfSopenharmony_ci 1990f08c3bdfSopenharmony_ci if (cp1->memory_spread_page_valid && 1991f08c3bdfSopenharmony_ci cp1->memory_spread_page != cp2->memory_spread_page) 1992f08c3bdfSopenharmony_ci cp1->memory_spread_page_dirty = 1; 1993f08c3bdfSopenharmony_ci 1994f08c3bdfSopenharmony_ci if (cp1->memory_spread_slab_valid && 1995f08c3bdfSopenharmony_ci cp1->memory_spread_slab != cp2->memory_spread_slab) 1996f08c3bdfSopenharmony_ci cp1->memory_spread_slab_dirty = 1; 1997f08c3bdfSopenharmony_ci 1998f08c3bdfSopenharmony_ci if (cp1->sched_load_balance_valid && 1999f08c3bdfSopenharmony_ci cp1->sched_load_balance != cp2->sched_load_balance) 2000f08c3bdfSopenharmony_ci cp1->sched_load_balance_dirty = 1; 2001f08c3bdfSopenharmony_ci 2002f08c3bdfSopenharmony_ci if (cp1->sched_relax_domain_level_valid && 2003f08c3bdfSopenharmony_ci cp1->sched_relax_domain_level != cp2->sched_relax_domain_level) 2004f08c3bdfSopenharmony_ci cp1->sched_relax_domain_level_dirty = 1; 2005f08c3bdfSopenharmony_ci 2006f08c3bdfSopenharmony_ci if (cp1->cpus_valid && !bitmask_equal(cp1->cpus, cp2->cpus)) 2007f08c3bdfSopenharmony_ci cp1->cpus_dirty = 1; 2008f08c3bdfSopenharmony_ci if (cp1->mems_valid && !bitmask_equal(cp1->mems, cp2->mems)) 2009f08c3bdfSopenharmony_ci cp1->mems_dirty = 1; 2010f08c3bdfSopenharmony_ci} 2011f08c3bdfSopenharmony_ci 2012f08c3bdfSopenharmony_ci/* Create (if new set) or modify cpuset 'cp' at location 'relpath' */ 2013f08c3bdfSopenharmony_cistatic int cr_or_mod(const char *relpath, const struct cpuset *cp, int new) 2014f08c3bdfSopenharmony_ci{ 2015f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 2016f08c3bdfSopenharmony_ci int do_rmdir_on_err = 0; 2017f08c3bdfSopenharmony_ci int do_restore_cp_sav_on_err = 0; 2018f08c3bdfSopenharmony_ci struct cpuset *cp_sav = NULL; 2019f08c3bdfSopenharmony_ci int sav_errno; 2020f08c3bdfSopenharmony_ci 2021f08c3bdfSopenharmony_ci if (check() < 0) 2022f08c3bdfSopenharmony_ci goto err; 2023f08c3bdfSopenharmony_ci 2024f08c3bdfSopenharmony_ci if (cpuset_would_crash_kernel(cp)) 2025f08c3bdfSopenharmony_ci goto err; 2026f08c3bdfSopenharmony_ci 2027f08c3bdfSopenharmony_ci fullpath(buf, sizeof(buf), relpath); 2028f08c3bdfSopenharmony_ci 2029f08c3bdfSopenharmony_ci if (new) { 2030f08c3bdfSopenharmony_ci if (mkdir(buf, 0755) < 0) 2031f08c3bdfSopenharmony_ci goto err; 2032f08c3bdfSopenharmony_ci /* we made it, so we should remove it on error */ 2033f08c3bdfSopenharmony_ci do_rmdir_on_err = 1; 2034f08c3bdfSopenharmony_ci } 2035f08c3bdfSopenharmony_ci 2036f08c3bdfSopenharmony_ci if ((cp_sav = cpuset_alloc()) == NULL) 2037f08c3bdfSopenharmony_ci goto err; 2038f08c3bdfSopenharmony_ci if (cpuset_query(cp_sav, relpath) < 0) 2039f08c3bdfSopenharmony_ci goto err; 2040f08c3bdfSopenharmony_ci /* we have old settings to restore on error */ 2041f08c3bdfSopenharmony_ci do_restore_cp_sav_on_err = 1; 2042f08c3bdfSopenharmony_ci 2043f08c3bdfSopenharmony_ci /* check which variable need to restore on error */ 2044f08c3bdfSopenharmony_ci mark_dirty_variable(cp_sav, cp); 2045f08c3bdfSopenharmony_ci 2046f08c3bdfSopenharmony_ci if (apply_cpuset_settings(buf, cp) < 0) 2047f08c3bdfSopenharmony_ci goto err; 2048f08c3bdfSopenharmony_ci 2049f08c3bdfSopenharmony_ci cpuset_free(cp_sav); 2050f08c3bdfSopenharmony_ci return 0; 2051f08c3bdfSopenharmony_cierr: 2052f08c3bdfSopenharmony_ci sav_errno = errno; 2053f08c3bdfSopenharmony_ci if (do_restore_cp_sav_on_err) 2054f08c3bdfSopenharmony_ci (void)apply_cpuset_settings(buf, cp_sav); 2055f08c3bdfSopenharmony_ci if (cp_sav) 2056f08c3bdfSopenharmony_ci cpuset_free(cp_sav); 2057f08c3bdfSopenharmony_ci if (do_rmdir_on_err) 2058f08c3bdfSopenharmony_ci (void)rmdir(buf); 2059f08c3bdfSopenharmony_ci errno = sav_errno; 2060f08c3bdfSopenharmony_ci return -1; 2061f08c3bdfSopenharmony_ci} 2062f08c3bdfSopenharmony_ci 2063f08c3bdfSopenharmony_ci/* Create cpuset 'cp' at location 'relpath' */ 2064f08c3bdfSopenharmony_ciint cpuset_create(const char *relpath, const struct cpuset *cp) 2065f08c3bdfSopenharmony_ci{ 2066f08c3bdfSopenharmony_ci return cr_or_mod(relpath, cp, 1); 2067f08c3bdfSopenharmony_ci} 2068f08c3bdfSopenharmony_ci 2069f08c3bdfSopenharmony_ci/* Delete cpuset at location 'path' (if empty) */ 2070f08c3bdfSopenharmony_ciint cpuset_delete(const char *relpath) 2071f08c3bdfSopenharmony_ci{ 2072f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 2073f08c3bdfSopenharmony_ci 2074f08c3bdfSopenharmony_ci if (check() < 0) 2075f08c3bdfSopenharmony_ci goto err; 2076f08c3bdfSopenharmony_ci 2077f08c3bdfSopenharmony_ci fullpath(buf, sizeof(buf), relpath); 2078f08c3bdfSopenharmony_ci if (rmdir(buf) < 0) 2079f08c3bdfSopenharmony_ci goto err; 2080f08c3bdfSopenharmony_ci 2081f08c3bdfSopenharmony_ci return 0; 2082f08c3bdfSopenharmony_cierr: 2083f08c3bdfSopenharmony_ci return -1; 2084f08c3bdfSopenharmony_ci} 2085f08c3bdfSopenharmony_ci 2086f08c3bdfSopenharmony_ci/* Set cpuset cp to the cpuset at location 'path' */ 2087f08c3bdfSopenharmony_ciint cpuset_query(struct cpuset *cp, const char *relpath) 2088f08c3bdfSopenharmony_ci{ 2089f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 2090f08c3bdfSopenharmony_ci 2091f08c3bdfSopenharmony_ci if (check() < 0) 2092f08c3bdfSopenharmony_ci goto err; 2093f08c3bdfSopenharmony_ci 2094f08c3bdfSopenharmony_ci fullpath(buf, sizeof(buf), relpath); 2095f08c3bdfSopenharmony_ci 2096f08c3bdfSopenharmony_ci if (load_flag(buf, &cp->cpu_exclusive, "cpuset.cpu_exclusive") < 0) 2097f08c3bdfSopenharmony_ci goto err; 2098f08c3bdfSopenharmony_ci cp->cpu_exclusive_valid = 1; 2099f08c3bdfSopenharmony_ci 2100f08c3bdfSopenharmony_ci if (load_flag(buf, &cp->mem_exclusive, "cpuset.mem_exclusive") < 0) 2101f08c3bdfSopenharmony_ci goto err; 2102f08c3bdfSopenharmony_ci cp->mem_exclusive_valid = 1; 2103f08c3bdfSopenharmony_ci 2104f08c3bdfSopenharmony_ci if (load_flag(buf, &cp->notify_on_release, "notify_on_release") < 0) 2105f08c3bdfSopenharmony_ci goto err; 2106f08c3bdfSopenharmony_ci cp->notify_on_release_valid = 1; 2107f08c3bdfSopenharmony_ci 2108f08c3bdfSopenharmony_ci if (exists_flag(buf, "cpuset.memory_migrate")) { 2109f08c3bdfSopenharmony_ci if (load_flag(buf, &cp->memory_migrate, "cpuset.memory_migrate") < 0) 2110f08c3bdfSopenharmony_ci goto err; 2111f08c3bdfSopenharmony_ci cp->memory_migrate_valid = 1; 2112f08c3bdfSopenharmony_ci } 2113f08c3bdfSopenharmony_ci 2114f08c3bdfSopenharmony_ci if (exists_flag(buf, "cpuset.mem_hardwall")) { 2115f08c3bdfSopenharmony_ci if (load_flag(buf, &cp->mem_hardwall, "cpuset.mem_hardwall") < 0) 2116f08c3bdfSopenharmony_ci goto err; 2117f08c3bdfSopenharmony_ci cp->mem_hardwall_valid = 1; 2118f08c3bdfSopenharmony_ci } 2119f08c3bdfSopenharmony_ci 2120f08c3bdfSopenharmony_ci if (exists_flag(buf, "cpuset.memory_pressure_enabled")) { 2121f08c3bdfSopenharmony_ci if (load_flag 2122f08c3bdfSopenharmony_ci (buf, &cp->memory_pressure_enabled, 2123f08c3bdfSopenharmony_ci "cpuset.memory_pressure_enabled") < 0) 2124f08c3bdfSopenharmony_ci goto err; 2125f08c3bdfSopenharmony_ci cp->memory_pressure_enabled_valid = 1; 2126f08c3bdfSopenharmony_ci } 2127f08c3bdfSopenharmony_ci 2128f08c3bdfSopenharmony_ci if (exists_flag(buf, "cpuset.memory_spread_page")) { 2129f08c3bdfSopenharmony_ci if (load_flag 2130f08c3bdfSopenharmony_ci (buf, &cp->memory_spread_page, "cpuset.memory_spread_page") < 0) 2131f08c3bdfSopenharmony_ci goto err; 2132f08c3bdfSopenharmony_ci cp->memory_spread_page_valid = 1; 2133f08c3bdfSopenharmony_ci } 2134f08c3bdfSopenharmony_ci 2135f08c3bdfSopenharmony_ci if (exists_flag(buf, "cpuset.memory_spread_slab")) { 2136f08c3bdfSopenharmony_ci if (load_flag 2137f08c3bdfSopenharmony_ci (buf, &cp->memory_spread_slab, "cpuset.memory_spread_slab") < 0) 2138f08c3bdfSopenharmony_ci goto err; 2139f08c3bdfSopenharmony_ci cp->memory_spread_slab_valid = 1; 2140f08c3bdfSopenharmony_ci } 2141f08c3bdfSopenharmony_ci 2142f08c3bdfSopenharmony_ci if (exists_flag(buf, "cpuset.sched_load_balance")) { 2143f08c3bdfSopenharmony_ci if (load_flag 2144f08c3bdfSopenharmony_ci (buf, &cp->sched_load_balance, "cpuset.sched_load_balance") < 0) 2145f08c3bdfSopenharmony_ci goto err; 2146f08c3bdfSopenharmony_ci cp->sched_load_balance_valid = 1; 2147f08c3bdfSopenharmony_ci } 2148f08c3bdfSopenharmony_ci 2149f08c3bdfSopenharmony_ci if (exists_flag(buf, "cpuset.sched_relax_domain_level")) { 2150f08c3bdfSopenharmony_ci if (load_number 2151f08c3bdfSopenharmony_ci (buf, &cp->sched_relax_domain_level, 2152f08c3bdfSopenharmony_ci "cpuset.sched_relax_domain_level") < 0) 2153f08c3bdfSopenharmony_ci goto err; 2154f08c3bdfSopenharmony_ci cp->sched_relax_domain_level_valid = 1; 2155f08c3bdfSopenharmony_ci } 2156f08c3bdfSopenharmony_ci 2157f08c3bdfSopenharmony_ci if (load_mask(buf, &cp->cpus, cpuset_cpus_nbits(), "cpuset.cpus") < 0) 2158f08c3bdfSopenharmony_ci goto err; 2159f08c3bdfSopenharmony_ci cp->cpus_valid = 1; 2160f08c3bdfSopenharmony_ci 2161f08c3bdfSopenharmony_ci if (load_mask(buf, &cp->mems, cpuset_mems_nbits(), "cpuset.mems") < 0) 2162f08c3bdfSopenharmony_ci goto err; 2163f08c3bdfSopenharmony_ci cp->mems_valid = 1; 2164f08c3bdfSopenharmony_ci 2165f08c3bdfSopenharmony_ci return 0; 2166f08c3bdfSopenharmony_cierr: 2167f08c3bdfSopenharmony_ci return -1; 2168f08c3bdfSopenharmony_ci} 2169f08c3bdfSopenharmony_ci 2170f08c3bdfSopenharmony_ci/* Modify cpuset at location 'relpath' to values of 'cp' */ 2171f08c3bdfSopenharmony_ciint cpuset_modify(const char *relpath, const struct cpuset *cp) 2172f08c3bdfSopenharmony_ci{ 2173f08c3bdfSopenharmony_ci return cr_or_mod(relpath, cp, 0); 2174f08c3bdfSopenharmony_ci} 2175f08c3bdfSopenharmony_ci 2176f08c3bdfSopenharmony_ci/* Get cpuset path of pid into buf */ 2177f08c3bdfSopenharmony_cichar *cpuset_getcpusetpath(pid_t pid, char *buf, size_t size) 2178f08c3bdfSopenharmony_ci{ 2179f08c3bdfSopenharmony_ci int fd; /* dual use: cpuset file for pid and self */ 2180f08c3bdfSopenharmony_ci int rc; /* dual use: snprintf and read return codes */ 2181f08c3bdfSopenharmony_ci 2182f08c3bdfSopenharmony_ci if (check() < 0) 2183f08c3bdfSopenharmony_ci return NULL; 2184f08c3bdfSopenharmony_ci 2185f08c3bdfSopenharmony_ci /* borrow result buf[] to build cpuset file path */ 2186f08c3bdfSopenharmony_ci if (pid == 0) 2187f08c3bdfSopenharmony_ci rc = snprintf(buf, size, "/proc/self/cpuset"); 2188f08c3bdfSopenharmony_ci else 2189f08c3bdfSopenharmony_ci rc = snprintf(buf, size, "/proc/%d/cpuset", pid); 2190f08c3bdfSopenharmony_ci if (rc >= (int)size) { 2191f08c3bdfSopenharmony_ci errno = E2BIG; 2192f08c3bdfSopenharmony_ci return NULL; 2193f08c3bdfSopenharmony_ci } 2194f08c3bdfSopenharmony_ci if ((fd = open(buf, O_RDONLY)) < 0) { 2195f08c3bdfSopenharmony_ci int e = errno; 2196f08c3bdfSopenharmony_ci if (e == ENOENT) 2197f08c3bdfSopenharmony_ci e = ESRCH; 2198f08c3bdfSopenharmony_ci if ((fd = open("/proc/self/cpuset", O_RDONLY)) < 0) 2199f08c3bdfSopenharmony_ci e = ENOSYS; 2200f08c3bdfSopenharmony_ci else 2201f08c3bdfSopenharmony_ci close(fd); 2202f08c3bdfSopenharmony_ci errno = e; 2203f08c3bdfSopenharmony_ci return NULL; 2204f08c3bdfSopenharmony_ci } 2205f08c3bdfSopenharmony_ci rc = read(fd, buf, size); 2206f08c3bdfSopenharmony_ci close(fd); 2207f08c3bdfSopenharmony_ci if (rc < 0) 2208f08c3bdfSopenharmony_ci return NULL; 2209f08c3bdfSopenharmony_ci if (rc >= (int)size) { 2210f08c3bdfSopenharmony_ci errno = E2BIG; 2211f08c3bdfSopenharmony_ci return NULL; 2212f08c3bdfSopenharmony_ci } 2213f08c3bdfSopenharmony_ci buf[rc] = 0; 2214f08c3bdfSopenharmony_ci chomp(buf); 2215f08c3bdfSopenharmony_ci return buf; 2216f08c3bdfSopenharmony_ci 2217f08c3bdfSopenharmony_ci} 2218f08c3bdfSopenharmony_ci 2219f08c3bdfSopenharmony_ci/* Get cpuset 'cp' of pid */ 2220f08c3bdfSopenharmony_ciint cpuset_cpusetofpid(struct cpuset *cp, pid_t pid) 2221f08c3bdfSopenharmony_ci{ 2222f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 2223f08c3bdfSopenharmony_ci 2224f08c3bdfSopenharmony_ci if (cpuset_getcpusetpath(pid, buf, sizeof(buf)) == NULL) 2225f08c3bdfSopenharmony_ci return -1; 2226f08c3bdfSopenharmony_ci if (cpuset_query(cp, buf) < 0) 2227f08c3bdfSopenharmony_ci return -1; 2228f08c3bdfSopenharmony_ci return 0; 2229f08c3bdfSopenharmony_ci} 2230f08c3bdfSopenharmony_ci 2231f08c3bdfSopenharmony_ci/* [optional] Return mountpoint of cpuset filesystem */ 2232f08c3bdfSopenharmony_ciconst char *cpuset_mountpoint(void) 2233f08c3bdfSopenharmony_ci{ 2234f08c3bdfSopenharmony_ci if (check() < 0) { 2235f08c3bdfSopenharmony_ci switch (errno) { 2236f08c3bdfSopenharmony_ci case ENODEV: 2237f08c3bdfSopenharmony_ci return "[cpuset filesystem not mounted]"; 2238f08c3bdfSopenharmony_ci default: 2239f08c3bdfSopenharmony_ci return "[cpuset filesystem not supported]"; 2240f08c3bdfSopenharmony_ci } 2241f08c3bdfSopenharmony_ci } 2242f08c3bdfSopenharmony_ci return cpusetmnt; 2243f08c3bdfSopenharmony_ci} 2244f08c3bdfSopenharmony_ci 2245f08c3bdfSopenharmony_ci/* Return true if path is a directory. */ 2246f08c3bdfSopenharmony_cistatic int isdir(const char *path) 2247f08c3bdfSopenharmony_ci{ 2248f08c3bdfSopenharmony_ci struct stat statbuf; 2249f08c3bdfSopenharmony_ci 2250f08c3bdfSopenharmony_ci if (stat(path, &statbuf) < 0) 2251f08c3bdfSopenharmony_ci return 0; 2252f08c3bdfSopenharmony_ci return S_ISDIR(statbuf.st_mode); 2253f08c3bdfSopenharmony_ci} 2254f08c3bdfSopenharmony_ci 2255f08c3bdfSopenharmony_ci/* 2256f08c3bdfSopenharmony_ci * [optional] cpuset_collides_exclusive() - True if would collide exclusive. 2257f08c3bdfSopenharmony_ci * 2258f08c3bdfSopenharmony_ci * Return true iff the specified cpuset would overlap with any 2259f08c3bdfSopenharmony_ci * sibling cpusets in either cpus or mems, where either this 2260f08c3bdfSopenharmony_ci * cpuset or the sibling is cpu_exclusive or mem_exclusive. 2261f08c3bdfSopenharmony_ci * 2262f08c3bdfSopenharmony_ci * cpuset_create() fails with errno == EINVAL if the requested cpuset 2263f08c3bdfSopenharmony_ci * would overlap with any sibling, where either one is cpu_exclusive or 2264f08c3bdfSopenharmony_ci * mem_exclusive. This is a common, and not obvious error. The 2265f08c3bdfSopenharmony_ci * following routine checks for this particular case, so that code 2266f08c3bdfSopenharmony_ci * creating cpusets can better identify the situation, perhaps to issue 2267f08c3bdfSopenharmony_ci * a more informative error message. 2268f08c3bdfSopenharmony_ci * 2269f08c3bdfSopenharmony_ci * Can also be used to diagnose cpuset_modify failures. This 2270f08c3bdfSopenharmony_ci * routine ignores any existing cpuset with the same path as the 2271f08c3bdfSopenharmony_ci * given 'cpusetpath', and only looks for exclusive collisions with 2272f08c3bdfSopenharmony_ci * sibling cpusets of that path. 2273f08c3bdfSopenharmony_ci * 2274f08c3bdfSopenharmony_ci * In case of any error, returns (0) -- does not collide. Presumably 2275f08c3bdfSopenharmony_ci * any actual attempt to create or modify a cpuset will encounter the 2276f08c3bdfSopenharmony_ci * same error, and report it usefully. 2277f08c3bdfSopenharmony_ci * 2278f08c3bdfSopenharmony_ci * This routine is not particularly efficient; most likely code creating or 2279f08c3bdfSopenharmony_ci * modifying a cpuset will want to try the operation first, and then if that 2280f08c3bdfSopenharmony_ci * fails with errno EINVAL, perhaps call this routine to determine if an 2281f08c3bdfSopenharmony_ci * exclusive cpuset collision caused the error. 2282f08c3bdfSopenharmony_ci */ 2283f08c3bdfSopenharmony_ci 2284f08c3bdfSopenharmony_ciint cpuset_collides_exclusive(const char *cpusetpath, const struct cpuset *cp1) 2285f08c3bdfSopenharmony_ci{ 2286f08c3bdfSopenharmony_ci char parent[PATH_MAX]; 2287f08c3bdfSopenharmony_ci char *p; 2288f08c3bdfSopenharmony_ci char *pathcopy = NULL; 2289f08c3bdfSopenharmony_ci char *base; 2290f08c3bdfSopenharmony_ci DIR *dir = NULL; 2291f08c3bdfSopenharmony_ci struct dirent *dent; 2292f08c3bdfSopenharmony_ci struct cpuset *cp2 = NULL; 2293f08c3bdfSopenharmony_ci struct bitmask *cpus1 = NULL, *cpus2 = NULL; 2294f08c3bdfSopenharmony_ci struct bitmask *mems1 = NULL, *mems2 = NULL; 2295f08c3bdfSopenharmony_ci int ret; 2296f08c3bdfSopenharmony_ci 2297f08c3bdfSopenharmony_ci if (check() < 0) 2298f08c3bdfSopenharmony_ci goto err; 2299f08c3bdfSopenharmony_ci 2300f08c3bdfSopenharmony_ci fullpath(parent, sizeof(parent), cpusetpath); 2301f08c3bdfSopenharmony_ci if (streq(parent, cpusetmnt)) 2302f08c3bdfSopenharmony_ci goto err; /* only one cpuset root - can't collide */ 2303f08c3bdfSopenharmony_ci pathcopy = strdup(parent); 2304f08c3bdfSopenharmony_ci p = strrchr(parent, '/'); 2305f08c3bdfSopenharmony_ci if (!p) 2306f08c3bdfSopenharmony_ci goto err; /* huh? - impossible - run and hide */ 2307f08c3bdfSopenharmony_ci *p = 0; /* now parent is dirname of fullpath */ 2308f08c3bdfSopenharmony_ci 2309f08c3bdfSopenharmony_ci p = strrchr(pathcopy, '/'); 2310f08c3bdfSopenharmony_ci base = p + 1; /* now base is basename of fullpath */ 2311f08c3bdfSopenharmony_ci if (!*base) 2312f08c3bdfSopenharmony_ci goto err; /* this is also impossible - run away */ 2313f08c3bdfSopenharmony_ci 2314f08c3bdfSopenharmony_ci if ((dir = opendir(parent)) == NULL) 2315f08c3bdfSopenharmony_ci goto err; 2316f08c3bdfSopenharmony_ci if ((cp2 = cpuset_alloc()) == NULL) 2317f08c3bdfSopenharmony_ci goto err; 2318f08c3bdfSopenharmony_ci if ((cpus1 = bitmask_alloc(cpuset_cpus_nbits())) == NULL) 2319f08c3bdfSopenharmony_ci goto err; 2320f08c3bdfSopenharmony_ci if ((cpus2 = bitmask_alloc(cpuset_cpus_nbits())) == NULL) 2321f08c3bdfSopenharmony_ci goto err; 2322f08c3bdfSopenharmony_ci if ((mems1 = bitmask_alloc(cpuset_mems_nbits())) == NULL) 2323f08c3bdfSopenharmony_ci goto err; 2324f08c3bdfSopenharmony_ci if ((mems2 = bitmask_alloc(cpuset_mems_nbits())) == NULL) 2325f08c3bdfSopenharmony_ci goto err; 2326f08c3bdfSopenharmony_ci 2327f08c3bdfSopenharmony_ci while ((dent = readdir(dir)) != NULL) { 2328f08c3bdfSopenharmony_ci char child[PATH_MAX]; 2329f08c3bdfSopenharmony_ci 2330f08c3bdfSopenharmony_ci if (streq(dent->d_name, ".") || streq(dent->d_name, "..")) 2331f08c3bdfSopenharmony_ci continue; 2332f08c3bdfSopenharmony_ci if (streq(dent->d_name, base)) 2333f08c3bdfSopenharmony_ci continue; 2334f08c3bdfSopenharmony_ci pathcat2(child, sizeof(child), parent, dent->d_name); 2335f08c3bdfSopenharmony_ci if (!isdir(child)) 2336f08c3bdfSopenharmony_ci continue; 2337f08c3bdfSopenharmony_ci if (cpuset_query(cp2, child + strlen(cpusetmnt)) < 0) 2338f08c3bdfSopenharmony_ci goto err; 2339f08c3bdfSopenharmony_ci if (cp1->cpu_exclusive || cp2->cpu_exclusive) { 2340f08c3bdfSopenharmony_ci cpuset_getcpus(cp1, cpus1); 2341f08c3bdfSopenharmony_ci cpuset_getcpus(cp2, cpus2); 2342f08c3bdfSopenharmony_ci if (bitmask_intersects(cpus1, cpus2)) 2343f08c3bdfSopenharmony_ci goto collides; 2344f08c3bdfSopenharmony_ci } 2345f08c3bdfSopenharmony_ci if (cp1->mem_exclusive || cp2->mem_exclusive) { 2346f08c3bdfSopenharmony_ci cpuset_getmems(cp1, mems1); 2347f08c3bdfSopenharmony_ci cpuset_getmems(cp2, mems2); 2348f08c3bdfSopenharmony_ci if (bitmask_intersects(mems1, mems2)) 2349f08c3bdfSopenharmony_ci goto collides; 2350f08c3bdfSopenharmony_ci } 2351f08c3bdfSopenharmony_ci } 2352f08c3bdfSopenharmony_cierr: 2353f08c3bdfSopenharmony_ci /* error, or did not collide */ 2354f08c3bdfSopenharmony_ci ret = 0; 2355f08c3bdfSopenharmony_ci goto done; 2356f08c3bdfSopenharmony_cicollides: 2357f08c3bdfSopenharmony_ci /* collides */ 2358f08c3bdfSopenharmony_ci ret = 1; 2359f08c3bdfSopenharmony_ci /* fall into ... */ 2360f08c3bdfSopenharmony_cidone: 2361f08c3bdfSopenharmony_ci if (dir) 2362f08c3bdfSopenharmony_ci closedir(dir); 2363f08c3bdfSopenharmony_ci cpuset_free(cp2); 2364f08c3bdfSopenharmony_ci free(pathcopy); 2365f08c3bdfSopenharmony_ci bitmask_free(cpus1); 2366f08c3bdfSopenharmony_ci bitmask_free(cpus2); 2367f08c3bdfSopenharmony_ci bitmask_free(mems1); 2368f08c3bdfSopenharmony_ci bitmask_free(mems2); 2369f08c3bdfSopenharmony_ci return ret; 2370f08c3bdfSopenharmony_ci} 2371f08c3bdfSopenharmony_ci 2372f08c3bdfSopenharmony_ci/* 2373f08c3bdfSopenharmony_ci * [optional] cpuset_nuke() - Remove cpuset anyway possible 2374f08c3bdfSopenharmony_ci * 2375f08c3bdfSopenharmony_ci * Remove a cpuset, including killing tasks in it, and 2376f08c3bdfSopenharmony_ci * removing any descendent cpusets and killing their tasks. 2377f08c3bdfSopenharmony_ci * 2378f08c3bdfSopenharmony_ci * Tasks can take a long time (minutes on some configurations) 2379f08c3bdfSopenharmony_ci * to exit. Loop up to 'seconds' seconds, trying to kill them. 2380f08c3bdfSopenharmony_ci * 2381f08c3bdfSopenharmony_ci * How we do it: 2382f08c3bdfSopenharmony_ci * 1) First, kill all the pids, looping until there are 2383f08c3bdfSopenharmony_ci * no more pids in this cpuset or below, or until the 2384f08c3bdfSopenharmony_ci * 'seconds' timeout limit is exceeded. 2385f08c3bdfSopenharmony_ci * 2) Then depth first recursively rmdir the cpuset directories. 2386f08c3bdfSopenharmony_ci * 3) If by this point the original cpuset is gone, we succeeded. 2387f08c3bdfSopenharmony_ci * 2388f08c3bdfSopenharmony_ci * If the timeout is exceeded, and tasks still exist, fail with 2389f08c3bdfSopenharmony_ci * errno == ETIME. 2390f08c3bdfSopenharmony_ci * 2391f08c3bdfSopenharmony_ci * We sleep a variable amount of time. After the first attempt to 2392f08c3bdfSopenharmony_ci * kill all the tasks in the cpuset or its descendents, we sleep 1 2393f08c3bdfSopenharmony_ci * second, the next time 2 seconds, increasing 1 second each loop 2394f08c3bdfSopenharmony_ci * up to a max of 10 seconds. If more loops past 10 are required 2395f08c3bdfSopenharmony_ci * to kill all the tasks, we sleep 10 seconds each subsequent loop. 2396f08c3bdfSopenharmony_ci * In any case, before the last loop, we sleep however many seconds 2397f08c3bdfSopenharmony_ci * remain of the original timeout 'seconds' requested. The total 2398f08c3bdfSopenharmony_ci * time of all sleeps will be no more than the requested 'seconds'. 2399f08c3bdfSopenharmony_ci * 2400f08c3bdfSopenharmony_ci * If the cpuset started out empty of any tasks, or if the passed in 2401f08c3bdfSopenharmony_ci * 'seconds' was zero, then this routine will return quickly, having 2402f08c3bdfSopenharmony_ci * not slept at all. Otherwise, this routine will at a minimum send 2403f08c3bdfSopenharmony_ci * a SIGKILL to all the tasks in this cpuset subtree, then sleep one 2404f08c3bdfSopenharmony_ci * second, before looking to see if any tasks remain. If tasks remain 2405f08c3bdfSopenharmony_ci * in the cpuset subtree, and a longer 'seconds' timeout was requested 2406f08c3bdfSopenharmony_ci * (more than one), it will continue to kill remaining tasks and sleep, 2407f08c3bdfSopenharmony_ci * in a loop, for as long as time and tasks remain. 2408f08c3bdfSopenharmony_ci * 2409f08c3bdfSopenharmony_ci * The signal sent for the kill is hardcoded to SIGKILL (9). If some 2410f08c3bdfSopenharmony_ci * other signal should be sent first, use a separate code loop, 2411f08c3bdfSopenharmony_ci * perhaps based on cpuset_init_pidlist and cpuset_get_pidlist, to 2412f08c3bdfSopenharmony_ci * scan the task pids in a cpuset. If SIGKILL should -not- be sent, 2413f08c3bdfSopenharmony_ci * this cpuset_nuke() routine can still be called to recursively 2414f08c3bdfSopenharmony_ci * remove a cpuset subtree, by specifying a timeout of zero 'seconds'. 2415f08c3bdfSopenharmony_ci * 2416f08c3bdfSopenharmony_ci * On success, returns 0 with errno == 0. 2417f08c3bdfSopenharmony_ci * 2418f08c3bdfSopenharmony_ci * On failure, returns -1, with errno possibly one of: 2419f08c3bdfSopenharmony_ci * EACCES - search permission denied on intervening directory 2420f08c3bdfSopenharmony_ci * ETIME - timed out - tasks remain after 'seconds' timeout 2421f08c3bdfSopenharmony_ci * EMFILE - too many open files 2422f08c3bdfSopenharmony_ci * ENODEV - /dev/cpuset not mounted 2423f08c3bdfSopenharmony_ci * ENOENT - component of cpuset path doesn't exist 2424f08c3bdfSopenharmony_ci * ENOMEM - out of memory 2425f08c3bdfSopenharmony_ci * ENOSYS - kernel doesn't support cpusets 2426f08c3bdfSopenharmony_ci * ENOTDIR - component of cpuset path is not a directory 2427f08c3bdfSopenharmony_ci * EPERM - lacked permission to kill a task 2428f08c3bdfSopenharmony_ci * EPERM - lacked permission to read cpusets or files therein 2429f08c3bdfSopenharmony_ci */ 2430f08c3bdfSopenharmony_ci 2431f08c3bdfSopenharmony_civoid cpuset_fts_reverse(struct cpuset_fts_tree *cs_tree); 2432f08c3bdfSopenharmony_ci 2433f08c3bdfSopenharmony_ciint cpuset_nuke(const char *relpath, unsigned int seconds) 2434f08c3bdfSopenharmony_ci{ 2435f08c3bdfSopenharmony_ci unsigned int secs_left = seconds; /* total sleep seconds left */ 2436f08c3bdfSopenharmony_ci unsigned int secs_loop = 1; /* how much sleep next loop */ 2437f08c3bdfSopenharmony_ci unsigned int secs_slept; /* seconds slept in sleep() */ 2438f08c3bdfSopenharmony_ci struct cpuset_pidlist *pl = NULL; /* pids in cpuset subtree */ 2439f08c3bdfSopenharmony_ci struct cpuset_fts_tree *cs_tree; 2440f08c3bdfSopenharmony_ci const struct cpuset_fts_entry *cs_entry; 2441f08c3bdfSopenharmony_ci int ret, sav_errno = 0; 2442f08c3bdfSopenharmony_ci 2443f08c3bdfSopenharmony_ci if (check() < 0) 2444f08c3bdfSopenharmony_ci return -1; 2445f08c3bdfSopenharmony_ci 2446f08c3bdfSopenharmony_ci if (seconds == 0) 2447f08c3bdfSopenharmony_ci goto rmdir_cpusets; 2448f08c3bdfSopenharmony_ci 2449f08c3bdfSopenharmony_ci while (1) { 2450f08c3bdfSopenharmony_ci int plen, j; 2451f08c3bdfSopenharmony_ci 2452f08c3bdfSopenharmony_ci if ((pl = cpuset_init_pidlist(relpath, 1)) == NULL) { 2453f08c3bdfSopenharmony_ci /* missing cpuset is as good as if already nuked */ 2454f08c3bdfSopenharmony_ci if (errno == ENOENT) { 2455f08c3bdfSopenharmony_ci ret = 0; 2456f08c3bdfSopenharmony_ci goto no_more_cpuset; 2457f08c3bdfSopenharmony_ci } 2458f08c3bdfSopenharmony_ci 2459f08c3bdfSopenharmony_ci /* other problems reading cpuset are bad news */ 2460f08c3bdfSopenharmony_ci sav_errno = errno; 2461f08c3bdfSopenharmony_ci goto failed; 2462f08c3bdfSopenharmony_ci } 2463f08c3bdfSopenharmony_ci 2464f08c3bdfSopenharmony_ci if ((plen = cpuset_pidlist_length(pl)) == 0) 2465f08c3bdfSopenharmony_ci goto rmdir_cpusets; 2466f08c3bdfSopenharmony_ci 2467f08c3bdfSopenharmony_ci for (j = 0; j < plen; j++) { 2468f08c3bdfSopenharmony_ci pid_t pid; 2469f08c3bdfSopenharmony_ci 2470f08c3bdfSopenharmony_ci if ((pid = cpuset_get_pidlist(pl, j)) > 1) { 2471f08c3bdfSopenharmony_ci if (kill(pid, SIGKILL) < 0 && errno != ESRCH) { 2472f08c3bdfSopenharmony_ci sav_errno = errno; 2473f08c3bdfSopenharmony_ci goto failed; 2474f08c3bdfSopenharmony_ci } 2475f08c3bdfSopenharmony_ci } 2476f08c3bdfSopenharmony_ci } 2477f08c3bdfSopenharmony_ci 2478f08c3bdfSopenharmony_ci if (secs_left == 0) 2479f08c3bdfSopenharmony_ci goto took_too_long; 2480f08c3bdfSopenharmony_ci 2481f08c3bdfSopenharmony_ci cpuset_freepidlist(pl); 2482f08c3bdfSopenharmony_ci pl = NULL; 2483f08c3bdfSopenharmony_ci 2484f08c3bdfSopenharmony_ci secs_slept = secs_loop - sleep(secs_loop); 2485f08c3bdfSopenharmony_ci 2486f08c3bdfSopenharmony_ci /* Ensure forward progress */ 2487f08c3bdfSopenharmony_ci if (secs_slept == 0) 2488f08c3bdfSopenharmony_ci secs_slept = 1; 2489f08c3bdfSopenharmony_ci 2490f08c3bdfSopenharmony_ci /* Ensure sane sleep() return (unnecessary?) */ 2491f08c3bdfSopenharmony_ci if (secs_slept > secs_loop) 2492f08c3bdfSopenharmony_ci secs_slept = secs_loop; 2493f08c3bdfSopenharmony_ci 2494f08c3bdfSopenharmony_ci secs_left -= secs_slept; 2495f08c3bdfSopenharmony_ci 2496f08c3bdfSopenharmony_ci if (secs_loop < 10) 2497f08c3bdfSopenharmony_ci secs_loop++; 2498f08c3bdfSopenharmony_ci 2499f08c3bdfSopenharmony_ci secs_loop = MIN(secs_left, secs_loop); 2500f08c3bdfSopenharmony_ci } 2501f08c3bdfSopenharmony_ci 2502f08c3bdfSopenharmony_citook_too_long: 2503f08c3bdfSopenharmony_ci sav_errno = ETIME; 2504f08c3bdfSopenharmony_ci /* fall into ... */ 2505f08c3bdfSopenharmony_cifailed: 2506f08c3bdfSopenharmony_ci cpuset_freepidlist(pl); 2507f08c3bdfSopenharmony_ci errno = sav_errno; 2508f08c3bdfSopenharmony_ci return -1; 2509f08c3bdfSopenharmony_ci 2510f08c3bdfSopenharmony_cirmdir_cpusets: 2511f08c3bdfSopenharmony_ci /* Let's try removing cpuset(s) now. */ 2512f08c3bdfSopenharmony_ci cpuset_freepidlist(pl); 2513f08c3bdfSopenharmony_ci 2514f08c3bdfSopenharmony_ci if ((cs_tree = cpuset_fts_open(relpath)) == NULL && errno != ENOENT) 2515f08c3bdfSopenharmony_ci return -1; 2516f08c3bdfSopenharmony_ci ret = 0; 2517f08c3bdfSopenharmony_ci cpuset_fts_reverse(cs_tree); /* rmdir's must be done bottom up */ 2518f08c3bdfSopenharmony_ci while ((cs_entry = cpuset_fts_read(cs_tree)) != NULL) { 2519f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 2520f08c3bdfSopenharmony_ci 2521f08c3bdfSopenharmony_ci fullpath(buf, sizeof(buf), cpuset_fts_get_path(cs_entry)); 2522f08c3bdfSopenharmony_ci if (rmdir(buf) < 0 && errno != ENOENT) { 2523f08c3bdfSopenharmony_ci sav_errno = errno; 2524f08c3bdfSopenharmony_ci ret = -1; 2525f08c3bdfSopenharmony_ci } 2526f08c3bdfSopenharmony_ci } 2527f08c3bdfSopenharmony_ci cpuset_fts_close(cs_tree); 2528f08c3bdfSopenharmony_ci /* fall into ... */ 2529f08c3bdfSopenharmony_cino_more_cpuset: 2530f08c3bdfSopenharmony_ci if (ret == 0) 2531f08c3bdfSopenharmony_ci errno = 0; 2532f08c3bdfSopenharmony_ci else 2533f08c3bdfSopenharmony_ci errno = sav_errno; 2534f08c3bdfSopenharmony_ci return ret; 2535f08c3bdfSopenharmony_ci} 2536f08c3bdfSopenharmony_ci 2537f08c3bdfSopenharmony_ci/* 2538f08c3bdfSopenharmony_ci * When recursively reading all the tasks files from a subtree, 2539f08c3bdfSopenharmony_ci * chain together the read results, one pidblock per tasks file, 2540f08c3bdfSopenharmony_ci * containing the raw unprocessed ascii as read(2) in. After 2541f08c3bdfSopenharmony_ci * we gather up this raw data, we then go back to count how 2542f08c3bdfSopenharmony_ci * many pid's there are in total, allocate an array of pid_t 2543f08c3bdfSopenharmony_ci * of that size, and transform the raw ascii data into this 2544f08c3bdfSopenharmony_ci * array of pid_t's. 2545f08c3bdfSopenharmony_ci */ 2546f08c3bdfSopenharmony_ci 2547f08c3bdfSopenharmony_cistruct pidblock { 2548f08c3bdfSopenharmony_ci char *buf; 2549f08c3bdfSopenharmony_ci int buflen; 2550f08c3bdfSopenharmony_ci struct pidblock *next; 2551f08c3bdfSopenharmony_ci}; 2552f08c3bdfSopenharmony_ci 2553f08c3bdfSopenharmony_ci/* 2554f08c3bdfSopenharmony_ci * Chain the raw contents of a file onto the pbhead list. 2555f08c3bdfSopenharmony_ci * 2556f08c3bdfSopenharmony_ci * We malloc "+ 1" extra byte for a nul-terminator, so that 2557f08c3bdfSopenharmony_ci * the strtoul() loop in pid_transform() won't scan past 2558f08c3bdfSopenharmony_ci * the end of pb->buf[] and accidentally find more pids. 2559f08c3bdfSopenharmony_ci */ 2560f08c3bdfSopenharmony_cistatic void add_pidblock(const char *file, struct pidblock **ppbhead) 2561f08c3bdfSopenharmony_ci{ 2562f08c3bdfSopenharmony_ci FILE *fp = NULL; 2563f08c3bdfSopenharmony_ci struct pidblock *pb = NULL; 2564f08c3bdfSopenharmony_ci int fsz; 2565f08c3bdfSopenharmony_ci 2566f08c3bdfSopenharmony_ci if ((fp = fopen(file, "r")) == NULL) 2567f08c3bdfSopenharmony_ci goto err; 2568f08c3bdfSopenharmony_ci fsz = filesize(fp); 2569f08c3bdfSopenharmony_ci if (fsz == 0) 2570f08c3bdfSopenharmony_ci goto err; 2571f08c3bdfSopenharmony_ci if ((pb = calloc(1, sizeof(*pb))) == NULL) 2572f08c3bdfSopenharmony_ci goto err; 2573f08c3bdfSopenharmony_ci pb->buflen = fsz; 2574f08c3bdfSopenharmony_ci if ((pb->buf = malloc(pb->buflen + 1)) == NULL) 2575f08c3bdfSopenharmony_ci goto err; 2576f08c3bdfSopenharmony_ci if (fread(pb->buf, 1, pb->buflen, fp) > 0) { 2577f08c3bdfSopenharmony_ci pb->buf[pb->buflen] = '\0'; 2578f08c3bdfSopenharmony_ci pb->next = *ppbhead; 2579f08c3bdfSopenharmony_ci *ppbhead = pb; 2580f08c3bdfSopenharmony_ci } 2581f08c3bdfSopenharmony_ci fclose(fp); 2582f08c3bdfSopenharmony_ci return; 2583f08c3bdfSopenharmony_cierr: 2584f08c3bdfSopenharmony_ci if (fp) 2585f08c3bdfSopenharmony_ci fclose(fp); 2586f08c3bdfSopenharmony_ci free(pb); 2587f08c3bdfSopenharmony_ci} 2588f08c3bdfSopenharmony_ci 2589f08c3bdfSopenharmony_cistatic void read_task_file(const char *relpath, struct pidblock **ppbhead) 2590f08c3bdfSopenharmony_ci{ 2591f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 2592f08c3bdfSopenharmony_ci 2593f08c3bdfSopenharmony_ci fullpath2(buf, sizeof(buf), relpath, "tasks"); 2594f08c3bdfSopenharmony_ci add_pidblock(buf, ppbhead); 2595f08c3bdfSopenharmony_ci} 2596f08c3bdfSopenharmony_ci 2597f08c3bdfSopenharmony_cistruct cpuset_pidlist { 2598f08c3bdfSopenharmony_ci pid_t *pids; 2599f08c3bdfSopenharmony_ci int npids; 2600f08c3bdfSopenharmony_ci}; 2601f08c3bdfSopenharmony_ci 2602f08c3bdfSopenharmony_ci/* Count how many pids in buf (one per line - just count newlines) */ 2603f08c3bdfSopenharmony_cistatic int pidcount(const char *buf, int buflen) 2604f08c3bdfSopenharmony_ci{ 2605f08c3bdfSopenharmony_ci int n = 0; 2606f08c3bdfSopenharmony_ci const char *cp; 2607f08c3bdfSopenharmony_ci 2608f08c3bdfSopenharmony_ci for (cp = buf; cp < buf + buflen; cp++) { 2609f08c3bdfSopenharmony_ci if (*cp == '\n') 2610f08c3bdfSopenharmony_ci n++; 2611f08c3bdfSopenharmony_ci } 2612f08c3bdfSopenharmony_ci return n; 2613f08c3bdfSopenharmony_ci} 2614f08c3bdfSopenharmony_ci 2615f08c3bdfSopenharmony_ci/* Transform one-per-line ascii pids in pb to pid_t entries in pl */ 2616f08c3bdfSopenharmony_cistatic int pid_transform(struct pidblock *pb, struct cpuset_pidlist *pl, int n) 2617f08c3bdfSopenharmony_ci{ 2618f08c3bdfSopenharmony_ci char *a, *b; 2619f08c3bdfSopenharmony_ci 2620f08c3bdfSopenharmony_ci for (a = pb->buf; a < pb->buf + pb->buflen; a = b) { 2621f08c3bdfSopenharmony_ci pid_t p = strtoul(a, &b, 10); 2622f08c3bdfSopenharmony_ci if (a == b) 2623f08c3bdfSopenharmony_ci break; 2624f08c3bdfSopenharmony_ci pl->pids[n++] = p; 2625f08c3bdfSopenharmony_ci } 2626f08c3bdfSopenharmony_ci return n; 2627f08c3bdfSopenharmony_ci} 2628f08c3bdfSopenharmony_ci 2629f08c3bdfSopenharmony_cistatic void free_pidblocks(struct pidblock *pbhead) 2630f08c3bdfSopenharmony_ci{ 2631f08c3bdfSopenharmony_ci struct pidblock *pb, *nextpb; 2632f08c3bdfSopenharmony_ci 2633f08c3bdfSopenharmony_ci for (pb = pbhead; pb; pb = nextpb) { 2634f08c3bdfSopenharmony_ci nextpb = pb->next; 2635f08c3bdfSopenharmony_ci free(pb->buf); 2636f08c3bdfSopenharmony_ci free(pb); 2637f08c3bdfSopenharmony_ci } 2638f08c3bdfSopenharmony_ci} 2639f08c3bdfSopenharmony_ci 2640f08c3bdfSopenharmony_ci/* numeric comparison routine for qsort */ 2641f08c3bdfSopenharmony_cistatic int numericsort(const void *m1, const void *m2) 2642f08c3bdfSopenharmony_ci{ 2643f08c3bdfSopenharmony_ci pid_t p1 = *(pid_t *) m1; 2644f08c3bdfSopenharmony_ci pid_t p2 = *(pid_t *) m2; 2645f08c3bdfSopenharmony_ci 2646f08c3bdfSopenharmony_ci return p1 - p2; 2647f08c3bdfSopenharmony_ci} 2648f08c3bdfSopenharmony_ci 2649f08c3bdfSopenharmony_ci/* Return list pids in cpuset 'path' */ 2650f08c3bdfSopenharmony_cistruct cpuset_pidlist *cpuset_init_pidlist(const char *relpath, 2651f08c3bdfSopenharmony_ci int recursiveflag) 2652f08c3bdfSopenharmony_ci{ 2653f08c3bdfSopenharmony_ci struct pidblock *pb = NULL; 2654f08c3bdfSopenharmony_ci struct cpuset_pidlist *pl = NULL; 2655f08c3bdfSopenharmony_ci struct pidblock *pbhead = NULL; 2656f08c3bdfSopenharmony_ci int n; 2657f08c3bdfSopenharmony_ci 2658f08c3bdfSopenharmony_ci if (check() < 0) 2659f08c3bdfSopenharmony_ci goto err; 2660f08c3bdfSopenharmony_ci 2661f08c3bdfSopenharmony_ci if (recursiveflag) { 2662f08c3bdfSopenharmony_ci struct cpuset_fts_tree *cs_tree; 2663f08c3bdfSopenharmony_ci const struct cpuset_fts_entry *cs_entry; 2664f08c3bdfSopenharmony_ci 2665f08c3bdfSopenharmony_ci if ((cs_tree = cpuset_fts_open(relpath)) == NULL) 2666f08c3bdfSopenharmony_ci goto err; 2667f08c3bdfSopenharmony_ci while ((cs_entry = cpuset_fts_read(cs_tree)) != NULL) { 2668f08c3bdfSopenharmony_ci if (cpuset_fts_get_info(cs_entry) != CPUSET_FTS_CPUSET) 2669f08c3bdfSopenharmony_ci continue; 2670f08c3bdfSopenharmony_ci read_task_file(cpuset_fts_get_path(cs_entry), &pbhead); 2671f08c3bdfSopenharmony_ci } 2672f08c3bdfSopenharmony_ci cpuset_fts_close(cs_tree); 2673f08c3bdfSopenharmony_ci } else { 2674f08c3bdfSopenharmony_ci read_task_file(relpath, &pbhead); 2675f08c3bdfSopenharmony_ci } 2676f08c3bdfSopenharmony_ci 2677f08c3bdfSopenharmony_ci if ((pl = calloc(1, sizeof(*pl))) == NULL) 2678f08c3bdfSopenharmony_ci goto err; 2679f08c3bdfSopenharmony_ci pl->npids = 0; 2680f08c3bdfSopenharmony_ci for (pb = pbhead; pb; pb = pb->next) 2681f08c3bdfSopenharmony_ci pl->npids += pidcount(pb->buf, pb->buflen); 2682f08c3bdfSopenharmony_ci if ((pl->pids = calloc(pl->npids, sizeof(pid_t))) == NULL) 2683f08c3bdfSopenharmony_ci goto err; 2684f08c3bdfSopenharmony_ci n = 0; 2685f08c3bdfSopenharmony_ci for (pb = pbhead; pb; pb = pb->next) 2686f08c3bdfSopenharmony_ci n = pid_transform(pb, pl, n); 2687f08c3bdfSopenharmony_ci free_pidblocks(pbhead); 2688f08c3bdfSopenharmony_ci qsort(pl->pids, pl->npids, sizeof(pid_t), numericsort); 2689f08c3bdfSopenharmony_ci return pl; 2690f08c3bdfSopenharmony_cierr: 2691f08c3bdfSopenharmony_ci cpuset_freepidlist(pl); 2692f08c3bdfSopenharmony_ci free_pidblocks(pbhead); 2693f08c3bdfSopenharmony_ci return NULL; 2694f08c3bdfSopenharmony_ci} 2695f08c3bdfSopenharmony_ci 2696f08c3bdfSopenharmony_ci/* Return number of elements in pidlist */ 2697f08c3bdfSopenharmony_ciint cpuset_pidlist_length(const struct cpuset_pidlist *pl) 2698f08c3bdfSopenharmony_ci{ 2699f08c3bdfSopenharmony_ci if (pl) 2700f08c3bdfSopenharmony_ci return pl->npids; 2701f08c3bdfSopenharmony_ci else 2702f08c3bdfSopenharmony_ci return 0; 2703f08c3bdfSopenharmony_ci} 2704f08c3bdfSopenharmony_ci 2705f08c3bdfSopenharmony_ci/* Return i'th element of pidlist */ 2706f08c3bdfSopenharmony_cipid_t cpuset_get_pidlist(const struct cpuset_pidlist * pl, int i) 2707f08c3bdfSopenharmony_ci{ 2708f08c3bdfSopenharmony_ci if (pl && i >= 0 && i < pl->npids) 2709f08c3bdfSopenharmony_ci return pl->pids[i]; 2710f08c3bdfSopenharmony_ci else 2711f08c3bdfSopenharmony_ci return (pid_t) - 1; 2712f08c3bdfSopenharmony_ci} 2713f08c3bdfSopenharmony_ci 2714f08c3bdfSopenharmony_ci/* Free pidlist */ 2715f08c3bdfSopenharmony_civoid cpuset_freepidlist(struct cpuset_pidlist *pl) 2716f08c3bdfSopenharmony_ci{ 2717f08c3bdfSopenharmony_ci if (pl && pl->pids) 2718f08c3bdfSopenharmony_ci free(pl->pids); 2719f08c3bdfSopenharmony_ci free(pl); 2720f08c3bdfSopenharmony_ci} 2721f08c3bdfSopenharmony_ci 2722f08c3bdfSopenharmony_cistatic int __cpuset_move(pid_t pid, const char *path) 2723f08c3bdfSopenharmony_ci{ 2724f08c3bdfSopenharmony_ci char buf[SMALL_BUFSZ]; 2725f08c3bdfSopenharmony_ci 2726f08c3bdfSopenharmony_ci snprintf(buf, sizeof(buf), "%u", pid); 2727f08c3bdfSopenharmony_ci return write_string_file(path, buf); 2728f08c3bdfSopenharmony_ci} 2729f08c3bdfSopenharmony_ci 2730f08c3bdfSopenharmony_ci/* Move task (pid == 0 for current) to a cpuset */ 2731f08c3bdfSopenharmony_ciint cpuset_move(pid_t pid, const char *relpath) 2732f08c3bdfSopenharmony_ci{ 2733f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 2734f08c3bdfSopenharmony_ci 2735f08c3bdfSopenharmony_ci if (check() < 0) 2736f08c3bdfSopenharmony_ci return -1; 2737f08c3bdfSopenharmony_ci 2738f08c3bdfSopenharmony_ci if (pid == 0) 2739f08c3bdfSopenharmony_ci pid = getpid(); 2740f08c3bdfSopenharmony_ci 2741f08c3bdfSopenharmony_ci fullpath2(buf, sizeof(buf), relpath, "tasks"); 2742f08c3bdfSopenharmony_ci return __cpuset_move(pid, buf); 2743f08c3bdfSopenharmony_ci} 2744f08c3bdfSopenharmony_ci 2745f08c3bdfSopenharmony_ci/* Move all tasks in pidlist to a cpuset */ 2746f08c3bdfSopenharmony_ciint cpuset_move_all(struct cpuset_pidlist *pl, const char *relpath) 2747f08c3bdfSopenharmony_ci{ 2748f08c3bdfSopenharmony_ci int i; 2749f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 2750f08c3bdfSopenharmony_ci int ret; 2751f08c3bdfSopenharmony_ci 2752f08c3bdfSopenharmony_ci if (check() < 0) 2753f08c3bdfSopenharmony_ci return -1; 2754f08c3bdfSopenharmony_ci 2755f08c3bdfSopenharmony_ci fullpath2(buf, sizeof(buf), relpath, "tasks"); 2756f08c3bdfSopenharmony_ci 2757f08c3bdfSopenharmony_ci ret = 0; 2758f08c3bdfSopenharmony_ci for (i = 0; i < pl->npids; i++) 2759f08c3bdfSopenharmony_ci if (__cpuset_move(pl->pids[i], buf) < 0) 2760f08c3bdfSopenharmony_ci ret = -1; 2761f08c3bdfSopenharmony_ci return ret; 2762f08c3bdfSopenharmony_ci} 2763f08c3bdfSopenharmony_ci 2764f08c3bdfSopenharmony_ci/* 2765f08c3bdfSopenharmony_ci * [optional] cpuset_move_cpuset_tasks() - Move all tasks in a 2766f08c3bdfSopenharmony_ci * cpuset to another cpuset 2767f08c3bdfSopenharmony_ci * 2768f08c3bdfSopenharmony_ci * Move all tasks in cpuset fromrelpath to cpuset torelpath. This may 2769f08c3bdfSopenharmony_ci * race with tasks being added to or forking into fromrelpath. Loop 2770f08c3bdfSopenharmony_ci * repeatedly, reading the tasks file of cpuset fromrelpath and writing 2771f08c3bdfSopenharmony_ci * any task pid's found there to the tasks file of cpuset torelpath, 2772f08c3bdfSopenharmony_ci * up to ten attempts, or until the tasks file of cpuset fromrelpath 2773f08c3bdfSopenharmony_ci * is empty, or until fromrelpath is no longer present. 2774f08c3bdfSopenharmony_ci * 2775f08c3bdfSopenharmony_ci * Returns 0 with errno == 0 if able to empty the tasks file of cpuset 2776f08c3bdfSopenharmony_ci * fromrelpath. Of course it is still possible that some independent 2777f08c3bdfSopenharmony_ci * task could add another task to cpuset fromrelpath at the same time 2778f08c3bdfSopenharmony_ci * that such a successful result is being returned, so there can be 2779f08c3bdfSopenharmony_ci * no guarantee that a successful return means that fromrelpath is 2780f08c3bdfSopenharmony_ci * still empty of tasks. 2781f08c3bdfSopenharmony_ci * 2782f08c3bdfSopenharmony_ci * We are careful to allow for the possibility that the cpuset 2783f08c3bdfSopenharmony_ci * fromrelpath might disappear out from under us, perhaps because it 2784f08c3bdfSopenharmony_ci * has notify_on_release set and gets automatically removed as soon 2785f08c3bdfSopenharmony_ci * as we detach its last task from it. Consider a missing fromrelpath 2786f08c3bdfSopenharmony_ci * to be a successful move. 2787f08c3bdfSopenharmony_ci * 2788f08c3bdfSopenharmony_ci * If called with fromrelpath and torelpath pathnames that evaluate to 2789f08c3bdfSopenharmony_ci * the same cpuset, then treat that as if cpuset_reattach() was called, 2790f08c3bdfSopenharmony_ci * rebinding each task in this cpuset one time, and return success or 2791f08c3bdfSopenharmony_ci * failure depending on the return of that cpuset_reattach() call. 2792f08c3bdfSopenharmony_ci * 2793f08c3bdfSopenharmony_ci * On failure, returns -1, with errno possibly one of: 2794f08c3bdfSopenharmony_ci * EACCES - search permission denied on intervening directory 2795f08c3bdfSopenharmony_ci * ENOTEMPTY - tasks remain after multiple attempts to move them 2796f08c3bdfSopenharmony_ci * EMFILE - too many open files 2797f08c3bdfSopenharmony_ci * ENODEV - /dev/cpuset not mounted 2798f08c3bdfSopenharmony_ci * ENOENT - component of cpuset path doesn't exist 2799f08c3bdfSopenharmony_ci * ENOMEM - out of memory 2800f08c3bdfSopenharmony_ci * ENOSYS - kernel doesn't support cpusets 2801f08c3bdfSopenharmony_ci * ENOTDIR - component of cpuset path is not a directory 2802f08c3bdfSopenharmony_ci * EPERM - lacked permission to kill a task 2803f08c3bdfSopenharmony_ci * EPERM - lacked permission to read cpusets or files therein 2804f08c3bdfSopenharmony_ci * 2805f08c3bdfSopenharmony_ci * This is an [optional] function. Use cpuset_function to invoke it. 2806f08c3bdfSopenharmony_ci */ 2807f08c3bdfSopenharmony_ci 2808f08c3bdfSopenharmony_ci#define NUMBER_MOVE_TASK_ATTEMPTS 10 2809f08c3bdfSopenharmony_ci 2810f08c3bdfSopenharmony_ciint cpuset_move_cpuset_tasks(const char *fromrelpath, const char *torelpath) 2811f08c3bdfSopenharmony_ci{ 2812f08c3bdfSopenharmony_ci char fromfullpath[PATH_MAX]; 2813f08c3bdfSopenharmony_ci char tofullpath[PATH_MAX]; 2814f08c3bdfSopenharmony_ci int i; 2815f08c3bdfSopenharmony_ci struct cpuset_pidlist *pl = NULL; 2816f08c3bdfSopenharmony_ci int sav_errno; 2817f08c3bdfSopenharmony_ci 2818f08c3bdfSopenharmony_ci fullpath(fromfullpath, sizeof(fromfullpath), fromrelpath); 2819f08c3bdfSopenharmony_ci fullpath(tofullpath, sizeof(tofullpath), torelpath); 2820f08c3bdfSopenharmony_ci 2821f08c3bdfSopenharmony_ci if (samefile(fromfullpath, tofullpath)) 2822f08c3bdfSopenharmony_ci return cpuset_reattach(fromrelpath); 2823f08c3bdfSopenharmony_ci 2824f08c3bdfSopenharmony_ci for (i = 0; i < NUMBER_MOVE_TASK_ATTEMPTS; i++) { 2825f08c3bdfSopenharmony_ci int plen, j; 2826f08c3bdfSopenharmony_ci 2827f08c3bdfSopenharmony_ci if ((pl = cpuset_init_pidlist(fromrelpath, 0)) == NULL) { 2828f08c3bdfSopenharmony_ci /* missing cpuset is as good as if all moved */ 2829f08c3bdfSopenharmony_ci if (errno == ENOENT) 2830f08c3bdfSopenharmony_ci goto no_more_cpuset; 2831f08c3bdfSopenharmony_ci 2832f08c3bdfSopenharmony_ci /* other problems reading cpuset are bad news */ 2833f08c3bdfSopenharmony_ci sav_errno = errno; 2834f08c3bdfSopenharmony_ci goto failed; 2835f08c3bdfSopenharmony_ci } 2836f08c3bdfSopenharmony_ci 2837f08c3bdfSopenharmony_ci if ((plen = cpuset_pidlist_length(pl)) == 0) 2838f08c3bdfSopenharmony_ci goto no_more_pids; 2839f08c3bdfSopenharmony_ci 2840f08c3bdfSopenharmony_ci for (j = 0; j < plen; j++) { 2841f08c3bdfSopenharmony_ci pid_t pid; 2842f08c3bdfSopenharmony_ci 2843f08c3bdfSopenharmony_ci pid = cpuset_get_pidlist(pl, j); 2844f08c3bdfSopenharmony_ci if (cpuset_move(pid, torelpath) < 0) { 2845f08c3bdfSopenharmony_ci /* missing task is as good as if moved */ 2846f08c3bdfSopenharmony_ci if (errno == ESRCH) 2847f08c3bdfSopenharmony_ci continue; 2848f08c3bdfSopenharmony_ci 2849f08c3bdfSopenharmony_ci /* other per-task errors are bad news */ 2850f08c3bdfSopenharmony_ci sav_errno = errno; 2851f08c3bdfSopenharmony_ci goto failed; 2852f08c3bdfSopenharmony_ci } 2853f08c3bdfSopenharmony_ci } 2854f08c3bdfSopenharmony_ci 2855f08c3bdfSopenharmony_ci cpuset_freepidlist(pl); 2856f08c3bdfSopenharmony_ci pl = NULL; 2857f08c3bdfSopenharmony_ci } 2858f08c3bdfSopenharmony_ci 2859f08c3bdfSopenharmony_ci sav_errno = ENOTEMPTY; 2860f08c3bdfSopenharmony_ci /* fall into ... */ 2861f08c3bdfSopenharmony_cifailed: 2862f08c3bdfSopenharmony_ci cpuset_freepidlist(pl); 2863f08c3bdfSopenharmony_ci errno = sav_errno; 2864f08c3bdfSopenharmony_ci return -1; 2865f08c3bdfSopenharmony_ci 2866f08c3bdfSopenharmony_cino_more_pids: 2867f08c3bdfSopenharmony_cino_more_cpuset: 2868f08c3bdfSopenharmony_ci /* Success - all tasks (or entire cpuset ;) gone. */ 2869f08c3bdfSopenharmony_ci cpuset_freepidlist(pl); 2870f08c3bdfSopenharmony_ci errno = 0; 2871f08c3bdfSopenharmony_ci return 0; 2872f08c3bdfSopenharmony_ci} 2873f08c3bdfSopenharmony_ci 2874f08c3bdfSopenharmony_ci/* Migrate task (pid == 0 for current) to a cpuset (moves task and memory) */ 2875f08c3bdfSopenharmony_ciint cpuset_migrate(pid_t pid, const char *relpath) 2876f08c3bdfSopenharmony_ci{ 2877f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 2878f08c3bdfSopenharmony_ci char buf2[PATH_MAX]; 2879f08c3bdfSopenharmony_ci char memory_migrate_flag; 2880f08c3bdfSopenharmony_ci int r; 2881f08c3bdfSopenharmony_ci 2882f08c3bdfSopenharmony_ci if (check() < 0) 2883f08c3bdfSopenharmony_ci return -1; 2884f08c3bdfSopenharmony_ci 2885f08c3bdfSopenharmony_ci if (pid == 0) 2886f08c3bdfSopenharmony_ci pid = getpid(); 2887f08c3bdfSopenharmony_ci 2888f08c3bdfSopenharmony_ci fullpath(buf2, sizeof(buf2), relpath); 2889f08c3bdfSopenharmony_ci 2890f08c3bdfSopenharmony_ci if (load_flag(buf2, &memory_migrate_flag, "memory_migrate") < 0) 2891f08c3bdfSopenharmony_ci return -1; 2892f08c3bdfSopenharmony_ci if (store_flag(buf2, "memory_migrate", 1) < 0) 2893f08c3bdfSopenharmony_ci return -1; 2894f08c3bdfSopenharmony_ci 2895f08c3bdfSopenharmony_ci fullpath2(buf, sizeof(buf), relpath, "tasks"); 2896f08c3bdfSopenharmony_ci 2897f08c3bdfSopenharmony_ci r = __cpuset_move(pid, buf); 2898f08c3bdfSopenharmony_ci 2899f08c3bdfSopenharmony_ci store_flag(buf2, "memory_migrate", memory_migrate_flag); 2900f08c3bdfSopenharmony_ci return r; 2901f08c3bdfSopenharmony_ci} 2902f08c3bdfSopenharmony_ci 2903f08c3bdfSopenharmony_ci/* Migrate all tasks in pidlist to a cpuset (moves task and memory) */ 2904f08c3bdfSopenharmony_ciint cpuset_migrate_all(struct cpuset_pidlist *pl, const char *relpath) 2905f08c3bdfSopenharmony_ci{ 2906f08c3bdfSopenharmony_ci int i; 2907f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 2908f08c3bdfSopenharmony_ci char buf2[PATH_MAX]; 2909f08c3bdfSopenharmony_ci char memory_migrate_flag; 2910f08c3bdfSopenharmony_ci int ret; 2911f08c3bdfSopenharmony_ci 2912f08c3bdfSopenharmony_ci if (check() < 0) 2913f08c3bdfSopenharmony_ci return -1; 2914f08c3bdfSopenharmony_ci 2915f08c3bdfSopenharmony_ci fullpath(buf2, sizeof(buf2), relpath); 2916f08c3bdfSopenharmony_ci 2917f08c3bdfSopenharmony_ci if (load_flag(buf2, &memory_migrate_flag, "memory_migrate") < 0) 2918f08c3bdfSopenharmony_ci return -1; 2919f08c3bdfSopenharmony_ci if (store_flag(buf2, "memory_migrate", 1) < 0) 2920f08c3bdfSopenharmony_ci return -1; 2921f08c3bdfSopenharmony_ci 2922f08c3bdfSopenharmony_ci fullpath2(buf, sizeof(buf), relpath, "tasks"); 2923f08c3bdfSopenharmony_ci 2924f08c3bdfSopenharmony_ci ret = 0; 2925f08c3bdfSopenharmony_ci for (i = 0; i < pl->npids; i++) 2926f08c3bdfSopenharmony_ci if (__cpuset_move(pl->pids[i], buf) < 0) 2927f08c3bdfSopenharmony_ci ret = -1; 2928f08c3bdfSopenharmony_ci 2929f08c3bdfSopenharmony_ci if (store_flag(buf2, "memory_migrate", memory_migrate_flag) < 0) 2930f08c3bdfSopenharmony_ci ret = -1; 2931f08c3bdfSopenharmony_ci return ret; 2932f08c3bdfSopenharmony_ci} 2933f08c3bdfSopenharmony_ci 2934f08c3bdfSopenharmony_ci/* Rebind cpus_allowed of each task in cpuset 'path' */ 2935f08c3bdfSopenharmony_ciint cpuset_reattach(const char *relpath) 2936f08c3bdfSopenharmony_ci{ 2937f08c3bdfSopenharmony_ci struct cpuset_pidlist *pl; 2938f08c3bdfSopenharmony_ci int rc; 2939f08c3bdfSopenharmony_ci 2940f08c3bdfSopenharmony_ci if ((pl = cpuset_init_pidlist(relpath, 0)) == NULL) 2941f08c3bdfSopenharmony_ci return -1; 2942f08c3bdfSopenharmony_ci rc = cpuset_move_all(pl, relpath); 2943f08c3bdfSopenharmony_ci cpuset_freepidlist(pl); 2944f08c3bdfSopenharmony_ci return rc; 2945f08c3bdfSopenharmony_ci} 2946f08c3bdfSopenharmony_ci 2947f08c3bdfSopenharmony_ci/* Map cpuset relative cpu number to system wide cpu number */ 2948f08c3bdfSopenharmony_ciint cpuset_c_rel_to_sys_cpu(const struct cpuset *cp, int cpu) 2949f08c3bdfSopenharmony_ci{ 2950f08c3bdfSopenharmony_ci struct cpuset *cp_tofree = NULL; 2951f08c3bdfSopenharmony_ci const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree); 2952f08c3bdfSopenharmony_ci int pos = -1; 2953f08c3bdfSopenharmony_ci 2954f08c3bdfSopenharmony_ci if (!cp1) 2955f08c3bdfSopenharmony_ci goto err; 2956f08c3bdfSopenharmony_ci pos = bitmask_rel_to_abs_pos(cp1->cpus, cpu); 2957f08c3bdfSopenharmony_ci /* fall into ... */ 2958f08c3bdfSopenharmony_cierr: 2959f08c3bdfSopenharmony_ci cpuset_free(cp_tofree); 2960f08c3bdfSopenharmony_ci return pos; 2961f08c3bdfSopenharmony_ci} 2962f08c3bdfSopenharmony_ci 2963f08c3bdfSopenharmony_ci/* Map system wide cpu number to cpuset relative cpu number */ 2964f08c3bdfSopenharmony_ciint cpuset_c_sys_to_rel_cpu(const struct cpuset *cp, int cpu) 2965f08c3bdfSopenharmony_ci{ 2966f08c3bdfSopenharmony_ci struct cpuset *cp_tofree = NULL; 2967f08c3bdfSopenharmony_ci const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree); 2968f08c3bdfSopenharmony_ci int pos = -1; 2969f08c3bdfSopenharmony_ci 2970f08c3bdfSopenharmony_ci if (!cp1) 2971f08c3bdfSopenharmony_ci goto err; 2972f08c3bdfSopenharmony_ci pos = bitmask_abs_to_rel_pos(cp1->cpus, cpu); 2973f08c3bdfSopenharmony_ci /* fall into ... */ 2974f08c3bdfSopenharmony_cierr: 2975f08c3bdfSopenharmony_ci cpuset_free(cp_tofree); 2976f08c3bdfSopenharmony_ci return pos; 2977f08c3bdfSopenharmony_ci} 2978f08c3bdfSopenharmony_ci 2979f08c3bdfSopenharmony_ci/* Map cpuset relative mem number to system wide mem number */ 2980f08c3bdfSopenharmony_ciint cpuset_c_rel_to_sys_mem(const struct cpuset *cp, int mem) 2981f08c3bdfSopenharmony_ci{ 2982f08c3bdfSopenharmony_ci struct cpuset *cp_tofree = NULL; 2983f08c3bdfSopenharmony_ci const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree); 2984f08c3bdfSopenharmony_ci int pos = -1; 2985f08c3bdfSopenharmony_ci 2986f08c3bdfSopenharmony_ci if (!cp1) 2987f08c3bdfSopenharmony_ci goto err; 2988f08c3bdfSopenharmony_ci pos = bitmask_rel_to_abs_pos(cp1->mems, mem); 2989f08c3bdfSopenharmony_ci /* fall into ... */ 2990f08c3bdfSopenharmony_cierr: 2991f08c3bdfSopenharmony_ci cpuset_free(cp_tofree); 2992f08c3bdfSopenharmony_ci return pos; 2993f08c3bdfSopenharmony_ci} 2994f08c3bdfSopenharmony_ci 2995f08c3bdfSopenharmony_ci/* Map system wide mem number to cpuset relative mem number */ 2996f08c3bdfSopenharmony_ciint cpuset_c_sys_to_rel_mem(const struct cpuset *cp, int mem) 2997f08c3bdfSopenharmony_ci{ 2998f08c3bdfSopenharmony_ci struct cpuset *cp_tofree = NULL; 2999f08c3bdfSopenharmony_ci const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree); 3000f08c3bdfSopenharmony_ci int pos = -1; 3001f08c3bdfSopenharmony_ci 3002f08c3bdfSopenharmony_ci if (!cp1) 3003f08c3bdfSopenharmony_ci goto err; 3004f08c3bdfSopenharmony_ci pos = bitmask_abs_to_rel_pos(cp1->mems, mem); 3005f08c3bdfSopenharmony_ci /* fall into ... */ 3006f08c3bdfSopenharmony_cierr: 3007f08c3bdfSopenharmony_ci cpuset_free(cp_tofree); 3008f08c3bdfSopenharmony_ci return pos; 3009f08c3bdfSopenharmony_ci} 3010f08c3bdfSopenharmony_ci 3011f08c3bdfSopenharmony_ci/* Map pid's cpuset relative cpu number to system wide cpu number */ 3012f08c3bdfSopenharmony_ciint cpuset_p_rel_to_sys_cpu(pid_t pid, int cpu) 3013f08c3bdfSopenharmony_ci{ 3014f08c3bdfSopenharmony_ci struct cpuset *cp; 3015f08c3bdfSopenharmony_ci int rc = -1; 3016f08c3bdfSopenharmony_ci 3017f08c3bdfSopenharmony_ci if ((cp = cpuset_alloc()) == NULL) 3018f08c3bdfSopenharmony_ci goto done; 3019f08c3bdfSopenharmony_ci if (cpuset_cpusetofpid(cp, pid) < 0) 3020f08c3bdfSopenharmony_ci goto done; 3021f08c3bdfSopenharmony_ci rc = cpuset_c_rel_to_sys_cpu(cp, cpu); 3022f08c3bdfSopenharmony_cidone: 3023f08c3bdfSopenharmony_ci cpuset_free(cp); 3024f08c3bdfSopenharmony_ci return rc; 3025f08c3bdfSopenharmony_ci} 3026f08c3bdfSopenharmony_ci 3027f08c3bdfSopenharmony_ci/* Map system wide cpu number to pid's cpuset relative cpu number */ 3028f08c3bdfSopenharmony_ciint cpuset_p_sys_to_rel_cpu(pid_t pid, int cpu) 3029f08c3bdfSopenharmony_ci{ 3030f08c3bdfSopenharmony_ci struct cpuset *cp; 3031f08c3bdfSopenharmony_ci int rc = -1; 3032f08c3bdfSopenharmony_ci 3033f08c3bdfSopenharmony_ci if ((cp = cpuset_alloc()) == NULL) 3034f08c3bdfSopenharmony_ci goto done; 3035f08c3bdfSopenharmony_ci if (cpuset_cpusetofpid(cp, pid) < 0) 3036f08c3bdfSopenharmony_ci goto done; 3037f08c3bdfSopenharmony_ci rc = cpuset_c_sys_to_rel_cpu(cp, cpu); 3038f08c3bdfSopenharmony_cidone: 3039f08c3bdfSopenharmony_ci cpuset_free(cp); 3040f08c3bdfSopenharmony_ci return rc; 3041f08c3bdfSopenharmony_ci} 3042f08c3bdfSopenharmony_ci 3043f08c3bdfSopenharmony_ci/* Map pid's cpuset relative mem number to system wide mem number */ 3044f08c3bdfSopenharmony_ciint cpuset_p_rel_to_sys_mem(pid_t pid, int mem) 3045f08c3bdfSopenharmony_ci{ 3046f08c3bdfSopenharmony_ci struct cpuset *cp; 3047f08c3bdfSopenharmony_ci int rc = -1; 3048f08c3bdfSopenharmony_ci 3049f08c3bdfSopenharmony_ci if ((cp = cpuset_alloc()) == NULL) 3050f08c3bdfSopenharmony_ci goto done; 3051f08c3bdfSopenharmony_ci if (cpuset_cpusetofpid(cp, pid) < 0) 3052f08c3bdfSopenharmony_ci goto done; 3053f08c3bdfSopenharmony_ci rc = cpuset_c_rel_to_sys_mem(cp, mem); 3054f08c3bdfSopenharmony_cidone: 3055f08c3bdfSopenharmony_ci cpuset_free(cp); 3056f08c3bdfSopenharmony_ci return rc; 3057f08c3bdfSopenharmony_ci} 3058f08c3bdfSopenharmony_ci 3059f08c3bdfSopenharmony_ci/* Map system wide mem number to pid's cpuset relative mem number */ 3060f08c3bdfSopenharmony_ciint cpuset_p_sys_to_rel_mem(pid_t pid, int mem) 3061f08c3bdfSopenharmony_ci{ 3062f08c3bdfSopenharmony_ci struct cpuset *cp; 3063f08c3bdfSopenharmony_ci int rc = -1; 3064f08c3bdfSopenharmony_ci 3065f08c3bdfSopenharmony_ci if ((cp = cpuset_alloc()) == NULL) 3066f08c3bdfSopenharmony_ci goto done; 3067f08c3bdfSopenharmony_ci if (cpuset_cpusetofpid(cp, pid) < 0) 3068f08c3bdfSopenharmony_ci goto done; 3069f08c3bdfSopenharmony_ci rc = cpuset_c_sys_to_rel_mem(cp, mem); 3070f08c3bdfSopenharmony_cidone: 3071f08c3bdfSopenharmony_ci cpuset_free(cp); 3072f08c3bdfSopenharmony_ci return rc; 3073f08c3bdfSopenharmony_ci} 3074f08c3bdfSopenharmony_ci 3075f08c3bdfSopenharmony_ci/* 3076f08c3bdfSopenharmony_ci * Override glibc's calls for get/set affinity - they have 3077f08c3bdfSopenharmony_ci * something using cpu_set_t that will die when NR_CPUS > 1024. 3078f08c3bdfSopenharmony_ci * Go directly to the 'real' system calls. Also override calls 3079f08c3bdfSopenharmony_ci * for get_mempolicy and set_mempolicy. None of these 3080f08c3bdfSopenharmony_ci * calls are yet (July 2004) guaranteed to be in all glibc versions 3081f08c3bdfSopenharmony_ci * that we care about. 3082f08c3bdfSopenharmony_ci */ 3083f08c3bdfSopenharmony_ci 3084f08c3bdfSopenharmony_cistatic int sched_setaffinity(pid_t pid, unsigned len, unsigned long *mask) 3085f08c3bdfSopenharmony_ci{ 3086f08c3bdfSopenharmony_ci return tst_syscall(__NR_sched_setaffinity, pid, len, mask); 3087f08c3bdfSopenharmony_ci} 3088f08c3bdfSopenharmony_ci 3089f08c3bdfSopenharmony_cistatic int get_mempolicy(int *policy, unsigned long *nmask, 3090f08c3bdfSopenharmony_ci unsigned long maxnode, void *addr, int flags) 3091f08c3bdfSopenharmony_ci{ 3092f08c3bdfSopenharmony_ci return tst_syscall(__NR_get_mempolicy, policy, nmask, maxnode, 3093f08c3bdfSopenharmony_ci addr, flags); 3094f08c3bdfSopenharmony_ci} 3095f08c3bdfSopenharmony_ci 3096f08c3bdfSopenharmony_cistatic int set_mempolicy(int mode, unsigned long *nmask, unsigned long maxnode) 3097f08c3bdfSopenharmony_ci{ 3098f08c3bdfSopenharmony_ci return tst_syscall(__NR_set_mempolicy, mode, nmask, maxnode); 3099f08c3bdfSopenharmony_ci} 3100f08c3bdfSopenharmony_ci 3101f08c3bdfSopenharmony_cistruct cpuset_placement { 3102f08c3bdfSopenharmony_ci struct bitmask *cpus; 3103f08c3bdfSopenharmony_ci struct bitmask *mems; 3104f08c3bdfSopenharmony_ci char *path; 3105f08c3bdfSopenharmony_ci}; 3106f08c3bdfSopenharmony_ci 3107f08c3bdfSopenharmony_ci/* Allocate and fill in a placement struct - cpatures current placement */ 3108f08c3bdfSopenharmony_cistruct cpuset_placement *cpuset_get_placement(pid_t pid) 3109f08c3bdfSopenharmony_ci{ 3110f08c3bdfSopenharmony_ci struct cpuset_placement *plc; 3111f08c3bdfSopenharmony_ci struct cpuset *cp = NULL; 3112f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 3113f08c3bdfSopenharmony_ci int nbits; 3114f08c3bdfSopenharmony_ci 3115f08c3bdfSopenharmony_ci if ((plc = calloc(1, sizeof(*plc))) == NULL) 3116f08c3bdfSopenharmony_ci goto err; 3117f08c3bdfSopenharmony_ci 3118f08c3bdfSopenharmony_ci nbits = cpuset_cpus_nbits(); 3119f08c3bdfSopenharmony_ci if ((plc->cpus = bitmask_alloc(nbits)) == NULL) 3120f08c3bdfSopenharmony_ci goto err; 3121f08c3bdfSopenharmony_ci 3122f08c3bdfSopenharmony_ci nbits = cpuset_mems_nbits(); 3123f08c3bdfSopenharmony_ci if ((plc->mems = bitmask_alloc(nbits)) == NULL) 3124f08c3bdfSopenharmony_ci goto err; 3125f08c3bdfSopenharmony_ci 3126f08c3bdfSopenharmony_ci if ((cp = cpuset_alloc()) == NULL) 3127f08c3bdfSopenharmony_ci goto err; 3128f08c3bdfSopenharmony_ci if (cpuset_getcpusetpath(pid, buf, sizeof(buf)) == NULL) 3129f08c3bdfSopenharmony_ci goto err; 3130f08c3bdfSopenharmony_ci if (cpuset_query(cp, buf) < 0) 3131f08c3bdfSopenharmony_ci goto err; 3132f08c3bdfSopenharmony_ci 3133f08c3bdfSopenharmony_ci bitmask_copy(plc->cpus, cp->cpus); 3134f08c3bdfSopenharmony_ci bitmask_copy(plc->mems, cp->mems); 3135f08c3bdfSopenharmony_ci plc->path = strdup(buf); 3136f08c3bdfSopenharmony_ci 3137f08c3bdfSopenharmony_ci cpuset_free(cp); 3138f08c3bdfSopenharmony_ci return plc; 3139f08c3bdfSopenharmony_cierr: 3140f08c3bdfSopenharmony_ci cpuset_free(cp); 3141f08c3bdfSopenharmony_ci cpuset_free_placement(plc); 3142f08c3bdfSopenharmony_ci return NULL; 3143f08c3bdfSopenharmony_ci} 3144f08c3bdfSopenharmony_ci 3145f08c3bdfSopenharmony_ci/* Compare two placement structs - use to detect changes in placement */ 3146f08c3bdfSopenharmony_ciint cpuset_equal_placement(const struct cpuset_placement *plc1, 3147f08c3bdfSopenharmony_ci const struct cpuset_placement *plc2) 3148f08c3bdfSopenharmony_ci{ 3149f08c3bdfSopenharmony_ci return bitmask_equal(plc1->cpus, plc2->cpus) && 3150f08c3bdfSopenharmony_ci bitmask_equal(plc1->mems, plc2->mems) && 3151f08c3bdfSopenharmony_ci streq(plc1->path, plc2->path); 3152f08c3bdfSopenharmony_ci} 3153f08c3bdfSopenharmony_ci 3154f08c3bdfSopenharmony_ci/* Free a placement struct */ 3155f08c3bdfSopenharmony_civoid cpuset_free_placement(struct cpuset_placement *plc) 3156f08c3bdfSopenharmony_ci{ 3157f08c3bdfSopenharmony_ci if (!plc) 3158f08c3bdfSopenharmony_ci return; 3159f08c3bdfSopenharmony_ci bitmask_free(plc->cpus); 3160f08c3bdfSopenharmony_ci bitmask_free(plc->mems); 3161f08c3bdfSopenharmony_ci free(plc->path); 3162f08c3bdfSopenharmony_ci free(plc); 3163f08c3bdfSopenharmony_ci} 3164f08c3bdfSopenharmony_ci 3165f08c3bdfSopenharmony_ci/* 3166f08c3bdfSopenharmony_ci * A cpuset_fts_open() call constructs a linked list of entries 3167f08c3bdfSopenharmony_ci * called a "cpuset_fts_tree", with one entry per cpuset below 3168f08c3bdfSopenharmony_ci * the specified path. The cpuset_fts_read() routine returns the 3169f08c3bdfSopenharmony_ci * next entry on this list. The various cpuset_fts_get_*() calls 3170f08c3bdfSopenharmony_ci * return attributes of the specified entry. The cpuset_fts_close() 3171f08c3bdfSopenharmony_ci * call frees the linked list and all associated data. All cpuset 3172f08c3bdfSopenharmony_ci * entries and attributes for the cpuset_fts_tree returned from a 3173f08c3bdfSopenharmony_ci * given cpuset_fts_open() call remain allocated and unchanged until 3174f08c3bdfSopenharmony_ci * that cpuset_fts_tree is closed by a cpuset_fts_close() call. Any 3175f08c3bdfSopenharmony_ci * subsequent changes to the cpuset filesystem will go unnoticed 3176f08c3bdfSopenharmony_ci * (not affect open cpuset_fts_tree's.) 3177f08c3bdfSopenharmony_ci */ 3178f08c3bdfSopenharmony_ci 3179f08c3bdfSopenharmony_cistruct cpuset_fts_entry; 3180f08c3bdfSopenharmony_civoid cpuset_fts_rewind(struct cpuset_fts_tree *cs_tree); 3181f08c3bdfSopenharmony_ci 3182f08c3bdfSopenharmony_cistruct cpuset_fts_tree { 3183f08c3bdfSopenharmony_ci struct cpuset_fts_entry *head; /* head of linked entry list */ 3184f08c3bdfSopenharmony_ci struct cpuset_fts_entry *next; /* cpuset_fts_read() offset */ 3185f08c3bdfSopenharmony_ci}; 3186f08c3bdfSopenharmony_ci 3187f08c3bdfSopenharmony_cistruct cpuset_fts_entry { 3188f08c3bdfSopenharmony_ci struct cpuset_fts_entry *next; /* linked entry list chain */ 3189f08c3bdfSopenharmony_ci struct cpuset *cpuset; 3190f08c3bdfSopenharmony_ci struct stat *stat; 3191f08c3bdfSopenharmony_ci char *path; 3192f08c3bdfSopenharmony_ci int info; 3193f08c3bdfSopenharmony_ci int err; 3194f08c3bdfSopenharmony_ci}; 3195f08c3bdfSopenharmony_ci 3196f08c3bdfSopenharmony_ci/* Open a handle on a cpuset hierarchy. All the real work is done here. */ 3197f08c3bdfSopenharmony_cistruct cpuset_fts_tree *cpuset_fts_open(const char *cpusetpath) 3198f08c3bdfSopenharmony_ci{ 3199f08c3bdfSopenharmony_ci FTS *fts = NULL; 3200f08c3bdfSopenharmony_ci FTSENT *ftsent; 3201f08c3bdfSopenharmony_ci char *path_argv[2]; 3202f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 3203f08c3bdfSopenharmony_ci struct cpuset_fts_tree *cs_tree = NULL; 3204f08c3bdfSopenharmony_ci struct cpuset_fts_entry *ep; /* the latest new list entry */ 3205f08c3bdfSopenharmony_ci struct cpuset_fts_entry **pnlep; /* ptr to next list entry ptr */ 3206f08c3bdfSopenharmony_ci char *relpath; 3207f08c3bdfSopenharmony_ci int fts_flags; 3208f08c3bdfSopenharmony_ci 3209f08c3bdfSopenharmony_ci fullpath(buf, sizeof(buf), cpusetpath); 3210f08c3bdfSopenharmony_ci path_argv[0] = buf; 3211f08c3bdfSopenharmony_ci path_argv[1] = NULL; 3212f08c3bdfSopenharmony_ci 3213f08c3bdfSopenharmony_ci fts_flags = FTS_PHYSICAL | FTS_NOCHDIR | FTS_NOSTAT | FTS_XDEV; 3214f08c3bdfSopenharmony_ci fts = fts_open(path_argv, fts_flags, NULL); 3215f08c3bdfSopenharmony_ci if (fts == NULL) 3216f08c3bdfSopenharmony_ci goto err; 3217f08c3bdfSopenharmony_ci 3218f08c3bdfSopenharmony_ci cs_tree = malloc(sizeof(*cs_tree)); 3219f08c3bdfSopenharmony_ci if (cs_tree == NULL) 3220f08c3bdfSopenharmony_ci goto err; 3221f08c3bdfSopenharmony_ci pnlep = &cs_tree->head; 3222f08c3bdfSopenharmony_ci *pnlep = NULL; 3223f08c3bdfSopenharmony_ci 3224f08c3bdfSopenharmony_ci while ((ftsent = fts_read(fts)) != NULL) { 3225f08c3bdfSopenharmony_ci if (ftsent->fts_info != FTS_D && ftsent->fts_info != FTS_DNR) 3226f08c3bdfSopenharmony_ci continue; 3227f08c3bdfSopenharmony_ci 3228f08c3bdfSopenharmony_ci /* ftsent is a directory (perhaps unreadable) ==> cpuset */ 3229f08c3bdfSopenharmony_ci ep = calloc(1, sizeof(*ep)); 3230f08c3bdfSopenharmony_ci if (ep == NULL) 3231f08c3bdfSopenharmony_ci goto err; 3232f08c3bdfSopenharmony_ci *pnlep = ep; 3233f08c3bdfSopenharmony_ci pnlep = &ep->next; 3234f08c3bdfSopenharmony_ci 3235f08c3bdfSopenharmony_ci /* Set entry's path, and if DNR, error */ 3236f08c3bdfSopenharmony_ci relpath = ftsent->fts_path + strlen(cpusetmnt); 3237f08c3bdfSopenharmony_ci if (strlen(relpath) == 0) 3238f08c3bdfSopenharmony_ci relpath = "/"; 3239f08c3bdfSopenharmony_ci ep->path = strdup(relpath); 3240f08c3bdfSopenharmony_ci if (ep->path == NULL) 3241f08c3bdfSopenharmony_ci goto err; 3242f08c3bdfSopenharmony_ci if (ftsent->fts_info == FTS_DNR) { 3243f08c3bdfSopenharmony_ci ep->info = CPUSET_FTS_ERR_DNR; 3244f08c3bdfSopenharmony_ci ep->err = ftsent->fts_errno; 3245f08c3bdfSopenharmony_ci continue; 3246f08c3bdfSopenharmony_ci } 3247f08c3bdfSopenharmony_ci 3248f08c3bdfSopenharmony_ci /* ftsent is a -readable- cpuset: set entry's stat, etc */ 3249f08c3bdfSopenharmony_ci ep->stat = calloc(1, sizeof(struct stat)); 3250f08c3bdfSopenharmony_ci if (ep->stat == NULL) 3251f08c3bdfSopenharmony_ci goto err; 3252f08c3bdfSopenharmony_ci if (stat(ftsent->fts_path, ep->stat) < 0) { 3253f08c3bdfSopenharmony_ci ep->info = CPUSET_FTS_ERR_STAT; 3254f08c3bdfSopenharmony_ci ep->err = ftsent->fts_errno; 3255f08c3bdfSopenharmony_ci continue; 3256f08c3bdfSopenharmony_ci } 3257f08c3bdfSopenharmony_ci 3258f08c3bdfSopenharmony_ci ep->cpuset = calloc(1, sizeof(struct cpuset)); 3259f08c3bdfSopenharmony_ci if (ep->cpuset == NULL) 3260f08c3bdfSopenharmony_ci goto err; 3261f08c3bdfSopenharmony_ci if (cpuset_query(ep->cpuset, relpath) < 0) { 3262f08c3bdfSopenharmony_ci ep->info = CPUSET_FTS_ERR_CPUSET; 3263f08c3bdfSopenharmony_ci ep->err = errno; 3264f08c3bdfSopenharmony_ci continue; 3265f08c3bdfSopenharmony_ci } 3266f08c3bdfSopenharmony_ci ep->info = CPUSET_FTS_CPUSET; 3267f08c3bdfSopenharmony_ci } 3268f08c3bdfSopenharmony_ci 3269f08c3bdfSopenharmony_ci (void)fts_close(fts); 3270f08c3bdfSopenharmony_ci cpuset_fts_rewind(cs_tree); 3271f08c3bdfSopenharmony_ci return cs_tree; 3272f08c3bdfSopenharmony_ci 3273f08c3bdfSopenharmony_cierr: 3274f08c3bdfSopenharmony_ci if (cs_tree) 3275f08c3bdfSopenharmony_ci cpuset_fts_close(cs_tree); 3276f08c3bdfSopenharmony_ci if (fts) 3277f08c3bdfSopenharmony_ci (void)fts_close(fts); 3278f08c3bdfSopenharmony_ci return NULL; 3279f08c3bdfSopenharmony_ci} 3280f08c3bdfSopenharmony_ci 3281f08c3bdfSopenharmony_ci/* Return pointer to next cpuset entry in hierarchy */ 3282f08c3bdfSopenharmony_ciconst struct cpuset_fts_entry *cpuset_fts_read(struct cpuset_fts_tree *cs_tree) 3283f08c3bdfSopenharmony_ci{ 3284f08c3bdfSopenharmony_ci const struct cpuset_fts_entry *cs_entry = cs_tree->next; 3285f08c3bdfSopenharmony_ci if (cs_tree->next != NULL) /* seek to next entry */ 3286f08c3bdfSopenharmony_ci cs_tree->next = cs_tree->next->next; 3287f08c3bdfSopenharmony_ci return cs_entry; 3288f08c3bdfSopenharmony_ci} 3289f08c3bdfSopenharmony_ci 3290f08c3bdfSopenharmony_ci/* Reverse list of cpusets, in place. Simulates pre-order/post-order flip. */ 3291f08c3bdfSopenharmony_civoid cpuset_fts_reverse(struct cpuset_fts_tree *cs_tree) 3292f08c3bdfSopenharmony_ci{ 3293f08c3bdfSopenharmony_ci struct cpuset_fts_entry *cs1, *cs2, *cs3; 3294f08c3bdfSopenharmony_ci 3295f08c3bdfSopenharmony_ci /* 3296f08c3bdfSopenharmony_ci * At each step, cs1 < cs2 < cs3 and the cs2->next pointer 3297f08c3bdfSopenharmony_ci * is redirected from cs3 to cs1. 3298f08c3bdfSopenharmony_ci */ 3299f08c3bdfSopenharmony_ci 3300f08c3bdfSopenharmony_ci cs1 = cs2 = NULL; 3301f08c3bdfSopenharmony_ci cs3 = cs_tree->head; 3302f08c3bdfSopenharmony_ci while (cs3) { 3303f08c3bdfSopenharmony_ci cs1 = cs2; 3304f08c3bdfSopenharmony_ci cs2 = cs3; 3305f08c3bdfSopenharmony_ci cs3 = cs3->next; 3306f08c3bdfSopenharmony_ci cs2->next = cs1; 3307f08c3bdfSopenharmony_ci } 3308f08c3bdfSopenharmony_ci cs_tree->head = cs2; 3309f08c3bdfSopenharmony_ci cpuset_fts_rewind(cs_tree); 3310f08c3bdfSopenharmony_ci} 3311f08c3bdfSopenharmony_ci 3312f08c3bdfSopenharmony_ci/* Rewind cpuset list to beginning */ 3313f08c3bdfSopenharmony_civoid cpuset_fts_rewind(struct cpuset_fts_tree *cs_tree) 3314f08c3bdfSopenharmony_ci{ 3315f08c3bdfSopenharmony_ci cs_tree->next = cs_tree->head; 3316f08c3bdfSopenharmony_ci} 3317f08c3bdfSopenharmony_ci 3318f08c3bdfSopenharmony_ci/* Return pointer to nul-terminated cpuset path of entry in hierarchy */ 3319f08c3bdfSopenharmony_ciconst char *cpuset_fts_get_path(const struct cpuset_fts_entry *cs_entry) 3320f08c3bdfSopenharmony_ci{ 3321f08c3bdfSopenharmony_ci return cs_entry->path; 3322f08c3bdfSopenharmony_ci} 3323f08c3bdfSopenharmony_ci 3324f08c3bdfSopenharmony_ci/* Return pointer to stat(2) structure of a cpuset entry's directory */ 3325f08c3bdfSopenharmony_ciconst struct stat *cpuset_fts_get_stat(const struct cpuset_fts_entry *cs_entry) 3326f08c3bdfSopenharmony_ci{ 3327f08c3bdfSopenharmony_ci return cs_entry->stat; 3328f08c3bdfSopenharmony_ci} 3329f08c3bdfSopenharmony_ci 3330f08c3bdfSopenharmony_ci/* Return pointer to cpuset structure of a cpuset entry */ 3331f08c3bdfSopenharmony_ciconst struct cpuset *cpuset_fts_get_cpuset(const struct cpuset_fts_entry 3332f08c3bdfSopenharmony_ci *cs_entry) 3333f08c3bdfSopenharmony_ci{ 3334f08c3bdfSopenharmony_ci return cs_entry->cpuset; 3335f08c3bdfSopenharmony_ci} 3336f08c3bdfSopenharmony_ci 3337f08c3bdfSopenharmony_ci/* Return value of errno (0 if no error) on attempted cpuset operations */ 3338f08c3bdfSopenharmony_ciint cpuset_fts_get_errno(const struct cpuset_fts_entry *cs_entry) 3339f08c3bdfSopenharmony_ci{ 3340f08c3bdfSopenharmony_ci return cs_entry->err; 3341f08c3bdfSopenharmony_ci} 3342f08c3bdfSopenharmony_ci 3343f08c3bdfSopenharmony_ci/* Return operation identity causing error */ 3344f08c3bdfSopenharmony_ciint cpuset_fts_get_info(const struct cpuset_fts_entry *cs_entry) 3345f08c3bdfSopenharmony_ci{ 3346f08c3bdfSopenharmony_ci return cs_entry->info; 3347f08c3bdfSopenharmony_ci} 3348f08c3bdfSopenharmony_ci 3349f08c3bdfSopenharmony_ci/* Close a cpuset hierarchy handle (free's all associated memory) */ 3350f08c3bdfSopenharmony_civoid cpuset_fts_close(struct cpuset_fts_tree *cs_tree) 3351f08c3bdfSopenharmony_ci{ 3352f08c3bdfSopenharmony_ci struct cpuset_fts_entry *cs_entry = cs_tree->head; 3353f08c3bdfSopenharmony_ci 3354f08c3bdfSopenharmony_ci while (cs_entry) { 3355f08c3bdfSopenharmony_ci struct cpuset_fts_entry *ep = cs_entry; 3356f08c3bdfSopenharmony_ci 3357f08c3bdfSopenharmony_ci cs_entry = cs_entry->next; 3358f08c3bdfSopenharmony_ci free(ep->path); 3359f08c3bdfSopenharmony_ci free(ep->stat); 3360f08c3bdfSopenharmony_ci cpuset_free(ep->cpuset); 3361f08c3bdfSopenharmony_ci free(ep); 3362f08c3bdfSopenharmony_ci } 3363f08c3bdfSopenharmony_ci free(cs_tree); 3364f08c3bdfSopenharmony_ci} 3365f08c3bdfSopenharmony_ci 3366f08c3bdfSopenharmony_ci/* Bind current task to cpu (uses sched_setaffinity(2)) */ 3367f08c3bdfSopenharmony_ciint cpuset_cpubind(int cpu) 3368f08c3bdfSopenharmony_ci{ 3369f08c3bdfSopenharmony_ci struct bitmask *bmp; 3370f08c3bdfSopenharmony_ci int r; 3371f08c3bdfSopenharmony_ci 3372f08c3bdfSopenharmony_ci if ((bmp = bitmask_alloc(cpuset_cpus_nbits())) == NULL) 3373f08c3bdfSopenharmony_ci return -1; 3374f08c3bdfSopenharmony_ci bitmask_setbit(bmp, cpu); 3375f08c3bdfSopenharmony_ci r = sched_setaffinity(0, bitmask_nbytes(bmp), bitmask_mask(bmp)); 3376f08c3bdfSopenharmony_ci bitmask_free(bmp); 3377f08c3bdfSopenharmony_ci return r; 3378f08c3bdfSopenharmony_ci} 3379f08c3bdfSopenharmony_ci 3380f08c3bdfSopenharmony_ci/* 3381f08c3bdfSopenharmony_ci * int cpuset_latestcpu(pid_t pid) 3382f08c3bdfSopenharmony_ci * 3383f08c3bdfSopenharmony_ci * Return most recent CPU on which task pid executed. If pid == 0, 3384f08c3bdfSopenharmony_ci * examine current task. 3385f08c3bdfSopenharmony_ci * 3386f08c3bdfSopenharmony_ci * The last used CPU is visible for a given pid as field #39 (starting 3387f08c3bdfSopenharmony_ci * with #1) in the file /proc/pid/stat. Currently this file has 41 3388f08c3bdfSopenharmony_ci * fields, in which case this is the 3rd to the last field. 3389f08c3bdfSopenharmony_ci * 3390f08c3bdfSopenharmony_ci * Unfortunately field #2 is a command name and might have embedded 3391f08c3bdfSopenharmony_ci * whitespace. So we can't just count white space separated fields. 3392f08c3bdfSopenharmony_ci * Fortunately, this command name is surrounded by parentheses, as 3393f08c3bdfSopenharmony_ci * for example "(sh)", and that closing parenthesis is the last ')' 3394f08c3bdfSopenharmony_ci * character in the line. No remaining fields can have embedded 3395f08c3bdfSopenharmony_ci * whitespace or parentheses. So instead of looking for the 39th 3396f08c3bdfSopenharmony_ci * white space separated field, we can look for the 37th white space 3397f08c3bdfSopenharmony_ci * separated field past the last ')' character on the line. 3398f08c3bdfSopenharmony_ci */ 3399f08c3bdfSopenharmony_ci 3400f08c3bdfSopenharmony_ci/* Return most recent CPU on which task pid executed */ 3401f08c3bdfSopenharmony_ciint cpuset_latestcpu(pid_t pid) 3402f08c3bdfSopenharmony_ci{ 3403f08c3bdfSopenharmony_ci char buf[PATH_MAX]; 3404f08c3bdfSopenharmony_ci char *bp; 3405f08c3bdfSopenharmony_ci int fd = -1; 3406f08c3bdfSopenharmony_ci int cpu = -1; 3407f08c3bdfSopenharmony_ci 3408f08c3bdfSopenharmony_ci if (pid == 0) 3409f08c3bdfSopenharmony_ci snprintf(buf, sizeof(buf), "/proc/self/stat"); 3410f08c3bdfSopenharmony_ci else 3411f08c3bdfSopenharmony_ci snprintf(buf, sizeof(buf), "/proc/%d/stat", pid); 3412f08c3bdfSopenharmony_ci 3413f08c3bdfSopenharmony_ci if ((fd = open(buf, O_RDONLY)) < 0) 3414f08c3bdfSopenharmony_ci goto err; 3415f08c3bdfSopenharmony_ci if (read(fd, buf, sizeof(buf)) < 1) 3416f08c3bdfSopenharmony_ci goto err; 3417f08c3bdfSopenharmony_ci close(fd); 3418f08c3bdfSopenharmony_ci 3419f08c3bdfSopenharmony_ci bp = strrchr(buf, ')'); 3420f08c3bdfSopenharmony_ci if (bp) 3421f08c3bdfSopenharmony_ci sscanf(bp + 1, "%*s %*u %*u %*u %*u %*u %*u %*u " "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u " "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u " "%*u %*u %*u %*u %*u %*u %*u %*u %u", /* 37th field past ')' */ 3422f08c3bdfSopenharmony_ci &cpu); 3423f08c3bdfSopenharmony_ci if (cpu < 0) 3424f08c3bdfSopenharmony_ci errno = EINVAL; 3425f08c3bdfSopenharmony_ci return cpu; 3426f08c3bdfSopenharmony_cierr: 3427f08c3bdfSopenharmony_ci if (fd >= 0) 3428f08c3bdfSopenharmony_ci close(fd); 3429f08c3bdfSopenharmony_ci return -1; 3430f08c3bdfSopenharmony_ci} 3431f08c3bdfSopenharmony_ci 3432f08c3bdfSopenharmony_ci/* Bind current task to memory (uses set_mempolicy(2)) */ 3433f08c3bdfSopenharmony_ciint cpuset_membind(int mem) 3434f08c3bdfSopenharmony_ci{ 3435f08c3bdfSopenharmony_ci struct bitmask *bmp; 3436f08c3bdfSopenharmony_ci int r; 3437f08c3bdfSopenharmony_ci 3438f08c3bdfSopenharmony_ci if ((bmp = bitmask_alloc(cpuset_mems_nbits())) == NULL) 3439f08c3bdfSopenharmony_ci return -1; 3440f08c3bdfSopenharmony_ci bitmask_setbit(bmp, mem); 3441f08c3bdfSopenharmony_ci r = set_mempolicy(MPOL_BIND, bitmask_mask(bmp), bitmask_nbits(bmp) + 1); 3442f08c3bdfSopenharmony_ci bitmask_free(bmp); 3443f08c3bdfSopenharmony_ci return r; 3444f08c3bdfSopenharmony_ci} 3445f08c3bdfSopenharmony_ci 3446f08c3bdfSopenharmony_ci/* [optional] Return Memory Node holding page at specified addr */ 3447f08c3bdfSopenharmony_ciint cpuset_addr2node(void *addr) 3448f08c3bdfSopenharmony_ci{ 3449f08c3bdfSopenharmony_ci int node = -1; 3450f08c3bdfSopenharmony_ci 3451f08c3bdfSopenharmony_ci if (get_mempolicy(&node, NULL, 0, addr, MPOL_F_NODE | MPOL_F_ADDR)) { 3452f08c3bdfSopenharmony_ci /* I realize this seems redundant, but I _want_ to make sure 3453f08c3bdfSopenharmony_ci * that this value is -1. */ 3454f08c3bdfSopenharmony_ci node = -1; 3455f08c3bdfSopenharmony_ci } 3456f08c3bdfSopenharmony_ci return node; 3457f08c3bdfSopenharmony_ci} 3458f08c3bdfSopenharmony_ci 3459f08c3bdfSopenharmony_ci/* 3460f08c3bdfSopenharmony_ci * Transform cpuset into Text Format Representation in buffer 'buf', 3461f08c3bdfSopenharmony_ci * of length 'buflen', nul-terminated if space allows. Return number 3462f08c3bdfSopenharmony_ci * of characters that would have been written, if enough space had 3463f08c3bdfSopenharmony_ci * been available, in the same way that snprintf() does. 3464f08c3bdfSopenharmony_ci */ 3465f08c3bdfSopenharmony_ci 3466f08c3bdfSopenharmony_ci/* Export cpuset settings to a regular file */ 3467f08c3bdfSopenharmony_ciint cpuset_export(const struct cpuset *cp, char *buf, int buflen) 3468f08c3bdfSopenharmony_ci{ 3469f08c3bdfSopenharmony_ci char *tmp = NULL; 3470f08c3bdfSopenharmony_ci int n = 0; 3471f08c3bdfSopenharmony_ci 3472f08c3bdfSopenharmony_ci if (cp->cpu_exclusive) 3473f08c3bdfSopenharmony_ci n += snprintf(buf + n, MAX(buflen - n, 0), "cpu_exclusive\n"); 3474f08c3bdfSopenharmony_ci 3475f08c3bdfSopenharmony_ci if (cp->mem_exclusive) 3476f08c3bdfSopenharmony_ci n += snprintf(buf + n, MAX(buflen - n, 0), "mem_exclusive\n"); 3477f08c3bdfSopenharmony_ci 3478f08c3bdfSopenharmony_ci if (cp->notify_on_release) 3479f08c3bdfSopenharmony_ci n += snprintf(buf + n, MAX(buflen - n, 0), 3480f08c3bdfSopenharmony_ci "notify_on_release\n"); 3481f08c3bdfSopenharmony_ci 3482f08c3bdfSopenharmony_ci if (cp->memory_pressure_enabled) 3483f08c3bdfSopenharmony_ci n += snprintf(buf + n, MAX(buflen - n, 0), 3484f08c3bdfSopenharmony_ci "memory_pressure_enabled\n"); 3485f08c3bdfSopenharmony_ci 3486f08c3bdfSopenharmony_ci if (cp->memory_migrate) 3487f08c3bdfSopenharmony_ci n += snprintf(buf + n, MAX(buflen - n, 0), "memory_migrate\n"); 3488f08c3bdfSopenharmony_ci 3489f08c3bdfSopenharmony_ci if (cp->memory_spread_page) 3490f08c3bdfSopenharmony_ci n += snprintf(buf + n, MAX(buflen - n, 0), 3491f08c3bdfSopenharmony_ci "memory_spread_page\n"); 3492f08c3bdfSopenharmony_ci 3493f08c3bdfSopenharmony_ci if (cp->memory_spread_slab) 3494f08c3bdfSopenharmony_ci n += snprintf(buf + n, MAX(buflen - n, 0), 3495f08c3bdfSopenharmony_ci "memory_spread_slab\n"); 3496f08c3bdfSopenharmony_ci 3497f08c3bdfSopenharmony_ci if ((tmp = sprint_mask_buf(cp->cpus)) == NULL) 3498f08c3bdfSopenharmony_ci return -1; 3499f08c3bdfSopenharmony_ci n += snprintf(buf + n, MAX(buflen - n, 0), "cpus %s\n", tmp); 3500f08c3bdfSopenharmony_ci free(tmp); 3501f08c3bdfSopenharmony_ci tmp = NULL; 3502f08c3bdfSopenharmony_ci 3503f08c3bdfSopenharmony_ci if ((tmp = sprint_mask_buf(cp->mems)) == NULL) 3504f08c3bdfSopenharmony_ci return -1; 3505f08c3bdfSopenharmony_ci n += snprintf(buf + n, MAX(buflen - n, 0), "mems %s\n", tmp); 3506f08c3bdfSopenharmony_ci free(tmp); 3507f08c3bdfSopenharmony_ci tmp = NULL; 3508f08c3bdfSopenharmony_ci 3509f08c3bdfSopenharmony_ci return n; 3510f08c3bdfSopenharmony_ci} 3511f08c3bdfSopenharmony_ci 3512f08c3bdfSopenharmony_cistatic int import_list(UNUSED const char *tok, const char *arg, 3513f08c3bdfSopenharmony_ci struct bitmask *bmp, char *emsg, int elen) 3514f08c3bdfSopenharmony_ci{ 3515f08c3bdfSopenharmony_ci if (bitmask_parselist(arg, bmp) < 0) { 3516f08c3bdfSopenharmony_ci if (emsg) 3517f08c3bdfSopenharmony_ci snprintf(emsg, elen, "Invalid list format: %s", arg); 3518f08c3bdfSopenharmony_ci return -1; 3519f08c3bdfSopenharmony_ci } 3520f08c3bdfSopenharmony_ci return 0; 3521f08c3bdfSopenharmony_ci} 3522f08c3bdfSopenharmony_ci 3523f08c3bdfSopenharmony_cistatic void stolower(char *s) 3524f08c3bdfSopenharmony_ci{ 3525f08c3bdfSopenharmony_ci while (*s) { 3526f08c3bdfSopenharmony_ci unsigned char c = *s; 3527f08c3bdfSopenharmony_ci *s = tolower(c); 3528f08c3bdfSopenharmony_ci s++; 3529f08c3bdfSopenharmony_ci } 3530f08c3bdfSopenharmony_ci} 3531f08c3bdfSopenharmony_ci 3532f08c3bdfSopenharmony_ci/* Import cpuset settings from a regular file */ 3533f08c3bdfSopenharmony_ciint cpuset_import(struct cpuset *cp, const char *buf, int *elinenum, 3534f08c3bdfSopenharmony_ci char *emsg, int elen) 3535f08c3bdfSopenharmony_ci{ 3536f08c3bdfSopenharmony_ci char *linebuf = NULL; 3537f08c3bdfSopenharmony_ci int linebuflen; 3538f08c3bdfSopenharmony_ci int linenum = 0; 3539f08c3bdfSopenharmony_ci int offset = 0; 3540f08c3bdfSopenharmony_ci 3541f08c3bdfSopenharmony_ci linebuflen = strlen(buf) + 1; 3542f08c3bdfSopenharmony_ci if ((linebuf = malloc(linebuflen)) == NULL) { 3543f08c3bdfSopenharmony_ci if (emsg) 3544f08c3bdfSopenharmony_ci snprintf(emsg, elen, "Insufficient memory"); 3545f08c3bdfSopenharmony_ci goto err; 3546f08c3bdfSopenharmony_ci } 3547f08c3bdfSopenharmony_ci 3548f08c3bdfSopenharmony_ci while (slgets(linebuf, linebuflen, buf, &offset)) { 3549f08c3bdfSopenharmony_ci char *tok, *arg; 3550f08c3bdfSopenharmony_ci char *ptr; /* for strtok_r */ 3551f08c3bdfSopenharmony_ci 3552f08c3bdfSopenharmony_ci linenum++; 3553f08c3bdfSopenharmony_ci if ((tok = strchr(linebuf, '#')) != NULL) 3554f08c3bdfSopenharmony_ci *tok = 0; 3555f08c3bdfSopenharmony_ci if ((tok = strtok_r(linebuf, " \t", &ptr)) == NULL) 3556f08c3bdfSopenharmony_ci continue; 3557f08c3bdfSopenharmony_ci stolower(tok); 3558f08c3bdfSopenharmony_ci 3559f08c3bdfSopenharmony_ci arg = strtok_r(0, " \t", &ptr); 3560f08c3bdfSopenharmony_ci 3561f08c3bdfSopenharmony_ci if (streq(tok, "cpu_exclusive")) { 3562f08c3bdfSopenharmony_ci cp->cpu_exclusive = 1; 3563f08c3bdfSopenharmony_ci goto eol; 3564f08c3bdfSopenharmony_ci } 3565f08c3bdfSopenharmony_ci if (streq(tok, "mem_exclusive")) { 3566f08c3bdfSopenharmony_ci cp->mem_exclusive = 1; 3567f08c3bdfSopenharmony_ci goto eol; 3568f08c3bdfSopenharmony_ci } 3569f08c3bdfSopenharmony_ci if (streq(tok, "notify_on_release")) { 3570f08c3bdfSopenharmony_ci cp->notify_on_release = 1; 3571f08c3bdfSopenharmony_ci goto eol; 3572f08c3bdfSopenharmony_ci } 3573f08c3bdfSopenharmony_ci if (streq(tok, "memory_pressure_enabled")) { 3574f08c3bdfSopenharmony_ci cp->memory_pressure_enabled = 1; 3575f08c3bdfSopenharmony_ci goto eol; 3576f08c3bdfSopenharmony_ci } 3577f08c3bdfSopenharmony_ci if (streq(tok, "memory_migrate")) { 3578f08c3bdfSopenharmony_ci cp->memory_migrate = 1; 3579f08c3bdfSopenharmony_ci goto eol; 3580f08c3bdfSopenharmony_ci } 3581f08c3bdfSopenharmony_ci if (streq(tok, "memory_spread_page")) { 3582f08c3bdfSopenharmony_ci cp->memory_spread_page = 1; 3583f08c3bdfSopenharmony_ci goto eol; 3584f08c3bdfSopenharmony_ci } 3585f08c3bdfSopenharmony_ci if (streq(tok, "memory_spread_slab")) { 3586f08c3bdfSopenharmony_ci cp->memory_spread_slab = 1; 3587f08c3bdfSopenharmony_ci goto eol; 3588f08c3bdfSopenharmony_ci } 3589f08c3bdfSopenharmony_ci if (streq(tok, "cpu") || streq(tok, "cpus")) { 3590f08c3bdfSopenharmony_ci if (import_list(tok, arg, cp->cpus, emsg, elen) < 0) 3591f08c3bdfSopenharmony_ci goto err; 3592f08c3bdfSopenharmony_ci goto eol; 3593f08c3bdfSopenharmony_ci } 3594f08c3bdfSopenharmony_ci if (streq(tok, "mem") || streq(tok, "mems")) { 3595f08c3bdfSopenharmony_ci if (import_list(tok, arg, cp->mems, emsg, elen) < 0) 3596f08c3bdfSopenharmony_ci goto err; 3597f08c3bdfSopenharmony_ci goto eol; 3598f08c3bdfSopenharmony_ci } 3599f08c3bdfSopenharmony_ci if (emsg) 3600f08c3bdfSopenharmony_ci snprintf(emsg, elen, "Unrecognized token: '%s'", tok); 3601f08c3bdfSopenharmony_ci goto err; 3602f08c3bdfSopenharmony_cieol: 3603f08c3bdfSopenharmony_ci if ((tok = strtok_r(0, " \t", &ptr)) != NULL) { 3604f08c3bdfSopenharmony_ci if (emsg) 3605f08c3bdfSopenharmony_ci snprintf(emsg, elen, "Surplus token: '%s'", 3606f08c3bdfSopenharmony_ci tok); 3607f08c3bdfSopenharmony_ci goto err; 3608f08c3bdfSopenharmony_ci } 3609f08c3bdfSopenharmony_ci continue; 3610f08c3bdfSopenharmony_ci } 3611f08c3bdfSopenharmony_ci 3612f08c3bdfSopenharmony_ci free(linebuf); 3613f08c3bdfSopenharmony_ci 3614f08c3bdfSopenharmony_ci if (bitmask_isallclear(cp->cpus) && !bitmask_isallclear(cp->mems)) 3615f08c3bdfSopenharmony_ci cpuset_localcpus(cp->mems, cp->cpus); 3616f08c3bdfSopenharmony_ci else if (!bitmask_isallclear(cp->cpus) && bitmask_isallclear(cp->mems)) 3617f08c3bdfSopenharmony_ci cpuset_localmems(cp->cpus, cp->mems); 3618f08c3bdfSopenharmony_ci 3619f08c3bdfSopenharmony_ci /* 3620f08c3bdfSopenharmony_ci * All cpuset attributes are determined in an import. 3621f08c3bdfSopenharmony_ci * Those that aren't explicitly specified are presumed 3622f08c3bdfSopenharmony_ci * to be unchanged (zero, if it's a freshly allocated 3623f08c3bdfSopenharmony_ci * struct cpuset.) 3624f08c3bdfSopenharmony_ci */ 3625f08c3bdfSopenharmony_ci 3626f08c3bdfSopenharmony_ci cp->cpus_valid = 1; 3627f08c3bdfSopenharmony_ci cp->mems_valid = 1; 3628f08c3bdfSopenharmony_ci cp->cpu_exclusive_valid = 1; 3629f08c3bdfSopenharmony_ci cp->mem_exclusive_valid = 1; 3630f08c3bdfSopenharmony_ci cp->notify_on_release_valid = 1; 3631f08c3bdfSopenharmony_ci cp->memory_migrate_valid = 1; 3632f08c3bdfSopenharmony_ci cp->memory_pressure_enabled_valid = 1; 3633f08c3bdfSopenharmony_ci cp->memory_spread_page_valid = 1; 3634f08c3bdfSopenharmony_ci cp->memory_spread_slab_valid = 1; 3635f08c3bdfSopenharmony_ci 3636f08c3bdfSopenharmony_ci return 0; 3637f08c3bdfSopenharmony_cierr: 3638f08c3bdfSopenharmony_ci if (elinenum) 3639f08c3bdfSopenharmony_ci *elinenum = linenum; 3640f08c3bdfSopenharmony_ci free(linebuf); 3641f08c3bdfSopenharmony_ci return -1; 3642f08c3bdfSopenharmony_ci} 3643f08c3bdfSopenharmony_ci 3644f08c3bdfSopenharmony_ci/* Pin current task CPU (and memory) */ 3645f08c3bdfSopenharmony_ciint cpuset_pin(int relcpu) 3646f08c3bdfSopenharmony_ci{ 3647f08c3bdfSopenharmony_ci struct cpuset_placement *plc1 = NULL, *plc2 = NULL; 3648f08c3bdfSopenharmony_ci int cpu, r; 3649f08c3bdfSopenharmony_ci 3650f08c3bdfSopenharmony_ci if (check() < 0) 3651f08c3bdfSopenharmony_ci return -1; 3652f08c3bdfSopenharmony_ci 3653f08c3bdfSopenharmony_ci do { 3654f08c3bdfSopenharmony_ci cpuset_free_placement(plc1); 3655f08c3bdfSopenharmony_ci plc1 = cpuset_get_placement(0); 3656f08c3bdfSopenharmony_ci 3657f08c3bdfSopenharmony_ci r = 0; 3658f08c3bdfSopenharmony_ci if (cpuset_unpin() < 0) 3659f08c3bdfSopenharmony_ci r = -1; 3660f08c3bdfSopenharmony_ci cpu = cpuset_p_rel_to_sys_cpu(0, relcpu); 3661f08c3bdfSopenharmony_ci if (cpuset_cpubind(cpu) < 0) 3662f08c3bdfSopenharmony_ci r = -1; 3663f08c3bdfSopenharmony_ci 3664f08c3bdfSopenharmony_ci cpuset_free_placement(plc2); 3665f08c3bdfSopenharmony_ci plc2 = cpuset_get_placement(0); 3666f08c3bdfSopenharmony_ci } while (!cpuset_equal_placement(plc1, plc2)); 3667f08c3bdfSopenharmony_ci 3668f08c3bdfSopenharmony_ci cpuset_free_placement(plc1); 3669f08c3bdfSopenharmony_ci cpuset_free_placement(plc2); 3670f08c3bdfSopenharmony_ci return r; 3671f08c3bdfSopenharmony_ci} 3672f08c3bdfSopenharmony_ci 3673f08c3bdfSopenharmony_ci/* Return number CPUs in current tasks cpuset */ 3674f08c3bdfSopenharmony_ciint cpuset_size(void) 3675f08c3bdfSopenharmony_ci{ 3676f08c3bdfSopenharmony_ci struct cpuset_placement *plc1 = NULL, *plc2 = NULL; 3677f08c3bdfSopenharmony_ci int r; 3678f08c3bdfSopenharmony_ci 3679f08c3bdfSopenharmony_ci if (check() < 0) 3680f08c3bdfSopenharmony_ci return -1; 3681f08c3bdfSopenharmony_ci 3682f08c3bdfSopenharmony_ci do { 3683f08c3bdfSopenharmony_ci cpuset_free_placement(plc1); 3684f08c3bdfSopenharmony_ci plc1 = cpuset_get_placement(0); 3685f08c3bdfSopenharmony_ci 3686f08c3bdfSopenharmony_ci r = cpuset_cpus_weight(0); 3687f08c3bdfSopenharmony_ci 3688f08c3bdfSopenharmony_ci cpuset_free_placement(plc2); 3689f08c3bdfSopenharmony_ci plc2 = cpuset_get_placement(0); 3690f08c3bdfSopenharmony_ci } while (!cpuset_equal_placement(plc1, plc2)); 3691f08c3bdfSopenharmony_ci 3692f08c3bdfSopenharmony_ci cpuset_free_placement(plc1); 3693f08c3bdfSopenharmony_ci cpuset_free_placement(plc2); 3694f08c3bdfSopenharmony_ci return r; 3695f08c3bdfSopenharmony_ci} 3696f08c3bdfSopenharmony_ci 3697f08c3bdfSopenharmony_ci/* Return relative CPU number, within current cpuset, last executed on */ 3698f08c3bdfSopenharmony_ciint cpuset_where(void) 3699f08c3bdfSopenharmony_ci{ 3700f08c3bdfSopenharmony_ci struct cpuset_placement *plc1 = NULL, *plc2 = NULL; 3701f08c3bdfSopenharmony_ci int r; 3702f08c3bdfSopenharmony_ci 3703f08c3bdfSopenharmony_ci if (check() < 0) 3704f08c3bdfSopenharmony_ci return -1; 3705f08c3bdfSopenharmony_ci 3706f08c3bdfSopenharmony_ci do { 3707f08c3bdfSopenharmony_ci cpuset_free_placement(plc1); 3708f08c3bdfSopenharmony_ci plc1 = cpuset_get_placement(0); 3709f08c3bdfSopenharmony_ci 3710f08c3bdfSopenharmony_ci r = cpuset_p_sys_to_rel_cpu(0, cpuset_latestcpu(0)); 3711f08c3bdfSopenharmony_ci 3712f08c3bdfSopenharmony_ci cpuset_free_placement(plc2); 3713f08c3bdfSopenharmony_ci plc2 = cpuset_get_placement(0); 3714f08c3bdfSopenharmony_ci } while (!cpuset_equal_placement(plc1, plc2)); 3715f08c3bdfSopenharmony_ci 3716f08c3bdfSopenharmony_ci cpuset_free_placement(plc1); 3717f08c3bdfSopenharmony_ci cpuset_free_placement(plc2); 3718f08c3bdfSopenharmony_ci return r; 3719f08c3bdfSopenharmony_ci} 3720f08c3bdfSopenharmony_ci 3721f08c3bdfSopenharmony_ci/* Undo cpuset_pin - let current task have the run of all CPUs in its cpuset */ 3722f08c3bdfSopenharmony_ciint cpuset_unpin(void) 3723f08c3bdfSopenharmony_ci{ 3724f08c3bdfSopenharmony_ci struct bitmask *cpus = NULL, *mems = NULL; 3725f08c3bdfSopenharmony_ci int r = -1; 3726f08c3bdfSopenharmony_ci 3727f08c3bdfSopenharmony_ci if (check() < 0) 3728f08c3bdfSopenharmony_ci goto err; 3729f08c3bdfSopenharmony_ci 3730f08c3bdfSopenharmony_ci /* 3731f08c3bdfSopenharmony_ci * Don't need cpuset_*_placement() guard against concurrent 3732f08c3bdfSopenharmony_ci * cpuset migration, because none of the following depends 3733f08c3bdfSopenharmony_ci * on the tasks cpuset placement. 3734f08c3bdfSopenharmony_ci */ 3735f08c3bdfSopenharmony_ci 3736f08c3bdfSopenharmony_ci if ((cpus = bitmask_alloc(cpuset_cpus_nbits())) == NULL) 3737f08c3bdfSopenharmony_ci goto err; 3738f08c3bdfSopenharmony_ci bitmask_setall(cpus); 3739f08c3bdfSopenharmony_ci if (sched_setaffinity(0, bitmask_nbytes(cpus), bitmask_mask(cpus)) < 0) 3740f08c3bdfSopenharmony_ci goto err; 3741f08c3bdfSopenharmony_ci 3742f08c3bdfSopenharmony_ci if ((mems = bitmask_alloc(cpuset_mems_nbits())) == NULL) 3743f08c3bdfSopenharmony_ci goto err; 3744f08c3bdfSopenharmony_ci if (set_mempolicy(MPOL_DEFAULT, bitmask_mask(mems), 3745f08c3bdfSopenharmony_ci bitmask_nbits(mems) + 1) < 0) 3746f08c3bdfSopenharmony_ci goto err; 3747f08c3bdfSopenharmony_ci r = 0; 3748f08c3bdfSopenharmony_ci /* fall into ... */ 3749f08c3bdfSopenharmony_cierr: 3750f08c3bdfSopenharmony_ci bitmask_free(cpus); 3751f08c3bdfSopenharmony_ci bitmask_free(mems); 3752f08c3bdfSopenharmony_ci return r; 3753f08c3bdfSopenharmony_ci 3754f08c3bdfSopenharmony_ci} 3755f08c3bdfSopenharmony_ci 3756f08c3bdfSopenharmony_cistruct cpuset_function_list { 3757f08c3bdfSopenharmony_ci const char *fname; 3758f08c3bdfSopenharmony_ci void *func; 3759f08c3bdfSopenharmony_ci} flist[] = { 3760f08c3bdfSopenharmony_ci { 3761f08c3bdfSopenharmony_ci "cpuset_version", cpuset_version}, { 3762f08c3bdfSopenharmony_ci "cpuset_alloc", cpuset_alloc}, { 3763f08c3bdfSopenharmony_ci "cpuset_free", cpuset_free}, { 3764f08c3bdfSopenharmony_ci "cpuset_cpus_nbits", cpuset_cpus_nbits}, { 3765f08c3bdfSopenharmony_ci "cpuset_mems_nbits", cpuset_mems_nbits}, { 3766f08c3bdfSopenharmony_ci "cpuset_setcpus", cpuset_setcpus}, { 3767f08c3bdfSopenharmony_ci "cpuset_setmems", cpuset_setmems}, { 3768f08c3bdfSopenharmony_ci "cpuset_set_iopt", cpuset_set_iopt}, { 3769f08c3bdfSopenharmony_ci "cpuset_set_sopt", cpuset_set_sopt}, { 3770f08c3bdfSopenharmony_ci "cpuset_getcpus", cpuset_getcpus}, { 3771f08c3bdfSopenharmony_ci "cpuset_getmems", cpuset_getmems}, { 3772f08c3bdfSopenharmony_ci "cpuset_cpus_weight", cpuset_cpus_weight}, { 3773f08c3bdfSopenharmony_ci "cpuset_mems_weight", cpuset_mems_weight}, { 3774f08c3bdfSopenharmony_ci "cpuset_get_iopt", cpuset_get_iopt}, { 3775f08c3bdfSopenharmony_ci "cpuset_get_sopt", cpuset_get_sopt}, { 3776f08c3bdfSopenharmony_ci "cpuset_localcpus", cpuset_localcpus}, { 3777f08c3bdfSopenharmony_ci "cpuset_localmems", cpuset_localmems}, { 3778f08c3bdfSopenharmony_ci "cpuset_cpumemdist", cpuset_cpumemdist}, { 3779f08c3bdfSopenharmony_ci "cpuset_cpu2node", cpuset_cpu2node}, { 3780f08c3bdfSopenharmony_ci "cpuset_addr2node", cpuset_addr2node}, { 3781f08c3bdfSopenharmony_ci "cpuset_create", cpuset_create}, { 3782f08c3bdfSopenharmony_ci "cpuset_delete", cpuset_delete}, { 3783f08c3bdfSopenharmony_ci "cpuset_query", cpuset_query}, { 3784f08c3bdfSopenharmony_ci "cpuset_modify", cpuset_modify}, { 3785f08c3bdfSopenharmony_ci "cpuset_getcpusetpath", cpuset_getcpusetpath}, { 3786f08c3bdfSopenharmony_ci "cpuset_cpusetofpid", cpuset_cpusetofpid}, { 3787f08c3bdfSopenharmony_ci "cpuset_mountpoint", cpuset_mountpoint}, { 3788f08c3bdfSopenharmony_ci "cpuset_collides_exclusive", cpuset_collides_exclusive}, { 3789f08c3bdfSopenharmony_ci "cpuset_nuke", cpuset_nuke}, { 3790f08c3bdfSopenharmony_ci "cpuset_init_pidlist", cpuset_init_pidlist}, { 3791f08c3bdfSopenharmony_ci "cpuset_pidlist_length", cpuset_pidlist_length}, { 3792f08c3bdfSopenharmony_ci "cpuset_get_pidlist", cpuset_get_pidlist}, { 3793f08c3bdfSopenharmony_ci "cpuset_freepidlist", cpuset_freepidlist}, { 3794f08c3bdfSopenharmony_ci "cpuset_move", cpuset_move}, { 3795f08c3bdfSopenharmony_ci "cpuset_move_all", cpuset_move_all}, { 3796f08c3bdfSopenharmony_ci "cpuset_move_cpuset_tasks", cpuset_move_cpuset_tasks}, { 3797f08c3bdfSopenharmony_ci "cpuset_migrate", cpuset_migrate}, { 3798f08c3bdfSopenharmony_ci "cpuset_migrate_all", cpuset_migrate_all}, { 3799f08c3bdfSopenharmony_ci "cpuset_reattach", cpuset_reattach}, { 3800f08c3bdfSopenharmony_ci "cpuset_open_memory_pressure", cpuset_open_memory_pressure}, { 3801f08c3bdfSopenharmony_ci "cpuset_read_memory_pressure", cpuset_read_memory_pressure}, { 3802f08c3bdfSopenharmony_ci "cpuset_close_memory_pressure", cpuset_close_memory_pressure}, { 3803f08c3bdfSopenharmony_ci "cpuset_c_rel_to_sys_cpu", cpuset_c_rel_to_sys_cpu}, { 3804f08c3bdfSopenharmony_ci "cpuset_c_sys_to_rel_cpu", cpuset_c_sys_to_rel_cpu}, { 3805f08c3bdfSopenharmony_ci "cpuset_c_rel_to_sys_mem", cpuset_c_rel_to_sys_mem}, { 3806f08c3bdfSopenharmony_ci "cpuset_c_sys_to_rel_mem", cpuset_c_sys_to_rel_mem}, { 3807f08c3bdfSopenharmony_ci "cpuset_p_rel_to_sys_cpu", cpuset_p_rel_to_sys_cpu}, { 3808f08c3bdfSopenharmony_ci "cpuset_p_sys_to_rel_cpu", cpuset_p_sys_to_rel_cpu}, { 3809f08c3bdfSopenharmony_ci "cpuset_p_rel_to_sys_mem", cpuset_p_rel_to_sys_mem}, { 3810f08c3bdfSopenharmony_ci "cpuset_p_sys_to_rel_mem", cpuset_p_sys_to_rel_mem}, { 3811f08c3bdfSopenharmony_ci "cpuset_get_placement", cpuset_get_placement}, { 3812f08c3bdfSopenharmony_ci "cpuset_equal_placement", cpuset_equal_placement}, { 3813f08c3bdfSopenharmony_ci "cpuset_free_placement", cpuset_free_placement}, { 3814f08c3bdfSopenharmony_ci "cpuset_fts_open", cpuset_fts_open}, { 3815f08c3bdfSopenharmony_ci "cpuset_fts_read", cpuset_fts_read}, { 3816f08c3bdfSopenharmony_ci "cpuset_fts_reverse", cpuset_fts_reverse}, { 3817f08c3bdfSopenharmony_ci "cpuset_fts_rewind", cpuset_fts_rewind}, { 3818f08c3bdfSopenharmony_ci "cpuset_fts_get_path", cpuset_fts_get_path}, { 3819f08c3bdfSopenharmony_ci "cpuset_fts_get_stat", cpuset_fts_get_stat}, { 3820f08c3bdfSopenharmony_ci "cpuset_fts_get_cpuset", cpuset_fts_get_cpuset}, { 3821f08c3bdfSopenharmony_ci "cpuset_fts_get_errno", cpuset_fts_get_errno}, { 3822f08c3bdfSopenharmony_ci "cpuset_fts_get_info", cpuset_fts_get_info}, { 3823f08c3bdfSopenharmony_ci "cpuset_fts_close", cpuset_fts_close}, { 3824f08c3bdfSopenharmony_ci "cpuset_cpubind", cpuset_cpubind}, { 3825f08c3bdfSopenharmony_ci "cpuset_latestcpu", cpuset_latestcpu}, { 3826f08c3bdfSopenharmony_ci "cpuset_membind", cpuset_membind}, { 3827f08c3bdfSopenharmony_ci "cpuset_export", cpuset_export}, { 3828f08c3bdfSopenharmony_ci "cpuset_import", cpuset_import}, { 3829f08c3bdfSopenharmony_ci "cpuset_function", cpuset_function}, { 3830f08c3bdfSopenharmony_ci "cpuset_pin", cpuset_pin}, { 3831f08c3bdfSopenharmony_ci "cpuset_size", cpuset_size}, { 3832f08c3bdfSopenharmony_ci "cpuset_where", cpuset_where}, { 3833f08c3bdfSopenharmony_ci"cpuset_unpin", cpuset_unpin},}; 3834f08c3bdfSopenharmony_ci 3835f08c3bdfSopenharmony_ci/* Return pointer to a libcpuset.so function, or NULL */ 3836f08c3bdfSopenharmony_civoid *cpuset_function(const char *function_name) 3837f08c3bdfSopenharmony_ci{ 3838f08c3bdfSopenharmony_ci unsigned int i; 3839f08c3bdfSopenharmony_ci 3840f08c3bdfSopenharmony_ci for (i = 0; i < sizeof(flist) / sizeof(flist[0]); i++) 3841f08c3bdfSopenharmony_ci if (streq(function_name, flist[i].fname)) 3842f08c3bdfSopenharmony_ci return flist[i].func; 3843f08c3bdfSopenharmony_ci return NULL; 3844f08c3bdfSopenharmony_ci} 3845f08c3bdfSopenharmony_ci 3846f08c3bdfSopenharmony_ci/* Fortran interface to basic cpuset routines */ 3847f08c3bdfSopenharmony_ciint cpuset_pin_(int *ptr_relcpu) 3848f08c3bdfSopenharmony_ci{ 3849f08c3bdfSopenharmony_ci return cpuset_pin(*ptr_relcpu); 3850f08c3bdfSopenharmony_ci} 3851f08c3bdfSopenharmony_ci 3852f08c3bdfSopenharmony_ciint cpuset_size_(void) 3853f08c3bdfSopenharmony_ci{ 3854f08c3bdfSopenharmony_ci return cpuset_size(); 3855f08c3bdfSopenharmony_ci} 3856f08c3bdfSopenharmony_ci 3857f08c3bdfSopenharmony_ciint cpuset_where_(void) 3858f08c3bdfSopenharmony_ci{ 3859f08c3bdfSopenharmony_ci return cpuset_where(); 3860f08c3bdfSopenharmony_ci} 3861f08c3bdfSopenharmony_ci 3862f08c3bdfSopenharmony_ciint cpuset_unpin_(void) 3863f08c3bdfSopenharmony_ci{ 3864f08c3bdfSopenharmony_ci return cpuset_unpin(); 3865f08c3bdfSopenharmony_ci} 3866f08c3bdfSopenharmony_ci 3867f08c3bdfSopenharmony_ci#endif /* HAVE_LINUX_MEMPOLICY_H */ 3868