• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <string.h>
15 #include <sys/stat.h>
16 #include <sys/sysinfo.h>
17 #include <sys/types.h>
18 #include <sys/utsname.h>
19 #include <unistd.h>
20 
21 #include "utils.h"
22 
23 static char auxv[4096];
24 
read_auxv(char * buf,ssize_t buf_size)25 int read_auxv(char *buf, ssize_t buf_size)
26 {
27 	ssize_t num;
28 	int rc, fd;
29 
30 	fd = open("/proc/self/auxv", O_RDONLY);
31 	if (fd == -1) {
32 		perror("open");
33 		return -errno;
34 	}
35 
36 	num = read(fd, buf, buf_size);
37 	if (num < 0) {
38 		perror("read");
39 		rc = -EIO;
40 		goto out;
41 	}
42 
43 	if (num > buf_size) {
44 		printf("overflowed auxv buffer\n");
45 		rc = -EOVERFLOW;
46 		goto out;
47 	}
48 
49 	rc = 0;
50 out:
51 	close(fd);
52 	return rc;
53 }
54 
find_auxv_entry(int type,char * auxv)55 void *find_auxv_entry(int type, char *auxv)
56 {
57 	ElfW(auxv_t) *p;
58 
59 	p = (ElfW(auxv_t) *)auxv;
60 
61 	while (p->a_type != AT_NULL) {
62 		if (p->a_type == type)
63 			return p;
64 
65 		p++;
66 	}
67 
68 	return NULL;
69 }
70 
get_auxv_entry(int type)71 void *get_auxv_entry(int type)
72 {
73 	ElfW(auxv_t) *p;
74 
75 	if (read_auxv(auxv, sizeof(auxv)))
76 		return NULL;
77 
78 	p = find_auxv_entry(type, auxv);
79 	if (p)
80 		return (void *)p->a_un.a_val;
81 
82 	return NULL;
83 }
84 
pick_online_cpu(void)85 int pick_online_cpu(void)
86 {
87 	int ncpus, cpu = -1;
88 	cpu_set_t *mask;
89 	size_t size;
90 
91 	ncpus = get_nprocs_conf();
92 	size = CPU_ALLOC_SIZE(ncpus);
93 	mask = CPU_ALLOC(ncpus);
94 	if (!mask) {
95 		perror("malloc");
96 		return -1;
97 	}
98 
99 	CPU_ZERO_S(size, mask);
100 
101 	if (sched_getaffinity(0, size, mask)) {
102 		perror("sched_getaffinity");
103 		goto done;
104 	}
105 
106 	/* We prefer a primary thread, but skip 0 */
107 	for (cpu = 8; cpu < ncpus; cpu += 8)
108 		if (CPU_ISSET_S(cpu, size, mask))
109 			goto done;
110 
111 	/* Search for anything, but in reverse */
112 	for (cpu = ncpus - 1; cpu >= 0; cpu--)
113 		if (CPU_ISSET_S(cpu, size, mask))
114 			goto done;
115 
116 	printf("No cpus in affinity mask?!\n");
117 
118 done:
119 	CPU_FREE(mask);
120 	return cpu;
121 }
122 
is_ppc64le(void)123 bool is_ppc64le(void)
124 {
125 	struct utsname uts;
126 	int rc;
127 
128 	errno = 0;
129 	rc = uname(&uts);
130 	if (rc) {
131 		perror("uname");
132 		return false;
133 	}
134 
135 	return strcmp(uts.machine, "ppc64le") == 0;
136 }
137