1 /* $NetBSD: cpuset.c,v 1.16 2010/09/21 02:03:29 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.16 2010/09/21 02:03:29 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 len = sizeof(nc); 148 if (sysctl(mib, __arraycount(mib), &nc, &len, NULL, 0) == -1) 149 return NULL; 150 151 cpuset_nentries = CPUSET_NENTRIES(nc); 152 cpuset_size = CPUSET_SIZE(cpuset_nentries); 153 } 154 return calloc(1, cpuset_size); 155 } 156 157 void 158 _cpuset_destroy(cpuset_t *c) 159 { 160 161 free(c); 162 } 163 164 #else 165 166 kcpuset_t * 167 kcpuset_create(void) 168 { 169 kcpuset_t *c; 170 171 if (cpuset_size == 0) { 172 cpuset_nentries = CPUSET_NENTRIES(MAXCPUS); 173 cpuset_size = KCPUSET_SIZE(cpuset_nentries); 174 } 175 c = kmem_zalloc(cpuset_size, KM_SLEEP); 176 c->next = NULL; 177 c->nused = 1; 178 return c; 179 } 180 181 void 182 kcpuset_destroy(kcpuset_t *c) 183 { 184 kcpuset_t *nc; 185 186 while (c) { 187 KASSERT(c->nused == 0); 188 nc = c->next; 189 kmem_free(c, cpuset_size); 190 c = nc; 191 } 192 } 193 194 void 195 kcpuset_copy(kcpuset_t *d, const kcpuset_t *s) 196 { 197 198 KASSERT(d->nused == 1); 199 memcpy(d->bits, s->bits, cpuset_nentries * sizeof(s->bits[0])); 200 } 201 202 void 203 kcpuset_use(kcpuset_t *c) 204 { 205 206 atomic_inc_uint(&c->nused); 207 } 208 209 void 210 kcpuset_unuse(kcpuset_t *c, kcpuset_t **lst) 211 { 212 213 if (atomic_dec_uint_nv(&c->nused) != 0) 214 return; 215 KASSERT(c->nused == 0); 216 KASSERT(c->next == NULL); 217 if (lst == NULL) { 218 kcpuset_destroy(c); 219 return; 220 } 221 c->next = *lst; 222 *lst = c; 223 } 224 225 int 226 kcpuset_copyin(const cpuset_t *u, kcpuset_t *k, size_t len) 227 { 228 229 KASSERT(k->nused > 0); 230 KASSERT(k->next == NULL); 231 if (len != CPUSET_SIZE(cpuset_nentries)) 232 return EINVAL; 233 return copyin(u->bits, k->bits, cpuset_nentries * sizeof(k->bits[0])); 234 } 235 236 int 237 kcpuset_copyout(const kcpuset_t *k, cpuset_t *u, size_t len) 238 { 239 240 KASSERT(k->nused > 0); 241 KASSERT(k->next == NULL); 242 if (len != CPUSET_SIZE(cpuset_nentries)) 243 return EINVAL; 244 return copyout(k->bits, u->bits, cpuset_nentries * sizeof(u->bits[0])); 245 } 246 247 void 248 kcpuset_zero(kcpuset_t *c) 249 { 250 251 KASSERT(c->nused > 0); 252 KASSERT(c->next == NULL); 253 memset(c->bits, 0, cpuset_nentries * sizeof(c->bits[0])); 254 } 255 256 void 257 kcpuset_fill(kcpuset_t *c) 258 { 259 260 KASSERT(c->nused > 0); 261 KASSERT(c->next == NULL); 262 memset(c->bits, ~0, cpuset_nentries * sizeof(c->bits[0])); 263 } 264 265 void 266 kcpuset_set(cpuid_t i, kcpuset_t *c) 267 { 268 const unsigned long j = i >> CPUSET_SHIFT; 269 270 KASSERT(c->next == NULL); 271 KASSERT(j < cpuset_nentries); 272 c->bits[j] |= 1 << (i & CPUSET_MASK); 273 } 274 275 int 276 kcpuset_isset(cpuid_t i, const kcpuset_t *c) 277 { 278 const unsigned long j = i >> CPUSET_SHIFT; 279 280 KASSERT(c != NULL); 281 KASSERT(c->nused > 0); 282 KASSERT(c->next == NULL); 283 KASSERT(j < cpuset_nentries); 284 return ((1 << (i & CPUSET_MASK)) & c->bits[j]) != 0; 285 } 286 287 bool 288 kcpuset_iszero(const kcpuset_t *c) 289 { 290 unsigned long j; 291 292 for (j = 0; j < cpuset_nentries; j++) 293 if (c->bits[j] != 0) 294 return false; 295 return true; 296 } 297 298 bool 299 kcpuset_match(const kcpuset_t *c1, const kcpuset_t *c2) 300 { 301 unsigned long j; 302 303 for (j = 0; j < cpuset_nentries; j++) 304 if ((c1->bits[j] & c2->bits[j]) != c2->bits[j]) 305 return false; 306 return true; 307 } 308 309 #endif 310 #endif 311