Index: sys/Makefile =================================================================== RCS file: /cvsroot/src/sys/sys/Makefile,v retrieving revision 1.100 diff -u -p -r1.100 Makefile --- sys/Makefile 6 Nov 2007 23:39:25 -0000 1.100 +++ sys/Makefile 8 Nov 2007 22:27:49 -0000 @@ -18,7 +18,7 @@ INCS= acct.h agpio.h aio.h ansi.h ataio. ieee754.h inttypes.h ioccom.h ioctl.h ioctl_compat.h iostat.h ipc.h \ joystick.h \ kcore.h kgdb.h ksem.h ksyms.h ktrace.h \ - lkm.h localedef.h lock.h lockf.h lwp.h \ + lkm.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 mount.h mqueue.h msg.h msgbuf.h mtio.h mutex.h \ namei.h null.h \ Index: sys/lwp.h =================================================================== RCS file: /cvsroot/src/sys/sys/lwp.h,v retrieving revision 1.68 diff -u -p -r1.68 lwp.h --- sys/lwp.h 6 Nov 2007 00:42:45 -0000 1.68 +++ sys/lwp.h 8 Nov 2007 22:27:49 -0000 @@ -97,6 +97,8 @@ struct lwp { fixpt_t l_pctcpu; /* t: %cpu during l_swtime */ fixpt_t l_estcpu; /* l: cpu time for SCHED_4BSD */ kmutex_t l_swaplock; /* l: lock to prevent swapping */ + struct lwpctl *l_lwpctl; /* p: lwpctl block kernel address */ + struct lcpage *l_lcpage; /* p: lwpctl containing page */ /* Synchronisation */ struct turnstile *l_ts; /* l: current turnstile */ Index: sys/param.h =================================================================== RCS file: /cvsroot/src/sys/sys/param.h,v retrieving revision 1.283 diff -u -p -r1.283 param.h --- sys/param.h 7 Nov 2007 00:39:10 -0000 1.283 +++ sys/param.h 8 Nov 2007 22:27:50 -0000 @@ -163,6 +163,9 @@ #ifndef MAXCPUS #define MAXCPUS 32 #endif +#ifndef MAX_LWP_PER_PROC +#define MAX_LWP_PER_PROC 8000 +#endif /* * Stack macros. On most architectures, the stack grows down, Index: sys/proc.h =================================================================== RCS file: /cvsroot/src/sys/sys/proc.h,v retrieving revision 1.260 diff -u -p -r1.260 proc.h --- sys/proc.h 7 Nov 2007 00:23:43 -0000 1.260 +++ sys/proc.h 8 Nov 2007 22:27:50 -0000 @@ -298,6 +298,7 @@ struct proc { LIST_HEAD(, lwp) p_sigwaiters; /* s: LWPs waiting for signals */ sigpend_t p_sigpend; /* s: pending signals */ + struct lcproc *p_lwpctl; /* s: _lwp_ctl() information */ /* * End area that is zeroed on creation Index: kern/kern_exec.c =================================================================== RCS file: /cvsroot/src/sys/kern/kern_exec.c,v retrieving revision 1.252 diff -u -p -r1.252 kern_exec.c --- kern/kern_exec.c 7 Nov 2007 00:23:20 -0000 1.252 +++ kern/kern_exec.c 8 Nov 2007 22:27:52 -0000 @@ -62,6 +62,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_exec.c, #include #include #include +#include #include #if NVERIEXEC > 0 @@ -623,6 +624,10 @@ execve1(struct lwp *l, const char *path, } KDASSERT(p->p_nlwps == 1); + /* Destroy any lwpctl info. */ + if (p->p_lwpctl != NULL) + lwp_ctl_exit(); + /* This is now LWP 1 */ l->l_lid = 1; p->p_nlwpid = 1; Index: kern/kern_exit.c =================================================================== RCS file: /cvsroot/src/sys/kern/kern_exit.c,v retrieving revision 1.192 diff -u -p -r1.192 kern_exit.c --- kern/kern_exit.c 7 Nov 2007 15:56:21 -0000 1.192 +++ kern/kern_exit.c 8 Nov 2007 22:27:52 -0000 @@ -114,8 +114,8 @@ __KERNEL_RCSID(0, "$NetBSD: kern_exit.c, #include #include #include - #include +#include #include @@ -238,6 +238,10 @@ exit1(struct lwp *l, int rv) } else mutex_exit(&p->p_smutex); + /* Destroy any lwpctl info. */ + if (p->p_lwpctl != NULL) + lwp_ctl_exit(); + /* Destroy all AIO works */ aio_exit(p, p->p_aio); Index: kern/kern_lwp.c =================================================================== RCS file: /cvsroot/src/sys/kern/kern_lwp.c,v retrieving revision 1.76 diff -u -p -r1.76 kern_lwp.c --- kern/kern_lwp.c 7 Nov 2007 00:23:21 -0000 1.76 +++ kern/kern_lwp.c 8 Nov 2007 22:27:53 -0000 @@ -224,6 +224,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v #include #include #include +#include #include @@ -236,15 +237,6 @@ POOL_INIT(lwp_uc_pool, sizeof(ucontext_t static specificdata_domain_t lwp_specificdata_domain; -#define LWP_DEBUG - -#ifdef LWP_DEBUG -int lwp_debug = 0; -#define DPRINTF(x) if (lwp_debug) printf x -#else -#define DPRINTF(x) -#endif - void lwpinit(void) { @@ -335,10 +327,6 @@ lwp_continue(struct lwp *l) KASSERT(mutex_owned(&l->l_proc->p_smutex)); KASSERT(lwp_locked(l, NULL)); - DPRINTF(("lwp_continue of %d.%d (%s), state %d, wchan %p\n", - l->l_proc->p_pid, l->l_lid, l->l_proc->p_comm, l->l_stat, - l->l_wchan)); - /* If rebooting or not suspended, then just bail out. */ if ((l->l_flag & LW_WREBOOT) != 0) { lwp_unlock(l); @@ -371,9 +359,6 @@ lwp_wait1(struct lwp *l, lwpid_t lid, lw lwpid_t curlid; bool exiting; - DPRINTF(("lwp_wait1: %d.%d waiting for %d.\n", - p->p_pid, l->l_lid, lid)); - KASSERT(mutex_owned(&p->p_smutex)); p->p_nlwpwait++; @@ -686,8 +671,6 @@ lwp_exit(struct lwp *l) current = (l == curlwp); - DPRINTF(("lwp_exit: %d.%d exiting.\n", p->p_pid, l->l_lid)); - DPRINTF((" nlwps: %d nzlwps: %d\n", p->p_nlwps, p->p_nzlwps)); KASSERT(current || l->l_stat == LSIDL); /* @@ -699,6 +682,7 @@ lwp_exit(struct lwp *l) LOCKDEBUG_BARRIER(NULL, 0); #endif + /* * If we are the last live LWP in a process, we need to exit the * entire process. We do so with an exit status of zero, because @@ -712,8 +696,6 @@ lwp_exit(struct lwp *l) mutex_enter(&p->p_smutex); if (p->p_nlwps - p->p_nzlwps == 1) { KASSERT(current == true); - DPRINTF(("lwp_exit: %d.%d calling exit1()\n", - p->p_pid, l->l_lid)); exit1(l, 0); /* NOTREACHED */ } @@ -790,6 +772,7 @@ lwp_exit(struct lwp *l) lwp_unlock(l); p->p_nrlwps--; cv_broadcast(&p->p_lwpcv); + l->l_lwpctl->lc_curcpu = LWPCTL_CPU_EXITED; mutex_exit(&p->p_smutex); /* @@ -921,6 +904,8 @@ lwp_free(struct lwp *l, bool recycle, bo */ KERNEL_LOCK(1, curlwp); /* XXXSMP */ + if (l->l_lwpctl != NULL) + lwp_ctl_free(l); sched_lwp_exit(l); if (!recycle && l->l_ts != &turnstile0) @@ -1435,3 +1420,188 @@ lwp_setspecific(specificdata_key_t key, specificdata_setspecific(lwp_specificdata_domain, &curlwp->l_specdataref, key, data); } + +/* + * Allocate a new lwpctl structure for a user LWP. + */ +int +lwp_ctl_alloc(lwp_t *l, vaddr_t *uaddr) +{ + lcproc_t *lp; + u_int bit, i, offset; + struct uvm_object *uao; + int error; + lcpage_t *lcp; + proc_t *p; + + if (l->l_lcpage != NULL) + return (EINVAL); + p = l->l_proc; + + /* First time around, allocate header structure for the process. */ + if ((lp = p->p_lwpctl) == NULL) { + lp = kmem_alloc(sizeof(*lp), KM_SLEEP); + mutex_init(&lp->lp_lock, MUTEX_DEFAULT, IPL_NONE); + lp->lp_uao = NULL; + TAILQ_INIT(&lp->lp_pages); + mutex_enter(&p->p_mutex); + if (p->p_lwpctl == NULL) { + p->p_lwpctl = lp; + mutex_exit(&p->p_mutex); + } else { + mutex_exit(&p->p_mutex); + mutex_destroy(&lp->lp_lock); + kmem_free(lp, sizeof(*lp)); + lp = p->p_lwpctl; + } + } + + /* + * Set up an anonymous memory region to hold the shared pages. + * Map them into the process' address space. The user vmspace + * gets the first reference on the UAO. + */ + mutex_enter(&lp->lp_lock); + if (lp->lp_uao == NULL) { + lp->lp_uao = uao_create(LWPCTL_UAREA_SZ, 0); + lp->lp_cur = 0; + lp->lp_max = LWPCTL_UAREA_SZ; + lp->lp_uva = p->p_emul->e_vm_default_addr(p, + (vaddr_t)p->p_vmspace->vm_daddr, LWPCTL_UAREA_SZ); + error = uvm_map(&p->p_vmspace->vm_map, &lp->lp_uva, + LWPCTL_UAREA_SZ, lp->lp_uao, 0, 0, UVM_MAPFLAG(UVM_PROT_RW, + UVM_PROT_RW, UVM_INH_NONE, UVM_ADV_NORMAL, 0)); + if (error != 0) { + uao_detach(lp->lp_uao); + lp->lp_uao = NULL; + mutex_exit(&lp->lp_lock); + return error; + } + } + + /* Get a free block and allocate for this LWP. */ + TAILQ_FOREACH(lcp, &lp->lp_pages, lcp_chain) { + if (lcp->lcp_nfree != 0) + break; + } + if (lcp == NULL) { + /* Nothing available - try to set up a free page. */ + if (lp->lp_cur == lp->lp_max) { + mutex_exit(&lp->lp_lock); + return ENOMEM; + } + lcp = kmem_alloc(LWPCTL_LCPAGE_SZ, KM_SLEEP); + if (lcp == NULL) + return ENOMEM; + /* + * Wire the next page down in kernel space. Since this + * is a new mapping, we must add a reference. + */ + uao = lp->lp_uao; + (*uao->pgops->pgo_reference)(uao); + error = uvm_map(kernel_map, &lcp->lcp_kaddr, PAGE_SIZE, + uao, lp->lp_cur, PAGE_SIZE, + UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, + UVM_INH_NONE, UVM_ADV_RANDOM, 0)); + if (error == 0) + error = uvm_map_pageable(kernel_map, lcp->lcp_kaddr, + lcp->lcp_kaddr + PAGE_SIZE, FALSE, 0); + if (error != 0) { + mutex_exit(&lp->lp_lock); + kmem_free(lcp, LWPCTL_LCPAGE_SZ); + (*uao->pgops->pgo_detach)(uao); + return error; + } + /* Prepare the page descriptor and link into the list. */ + lcp->lcp_uaddr = lp->lp_uva + lp->lp_cur; + lp->lp_cur += PAGE_SIZE; + lcp->lcp_nfree = LWPCTL_PER_PAGE; + lcp->lcp_rotor = 0; + memset(lcp->lcp_bitmap, 0xff, LWPCTL_BITMAP_SZ); + TAILQ_INSERT_HEAD(&lp->lp_pages, lcp, lcp_chain); + } + for (i = lcp->lcp_rotor; lcp->lcp_bitmap[i] == 0;) { + if (++i >= LWPCTL_BITMAP_ENTRIES) + i = 0; + } + bit = ffs(lcp->lcp_bitmap[i]) - 1; + lcp->lcp_bitmap[i] ^= (1 << bit); + lcp->lcp_rotor = i; + lcp->lcp_nfree--; + l->l_lcpage = lcp; + offset = (i << 5) + bit; + l->l_lwpctl = (lwpctl_t *)lcp->lcp_kaddr + offset; + *uaddr = lcp->lcp_uaddr + offset * sizeof(lwpctl_t); + mutex_exit(&lp->lp_lock); + + l->l_lwpctl->lc_curcpu = (short)curcpu()->ci_data.cpu_index; + + return 0; +} + +/* + * Free an lwpctl structure back to the per-process list. + */ +void +lwp_ctl_free(lwp_t *l) +{ + lcproc_t *lp; + lcpage_t *lcp; + u_int map, offset; + + lp = l->l_proc->p_lwpctl; + KASSERT(lp != NULL); + + lcp = l->l_lcpage; + offset = (u_int)((lwpctl_t *)l->l_lwpctl - (lwpctl_t *)lcp->lcp_kaddr); + KASSERT(offset < LWPCTL_PER_PAGE); + + mutex_enter(&lp->lp_lock); + lcp->lcp_nfree++; + map = offset >> 5; + lcp->lcp_bitmap[map] |= (1 << (offset & 31)); + if (lcp->lcp_bitmap[lcp->lcp_rotor] == 0) + lcp->lcp_rotor = map; + if (TAILQ_FIRST(&lp->lp_pages)->lcp_nfree == 0) { + TAILQ_REMOVE(&lp->lp_pages, lcp, lcp_chain); + TAILQ_INSERT_HEAD(&lp->lp_pages, lcp, lcp_chain); + } + mutex_exit(&lp->lp_lock); +} + +/* + * Process is exiting; tear down lwpctl state. This can only be safely + * called by the last LWP in the process. + */ +void +lwp_ctl_exit(void) +{ + lcpage_t *lcp, *next; + lcproc_t *lp; + proc_t *p; + lwp_t *l; + + l = curlwp; + l->l_lwpctl = NULL; + p = l->l_proc; + lp = p->p_lwpctl; + + KASSERT(lp != NULL); + KASSERT(p->p_nlwps == 1); + + for (lcp = TAILQ_FIRST(&lp->lp_pages); lcp != NULL; lcp = next) { + next = TAILQ_NEXT(lcp, lcp_chain); + uvm_unmap(kernel_map, lcp->lcp_kaddr, + lcp->lcp_kaddr + PAGE_SIZE); + kmem_free(lcp, LWPCTL_LCPAGE_SZ); + } + + if (lp->lp_uao != NULL) { + uvm_unmap(&p->p_vmspace->vm_map, lp->lp_uva, + lp->lp_uva + LWPCTL_UAREA_SZ); + } + + mutex_destroy(&lp->lp_lock); + kmem_free(lp, sizeof(*lp)); + p->p_lwpctl = NULL; +} Index: kern/kern_synch.c =================================================================== RCS file: /cvsroot/src/sys/kern/kern_synch.c,v retrieving revision 1.205 diff -u -p -r1.205 kern_synch.c --- kern/kern_synch.c 6 Nov 2007 17:57:46 -0000 1.205 +++ kern/kern_synch.c 8 Nov 2007 22:27:53 -0000 @@ -99,6 +99,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_synch.c #include #include #include +#include #include @@ -519,17 +520,23 @@ mi_switch(lwp_t *l) if (!returning) pmap_deactivate(l); + /* Update status for lwpctl, if present. */ + if (l->l_lwpctl != NULL) + l->l_lwpctl->lc_curcpu = LWPCTL_CPU_NONE; + /* Switch to the new LWP.. */ l->l_ncsw++; l->l_flag &= ~LW_RUNNING; oldspl = MUTEX_SPIN_OLDSPL(ci); prevlwp = cpu_switchto(l, newl, returning); + ci = curcpu(); + /* * .. we have switched away and are now back so we must * be the new curlwp. prevlwp is who we replaced. */ if (prevlwp != NULL) { - curcpu()->ci_mtx_oldspl = oldspl; + ci->ci_mtx_oldspl = oldspl; lwp_unlock(prevlwp); } else { splx(oldspl); @@ -538,6 +545,10 @@ mi_switch(lwp_t *l) /* Restore VM context. */ pmap_activate(l); retval = 1; + + /* Update status for lwpctl, if present. */ + if (l->l_lwpctl != NULL) + l->l_lwpctl->lc_curcpu = (short)ci->ci_data.cpu_index; } else { /* Nothing to do - just unlock and return. */ mutex_spin_exit(spc->spc_mutex); @@ -547,7 +558,7 @@ mi_switch(lwp_t *l) KASSERT(l == curlwp); KASSERT(l->l_stat == LSONPROC); - KASSERT(l->l_cpu == curcpu()); + KASSERT(l->l_cpu == ci); /* * XXXSMP If we are using h/w performance counters, restore context. @@ -565,7 +576,7 @@ mi_switch(lwp_t *l) */ SYSCALL_TIME_WAKEUP(l); KASSERT(curlwp == l); - KDASSERT(l->l_cpu == curcpu()); + KDASSERT(l->l_cpu == ci); LOCKDEBUG_BARRIER(NULL, 1); return retval; Index: kern/sys_lwp.c =================================================================== RCS file: /cvsroot/src/sys/kern/sys_lwp.c,v retrieving revision 1.29 diff -u -p -r1.29 sys_lwp.c --- kern/sys_lwp.c 7 Nov 2007 00:56:27 -0000 1.29 +++ kern/sys_lwp.c 8 Nov 2007 22:27:54 -0000 @@ -53,6 +53,7 @@ __KERNEL_RCSID(0, "$NetBSD: sys_lwp.c,v #include #include #include +#include #include @@ -743,10 +744,14 @@ sys__lwp_setname(struct lwp *l, void *v, syscallarg(const char *) name; } */ *uap = v; char *name, *oname; + lwpid_t target; proc_t *p; lwp_t *t; int error; + if ((target = SCARG(uap, target)) == 0) + target = l->l_lid; + name = kmem_alloc(MAXCOMLEN, KM_SLEEP); if (name == NULL) return ENOMEM; @@ -763,7 +768,7 @@ sys__lwp_setname(struct lwp *l, void *v, p = curproc; mutex_enter(&p->p_smutex); - if ((t = lwp_find(p, SCARG(uap, target))) == NULL) { + if ((t = lwp_find(p, target)) == NULL) { mutex_exit(&p->p_smutex); kmem_free(name, MAXCOMLEN); return ESRCH; @@ -789,12 +794,16 @@ sys__lwp_getname(struct lwp *l, void *v, syscallarg(size_t) len; } */ *uap = v; char name[MAXCOMLEN]; + lwpid_t target; proc_t *p; lwp_t *t; + if ((target = SCARG(uap, target)) == 0) + target = l->l_lid; + p = curproc; mutex_enter(&p->p_smutex); - if ((t = lwp_find(p, SCARG(uap, target))) == NULL) { + if ((t = lwp_find(p, target)) == NULL) { mutex_exit(&p->p_smutex); return ESRCH; } @@ -808,3 +817,37 @@ sys__lwp_getname(struct lwp *l, void *v, return copyoutstr(name, SCARG(uap, name), SCARG(uap, len), NULL); } + +int +sys__lwp_ctl(struct lwp *l, void *v, register_t *retval) +{ + struct sys__lwp_ctl_args /* { + syscallarg(lwpid_t) target; + syscallarg(int) op; + syscallarg(void *) arg; + } */ *uap = v; + int error; + lwpid_t target; + vaddr_t vaddr; + + if ((target = SCARG(uap, target)) == 0) + target = l->l_lid; + + switch (SCARG(uap, op)) { + case LWPCTL_OP_SET: + if (target != l->l_lid) { + error = EINVAL; + break; + } + error = lwp_ctl_alloc(l, &vaddr); + if (error != 0) + break; + error = copyout(&vaddr, SCARG(uap, arg), sizeof(void *)); + break; + default: + error = EINVAL; + break; + } + + return error; +} Index: kern/syscalls.master =================================================================== RCS file: /cvsroot/src/sys/kern/syscalls.master,v retrieving revision 1.178 diff -u -p -r1.178 syscalls.master --- kern/syscalls.master 7 Nov 2007 00:37:21 -0000 1.178 +++ kern/syscalls.master 8 Nov 2007 22:27:55 -0000 @@ -664,8 +664,8 @@ const char *name); } 324 STD { int sys__lwp_getname(lwpid_t target, \ char *name, size_t len); } -; Syscalls 325-339 reserved for LWP syscalls. -325 UNIMPL +325 STD { int sys__lwp_ctl(lwpid_t target, int op, void *arg); } +; Syscalls 326-339 reserved for LWP syscalls. 326 UNIMPL 327 UNIMPL 328 UNIMPL --- /dev/null 2007-11-08 20:14:45.000000000 +0000 +++ sys/lwpctl.h 2007-11-08 21:57:46.000000000 +0000 @@ -0,0 +1,90 @@ +/* $NetBSD: syncobj.h,v 1.4 2007/09/06 23:59:02 ad Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Andrew Doran. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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. + */ + +#if !defined(_SYS_LWPCTL_H_) +#define _SYS_LWPCTL_H_ + +typedef struct lwpctl { + volatile int lc_curcpu; + int lc_reserved; /* reduce size of bitmap */ +} lwpctl_t; + +#define LWPCTL_CPU_NONE (-1) +#define LWPCTL_CPU_EXITED (-2) + +#define LWPCTL_OP_SET 0 + +#if defined(_KERNEL) + +#include + +#include + +typedef struct lcpage { + TAILQ_ENTRY(lcpage) lcp_chain; + vaddr_t lcp_uaddr; + vaddr_t lcp_kaddr; + u_int lcp_nfree; + u_int lcp_rotor; + u_int lcp_bitmap[1]; +} lcpage_t; + +typedef struct lcproc { + kmutex_t lp_lock; + struct uvm_object *lp_uao; + TAILQ_HEAD(,lcpage) lp_pages; + vaddr_t lp_cur; + vaddr_t lp_max; + vaddr_t lp_uva; +} lcproc_t; + +#define LWPCTL_PER_PAGE ((PAGE_SIZE / sizeof(lwpctl_t)) & ~31) +#define LWPCTL_BITMAP_ENTRIES (LWPCTL_PER_PAGE >> 5) +#define LWPCTL_BITMAP_SZ (LWPCTL_BITMAP_ENTRIES * sizeof(u_int)) +#define LWPCTL_LCPAGE_SZ \ + (sizeof(lcpage_t) - sizeof(u_int) + LWPCTL_BITMAP_SZ) +#define LWPCTL_UAREA_SZ \ + (round_page(MAX_LWP_PER_PROC * sizeof(lwpctl_t))) + +int lwp_ctl_alloc(lwp_t *, vaddr_t *); +void lwp_ctl_free(lwp_t *); +void lwp_ctl_exit(void); + +#endif /* defined(_KERNEL) */ + +#endif /* !_SYS_LWPCTL_H_ */