1 /* 2 * Copyright 2013-2015, Michael Ellerman, IBM Corp. 3 * Licensed under GPLv2. 4 */ 5 6 #define _GNU_SOURCE /* For CPU_ZERO etc. */ 7 8 #include <elf.h> 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <link.h> 12 #include <sched.h> 13 #include <stdio.h> 14 #include <sys/stat.h> 15 #include <sys/types.h> 16 #include <unistd.h> 17 18 #include "utils.h" 19 20 static char auxv[4096]; 21 22 int read_auxv(char *buf, ssize_t buf_size) 23 { 24 ssize_t num; 25 int rc, fd; 26 27 fd = open("/proc/self/auxv", O_RDONLY); 28 if (fd == -1) { 29 perror("open"); 30 return -errno; 31 } 32 33 num = read(fd, buf, buf_size); 34 if (num < 0) { 35 perror("read"); 36 rc = -EIO; 37 goto out; 38 } 39 40 if (num > buf_size) { 41 printf("overflowed auxv buffer\n"); 42 rc = -EOVERFLOW; 43 goto out; 44 } 45 46 rc = 0; 47 out: 48 close(fd); 49 return rc; 50 } 51 52 void *find_auxv_entry(int type, char *auxv) 53 { 54 ElfW(auxv_t) *p; 55 56 p = (ElfW(auxv_t) *)auxv; 57 58 while (p->a_type != AT_NULL) { 59 if (p->a_type == type) 60 return p; 61 62 p++; 63 } 64 65 return NULL; 66 } 67 68 void *get_auxv_entry(int type) 69 { 70 ElfW(auxv_t) *p; 71 72 if (read_auxv(auxv, sizeof(auxv))) 73 return NULL; 74 75 p = find_auxv_entry(type, auxv); 76 if (p) 77 return (void *)p->a_un.a_val; 78 79 return NULL; 80 } 81 82 int pick_online_cpu(void) 83 { 84 cpu_set_t mask; 85 int cpu; 86 87 CPU_ZERO(&mask); 88 89 if (sched_getaffinity(0, sizeof(mask), &mask)) { 90 perror("sched_getaffinity"); 91 return -1; 92 } 93 94 /* We prefer a primary thread, but skip 0 */ 95 for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8) 96 if (CPU_ISSET(cpu, &mask)) 97 return cpu; 98 99 /* Search for anything, but in reverse */ 100 for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--) 101 if (CPU_ISSET(cpu, &mask)) 102 return cpu; 103 104 printf("No cpus in affinity mask?!\n"); 105 return -1; 106 } 107