Commit | Line | Data |
---|---|---|
fcb45ec0 ME |
1 | /* |
2 | * Copyright 2013-2015, Michael Ellerman, IBM Corp. | |
3 | * Licensed under GPLv2. | |
4 | */ | |
5 | ||
d1301afd ME |
6 | #define _GNU_SOURCE /* For CPU_ZERO etc. */ |
7 | ||
fcb45ec0 ME |
8 | #include <elf.h> |
9 | #include <errno.h> | |
10 | #include <fcntl.h> | |
11 | #include <link.h> | |
d1301afd | 12 | #include <sched.h> |
fcb45ec0 ME |
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 | ||
e3028437 | 22 | int read_auxv(char *buf, ssize_t buf_size) |
fcb45ec0 | 23 | { |
fcb45ec0 | 24 | ssize_t num; |
e3028437 | 25 | int rc, fd; |
fcb45ec0 ME |
26 | |
27 | fd = open("/proc/self/auxv", O_RDONLY); | |
28 | if (fd == -1) { | |
29 | perror("open"); | |
e3028437 | 30 | return -errno; |
fcb45ec0 ME |
31 | } |
32 | ||
e3028437 | 33 | num = read(fd, buf, buf_size); |
fcb45ec0 ME |
34 | if (num < 0) { |
35 | perror("read"); | |
e3028437 | 36 | rc = -EIO; |
fcb45ec0 ME |
37 | goto out; |
38 | } | |
39 | ||
e3028437 ME |
40 | if (num > buf_size) { |
41 | printf("overflowed auxv buffer\n"); | |
42 | rc = -EOVERFLOW; | |
fcb45ec0 ME |
43 | goto out; |
44 | } | |
45 | ||
e3028437 ME |
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 | ||
fcb45ec0 ME |
56 | p = (ElfW(auxv_t) *)auxv; |
57 | ||
58 | while (p->a_type != AT_NULL) { | |
e3028437 ME |
59 | if (p->a_type == type) |
60 | return p; | |
fcb45ec0 ME |
61 | |
62 | p++; | |
63 | } | |
e3028437 ME |
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; | |
fcb45ec0 | 80 | } |
d1301afd ME |
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 | } |