1 /* $NetBSD: cpuset.c,v 1.12 2008/07/27 05:47:56 dholland 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.12 2008/07/27 05:47:56 dholland 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() sizeof( \ 56 struct { \ 57 uint32_t bits[cpuset_nentries]; \ 58 }) 59 #else 60 #define CPUSET_SIZE() 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() sizeof( \ 74 struct { \ 75 unsigned int nused; \ 76 struct _kcpuset *next; \ 77 uint32_t bits[cpuset_nentries]; \ 78 }) 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 return cpuset_size; 90 } 91 92 void 93 _cpuset_zero(cpuset_t *c) 94 { 95 (void)memset(c->bits, 0, cpuset_nentries * sizeof(c->bits[0])); 96 } 97 98 int 99 _cpuset_isset(cpuid_t i, const cpuset_t *c) 100 { 101 const unsigned long j = i >> CPUSET_SHIFT; 102 103 if (j >= cpuset_nentries) { 104 errno = EINVAL; 105 return -1; 106 } 107 return ((1 << (i & CPUSET_MASK)) & c->bits[j]) != 0; 108 } 109 110 int 111 _cpuset_set(cpuid_t i, cpuset_t *c) 112 { 113 const unsigned long j = i >> CPUSET_SHIFT; 114 115 if (j >= cpuset_nentries) { 116 errno = EINVAL; 117 return -1; 118 } 119 c->bits[j] |= 1 << (i & CPUSET_MASK); 120 return 0; 121 } 122 123 int 124 _cpuset_clr(cpuid_t i, cpuset_t *c) 125 { 126 const unsigned long j = i >> CPUSET_SHIFT; 127 128 if (j >= cpuset_nentries) { 129 errno = EINVAL; 130 return -1; 131 } 132 c->bits[j] &= ~(1 << (i & CPUSET_MASK)); 133 return 0; 134 } 135 136 cpuset_t * 137 _cpuset_create(void) 138 { 139 if (cpuset_size == 0) { 140 static int mib[2] = { CTL_HW, HW_NCPU }; 141 size_t len; 142 u_int nc; 143 144 if (sysctl(mib, __arraycount(mib), &nc, &len, NULL, 0) == -1) 145 return NULL; 146 147 cpuset_nentries = CPUSET_NENTRIES(nc); 148 cpuset_size = CPUSET_SIZE(); 149 } 150 return calloc(1, cpuset_size); 151 } 152 153 void 154 _cpuset_destroy(cpuset_t *c) 155 { 156 free(c); 157 } 158 159 #else 160 161 kcpuset_t * 162 kcpuset_create(void) 163 { 164 kcpuset_t *c; 165 if (cpuset_size == 0) { 166 cpuset_nentries = CPUSET_NENTRIES(MAXCPUS); 167 cpuset_size = KCPUSET_SIZE(); 168 } 169 c = kmem_zalloc(cpuset_size, KM_SLEEP); 170 c->next = NULL; 171 c->nused = 1; 172 return c; 173 } 174 175 void 176 kcpuset_destroy(kcpuset_t *c) 177 { 178 kcpuset_t *nc; 179 while (c) { 180 KASSERT(c->nused == 0); 181 nc = c->next; 182 kmem_free(c, cpuset_size); 183 c = nc; 184 } 185 } 186 187 void 188 kcpuset_copy(kcpuset_t *d, const kcpuset_t *s) 189 { 190 KASSERT(d->nused == 1); 191 (void)memcpy(d->bits, s->bits, cpuset_nentries * sizeof(s->bits[0])); 192 } 193 194 void 195 kcpuset_use(kcpuset_t *c) 196 { 197 atomic_inc_uint(&c->nused); 198 } 199 200 void 201 kcpuset_unuse(kcpuset_t *c, kcpuset_t **lst) 202 { 203 if (atomic_dec_uint_nv(&c->nused) != 0) 204 return; 205 KASSERT(c->nused == 0); 206 KASSERT(c->next == NULL); 207 if (lst == NULL) { 208 kcpuset_destroy(c); 209 return; 210 } 211 c->next = *lst; 212 *lst = c; 213 } 214 215 int 216 kcpuset_copyin(const cpuset_t *u, kcpuset_t *k, size_t len) 217 { 218 KASSERT(k->nused > 0); 219 KASSERT(k->next == NULL); 220 if (len != CPUSET_SIZE()) 221 return EINVAL; 222 return copyin(u->bits, k->bits, cpuset_nentries * sizeof(k->bits[0])); 223 } 224 225 int 226 kcpuset_copyout(const kcpuset_t *k, cpuset_t *u, size_t len) 227 { 228 KASSERT(k->nused > 0); 229 KASSERT(k->next == NULL); 230 if (len != CPUSET_SIZE()) 231 return EINVAL; 232 return copyout(k->bits, u->bits, cpuset_nentries * sizeof(u->bits[0])); 233 } 234 235 void 236 kcpuset_zero(kcpuset_t *c) 237 { 238 KASSERT(c->nused > 0); 239 KASSERT(c->next == NULL); 240 (void)memset(c->bits, 0, cpuset_nentries * sizeof(c->bits[0])); 241 } 242 243 int 244 kcpuset_isset(cpuid_t i, const kcpuset_t *c) 245 { 246 const unsigned long j = i >> CPUSET_SHIFT; 247 248 KASSERT(c != NULL); 249 KASSERT(c->nused > 0); 250 KASSERT(c->next == NULL); 251 KASSERT(j < cpuset_nentries); 252 return ((1 << (i & CPUSET_MASK)) & c->bits[j]) != 0; 253 } 254 255 #endif 256 #endif 257