1 /*
2  * Copyright 2008 Google Inc. All Rights Reserved.
3  * Author: md@google.com (Michael Davidson)
4  */
5 #define _GNU_SOURCE	/* for cpu_set macros */
6 
7 #include <sched.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include "cpuset.h"
11 #include "logging.h"
12 
13 /*
14  * Return the number of cpus in a cpu_set
15  */
count_cpus(const cpu_set_t * cpus)16 int count_cpus(const cpu_set_t *cpus)
17 {
18 	int	count	= 0;
19 	int	cpu;
20 
21 	for (cpu = 0; cpu < CPU_SETSIZE; cpu++)
22 		if (CPU_ISSET(cpu, cpus))
23 			++count;
24 
25 	return count;
26 }
27 
28 /*
29  * Parse a string containing a comma separated list of ranges
30  * of cpu numbers such as: "0,2,4-7" into a cpu_set_t.
31  */
parse_cpu_set(const char * s,cpu_set_t * cpus)32 int parse_cpu_set(const char *s, cpu_set_t *cpus)
33 {
34 	CPU_ZERO(cpus);
35 
36 	while (*s) {
37 		char	*next;
38 		int	cpu;
39 		int	start, end;
40 
41 		start = end = (int)strtol(s, &next, 0);
42 		if (s == next)
43 			break;
44 		s = next;
45 
46 		if (*s == '-') {
47 			++s;
48 			end = (int)strtol(s, &next, 0);
49 			if (s == next)
50 				break;
51 			s = next;
52 		}
53 
54 		if (*s == ',')
55 			++s;
56 
57 		if (start < 0 || start >= CPU_SETSIZE) {
58 			ERROR(0, "bad cpu number '%d' in cpu set", start);
59 			return 1;
60 		}
61 
62 		if (end < 0 || end >= CPU_SETSIZE) {
63 			ERROR(0, "bad cpu number '%d' in cpu set", end);
64 			return 1;
65 		}
66 
67 		if (end < start) {
68 			ERROR(0, "bad range '%d-%d' in cpu set", start, end);
69 			return 1;
70 		}
71 
72 		for (cpu = start; cpu <= end; ++cpu)
73 			CPU_SET(cpu, cpus);
74 
75 	}
76 
77 	if (*s) {
78 		ERROR(0, "unexpected character '%c' in cpu set", *s);
79 		return 1;
80 	}
81 
82 	return 0;
83 }
84 
85 
show_range(char * buf,size_t len,const char * prefix,int start,int end)86 static int show_range(char *buf, size_t len, const char *prefix,
87 			int start, int end)
88 {
89 	int	n;
90 
91 	if (start == end)
92 		n = snprintf(buf, len, "%s%d", prefix, start);
93 	else
94 		n = snprintf(buf, len, "%s%d-%d", prefix, start, end);
95 
96 	if (n < len)
97 		return n;
98 
99 	return -1;
100 }
101 
102 /*
103  * Turn a cpu_set_t into a human readable string containing a
104  * comma separated list of ranges of cpu numbers.
105  *
106  * Returns the number of bytes written to the buffer,
107  * not including the terminating '\0' character,
108  * or -1 if there was not enough space in the  buffer.
109  */
show_cpu_set(char * buf,size_t len,const cpu_set_t * cpus)110 int show_cpu_set(char *buf, size_t len, const cpu_set_t *cpus)
111 {
112 	char	*bufp	= buf;
113 	int	start	= -1;
114 	int	end	= -1;
115 	char	*sep	= "";
116 	int	cpu;
117 
118 	for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
119 		if (CPU_ISSET(cpu, cpus)) {
120 			if (start < 0)
121 				start = cpu;
122 			end = cpu;
123 		} else if (start >= 0) {
124 			int	n;
125 			if ((n = show_range(bufp, len, sep, start, end)) < 0)
126 				return -1;
127 			len -= n;
128 			bufp += n;
129 			sep = ",";
130 			start = end = -1;
131 		}
132 	}
133 
134 	if (start >= 0) {
135 		int	n;
136 		if ((n = show_range(bufp, len, sep, start, end)) < 0)
137 			return -1;
138 		bufp += n;
139 	}
140 
141 	return bufp - buf;
142 }
143