Module Name: src Committed By: rmind Date: Sun Aug 7 13:33:03 UTC 2011
Modified Files: src/common/lib/libc/sys: cpuset.c src/distrib/sets/lists/comp: mi src/sys/conf: files src/sys/kern: init_main.c kern_cpu.c kern_runq.c subr_pserialize.c sys_pset.c sys_sched.c src/sys/sys: Makefile cpu.h lwp.h sched.h Added Files: src/sys/kern: subr_kcpuset.c src/sys/sys: kcpuset.h Log Message: 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@ To generate a diff of this commit: cvs rdiff -u -r1.16 -r1.17 src/common/lib/libc/sys/cpuset.c cvs rdiff -u -r1.1657 -r1.1658 src/distrib/sets/lists/comp/mi cvs rdiff -u -r1.1022 -r1.1023 src/sys/conf/files cvs rdiff -u -r1.434 -r1.435 src/sys/kern/init_main.c cvs rdiff -u -r1.47 -r1.48 src/sys/kern/kern_cpu.c cvs rdiff -u -r1.30 -r1.31 src/sys/kern/kern_runq.c cvs rdiff -u -r0 -r1.1 src/sys/kern/subr_kcpuset.c cvs rdiff -u -r1.2 -r1.3 src/sys/kern/subr_pserialize.c cvs rdiff -u -r1.15 -r1.16 src/sys/kern/sys_pset.c cvs rdiff -u -r1.35 -r1.36 src/sys/kern/sys_sched.c cvs rdiff -u -r1.136 -r1.137 src/sys/sys/Makefile cvs rdiff -u -r1.32 -r1.33 src/sys/sys/cpu.h cvs rdiff -u -r0 -r1.1 src/sys/sys/kcpuset.h cvs rdiff -u -r1.152 -r1.153 src/sys/sys/lwp.h cvs rdiff -u -r1.72 -r1.73 src/sys/sys/sched.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/common/lib/libc/sys/cpuset.c diff -u src/common/lib/libc/sys/cpuset.c:1.16 src/common/lib/libc/sys/cpuset.c:1.17 --- src/common/lib/libc/sys/cpuset.c:1.16 Tue Sep 21 02:03:29 2010 +++ src/common/lib/libc/sys/cpuset.c Sun Aug 7 13:33:02 2011 @@ -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 @@ 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 @@ 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 Index: src/distrib/sets/lists/comp/mi diff -u src/distrib/sets/lists/comp/mi:1.1657 src/distrib/sets/lists/comp/mi:1.1658 --- src/distrib/sets/lists/comp/mi:1.1657 Sat Aug 6 17:17:39 2011 +++ src/distrib/sets/lists/comp/mi Sun Aug 7 13:33:02 2011 @@ -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 Index: src/sys/conf/files diff -u src/sys/conf/files:1.1022 src/sys/conf/files:1.1023 --- src/sys/conf/files:1.1022 Sat Jul 30 17:01:04 2011 +++ src/sys/conf/files Sun Aug 7 13:33:01 2011 @@ -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_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 Index: src/sys/kern/init_main.c diff -u src/sys/kern/init_main.c:1.434 src/sys/kern/init_main.c:1.435 --- src/sys/kern/init_main.c:1.434 Sat Jul 30 17:01:04 2011 +++ src/sys/kern/init_main.c Sun Aug 7 13:33:01 2011 @@ -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 @@ #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 @@ evcnt_init(); uvm_init(); + kcpuset_sysinit(); prop_kern_init(); Index: src/sys/kern/kern_cpu.c diff -u src/sys/kern/kern_cpu.c:1.47 src/sys/kern/kern_cpu.c:1.48 --- src/sys/kern/kern_cpu.c:1.47 Wed Jun 29 06:22:21 2011 +++ src/sys/kern/kern_cpu.c Sun Aug 7 13:33:01 2011 @@ -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 @@ 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 @@ 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 @@ 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) { Index: src/sys/kern/kern_runq.c diff -u src/sys/kern/kern_runq.c:1.30 src/sys/kern/kern_runq.c:1.31 --- src/sys/kern/kern_runq.c:1.30 Wed Mar 3 00:47:30 2010 +++ src/sys/kern/kern_runq.c Sun Aug 7 13:33:01 2011 @@ -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 @@ /* 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); Index: src/sys/kern/subr_pserialize.c diff -u src/sys/kern/subr_pserialize.c:1.2 src/sys/kern/subr_pserialize.c:1.3 --- src/sys/kern/subr_pserialize.c:1.2 Mon Aug 1 15:26:31 2011 +++ src/sys/kern/subr_pserialize.c Sun Aug 7 13:33:01 2011 @@ -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 @@ 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 @@ return; } KASSERT(psz->psz_owner == NULL); - KASSERT(kcpuset_iszero(psz->psz_target)); KASSERT(ncpu > 0); /* @@ -157,7 +156,7 @@ * 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 @@ 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 @@ 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); Index: src/sys/kern/sys_pset.c diff -u src/sys/kern/sys_pset.c:1.15 src/sys/kern/sys_pset.c:1.16 --- src/sys/kern/sys_pset.c:1.15 Thu Jul 1 02:38:31 2010 +++ src/sys/kern/sys_pset.c Sun Aug 7 13:33:01 2011 @@ -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 @@ 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); Index: src/sys/kern/sys_sched.c diff -u src/sys/kern/sys_sched.c:1.35 src/sys/kern/sys_sched.c:1.36 --- src/sys/kern/sys_sched.c:1.35 Thu Jul 1 02:38:31 2010 +++ src/sys/kern/sys_sched.c Sun Aug 7 13:33:01 2011 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; } Index: src/sys/sys/Makefile diff -u src/sys/sys/Makefile:1.136 src/sys/sys/Makefile:1.137 --- src/sys/sys/Makefile:1.136 Sun Jul 17 20:54:54 2011 +++ src/sys/sys/Makefile Sun Aug 7 13:33:02 2011 @@ -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 @@ 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 \ Index: src/sys/sys/cpu.h diff -u src/sys/sys/cpu.h:1.32 src/sys/sys/cpu.h:1.33 --- src/sys/sys/cpu.h:1.32 Mon Dec 20 04:27:35 2010 +++ src/sys/sys/cpu.h Sun Aug 7 13:33:02 2011 @@ -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 @@ 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) Index: src/sys/sys/lwp.h diff -u src/sys/sys/lwp.h:1.152 src/sys/sys/lwp.h:1.153 --- src/sys/sys/lwp.h:1.152 Thu May 19 03:07:29 2011 +++ src/sys/sys/lwp.h Sun Aug 7 13:33:02 2011 @@ -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> Index: src/sys/sys/sched.h diff -u src/sys/sys/sched.h:1.72 src/sys/sys/sched.h:1.73 --- src/sys/sys/sched.h:1.72 Fri Apr 16 03:21:49 2010 +++ src/sys/sys/sched.h Sun Aug 7 13:33:02 2011 @@ -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 @@ * 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) Added files: Index: src/sys/kern/subr_kcpuset.c diff -u /dev/null src/sys/kern/subr_kcpuset.c:1.1 --- /dev/null Sun Aug 7 13:33:04 2011 +++ src/sys/kern/subr_kcpuset.c Sun Aug 7 13:33:01 2011 @@ -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; +} Index: src/sys/sys/kcpuset.h diff -u /dev/null src/sys/sys/kcpuset.h:1.1 --- /dev/null Sun Aug 7 13:33:04 2011 +++ src/sys/sys/kcpuset.h Sun Aug 7 13:33:02 2011 @@ -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_ */