1 /* $NetBSD: cpuset.c,v 1.15 2009/04/25 19:38:25 rmind Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #ifndef _STANDALONE 33 #include <sys/cdefs.h> 34 #if defined(LIBC_SCCS) && !defined(lint) 35 __RCSID("$NetBSD: cpuset.c,v 1.15 2009/04/25 19:38:25 rmind Exp $"); 36 #endif /* LIBC_SCCS and not lint */ 37 38 #include <sys/param.h> 39 #include <sys/sched.h> 40 #ifdef _KERNEL 41 #include <sys/kmem.h> 42 #include <lib/libkern/libkern.h> 43 #include <sys/atomic.h> 44 #else 45 #include <errno.h> 46 #include <string.h> 47 #include <stdlib.h> 48 #include <sys/sysctl.h> 49 #endif 50 51 #define CPUSET_SHIFT 5 52 #define CPUSET_MASK 31 53 #define CPUSET_NENTRIES(nc) ((nc) > 32 ? ((nc) >> CPUSET_SHIFT) : 1) 54 #ifndef __lint__ 55 #define CPUSET_SIZE(n) (sizeof( \ 56 struct { \ 57 uint32_t bits[0]; \ 58 }) + sizeof(uint32_t) * (n)) 59 #else 60 #define CPUSET_SIZE(n) 0 61 #endif 62 63 struct _cpuset { 64 uint32_t bits[0]; 65 }; 66 67 #ifdef _KERNEL 68 struct _kcpuset { 69 unsigned int nused; 70 struct _kcpuset *next; 71 uint32_t bits[0]; 72 }; 73 #define KCPUSET_SIZE(n) (sizeof( \ 74 struct { \ 75 unsigned int nused; \ 76 struct _kcpuset *next; \ 77 uint32_t bits[0]; \ 78 }) + sizeof(uint32_t) * (n)) 79 #endif 80 81 static size_t cpuset_size = 0; 82 static size_t cpuset_nentries = 0; 83 84 #ifndef _KERNEL 85 size_t 86 /*ARGSUSED*/ 87 _cpuset_size(const cpuset_t *c) 88 { 89 90 return cpuset_size; 91 } 92 93 void 94 _cpuset_zero(cpuset_t *c) 95 { 96 97 memset(c->bits, 0, cpuset_nentries * sizeof(c->bits[0])); 98 } 99 100 int 101 _cpuset_isset(cpuid_t i, const cpuset_t *c) 102 { 103 const unsigned long j = i >> CPUSET_SHIFT; 104 105 if (j >= cpuset_nentries) { 106 errno = EINVAL; 107 return -1; 108 } 109 return ((1 << (i & CPUSET_MASK)) & c->bits[j]) != 0; 110 } 111 112 int 113 _cpuset_set(cpuid_t i, cpuset_t *c) 114 { 115 const unsigned long j = i >> CPUSET_SHIFT; 116 117 if (j >= cpuset_nentries) { 118 errno = EINVAL; 119 return -1; 120 } 121 c->bits[j] |= 1 << (i & CPUSET_MASK); 122 return 0; 123 } 124 125 int 126 _cpuset_clr(cpuid_t i, cpuset_t *c) 127 { 128 const unsigned long j = i >> CPUSET_SHIFT; 129 130 if (j >= cpuset_nentries) { 131 errno = EINVAL; 132 return -1; 133 } 134 c->bits[j] &= ~(1 << (i & CPUSET_MASK)); 135 return 0; 136 } 137 138 cpuset_t * 139 _cpuset_create(void) 140 { 141 142 if (cpuset_size == 0) { 143 static int mib[2] = { CTL_HW, HW_NCPU }; 144 size_t len; 145 u_int nc; 146 147 if (sysctl(mib, __arraycount(mib), &nc, &len, NULL, 0) == -1) 148 return NULL; 149 150 cpuset_nentries = CPUSET_NENTRIES(nc); 151 cpuset_size = CPUSET_SIZE(cpuset_nentries); 152 } 153 return calloc(1, cpuset_size); 154 } 155 156 void 157 _cpuset_destroy(cpuset_t *c) 158 { 159 160 free(c); 161 } 162 163 #else 164 165 kcpuset_t * 166 kcpuset_create(void) 167 { 168 kcpuset_t *c; 169 170 if (cpuset_size == 0) { 171 cpuset_nentries = CPUSET_NENTRIES(MAXCPUS); 172 cpuset_size = KCPUSET_SIZE(cpuset_nentries); 173 } 174 c = kmem_zalloc(cpuset_size, KM_SLEEP); 175 c->next = NULL; 176 c->nused = 1; 177 return c; 178 } 179 180 void 181 kcpuset_destroy(kcpuset_t *c) 182 { 183 kcpuset_t *nc; 184 185 while (c) { 186 KASSERT(c->nused == 0); 187 nc = c->next; 188 kmem_free(c, cpuset_size); 189 c = nc; 190 } 191 } 192 193 void 194 kcpuset_copy(kcpuset_t *d, const kcpuset_t *s) 195 { 196 197 KASSERT(d->nused == 1); 198 memcpy(d->bits, s->bits, cpuset_nentries * sizeof(s->bits[0])); 199 } 200 201 void 202 kcpuset_use(kcpuset_t *c) 203 { 204 205 atomic_inc_uint(&c->nused); 206 } 207 208 void 209 kcpuset_unuse(kcpuset_t *c, kcpuset_t **lst) 210 { 211 212 if (atomic_dec_uint_nv(&c->nused) != 0) 213 return; 214 KASSERT(c->nused == 0); 215 KASSERT(c->next == NULL); 216 if (lst == NULL) { 217 kcpuset_destroy(c); 218 return; 219 } 220 c->next = *lst; 221 *lst = c; 222 } 223 224 int 225 kcpuset_copyin(const cpuset_t *u, kcpuset_t *k, size_t len) 226 { 227 228 KASSERT(k->nused > 0); 229 KASSERT(k->next == NULL); 230 if (len != CPUSET_SIZE(cpuset_nentries)) 231 return EINVAL; 232 return copyin(u->bits, k->bits, cpuset_nentries * sizeof(k->bits[0])); 233 } 234 235 int 236 kcpuset_copyout(const kcpuset_t *k, cpuset_t *u, size_t len) 237 { 238 239 KASSERT(k->nused > 0); 240 KASSERT(k->next == NULL); 241 if (len != CPUSET_SIZE(cpuset_nentries)) 242 return EINVAL; 243 return copyout(k->bits, u->bits, cpuset_nentries * sizeof(u->bits[0])); 244 } 245 246 void 247 kcpuset_zero(kcpuset_t *c) 248 { 249 250 KASSERT(c->nused > 0); 251 KASSERT(c->next == NULL); 252 memset(c->bits, 0, cpuset_nentries * sizeof(c->bits[0])); 253 } 254 255 void 256 kcpuset_fill(kcpuset_t *c) 257 { 258 259 KASSERT(c->nused > 0); 260 KASSERT(c->next == NULL); 261 memset(c->bits, ~0, cpuset_nentries * sizeof(c->bits[0])); 262 } 263 264 void 265 kcpuset_set(cpuid_t i, kcpuset_t *c) 266 { 267 const unsigned long j = i >> CPUSET_SHIFT; 268 269 KASSERT(c->next == NULL); 270 KASSERT(j < cpuset_nentries); 271 c->bits[j] |= 1 << (i & CPUSET_MASK); 272 } 273 274 int 275 kcpuset_isset(cpuid_t i, const kcpuset_t *c) 276 { 277 const unsigned long j = i >> CPUSET_SHIFT; 278 279 KASSERT(c != NULL); 280 KASSERT(c->nused > 0); 281 KASSERT(c->next == NULL); 282 KASSERT(j < cpuset_nentries); 283 return ((1 << (i & CPUSET_MASK)) & c->bits[j]) != 0; 284 } 285 286 bool 287 kcpuset_iszero(const kcpuset_t *c) 288 { 289 unsigned long j; 290 291 for (j = 0; j < cpuset_nentries; j++) 292 if (c->bits[j] != 0) 293 return false; 294 return true; 295 } 296 297 bool 298 kcpuset_match(const kcpuset_t *c1, const kcpuset_t *c2) 299 { 300 unsigned long j; 301 302 for (j = 0; j < cpuset_nentries; j++) 303 if ((c1->bits[j] & c2->bits[j]) != c2->bits[j]) 304 return false; 305 return true; 306 } 307 308 #endif 309 #endif 310