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 */
16int 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 */
32int 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
86static 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 */
110int 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