Add kcpuset(9) - a reworked dynamic CPU set implementation for kernel.

Suitable for use during the early boot.  MD and other implementations
should be replaced with this interface.

Discussed on: tech-kern@
This commit is contained in:
rmind 2011-08-07 13:33:01 +00:00
parent f398b121d3
commit 52b220e91d
15 changed files with 532 additions and 233 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: cpuset.c,v 1.16 2010/09/21 02:03:29 rmind Exp $ */
/* $NetBSD: cpuset.c,v 1.17 2011/08/07 13:33:02 rmind Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@ -32,7 +32,7 @@
#ifndef _STANDALONE
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: cpuset.c,v 1.16 2010/09/21 02:03:29 rmind Exp $");
__RCSID("$NetBSD: cpuset.c,v 1.17 2011/08/07 13:33:02 rmind Exp $");
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
@ -64,24 +64,11 @@ struct _cpuset {
uint32_t bits[0];
};
#ifdef _KERNEL
struct _kcpuset {
unsigned int nused;
struct _kcpuset *next;
uint32_t bits[0];
};
#define KCPUSET_SIZE(n) (sizeof( \
struct { \
unsigned int nused; \
struct _kcpuset *next; \
uint32_t bits[0]; \
}) + sizeof(uint32_t) * (n))
#endif
#ifndef _KERNEL
static size_t cpuset_size = 0;
static size_t cpuset_nentries = 0;
#ifndef _KERNEL
size_t
/*ARGSUSED*/
_cpuset_size(const cpuset_t *c)
@ -161,150 +148,5 @@ _cpuset_destroy(cpuset_t *c)
free(c);
}
#else
kcpuset_t *
kcpuset_create(void)
{
kcpuset_t *c;
if (cpuset_size == 0) {
cpuset_nentries = CPUSET_NENTRIES(MAXCPUS);
cpuset_size = KCPUSET_SIZE(cpuset_nentries);
}
c = kmem_zalloc(cpuset_size, KM_SLEEP);
c->next = NULL;
c->nused = 1;
return c;
}
void
kcpuset_destroy(kcpuset_t *c)
{
kcpuset_t *nc;
while (c) {
KASSERT(c->nused == 0);
nc = c->next;
kmem_free(c, cpuset_size);
c = nc;
}
}
void
kcpuset_copy(kcpuset_t *d, const kcpuset_t *s)
{
KASSERT(d->nused == 1);
memcpy(d->bits, s->bits, cpuset_nentries * sizeof(s->bits[0]));
}
void
kcpuset_use(kcpuset_t *c)
{
atomic_inc_uint(&c->nused);
}
void
kcpuset_unuse(kcpuset_t *c, kcpuset_t **lst)
{
if (atomic_dec_uint_nv(&c->nused) != 0)
return;
KASSERT(c->nused == 0);
KASSERT(c->next == NULL);
if (lst == NULL) {
kcpuset_destroy(c);
return;
}
c->next = *lst;
*lst = c;
}
int
kcpuset_copyin(const cpuset_t *u, kcpuset_t *k, size_t len)
{
KASSERT(k->nused > 0);
KASSERT(k->next == NULL);
if (len != CPUSET_SIZE(cpuset_nentries))
return EINVAL;
return copyin(u->bits, k->bits, cpuset_nentries * sizeof(k->bits[0]));
}
int
kcpuset_copyout(const kcpuset_t *k, cpuset_t *u, size_t len)
{
KASSERT(k->nused > 0);
KASSERT(k->next == NULL);
if (len != CPUSET_SIZE(cpuset_nentries))
return EINVAL;
return copyout(k->bits, u->bits, cpuset_nentries * sizeof(u->bits[0]));
}
void
kcpuset_zero(kcpuset_t *c)
{
KASSERT(c->nused > 0);
KASSERT(c->next == NULL);
memset(c->bits, 0, cpuset_nentries * sizeof(c->bits[0]));
}
void
kcpuset_fill(kcpuset_t *c)
{
KASSERT(c->nused > 0);
KASSERT(c->next == NULL);
memset(c->bits, ~0, cpuset_nentries * sizeof(c->bits[0]));
}
void
kcpuset_set(cpuid_t i, kcpuset_t *c)
{
const unsigned long j = i >> CPUSET_SHIFT;
KASSERT(c->next == NULL);
KASSERT(j < cpuset_nentries);
c->bits[j] |= 1 << (i & CPUSET_MASK);
}
int
kcpuset_isset(cpuid_t i, const kcpuset_t *c)
{
const unsigned long j = i >> CPUSET_SHIFT;
KASSERT(c != NULL);
KASSERT(c->nused > 0);
KASSERT(c->next == NULL);
KASSERT(j < cpuset_nentries);
return ((1 << (i & CPUSET_MASK)) & c->bits[j]) != 0;
}
bool
kcpuset_iszero(const kcpuset_t *c)
{
unsigned long j;
for (j = 0; j < cpuset_nentries; j++)
if (c->bits[j] != 0)
return false;
return true;
}
bool
kcpuset_match(const kcpuset_t *c1, const kcpuset_t *c2)
{
unsigned long j;
for (j = 0; j < cpuset_nentries; j++)
if ((c1->bits[j] & c2->bits[j]) != c2->bits[j])
return false;
return true;
}
#endif
#endif

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.1657 2011/08/06 17:17:39 jruoho Exp $
# $NetBSD: mi,v 1.1658 2011/08/07 13:33:02 rmind Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@ -2385,6 +2385,7 @@
./usr/include/sys/ipc.h comp-c-include
./usr/include/sys/joystick.h comp-c-include
./usr/include/sys/kcore.h comp-c-include
./usr/include/sys/kcpuset.h comp-c-include
./usr/include/sys/kernel.h comp-obsolete obsolete
./usr/include/sys/keylock.h comp-obsolete obsolete
./usr/include/sys/kgdb.h comp-c-include

