1 /* $OpenBSD: kern_sched.c,v 1.44 2017/01/21 05:42:03 guenther Exp $ */ 2 /* 3 * Copyright (c) 2007, 2008 Artur Grabowski <art@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 20 #include <sys/sched.h> 21 #include <sys/proc.h> 22 #include <sys/kthread.h> 23 #include <sys/systm.h> 24 #include <sys/resourcevar.h> 25 #include <sys/signalvar.h> 26 #include <sys/mutex.h> 27 #include <sys/task.h> 28 29 #include <uvm/uvm_extern.h> 30 31 void sched_kthreads_create(void *); 32 33 int sched_proc_to_cpu_cost(struct cpu_info *ci, struct proc *p); 34 struct proc *sched_steal_proc(struct cpu_info *); 35 36 /* 37 * To help choosing which cpu should run which process we keep track 38 * of cpus which are currently idle and which cpus have processes 39 * queued. 40 */ 41 struct cpuset sched_idle_cpus; 42 struct cpuset sched_queued_cpus; 43 struct cpuset sched_all_cpus; 44 45 /* 46 * Some general scheduler counters. 47 */ 48 uint64_t sched_nmigrations; /* Cpu migration counter */ 49 uint64_t sched_nomigrations; /* Cpu no migration counter */ 50 uint64_t sched_noidle; /* Times we didn't pick the idle task */ 51 uint64_t sched_stolen; /* Times we stole proc from other cpus */ 52 uint64_t sched_choose; /* Times we chose a cpu */ 53 uint64_t sched_wasidle; /* Times we came out of idle */ 54 55 #ifdef MULTIPROCESSOR 56 struct taskq *sbartq; 57 #endif 58 59 /* 60 * A few notes about cpu_switchto that is implemented in MD code. 61 * 62 * cpu_switchto takes two arguments, the old proc and the proc 63 * it should switch to. The new proc will never be NULL, so we always have 64 * a saved state that we need to switch to. The old proc however can 65 * be NULL if the process is exiting. NULL for the old proc simply 66 * means "don't bother saving old state". 67 * 68 * cpu_switchto is supposed to atomically load the new state of the process 69 * including the pcb, pmap and setting curproc, the p_cpu pointer in the 70 * proc and p_stat to SONPROC. Atomically with respect to interrupts, other 71 * cpus in the system must not depend on this state being consistent. 72 * Therefore no locking is necessary in cpu_switchto other than blocking 73 * interrupts during the context switch. 74 */ 75 76 /* 77 * sched_init_cpu is called from main() for the boot cpu, then it's the 78 * responsibility of the MD code to call it for all other cpus. 79 */ 80 void 81 sched_init_cpu(struct cpu_info *ci) 82 { 83 struct schedstate_percpu *spc = &ci->ci_schedstate; 84 int i; 85 86 for (i = 0; i < SCHED_NQS; i++) 87 TAILQ_INIT(&spc->spc_qs[i]); 88 89 spc->spc_idleproc = NULL; 90 91 kthread_create_deferred(sched_kthreads_create, ci); 92 93 LIST_INIT(&spc->spc_deadproc); 94 95 /* 96 * Slight hack here until the cpuset code handles cpu_info 97 * structures. 98 */ 99 cpuset_init_cpu(ci); 100 cpuset_add(&sched_all_cpus, ci); 101 } 102 103 void 104 sched_kthreads_create(void *v) 105 { 106 struct cpu_info *ci = v; 107 struct schedstate_percpu *spc = &ci->ci_schedstate; 108 static int num; 109 110 if (fork1(&proc0, FORK_SHAREVM|FORK_SHAREFILES|FORK_NOZOMBIE| 111 FORK_SYSTEM|FORK_SIGHAND|FORK_IDLE, NULL, 0, sched_idle, ci, NULL, 112 &spc->spc_idleproc)) 113 panic("fork idle"); 114 115 /* Name it as specified. */ 116 snprintf(spc->spc_idleproc->p_p->ps_comm, 117 sizeof(spc->spc_idleproc->p_p->ps_comm), 118 "idle%d", num); 119 120 num++; 121 } 122 123 void 124 sched_idle(void *v) 125 { 126 struct schedstate_percpu *spc; 127 struct proc *p = curproc; 128 struct cpu_info *ci = v; 129 int s; 130 131 KERNEL_UNLOCK(); 132 133 spc = &ci->ci_schedstate; 134 135 /* 136 * First time we enter here, we're not supposed to idle, 137 * just go away for a while. 138 */ 139 SCHED_LOCK(s); 140 cpuset_add(&sched_idle_cpus, ci); 141 p->p_stat = SSLEEP; 142 p->p_cpu = ci; 143 atomic_setbits_int(&p->p_flag, P_CPUPEG); 144 mi_switch(); 145 cpuset_del(&sched_idle_cpus, ci); 146 SCHED_UNLOCK(s); 147 148 KASSERT(ci == curcpu()); 149 KASSERT(curproc == spc->spc_idleproc); 150 151 while (1) { 152 while (!cpu_is_idle(curcpu())) { 153 struct proc *dead; 154 155 SCHED_LOCK(s); 156 p->p_stat = SSLEEP; 157 mi_switch(); 158 SCHED_UNLOCK(s); 159 160 while ((dead = LIST_FIRST(&spc->spc_deadproc))) { 161 LIST_REMOVE(dead, p_hash); 162 exit2(dead); 163 } 164 } 165 166 splassert(IPL_NONE); 167 168 cpuset_add(&sched_idle_cpus, ci); 169 cpu_idle_enter(); 170 while (spc->spc_whichqs == 0) { 171 #ifdef MULTIPROCESSOR 172 if (spc->spc_schedflags & SPCF_SHOULDHALT && 173 (spc->spc_schedflags & SPCF_HALTED) == 0) { 174 cpuset_del(&sched_idle_cpus, ci); 175 SCHED_LOCK(s); 176 atomic_setbits_int(&spc->spc_schedflags, 177 spc->spc_whichqs ? 0 : SPCF_HALTED); 178 SCHED_UNLOCK(s); 179 wakeup(spc); 180 } 181 #endif 182 cpu_idle_cycle(); 183 } 184 cpu_idle_leave(); 185 cpuset_del(&sched_idle_cpus, ci); 186 } 187 } 188 189 /* 190 * To free our address space we have to jump through a few hoops. 191 * The freeing is done by the reaper, but until we have one reaper 192 * per cpu, we have no way of putting this proc on the deadproc list 193 * and waking up the reaper without risking having our address space and 194 * stack torn from under us before we manage to switch to another proc. 195 * Therefore we have a per-cpu list of dead processes where we put this 196 * proc and have idle clean up that list and move it to the reaper list. 197 * All this will be unnecessary once we can bind the reaper this cpu 198 * and not risk having it switch to another in case it sleeps. 199 */ 200 void 201 sched_exit(struct proc *p) 202 { 203 struct schedstate_percpu *spc = &curcpu()->ci_schedstate; 204 struct timespec ts; 205 struct proc *idle; 206 int s; 207 208 nanouptime(&ts); 209 timespecsub(&ts, &spc->spc_runtime, &ts); 210 timespecadd(&p->p_rtime, &ts, &p->p_rtime); 211 212 LIST_INSERT_HEAD(&spc->spc_deadproc, p, p_hash); 213 214 /* This process no longer needs to hold the kernel lock. */ 215 KERNEL_UNLOCK(); 216 217 SCHED_LOCK(s); 218 idle = spc->spc_idleproc; 219 idle->p_stat = SRUN; 220 cpu_switchto(NULL, idle); 221 panic("cpu_switchto returned"); 222 } 223 224 /* 225 * Run queue management. 226 */ 227 void 228 sched_init_runqueues(void) 229 { 230 #ifdef MULTIPROCESSOR 231 sbartq = taskq_create("sbar", 1, IPL_NONE, 232 TASKQ_MPSAFE | TASKQ_CANTSLEEP); 233 if (sbartq == NULL) 234 panic("unable to create sbar taskq"); 235 #endif 236 } 237 238 void 239 setrunqueue(struct proc *p) 240 { 241 struct schedstate_percpu *spc; 242 int queue = p->p_priority >> 2; 243 244 SCHED_ASSERT_LOCKED(); 245 spc = &p->p_cpu->ci_schedstate; 246 spc->spc_nrun++; 247 248 TAILQ_INSERT_TAIL(&spc->spc_qs[queue], p, p_runq); 249 spc->spc_whichqs |= (1 << queue); 250 cpuset_add(&sched_queued_cpus, p->p_cpu); 251 252 if (cpuset_isset(&sched_idle_cpus, p->p_cpu)) 253 cpu_unidle(p->p_cpu); 254 } 255 256 void 257 remrunqueue(struct proc *p) 258 { 259 struct schedstate_percpu *spc; 260 int queue = p->p_priority >> 2; 261 262 SCHED_ASSERT_LOCKED(); 263 spc = &p->p_cpu->ci_schedstate; 264 spc->spc_nrun--; 265 266 TAILQ_REMOVE(&spc->spc_qs[queue], p, p_runq); 267 if (TAILQ_EMPTY(&spc->spc_qs[queue])) { 268 spc->spc_whichqs &= ~(1 << queue); 269 if (spc->spc_whichqs == 0) 270 cpuset_del(&sched_queued_cpus, p->p_cpu); 271 } 272 } 273 274 struct proc * 275 sched_chooseproc(void) 276 { 277 struct schedstate_percpu *spc = &curcpu()->ci_schedstate; 278 struct proc *p; 279 int queue; 280 281 SCHED_ASSERT_LOCKED(); 282 283 #ifdef MULTIPROCESSOR 284 if (spc->spc_schedflags & SPCF_SHOULDHALT) { 285 if (spc->spc_whichqs) { 286 for (queue = 0; queue < SCHED_NQS; queue++) { 287 while ((p = TAILQ_FIRST(&spc->spc_qs[queue]))) { 288 remrunqueue(p); 289 p->p_cpu = sched_choosecpu(p); 290 setrunqueue(p); 291 if (p->p_cpu == curcpu()) { 292 KASSERT(p->p_flag & P_CPUPEG); 293 goto again; 294 } 295 } 296 } 297 } 298 p = spc->spc_idleproc; 299 KASSERT(p); 300 KASSERT(p->p_wchan == NULL); 301 p->p_stat = SRUN; 302 return (p); 303 } 304 #endif 305 306 again: 307 if (spc->spc_whichqs) { 308 queue = ffs(spc->spc_whichqs) - 1; 309 p = TAILQ_FIRST(&spc->spc_qs[queue]); 310 remrunqueue(p); 311 sched_noidle++; 312 KASSERT(p->p_stat == SRUN); 313 } else if ((p = sched_steal_proc(curcpu())) == NULL) { 314 p = spc->spc_idleproc; 315 if (p == NULL) { 316 int s; 317 /* 318 * We get here if someone decides to switch during 319 * boot before forking kthreads, bleh. 320 * This is kind of like a stupid idle loop. 321 */ 322 #ifdef MULTIPROCESSOR 323 __mp_unlock(&sched_lock); 324 #endif 325 spl0(); 326 delay(10); 327 SCHED_LOCK(s); 328 goto again; 329 } 330 KASSERT(p); 331 p->p_stat = SRUN; 332 } 333 334 KASSERT(p->p_wchan == NULL); 335 return (p); 336 } 337 338 struct cpu_info * 339 sched_choosecpu_fork(struct proc *parent, int flags) 340 { 341 #ifdef MULTIPROCESSOR 342 struct cpu_info *choice = NULL; 343 fixpt_t load, best_load = ~0; 344 int run, best_run = INT_MAX; 345 struct cpu_info *ci; 346 struct cpuset set; 347 348 #if 0 349 /* 350 * XXX 351 * Don't do this until we have a painless way to move the cpu in exec. 352 * Preferably when nuking the old pmap and getting a new one on a 353 * new cpu. 354 */ 355 /* 356 * PPWAIT forks are simple. We know that the parent will not 357 * run until we exec and choose another cpu, so we just steal its 358 * cpu. 359 */ 360 if (flags & FORK_PPWAIT) 361 return (parent->p_cpu); 362 #endif 363 364 /* 365 * Look at all cpus that are currently idle and have nothing queued. 366 * If there are none, pick the one with least queued procs first, 367 * then the one with lowest load average. 368 */ 369 cpuset_complement(&set, &sched_queued_cpus, &sched_idle_cpus); 370 cpuset_intersection(&set, &set, &sched_all_cpus); 371 if (cpuset_first(&set) == NULL) 372 cpuset_copy(&set, &sched_all_cpus); 373 374 while ((ci = cpuset_first(&set)) != NULL) { 375 cpuset_del(&set, ci); 376 377 load = ci->ci_schedstate.spc_ldavg; 378 run = ci->ci_schedstate.spc_nrun; 379 380 if (choice == NULL || run < best_run || 381 (run == best_run &&load < best_load)) { 382 choice = ci; 383 best_load = load; 384 best_run = run; 385 } 386 } 387 388 return (choice); 389 #else 390 return (curcpu()); 391 #endif 392 } 393 394 struct cpu_info * 395 sched_choosecpu(struct proc *p) 396 { 397 #ifdef MULTIPROCESSOR 398 struct cpu_info *choice = NULL; 399 int last_cost = INT_MAX; 400 struct cpu_info *ci; 401 struct cpuset set; 402 403 /* 404 * If pegged to a cpu, don't allow it to move. 405 */ 406 if (p->p_flag & P_CPUPEG) 407 return (p->p_cpu); 408 409 sched_choose++; 410 411 /* 412 * Look at all cpus that are currently idle and have nothing queued. 413 * If there are none, pick the cheapest of those. 414 * (idle + queued could mean that the cpu is handling an interrupt 415 * at this moment and haven't had time to leave idle yet). 416 */ 417 cpuset_complement(&set, &sched_queued_cpus, &sched_idle_cpus); 418 cpuset_intersection(&set, &set, &sched_all_cpus); 419 420 /* 421 * First, just check if our current cpu is in that set, if it is, 422 * this is simple. 423 * Also, our cpu might not be idle, but if it's the current cpu 424 * and it has nothing else queued and we're curproc, take it. 425 */ 426 if (cpuset_isset(&set, p->p_cpu) || 427 (p->p_cpu == curcpu() && p->p_cpu->ci_schedstate.spc_nrun == 0 && 428 (p->p_cpu->ci_schedstate.spc_schedflags & SPCF_SHOULDHALT) == 0 && 429 curproc == p)) { 430 sched_wasidle++; 431 return (p->p_cpu); 432 } 433 434 if (cpuset_first(&set) == NULL) 435 cpuset_copy(&set, &sched_all_cpus); 436 437 while ((ci = cpuset_first(&set)) != NULL) { 438 int cost = sched_proc_to_cpu_cost(ci, p); 439 440 if (choice == NULL || cost < last_cost) { 441 choice = ci; 442 last_cost = cost; 443 } 444 cpuset_del(&set, ci); 445 } 446 447 if (p->p_cpu != choice) 448 sched_nmigrations++; 449 else 450 sched_nomigrations++; 451 452 return (choice); 453 #else 454 return (curcpu()); 455 #endif 456 } 457 458 /* 459 * Attempt to steal a proc from some cpu. 460 */ 461 struct proc * 462 sched_steal_proc(struct cpu_info *self) 463 { 464 struct proc *best = NULL; 465 #ifdef MULTIPROCESSOR 466 struct schedstate_percpu *spc; 467 int bestcost = INT_MAX; 468 struct cpu_info *ci; 469 struct cpuset set; 470 471 KASSERT((self->ci_schedstate.spc_schedflags & SPCF_SHOULDHALT) == 0); 472 473 cpuset_copy(&set, &sched_queued_cpus); 474 475 while ((ci = cpuset_first(&set)) != NULL) { 476 struct proc *p; 477 int queue; 478 int cost; 479 480 cpuset_del(&set, ci); 481 482 spc = &ci->ci_schedstate; 483 484 queue = ffs(spc->spc_whichqs) - 1; 485 TAILQ_FOREACH(p, &spc->spc_qs[queue], p_runq) { 486 if (p->p_flag & P_CPUPEG) 487 continue; 488 489 cost = sched_proc_to_cpu_cost(self, p); 490 491 if (best == NULL || cost < bestcost) { 492 best = p; 493 bestcost = cost; 494 } 495 } 496 } 497 if (best == NULL) 498 return (NULL); 499 500 spc = &best->p_cpu->ci_schedstate; 501 remrunqueue(best); 502 best->p_cpu = self; 503 504 sched_stolen++; 505 #endif 506 return (best); 507 } 508 509 #ifdef MULTIPROCESSOR 510 /* 511 * Base 2 logarithm of an int. returns 0 for 0 (yeye, I know). 512 */ 513 static int 514 log2(unsigned int i) 515 { 516 int ret = 0; 517 518 while (i >>= 1) 519 ret++; 520 521 return (ret); 522 } 523 524 /* 525 * Calculate the cost of moving the proc to this cpu. 526 * 527 * What we want is some guesstimate of how much "performance" it will 528 * cost us to move the proc here. Not just for caches and TLBs and NUMA 529 * memory, but also for the proc itself. A highly loaded cpu might not 530 * be the best candidate for this proc since it won't get run. 531 * 532 * Just total guesstimates for now. 533 */ 534 535 int sched_cost_load = 1; 536 int sched_cost_priority = 1; 537 int sched_cost_runnable = 3; 538 int sched_cost_resident = 1; 539 #endif 540 541 int 542 sched_proc_to_cpu_cost(struct cpu_info *ci, struct proc *p) 543 { 544 int cost = 0; 545 #ifdef MULTIPROCESSOR 546 struct schedstate_percpu *spc; 547 int l2resident = 0; 548 549 spc = &ci->ci_schedstate; 550 551 /* 552 * First, account for the priority of the proc we want to move. 553 * More willing to move, the lower the priority of the destination 554 * and the higher the priority of the proc. 555 */ 556 if (!cpuset_isset(&sched_idle_cpus, ci)) { 557 cost += (p->p_priority - spc->spc_curpriority) * 558 sched_cost_priority; 559 cost += sched_cost_runnable; 560 } 561 if (cpuset_isset(&sched_queued_cpus, ci)) 562 cost += spc->spc_nrun * sched_cost_runnable; 563 564 /* 565 * Try to avoid the primary cpu as it handles hardware interrupts. 566 * 567 * XXX Needs to be revisited when we distribute interrupts 568 * over cpus. 569 */ 570 if (CPU_IS_PRIMARY(ci)) 571 cost += sched_cost_runnable; 572 573 /* 574 * Higher load on the destination means we don't want to go there. 575 */ 576 cost += ((sched_cost_load * spc->spc_ldavg) >> FSHIFT); 577 578 /* 579 * If the proc is on this cpu already, lower the cost by how much 580 * it has been running and an estimate of its footprint. 581 */ 582 if (p->p_cpu == ci && p->p_slptime == 0) { 583 l2resident = 584 log2(pmap_resident_count(p->p_vmspace->vm_map.pmap)); 585 cost -= l2resident * sched_cost_resident; 586 } 587 #endif 588 return (cost); 589 } 590 591 /* 592 * Peg a proc to a cpu. 593 */ 594 void 595 sched_peg_curproc(struct cpu_info *ci) 596 { 597 struct proc *p = curproc; 598 int s; 599 600 SCHED_LOCK(s); 601 p->p_priority = p->p_usrpri; 602 p->p_stat = SRUN; 603 p->p_cpu = ci; 604 atomic_setbits_int(&p->p_flag, P_CPUPEG); 605 setrunqueue(p); 606 p->p_ru.ru_nvcsw++; 607 mi_switch(); 608 SCHED_UNLOCK(s); 609 } 610 611 #ifdef MULTIPROCESSOR 612 613 void 614 sched_start_secondary_cpus(void) 615 { 616 CPU_INFO_ITERATOR cii; 617 struct cpu_info *ci; 618 619 CPU_INFO_FOREACH(cii, ci) { 620 struct schedstate_percpu *spc = &ci->ci_schedstate; 621 622 if (CPU_IS_PRIMARY(ci)) 623 continue; 624 cpuset_add(&sched_all_cpus, ci); 625 atomic_clearbits_int(&spc->spc_schedflags, 626 SPCF_SHOULDHALT | SPCF_HALTED); 627 } 628 } 629 630 void 631 sched_stop_secondary_cpus(void) 632 { 633 CPU_INFO_ITERATOR cii; 634 struct cpu_info *ci; 635 636 /* 637 * Make sure we stop the secondary CPUs. 638 */ 639 CPU_INFO_FOREACH(cii, ci) { 640 struct schedstate_percpu *spc = &ci->ci_schedstate; 641 642 if (CPU_IS_PRIMARY(ci)) 643 continue; 644 cpuset_del(&sched_all_cpus, ci); 645 atomic_setbits_int(&spc->spc_schedflags, SPCF_SHOULDHALT); 646 } 647 CPU_INFO_FOREACH(cii, ci) { 648 struct schedstate_percpu *spc = &ci->ci_schedstate; 649 struct sleep_state sls; 650 651 if (CPU_IS_PRIMARY(ci)) 652 continue; 653 while ((spc->spc_schedflags & SPCF_HALTED) == 0) { 654 sleep_setup(&sls, spc, PZERO, "schedstate"); 655 sleep_finish(&sls, 656 (spc->spc_schedflags & SPCF_HALTED) == 0); 657 } 658 } 659 } 660 661 void 662 sched_barrier_task(void *arg) 663 { 664 struct cpu_info *ci = arg; 665 666 sched_peg_curproc(ci); 667 ci->ci_schedstate.spc_barrier = 1; 668 wakeup(&ci->ci_schedstate.spc_barrier); 669 atomic_clearbits_int(&curproc->p_flag, P_CPUPEG); 670 } 671 672 void 673 sched_barrier(struct cpu_info *ci) 674 { 675 struct sleep_state sls; 676 struct task task; 677 CPU_INFO_ITERATOR cii; 678 struct schedstate_percpu *spc; 679 680 if (ci == NULL) { 681 CPU_INFO_FOREACH(cii, ci) { 682 if (CPU_IS_PRIMARY(ci)) 683 break; 684 } 685 } 686 KASSERT(ci != NULL); 687 688 if (ci == curcpu()) 689 return; 690 691 task_set(&task, sched_barrier_task, ci); 692 spc = &ci->ci_schedstate; 693 spc->spc_barrier = 0; 694 task_add(sbartq, &task); 695 while (!spc->spc_barrier) { 696 sleep_setup(&sls, &spc->spc_barrier, PWAIT, "sbar"); 697 sleep_finish(&sls, !spc->spc_barrier); 698 } 699 } 700 701 #else 702 703 void 704 sched_barrier(struct cpu_info *ci) 705 { 706 } 707 708 #endif 709 710 /* 711 * Functions to manipulate cpu sets. 712 */ 713 struct cpu_info *cpuset_infos[MAXCPUS]; 714 static struct cpuset cpuset_all; 715 716 void 717 cpuset_init_cpu(struct cpu_info *ci) 718 { 719 cpuset_add(&cpuset_all, ci); 720 cpuset_infos[CPU_INFO_UNIT(ci)] = ci; 721 } 722 723 void 724 cpuset_clear(struct cpuset *cs) 725 { 726 memset(cs, 0, sizeof(*cs)); 727 } 728 729 void 730 cpuset_add(struct cpuset *cs, struct cpu_info *ci) 731 { 732 unsigned int num = CPU_INFO_UNIT(ci); 733 atomic_setbits_int(&cs->cs_set[num/32], (1 << (num % 32))); 734 } 735 736 void 737 cpuset_del(struct cpuset *cs, struct cpu_info *ci) 738 { 739 unsigned int num = CPU_INFO_UNIT(ci); 740 atomic_clearbits_int(&cs->cs_set[num/32], (1 << (num % 32))); 741 } 742 743 int 744 cpuset_isset(struct cpuset *cs, struct cpu_info *ci) 745 { 746 unsigned int num = CPU_INFO_UNIT(ci); 747 return (cs->cs_set[num/32] & (1 << (num % 32))); 748 } 749 750 void 751 cpuset_add_all(struct cpuset *cs) 752 { 753 cpuset_copy(cs, &cpuset_all); 754 } 755 756 void 757 cpuset_copy(struct cpuset *to, struct cpuset *from) 758 { 759 memcpy(to, from, sizeof(*to)); 760 } 761 762 struct cpu_info * 763 cpuset_first(struct cpuset *cs) 764 { 765 int i; 766 767 for (i = 0; i < CPUSET_ASIZE(ncpus); i++) 768 if (cs->cs_set[i]) 769 return (cpuset_infos[i * 32 + ffs(cs->cs_set[i]) - 1]); 770 771 return (NULL); 772 } 773 774 void 775 cpuset_union(struct cpuset *to, struct cpuset *a, struct cpuset *b) 776 { 777 int i; 778 779 for (i = 0; i < CPUSET_ASIZE(ncpus); i++) 780 to->cs_set[i] = a->cs_set[i] | b->cs_set[i]; 781 } 782 783 void 784 cpuset_intersection(struct cpuset *to, struct cpuset *a, struct cpuset *b) 785 { 786 int i; 787 788 for (i = 0; i < CPUSET_ASIZE(ncpus); i++) 789 to->cs_set[i] = a->cs_set[i] & b->cs_set[i]; 790 } 791 792 void 793 cpuset_complement(struct cpuset *to, struct cpuset *a, struct cpuset *b) 794 { 795 int i; 796 797 for (i = 0; i < CPUSET_ASIZE(ncpus); i++) 798 to->cs_set[i] = b->cs_set[i] & ~a->cs_set[i]; 799 } 800