View File

@ -1,4 +1,4 @@
# $NetBSD: files,v 1.1022 2011/07/30 17:01:04 christos Exp $
# $NetBSD: files,v 1.1023 2011/08/07 13:33:01 rmind Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
version 20100430
@ -1530,6 +1530,7 @@ file kern/subr_extent.c
file kern/subr_hash.c
file kern/subr_humanize.c
file kern/subr_iostat.c
file kern/subr_kcpuset.c
file kern/subr_kmem.c
file kern/subr_kobj.c
file kern/subr_kobj_vfs.c

View File

@ -1,4 +1,4 @@
/* $NetBSD: init_main.c,v 1.434 2011/07/30 17:01:04 christos Exp $ */
/* $NetBSD: init_main.c,v 1.435 2011/08/07 13:33:01 rmind Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@ -97,7 +97,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.434 2011/07/30 17:01:04 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.435 2011/08/07 13:33:01 rmind Exp $");
#include "opt_ddb.h"
#include "opt_ipsec.h"
@ -167,6 +167,7 @@ __KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.434 2011/07/30 17:01:04 christos Exp
#include <sys/event.h>
#include <sys/lockf.h>
#include <sys/once.h>
#include <sys/kcpuset.h>
#include <sys/ksyms.h>
#include <sys/uidinfo.h>
#include <sys/kprintf.h>
@ -310,6 +311,7 @@ main(void)
evcnt_init();
uvm_init();
kcpuset_sysinit();
prop_kern_init();

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_cpu.c,v 1.47 2011/06/29 06:22:21 matt Exp $ */
/* $NetBSD: kern_cpu.c,v 1.48 2011/08/07 13:33:01 rmind Exp $ */
/*-
* Copyright (c) 2007, 2008, 2009, 2010 The NetBSD Foundation, Inc.
@ -56,7 +56,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_cpu.c,v 1.47 2011/06/29 06:22:21 matt Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_cpu.c,v 1.48 2011/08/07 13:33:01 rmind Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -107,6 +107,9 @@ kmutex_t cpu_lock __cacheline_aligned;
int ncpu __read_mostly;
int ncpuonline __read_mostly;
bool mp_online __read_mostly;
kcpuset_t * kcpuset_attached __read_mostly;
struct cpuqueue cpu_queue __cacheline_aligned
= CIRCLEQ_HEAD_INITIALIZER(cpu_queue);
@ -131,8 +134,11 @@ mi_cpu_attach(struct cpu_info *ci)
if (__predict_false(cpu_infos == NULL)) {
cpu_infos =
kmem_zalloc(sizeof(cpu_infos[0]) * maxcpus, KM_SLEEP);
kcpuset_create(&kcpuset_attached);
kcpuset_zero(kcpuset_attached);
}
cpu_infos[cpu_index(ci)] = ci;
kcpuset_set(kcpuset_attached, ci->ci_index);
sched_cpuattach(ci);
@ -315,7 +321,7 @@ cpu_xc_offline(struct cpu_info *ci)
for (CPU_INFO_FOREACH(cii, mci)) {
mspc = &mci->ci_schedstate;
if ((mspc->spc_flags & SPCF_OFFLINE) == 0 &&
kcpuset_isset(cpu_index(mci), l->l_affinity))
kcpuset_isset(l->l_affinity, cpu_index(mci)))
break;
}
if (mci == NULL) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_runq.c,v 1.30 2010/03/03 00:47:30 yamt Exp $ */
/* $NetBSD: kern_runq.c,v 1.31 2011/08/07 13:33:01 rmind Exp $ */
/*
* Copyright (c) 2007, 2008 Mindaugas Rasiukevicius <rmind at NetBSD org>
@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_runq.c,v 1.30 2010/03/03 00:47:30 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_runq.c,v 1.31 2011/08/07 13:33:01 rmind Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@ -352,7 +352,7 @@ sched_migratable(const struct lwp *l, struct cpu_info *ci)
/* Affinity bind */
if (__predict_false(l->l_flag & LW_AFFINITY))
return kcpuset_isset(cpu_index(ci), l->l_affinity);
return kcpuset_isset(l->l_affinity, cpu_index(ci));
/* Processor-set */
return (spc->spc_psid == l->l_psid);

386
sys/kern/subr_kcpuset.c Normal file
View File

@ -0,0 +1,386 @@
/* $NetBSD: subr_kcpuset.c,v 1.1 2011/08/07 13:33:01 rmind Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mindaugas Rasiukevicius.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Kernel CPU set implementation.
*
* Interface can be used by kernel subsystems as a unified dynamic CPU
* bitset implementation handling many CPUs. Facility also supports early
* use by MD code on boot, as it fixups bitsets on further boot.
*
* TODO:
* - Handle "reverse" bitset on fixup/grow.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: subr_kcpuset.c,v 1.1 2011/08/07 13:33:01 rmind Exp $");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/atomic.h>
#include <sys/sched.h>
#include <sys/kcpuset.h>
#include <sys/pool.h>
/* Number of CPUs to support. */
#define KC_MAXCPUS roundup2(MAXCPUS, 32)
/*
* Structure of dynamic CPU set in the kernel.
*/
struct kcpuset {
uint32_t bits[0];
};
typedef struct kcpuset_impl {
/* Reference count. */
u_int kc_refcnt;
/* Next to free, if non-NULL (used when multiple references). */
struct kcpuset * kc_next;
/* Actual variable-sized field of bits. */
struct kcpuset kc_field;
} kcpuset_impl_t;
#define KC_BITS_OFF (offsetof(struct kcpuset_impl, kc_field))
#define KC_GETSTRUCT(b) ((kcpuset_impl_t *)((char *)(b) - KC_BITS_OFF))
/* Sizes of a single bitset. */
#define KC_SHIFT 5
#define KC_MASK 31
/* An array of noted early kcpuset creations and data. */
#define KC_SAVE_NITEMS 8
/* Structures for early boot mechanism (must be statically initialised). */
static kcpuset_t ** kc_noted_early[KC_SAVE_NITEMS];
static uint32_t kc_bits_early[KC_SAVE_NITEMS];
static int kc_last_idx = 0;
static bool kc_initialised = false;
#define KC_BITSIZE_EARLY sizeof(kc_bits_early[0])
#define KC_NFIELDS_EARLY (KC_BITSIZE_EARLY >> KC_SHIFT)
/*
* The size of whole bitset fields and amount of fields.
* The whole size must statically initialise for early case.
*/
static size_t kc_bitsize __read_mostly = KC_BITSIZE_EARLY;
static size_t kc_nfields __read_mostly = KC_NFIELDS_EARLY;
static pool_cache_t kc_cache __read_mostly;
static kcpuset_t * kcpuset_create_raw(void);
/*
* kcpuset_sysinit: initialize the subsystem, transfer early boot cases
* to dynamically allocated sets.
*/
void
kcpuset_sysinit(void)
{
kcpuset_t *kc_dynamic[KC_SAVE_NITEMS], *kcp;
int i, s;
/* Set a kcpuset_t sizes. */
kc_nfields = (KC_MAXCPUS >> KC_SHIFT);
kc_bitsize = sizeof(uint32_t) * kc_nfields;
kc_cache = pool_cache_init(sizeof(kcpuset_impl_t) + kc_bitsize,
coherency_unit, 0, 0, "kcpuset", NULL, IPL_NONE, NULL, NULL, NULL);
/* First, pre-allocate kcpuset entries. */
for (i = 0; i < kc_last_idx; i++) {
kcp = kcpuset_create_raw();
kcpuset_zero(kcp);
kc_dynamic[i] = kcp;
}
/*
* Prepare to convert all early noted kcpuset uses to dynamic sets.
* All processors, except the one we are currently running (primary),
* must not be spinned yet. Since MD facilities can use kcpuset,
* raise the IPL to high.
*/
KASSERT(mp_online == false);
s = splhigh();
for (i = 0; i < kc_last_idx; i++) {
/*
* Transfer the bits from early static storage to the kcpuset.
*/
KASSERT(kc_bitsize >= KC_BITSIZE_EARLY);
memcpy(kc_dynamic[i], &kc_bits_early[i], KC_BITSIZE_EARLY);
/*
* Store the new pointer, pointing to the allocated kcpuset.
* Note: we are not in an interrupt context and it is the only
* CPU running - thus store is safe (e.g. no need for pointer
* variable to be volatile).
*/
*kc_noted_early[i] = kc_dynamic[i];
}
kc_initialised = true;
kc_last_idx = 0;
splx(s);
}
/*
* kcpuset_early_ptr: note an early boot use by saving the pointer and
* returning a pointer to a static, temporary bit field.
*/
static kcpuset_t *
kcpuset_early_ptr(kcpuset_t **kcptr)
{
kcpuset_t *kcp;
int s;
s = splhigh();
if (kc_last_idx < KC_SAVE_NITEMS) {
/*
* Save the pointer, return pointer to static early field.
* Need to zero it out.
*/
kc_noted_early[kc_last_idx++] = kcptr;
kcp = (kcpuset_t *)&kc_bits_early[kc_last_idx];
memset(kcp, 0, KC_BITSIZE_EARLY);
KASSERT(kc_bitsize == KC_BITSIZE_EARLY);
} else {
panic("kcpuset(9): all early-use entries exhausted; "
"increase KC_SAVE_NITEMS\n");
}
splx(s);
return kcp;
}
/*
* Routines to create or destroy the CPU set.
* Early boot case is handled.
*/
static kcpuset_t *
kcpuset_create_raw(void)
{
kcpuset_impl_t *kc;
kc = pool_cache_get(kc_cache, PR_WAITOK);
kc->kc_refcnt = 1;
kc->kc_next = NULL;
/* Note: return pointer to the actual field of bits. */
KASSERT((uint8_t *)kc + KC_BITS_OFF == (uint8_t *)&kc->kc_field);
return &kc->kc_field;
}
void
kcpuset_create(kcpuset_t **retkcp)
{
if (__predict_false(!kc_initialised)) {
/* Early boot use - special case. */
*retkcp = kcpuset_early_ptr(retkcp);
return;
}
*retkcp = kcpuset_create_raw();
}
void
kcpuset_destroy(kcpuset_t *kcp)
{
kcpuset_impl_t *kc, *nkc;
KASSERT(kc_initialised);
KASSERT(kcp != NULL);
kc = KC_GETSTRUCT(kcp);
do {
nkc = KC_GETSTRUCT(kc->kc_next);
pool_cache_put(kc_cache, kc);
kc = nkc;
} while (kc);
}
/*
* Routines to copy or reference/unreference the CPU set.
* Note: early boot case is not supported by these routines.
*/
void
kcpuset_copy(kcpuset_t *dkcp, kcpuset_t *skcp)
{
KASSERT(kc_initialised);
KASSERT(KC_GETSTRUCT(dkcp)->kc_refcnt == 1);
memcpy(dkcp, skcp, kc_bitsize);
}
void
kcpuset_use(kcpuset_t *kcp)
{
kcpuset_impl_t *kc = KC_GETSTRUCT(kcp);
KASSERT(kc_initialised);
atomic_inc_uint(&kc->kc_refcnt);
}
void
kcpuset_unuse(kcpuset_t *kcp, kcpuset_t **lst)
{
kcpuset_impl_t *kc = KC_GETSTRUCT(kcp);
KASSERT(kc_initialised);
KASSERT(kc->kc_refcnt > 0);
if (atomic_dec_uint_nv(&kc->kc_refcnt) != 0) {
return;
}
KASSERT(kc->kc_next == NULL);
if (lst == NULL) {
kcpuset_destroy(kcp);
return;
}
kc->kc_next = *lst;
*lst = kcp;
}
/*
* Routines to transfer the CPU set from / to userspace.
* Note: early boot case is not supported by these routines.
*/
int
kcpuset_copyin(const cpuset_t *ucp, kcpuset_t *kcp, size_t len)
{
kcpuset_impl_t *kc = KC_GETSTRUCT(kcp);
KASSERT(kc_initialised);
KASSERT(kc->kc_refcnt > 0);
KASSERT(kc->kc_next == NULL);
(void)kc;
if (len != kc_bitsize) { /* XXX */
return EINVAL;
}
return copyin(ucp, kcp, kc_bitsize);
}
int
kcpuset_copyout(kcpuset_t *kcp, cpuset_t *ucp, size_t len)
{
kcpuset_impl_t *kc = KC_GETSTRUCT(kcp);
KASSERT(kc_initialised);
KASSERT(kc->kc_refcnt > 0);
KASSERT(kc->kc_next == NULL);
(void)kc;
if (len != kc_bitsize) { /* XXX */
return EINVAL;
}
return copyout(kcp, ucp, kc_bitsize);
}
/*
* Routines to change bit field - zero, fill, set, unset, etc.
*/
void
kcpuset_zero(kcpuset_t *kcp)
{
KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_refcnt > 0);
KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL);
memset(kcp, 0, kc_bitsize);
}
void
kcpuset_fill(kcpuset_t *kcp)
{
KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_refcnt > 0);
KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL);
memset(kcp, ~0, kc_bitsize);
}
void
kcpuset_set(kcpuset_t *kcp, cpuid_t i)
{
const size_t j = i >> KC_SHIFT;
KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL);
KASSERT(j < kc_nfields);
kcp->bits[j] |= 1 << (i & KC_MASK);
}
void
kcpuset_clear(kcpuset_t *kcp, cpuid_t i)
{
const size_t j = i >> KC_SHIFT;
KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL);
KASSERT(j < kc_nfields);
kcp->bits[j] &= ~(1 << (i & KC_MASK));
}
int
kcpuset_isset(kcpuset_t *kcp, cpuid_t i)
{
const size_t j = i >> KC_SHIFT;
KASSERT(kcp != NULL);
KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_refcnt > 0);
KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL);
KASSERT(j < kc_nfields);
return ((1 << (i & KC_MASK)) & kcp->bits[j]) != 0;
}
bool
kcpuset_iszero(kcpuset_t *kcp)
{
for (size_t j = 0; j < kc_nfields; j++) {
if (kcp->bits[j] != 0) {
return false;
}
}
return true;
}
bool
kcpuset_match(const kcpuset_t *kcp1, const kcpuset_t *kcp2)
{
return memcmp(kcp1, kcp2, kc_bitsize) == 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: subr_pserialize.c,v 1.2 2011/08/01 15:26:31 he Exp $ */
/* $NetBSD: subr_pserialize.c,v 1.3 2011/08/07 13:33:01 rmind Exp $ */
/*-
* Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
@ -38,7 +38,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: subr_pserialize.c,v 1.2 2011/08/01 15:26:31 he Exp $");
__KERNEL_RCSID(0, "$NetBSD: subr_pserialize.c,v 1.3 2011/08/07 13:33:01 rmind Exp $");
#include <sys/param.h>
@ -103,8 +103,8 @@ pserialize_create(void)
psz = kmem_zalloc(sizeof(struct pserialize), KM_SLEEP);
cv_init(&psz->psz_notifier, "psrlz");
psz->psz_target = kcpuset_create();
psz->psz_pass = kcpuset_create();
kcpuset_create(&psz->psz_target);
kcpuset_create(&psz->psz_pass);
psz->psz_owner = NULL;
return psz;
@ -147,7 +147,6 @@ pserialize_perform(pserialize_t psz)
return;
}
KASSERT(psz->psz_owner == NULL);
KASSERT(kcpuset_iszero(psz->psz_target));
KASSERT(ncpu > 0);
/*
@ -157,7 +156,7 @@ pserialize_perform(pserialize_t psz)
* other processors.
*/
psz->psz_owner = curlwp;
kcpuset_fill(psz->psz_target);
kcpuset_copy(psz->psz_target, kcpuset_attached);
kcpuset_zero(psz->psz_pass);
mutex_spin_enter(&psz_lock);
@ -234,7 +233,7 @@ pserialize_switchpoint(void)
for (psz = TAILQ_FIRST(&psz_queue1); psz != NULL; psz = next) {
next = TAILQ_NEXT(psz, psz_chain);
if (!kcpuset_match(psz->psz_pass, psz->psz_target)) {
kcpuset_set(cid, psz->psz_pass);
kcpuset_set(psz->psz_pass, cid);
continue;
}
kcpuset_zero(psz->psz_pass);
@ -248,7 +247,7 @@ pserialize_switchpoint(void)
for (psz = TAILQ_FIRST(&psz_queue0); psz != NULL; psz = next) {
next = TAILQ_NEXT(psz, psz_chain);
if (!kcpuset_match(psz->psz_pass, psz->psz_target)) {
kcpuset_set(cid, psz->psz_pass);
kcpuset_set(psz->psz_pass, cid);
continue;
}
kcpuset_zero(psz->psz_pass);

View File

@ -1,4 +1,4 @@
/* $NetBSD: sys_pset.c,v 1.15 2010/07/01 02:38:31 rmind Exp $ */
/* $NetBSD: sys_pset.c,v 1.16 2011/08/07 13:33:01 rmind Exp $ */
/*
* Copyright (c) 2008, Mindaugas Rasiukevicius <rmind at NetBSD org>
@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sys_pset.c,v 1.15 2010/07/01 02:38:31 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: sys_pset.c,v 1.16 2011/08/07 13:33:01 rmind Exp $");
#include <sys/param.h>
@ -373,7 +373,7 @@ sys_pset_assign(struct lwp *l, const struct sys_pset_assign_args *uap,
lwp_unlock(t);
continue;
}
if (kcpuset_isset(cpu_index(ci), t->l_affinity)) {
if (kcpuset_isset(t->l_affinity, cpu_index(ci))) {
lwp_unlock(t);
mutex_exit(proc_lock);
mutex_exit(&cpu_lock);

View File

@ -1,7 +1,7 @@
/* $NetBSD: sys_sched.c,v 1.35 2010/07/01 02:38:31 rmind Exp $ */
/* $NetBSD: sys_sched.c,v 1.36 2011/08/07 13:33:01 rmind Exp $ */
/*
* Copyright (c) 2008, Mindaugas Rasiukevicius <rmind at NetBSD org>
* Copyright (c) 2008, 2011 Mindaugas Rasiukevicius <rmind at NetBSD org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sys_sched.c,v 1.35 2010/07/01 02:38:31 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: sys_sched.c,v 1.36 2011/08/07 13:33:01 rmind Exp $");
#include <sys/param.h>
@ -298,12 +298,16 @@ out:
static int
genkcpuset(kcpuset_t **dset, const cpuset_t *sset, size_t size)
{
kcpuset_t *kset;
int error;
*dset = kcpuset_create();
error = kcpuset_copyin(sset, *dset, size);
if (error != 0)
kcpuset_unuse(*dset, NULL);
kcpuset_create(&kset);
error = kcpuset_copyin(sset, kset, size);
if (error) {
kcpuset_unuse(kset, NULL);
} else {
*dset = kset;
}
return error;
}
@ -320,7 +324,7 @@ sys__sched_setaffinity(struct lwp *l,
syscallarg(size_t) size;
syscallarg(const cpuset_t *) cpuset;
} */
kcpuset_t *cpuset, *cpulst = NULL;
kcpuset_t *kcset, *kcpulst = NULL;
struct cpu_info *ici, *ci;
struct proc *p;
struct lwp *t;
@ -330,7 +334,7 @@ sys__sched_setaffinity(struct lwp *l,
u_int lcnt;
int error;
error = genkcpuset(&cpuset, SCARG(uap, cpuset), SCARG(uap, size));
error = genkcpuset(&kcset, SCARG(uap, cpuset), SCARG(uap, size));
if (error)
return error;
@ -349,7 +353,7 @@ sys__sched_setaffinity(struct lwp *l,
for (CPU_INFO_FOREACH(cii, ici)) {
struct schedstate_percpu *ispc;
if (kcpuset_isset(cpu_index(ici), cpuset) == 0)
if (kcpuset_isset(kcset, cpu_index(ici)) == 0)
continue;
ispc = &ici->ci_schedstate;
@ -375,8 +379,8 @@ sys__sched_setaffinity(struct lwp *l,
goto out;
}
/* Empty set */
kcpuset_unuse(cpuset, &cpulst);
cpuset = NULL;
kcpuset_unuse(kcset, &kcpulst);
kcset = NULL;
}
if (SCARG(uap, pid) != 0) {
@ -433,33 +437,42 @@ sys__sched_setaffinity(struct lwp *l,
lwp_unlock(t);
continue;
}
if (cpuset) {
if (kcset) {
/* Set the affinity flag and new CPU set */
t->l_flag |= LW_AFFINITY;
kcpuset_use(cpuset);
kcpuset_use(kcset);
if (t->l_affinity != NULL)
kcpuset_unuse(t->l_affinity, &cpulst);
t->l_affinity = cpuset;
kcpuset_unuse(t->l_affinity, &kcpulst);
t->l_affinity = kcset;
/* Migrate to another CPU, unlocks LWP */
lwp_migrate(t, ci);
} else {
/* Unset the affinity flag */
t->l_flag &= ~LW_AFFINITY;
if (t->l_affinity != NULL)
kcpuset_unuse(t->l_affinity, &cpulst);
kcpuset_unuse(t->l_affinity, &kcpulst);
t->l_affinity = NULL;
lwp_unlock(t);
}
lcnt++;
}
mutex_exit(p->p_lock);
if (lcnt == 0)
if (lcnt == 0) {
error = ESRCH;
}
out:
mutex_exit(&cpu_lock);
if (cpuset != NULL)
kcpuset_unuse(cpuset, &cpulst);
kcpuset_destroy(cpulst);
/*
* Drop the initial reference (LWPs, if any, have the ownership now),
* and destroy whatever is in the G/C list, if filled.
*/
if (kcset) {
kcpuset_unuse(kcset, &kcpulst);
}
if (kcpulst) {
kcpuset_destroy(kcpulst);
}
return error;
}
@ -477,10 +490,10 @@ sys__sched_getaffinity(struct lwp *l,
syscallarg(cpuset_t *) cpuset;
} */
struct lwp *t;
kcpuset_t *cpuset;
kcpuset_t *kcset;
int error;
error = genkcpuset(&cpuset, SCARG(uap, cpuset), SCARG(uap, size));
error = genkcpuset(&kcset, SCARG(uap, cpuset), SCARG(uap, size));
if (error)
return error;
@ -500,15 +513,16 @@ sys__sched_getaffinity(struct lwp *l,
lwp_lock(t);
if (t->l_flag & LW_AFFINITY) {
KASSERT(t->l_affinity != NULL);
kcpuset_copy(cpuset, t->l_affinity);
} else
kcpuset_zero(cpuset);
kcpuset_copy(kcset, t->l_affinity);
} else {
kcpuset_zero(kcset);
}
lwp_unlock(t);
mutex_exit(t->l_proc->p_lock);
error = kcpuset_copyout(cpuset, SCARG(uap, cpuset), SCARG(uap, size));
error = kcpuset_copyout(kcset, SCARG(uap, cpuset), SCARG(uap, size));
out:
kcpuset_unuse(cpuset, NULL);
kcpuset_unuse(kcset, NULL);
return error;
}

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.136 2011/07/17 20:54:54 joerg Exp $
# $NetBSD: Makefile,v 1.137 2011/08/07 13:33:02 rmind Exp $
.include <bsd.sys.mk>
@ -19,7 +19,7 @@ INCS= acct.h agpio.h aio.h ansi.h aout_mids.h ataio.h atomic.h audioio.h \
flashio.h float_ieee754.h fstypes.h gcq.h gmon.h gpio.h hash.h \
ieee754.h inttypes.h ioccom.h ioctl.h ioctl_compat.h iostat.h ipc.h \
joystick.h \
kcore.h kgdb.h kmem.h ksem.h ksyms.h ktrace.h \
kcore.h kcpuset.h kgdb.h kmem.h ksem.h ksyms.h ktrace.h \
localedef.h lock.h lockf.h lwp.h lwpctl.h \
malloc.h mallocvar.h mbuf.h md4.h md5.h midiio.h \
mman.h module.h mount.h mqueue.h msg.h msgbuf.h mtio.h mutex.h \

View File

@ -1,4 +1,4 @@
/* $NetBSD: cpu.h,v 1.32 2010/12/20 04:27:35 christos Exp $ */
/* $NetBSD: cpu.h,v 1.33 2011/08/07 13:33:02 rmind Exp $ */
/*-
* Copyright (c) 2007 YAMAMOTO Takashi,
@ -89,6 +89,7 @@ CIRCLEQ_HEAD(cpuqueue, cpu_info);
extern kmutex_t cpu_lock;
extern u_int maxcpus;
extern struct cpuqueue cpu_queue;
extern kcpuset_t *kcpuset_attached;
static inline u_int
cpu_index(struct cpu_info *ci)

63
sys/sys/kcpuset.h Normal file
View File

@ -0,0 +1,63 @@
/* $NetBSD: kcpuset.h,v 1.1 2011/08/07 13:33:02 rmind Exp $ */
/*-
* Copyright (c) 2008, 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas and Mindaugas Rasiukevicius.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SYS_KCPUSET_H_
#define _SYS_KCPUSET_H_
struct kcpuset;
typedef struct kcpuset kcpuset_t;
#ifdef _KERNEL
void kcpuset_sysinit(void);
void kcpuset_create(kcpuset_t **);
void kcpuset_destroy(kcpuset_t *);
void kcpuset_copy(kcpuset_t *, kcpuset_t *);
void kcpuset_use(kcpuset_t *);
void kcpuset_unuse(kcpuset_t *, kcpuset_t **);
int kcpuset_copyin(const cpuset_t *, kcpuset_t *, size_t);
int kcpuset_copyout(kcpuset_t *, cpuset_t *, size_t);
void kcpuset_zero(kcpuset_t *);
void kcpuset_fill(kcpuset_t *);
void kcpuset_set(kcpuset_t *, cpuid_t);
void kcpuset_clear(kcpuset_t *, cpuid_t);
int kcpuset_isset(kcpuset_t *, cpuid_t);
bool kcpuset_iszero(kcpuset_t *);
bool kcpuset_match(const kcpuset_t *, const kcpuset_t *);
#endif
#endif /* _SYS_KCPUSET_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: lwp.h,v 1.152 2011/05/19 03:07:29 rmind Exp $ */
/* $NetBSD: lwp.h,v 1.153 2011/08/07 13:33:02 rmind Exp $ */
/*-
* Copyright (c) 2001, 2006, 2007, 2008, 2009, 2010
@ -37,6 +37,7 @@
#include <sys/time.h>
#include <sys/queue.h>
#include <sys/callout.h>
#include <sys/kcpuset.h>
#include <sys/mutex.h>
#include <sys/condvar.h>
#include <sys/signalvar.h>

View File

@ -1,4 +1,4 @@
/* $NetBSD: sched.h,v 1.72 2010/04/16 03:21:49 rmind Exp $ */
/* $NetBSD: sched.h,v 1.73 2011/08/07 13:33:02 rmind Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2007, 2008 The NetBSD Foundation, Inc.
@ -96,25 +96,8 @@ __BEGIN_DECLS
* Interface of CPU-sets.
*/
typedef struct _cpuset cpuset_t;
typedef struct _kcpuset kcpuset_t; /* XXX: lwp.h included from userland */
#ifdef _KERNEL
kcpuset_t *kcpuset_create(void);
void kcpuset_destroy(kcpuset_t *);
void kcpuset_copy(kcpuset_t *, const kcpuset_t *);
void kcpuset_use(kcpuset_t *);
void kcpuset_unuse(kcpuset_t *, kcpuset_t **);
int kcpuset_copyin(const cpuset_t *, kcpuset_t *, size_t);
int kcpuset_copyout(const kcpuset_t *, cpuset_t *, size_t);
void kcpuset_zero(kcpuset_t *);
void kcpuset_fill(kcpuset_t *);
void kcpuset_set(cpuid_t, kcpuset_t *);
int kcpuset_isset(cpuid_t, const kcpuset_t *);
bool kcpuset_iszero(const kcpuset_t *);
bool kcpuset_match(const kcpuset_t *, const kcpuset_t *);
#else
#ifndef _KERNEL
#define cpuset_create() _cpuset_create()
#define cpuset_destroy(c) _cpuset_destroy(c)