xref: /dflybsd-src/sys/kern/kern_usched.c (revision e4b9e6f6c4819e081b27592550b55458d4c3d0a7)
1cb7f4ab1SMatthew Dillon /*
2cb7f4ab1SMatthew Dillon  * Copyright (c) 2005 The DragonFly Project.  All rights reserved.
3cb7f4ab1SMatthew Dillon  *
4cb7f4ab1SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
5cb7f4ab1SMatthew Dillon  * by Sergey Glushchenko <deen@smz.com.ua>
6cb7f4ab1SMatthew Dillon  *
7cb7f4ab1SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
8cb7f4ab1SMatthew Dillon  * modification, are permitted provided that the following conditions
9cb7f4ab1SMatthew Dillon  * are met:
10cb7f4ab1SMatthew Dillon  *
11cb7f4ab1SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
12cb7f4ab1SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
13cb7f4ab1SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
14cb7f4ab1SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
15cb7f4ab1SMatthew Dillon  *    the documentation and/or other materials provided with the
16cb7f4ab1SMatthew Dillon  *    distribution.
17cb7f4ab1SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
18cb7f4ab1SMatthew Dillon  *    contributors may be used to endorse or promote products derived
19cb7f4ab1SMatthew Dillon  *    from this software without specific, prior written permission.
20cb7f4ab1SMatthew Dillon  *
21cb7f4ab1SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22cb7f4ab1SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23cb7f4ab1SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24cb7f4ab1SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25cb7f4ab1SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26cb7f4ab1SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27cb7f4ab1SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28cb7f4ab1SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29cb7f4ab1SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30cb7f4ab1SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31cb7f4ab1SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32cb7f4ab1SMatthew Dillon  * SUCH DAMAGE.
33cb7f4ab1SMatthew Dillon  *
34cb7f4ab1SMatthew Dillon  */
35cb7f4ab1SMatthew Dillon 
36da82a65aSzrj #include <sys/cpumask.h>
37cb7f4ab1SMatthew Dillon #include <sys/errno.h>
38cb7f4ab1SMatthew Dillon #include <sys/globaldata.h>		/* curthread */
39cb7f4ab1SMatthew Dillon #include <sys/proc.h>
402b3f93eaSMatthew Dillon #include <sys/caps.h>
4180d831e1SMatthew Dillon #include <sys/sysmsg.h>			/* struct usched_set_args */
42cb7f4ab1SMatthew Dillon #include <sys/systm.h>			/* strcmp() */
43cb7f4ab1SMatthew Dillon #include <sys/usched.h>
44684a93c4SMatthew Dillon 
45a60ccb85SDavid Xu #include <machine/smp.h>
46cb7f4ab1SMatthew Dillon 
47cb7f4ab1SMatthew Dillon static TAILQ_HEAD(, usched) usched_list = TAILQ_HEAD_INITIALIZER(usched_list);
48cb7f4ab1SMatthew Dillon 
49c07315c4SMatthew Dillon cpumask_t usched_mastermask = CPUMASK_INITIALIZER_ALLONES;
50a5ae2446SMatthew Dillon 
51480ed3deSMatthew Dillon static int setaffinity_lp(struct lwp *lp, cpumask_t *mask);
52480ed3deSMatthew Dillon 
53cb7f4ab1SMatthew Dillon /*
540a80a445Szrj  * Called from very low level boot code, sys/kern/init_main.c:mi_proc0init().
55cb7f4ab1SMatthew Dillon  * We cannot do anything fancy.  no malloc's, no nothing other then
56cb7f4ab1SMatthew Dillon  * static initialization.
57cb7f4ab1SMatthew Dillon  */
58cb7f4ab1SMatthew Dillon struct usched *
usched_init(void)59cb7f4ab1SMatthew Dillon usched_init(void)
60cb7f4ab1SMatthew Dillon {
6152eedfb5SMatthew Dillon 	const char *defsched;
6252eedfb5SMatthew Dillon 
63bc01a404SMatthew Dillon 	defsched = kgetenv("kern.user_scheduler");
6452eedfb5SMatthew Dillon 
65cb7f4ab1SMatthew Dillon 	/*
6652eedfb5SMatthew Dillon 	 * Add various userland schedulers to the system.
67cb7f4ab1SMatthew Dillon 	 */
68cb7f4ab1SMatthew Dillon 	usched_ctl(&usched_bsd4, USCH_ADD);
69e28d8b15SMatthew Dillon 	usched_ctl(&usched_dfly, USCH_ADD);
7052eedfb5SMatthew Dillon 	usched_ctl(&usched_dummy, USCH_ADD);
7152eedfb5SMatthew Dillon 	if (defsched == NULL )
72e28d8b15SMatthew Dillon 		return(&usched_dfly);
7352eedfb5SMatthew Dillon 	if (strcmp(defsched, "bsd4") == 0)
7452eedfb5SMatthew Dillon 		return(&usched_bsd4);
75e28d8b15SMatthew Dillon 	if (strcmp(defsched, "dfly") == 0)
76e28d8b15SMatthew Dillon 		return(&usched_dfly);
776ea70f76SSascha Wildner 	kprintf("WARNING: Running dummy userland scheduler\n");
7852eedfb5SMatthew Dillon 	return(&usched_dummy);
79cb7f4ab1SMatthew Dillon }
80cb7f4ab1SMatthew Dillon 
81cb7f4ab1SMatthew Dillon /*
82cb7f4ab1SMatthew Dillon  * USCHED_CTL
83cb7f4ab1SMatthew Dillon  *
84cb7f4ab1SMatthew Dillon  * SYNOPSIS:
85cb7f4ab1SMatthew Dillon  * 	Add/remove usched to/from list.
86cb7f4ab1SMatthew Dillon  *
87cb7f4ab1SMatthew Dillon  * ARGUMENTS:
88cb7f4ab1SMatthew Dillon  * 	usched - pointer to target scheduler
89cb7f4ab1SMatthew Dillon  * 	action - addition or removal ?
90cb7f4ab1SMatthew Dillon  *
91cb7f4ab1SMatthew Dillon  * RETURN VALUES:
92cb7f4ab1SMatthew Dillon  * 	0 - success
93cb7f4ab1SMatthew Dillon  * 	EINVAL - error
94cb7f4ab1SMatthew Dillon  */
95cb7f4ab1SMatthew Dillon int
usched_ctl(struct usched * usched,int action)96cb7f4ab1SMatthew Dillon usched_ctl(struct usched *usched, int action)
97cb7f4ab1SMatthew Dillon {
98cb7f4ab1SMatthew Dillon 	struct usched *item;	/* temporaly for TAILQ processing */
99cb7f4ab1SMatthew Dillon 	int error = 0;
100cb7f4ab1SMatthew Dillon 
101cb7f4ab1SMatthew Dillon 	switch(action) {
102cb7f4ab1SMatthew Dillon 	case USCH_ADD:
103cb7f4ab1SMatthew Dillon 		/*
104cb7f4ab1SMatthew Dillon 		 * Make sure it isn't already on the list
105cb7f4ab1SMatthew Dillon 		 */
106cb7f4ab1SMatthew Dillon #ifdef INVARIANTS
107cb7f4ab1SMatthew Dillon 		TAILQ_FOREACH(item, &usched_list, entry) {
108cb7f4ab1SMatthew Dillon 			KKASSERT(item != usched);
109cb7f4ab1SMatthew Dillon 		}
110cb7f4ab1SMatthew Dillon #endif
111cb7f4ab1SMatthew Dillon 		/*
112cb7f4ab1SMatthew Dillon 		 * Optional callback to the scheduler before we officially
113cb7f4ab1SMatthew Dillon 		 * add it to the list.
114cb7f4ab1SMatthew Dillon 		 */
115cb7f4ab1SMatthew Dillon 		if (usched->usched_register)
116cb7f4ab1SMatthew Dillon 			usched->usched_register();
117cb7f4ab1SMatthew Dillon 		TAILQ_INSERT_TAIL(&usched_list, usched, entry);
118cb7f4ab1SMatthew Dillon 		break;
119cb7f4ab1SMatthew Dillon 	case USCH_REM:
120cb7f4ab1SMatthew Dillon 		/*
121cb7f4ab1SMatthew Dillon 		 * Do not allow the default scheduler to be removed
122cb7f4ab1SMatthew Dillon 		 */
123cb7f4ab1SMatthew Dillon 		if (strcmp(usched->name, "bsd4") == 0) {
124cb7f4ab1SMatthew Dillon 			error = EINVAL;
125cb7f4ab1SMatthew Dillon 			break;
126cb7f4ab1SMatthew Dillon 		}
127cb7f4ab1SMatthew Dillon 		TAILQ_FOREACH(item, &usched_list, entry) {
128cb7f4ab1SMatthew Dillon 			if (item == usched)
129cb7f4ab1SMatthew Dillon 				break;
130cb7f4ab1SMatthew Dillon 		}
131cb7f4ab1SMatthew Dillon 		if (item) {
132cb7f4ab1SMatthew Dillon 			if (item->usched_unregister)
133cb7f4ab1SMatthew Dillon 				item->usched_unregister();
134cb7f4ab1SMatthew Dillon 			TAILQ_REMOVE(&usched_list, item, entry);
135cb7f4ab1SMatthew Dillon 		} else {
136cb7f4ab1SMatthew Dillon 			error = EINVAL;
137cb7f4ab1SMatthew Dillon 		}
138cb7f4ab1SMatthew Dillon 		break;
139cb7f4ab1SMatthew Dillon 	default:
140cb7f4ab1SMatthew Dillon 		error = EINVAL;
141cb7f4ab1SMatthew Dillon 		break;
142cb7f4ab1SMatthew Dillon 	}
143cb7f4ab1SMatthew Dillon 	return (error);
144cb7f4ab1SMatthew Dillon }
145cb7f4ab1SMatthew Dillon 
146cb7f4ab1SMatthew Dillon /*
147de4d4cb0SMatthew Dillon  * Called from the scheduler clock on each cpu independently at the
148*e4b9e6f6SMichael Neumann  * common scheduling rate.  If the scheduler clock interrupted a running
149de4d4cb0SMatthew Dillon  * lwp the lp will be non-NULL.
150de4d4cb0SMatthew Dillon  */
151de4d4cb0SMatthew Dillon void
usched_schedulerclock(struct lwp * lp,sysclock_t periodic,sysclock_t time)152de4d4cb0SMatthew Dillon usched_schedulerclock(struct lwp *lp, sysclock_t periodic, sysclock_t time)
153de4d4cb0SMatthew Dillon {
154de4d4cb0SMatthew Dillon 	struct usched *item;
155de4d4cb0SMatthew Dillon 
156de4d4cb0SMatthew Dillon 	TAILQ_FOREACH(item, &usched_list, entry) {
157de4d4cb0SMatthew Dillon 		if (lp && lp->lwp_proc->p_usched == item)
158de4d4cb0SMatthew Dillon 			item->schedulerclock(lp, periodic, time);
159de4d4cb0SMatthew Dillon 		else
160de4d4cb0SMatthew Dillon 			item->schedulerclock(NULL, periodic, time);
161de4d4cb0SMatthew Dillon 	}
162de4d4cb0SMatthew Dillon }
163de4d4cb0SMatthew Dillon 
164de4d4cb0SMatthew Dillon /*
165cb7f4ab1SMatthew Dillon  * USCHED_SET(syscall)
166cb7f4ab1SMatthew Dillon  *
167cb7f4ab1SMatthew Dillon  * SYNOPSIS:
168cb7f4ab1SMatthew Dillon  * 	Setting up a proc's usched.
169cb7f4ab1SMatthew Dillon  *
170cb7f4ab1SMatthew Dillon  * ARGUMENTS:
171a60ccb85SDavid Xu  *	pid	-
172a60ccb85SDavid Xu  *	cmd	-
173a60ccb85SDavid Xu  * 	data	-
174a60ccb85SDavid Xu  *	bytes	-
175cb7f4ab1SMatthew Dillon  * RETURN VALUES:
176cb7f4ab1SMatthew Dillon  * 	0 - success
177571f6375STomohiro Kusumi  * 	EFBIG  - error (invalid cpu#)
178571f6375STomohiro Kusumi  * 	EPERM  - error (failed to delete cpu#)
179571f6375STomohiro Kusumi  * 	EINVAL - error (other reasons)
1803919ced0SMatthew Dillon  *
1813919ced0SMatthew Dillon  * MPALMOSTSAFE
182cb7f4ab1SMatthew Dillon  */
183cb7f4ab1SMatthew Dillon int
sys_usched_set(struct sysmsg * sysmsg,const struct usched_set_args * uap)18480d831e1SMatthew Dillon sys_usched_set(struct sysmsg *sysmsg, const struct usched_set_args *uap)
185cb7f4ab1SMatthew Dillon {
186cb7f4ab1SMatthew Dillon 	struct proc *p = curthread->td_proc;
187cb7f4ab1SMatthew Dillon 	struct usched *item;	/* temporaly for TAILQ processing */
188cb7f4ab1SMatthew Dillon 	int error;
1891b31454eSDavid Rhodus 	char buffer[NAME_LENGTH];
190a60ccb85SDavid Xu 	cpumask_t mask;
191a60ccb85SDavid Xu 	struct lwp *lp;
192a60ccb85SDavid Xu 	int cpuid;
1933919ced0SMatthew Dillon 
194a60ccb85SDavid Xu 	if (uap->pid != 0 && uap->pid != curthread->td_proc->p_pid)
195a60ccb85SDavid Xu 		return (EINVAL);
1961b31454eSDavid Rhodus 
197a60ccb85SDavid Xu 	lp = curthread->td_lwp;
198480ed3deSMatthew Dillon 	lwkt_gettoken(&lp->lwp_token);
1993919ced0SMatthew Dillon 
200a60ccb85SDavid Xu 	switch (uap->cmd) {
201a60ccb85SDavid Xu 	case USCHED_SET_SCHEDULER:
2022b3f93eaSMatthew Dillon 		if ((error = caps_priv_check_self(SYSCAP_NOSCHED)) != 0)
2033919ced0SMatthew Dillon 			break;
2043919ced0SMatthew Dillon 		error = copyinstr(uap->data, buffer, sizeof(buffer), NULL);
2053919ced0SMatthew Dillon 		if (error)
2063919ced0SMatthew Dillon 			break;
207cb7f4ab1SMatthew Dillon 		TAILQ_FOREACH(item, &usched_list, entry) {
2081b31454eSDavid Rhodus 			if ((strcmp(item->name, buffer) == 0))
209cb7f4ab1SMatthew Dillon 				break;
210cb7f4ab1SMatthew Dillon 		}
211cb7f4ab1SMatthew Dillon 
212cb7f4ab1SMatthew Dillon 		/*
213cb7f4ab1SMatthew Dillon 		 * If the scheduler for a process is being changed, disassociate
214cb7f4ab1SMatthew Dillon 		 * the old scheduler before switching to the new one.
215cb7f4ab1SMatthew Dillon 		 *
216cb7f4ab1SMatthew Dillon 		 * XXX we might have to add an additional ABI call to do a 'full
217a60ccb85SDavid Xu 		 * disassociation' and another ABI call to do a 'full
218a60ccb85SDavid Xu 		 * reassociation'
219cb7f4ab1SMatthew Dillon 		 */
22008f2f1bbSSimon Schubert 		/* XXX lwp have to deal with multiple lwps here */
2213919ced0SMatthew Dillon 		if (p->p_nthreads != 1) {
2223919ced0SMatthew Dillon 			error = EINVAL;
2233919ced0SMatthew Dillon 			break;
2243919ced0SMatthew Dillon 		}
225cb7f4ab1SMatthew Dillon 		if (item && item != p->p_usched) {
22608f2f1bbSSimon Schubert 			/* XXX lwp */
22708f2f1bbSSimon Schubert 			p->p_usched->release_curproc(ONLY_LWP_IN_PROC(p));
228e28d8b15SMatthew Dillon 			p->p_usched->heuristic_exiting(ONLY_LWP_IN_PROC(p), p);
229cb7f4ab1SMatthew Dillon 			p->p_usched = item;
230cb7f4ab1SMatthew Dillon 		} else if (item == NULL) {
231cb7f4ab1SMatthew Dillon 			error = EINVAL;
232cb7f4ab1SMatthew Dillon 		}
233a60ccb85SDavid Xu 		break;
234a60ccb85SDavid Xu 	case USCHED_SET_CPU:
2352b3f93eaSMatthew Dillon 		if ((error = caps_priv_check_self(SYSCAP_NOSCHED_CPUSET)) != 0)
2363919ced0SMatthew Dillon 			break;
2373919ced0SMatthew Dillon 		if (uap->bytes != sizeof(int)) {
2383919ced0SMatthew Dillon 			error = EINVAL;
2393919ced0SMatthew Dillon 			break;
2403919ced0SMatthew Dillon 		}
241a60ccb85SDavid Xu 		error = copyin(uap->data, &cpuid, sizeof(int));
242a60ccb85SDavid Xu 		if (error)
243a60ccb85SDavid Xu 			break;
244a5ae2446SMatthew Dillon 		if (cpuid < 0 || cpuid >= ncpus) {
245a5ae2446SMatthew Dillon 			error = EFBIG;
246a5ae2446SMatthew Dillon 			break;
247a5ae2446SMatthew Dillon 		}
248c07315c4SMatthew Dillon 		if (CPUMASK_TESTBIT(smp_active_mask, cpuid) == 0) {
249a60ccb85SDavid Xu 			error = EINVAL;
250a60ccb85SDavid Xu 			break;
251a60ccb85SDavid Xu 		}
252c07315c4SMatthew Dillon 		CPUMASK_ASSBIT(lp->lwp_cpumask, cpuid);
2539809f2dfSMatthew Dillon 		if (cpuid != mycpu->gd_cpuid) {
254a60ccb85SDavid Xu 			lwkt_migratecpu(cpuid);
2559809f2dfSMatthew Dillon 			p->p_usched->changedcpu(lp);
2569809f2dfSMatthew Dillon 		}
257a60ccb85SDavid Xu 		break;
258dcf3266eSJoe Talbott 	case USCHED_GET_CPU:
259cc125f38SMichael Neumann 		/* USCHED_GET_CPU doesn't require special privileges. */
2603919ced0SMatthew Dillon 		if (uap->bytes != sizeof(int)) {
2613919ced0SMatthew Dillon 			error = EINVAL;
2623919ced0SMatthew Dillon 			break;
2633919ced0SMatthew Dillon 		}
264dcf3266eSJoe Talbott 		error = copyout(&(mycpu->gd_cpuid), uap->data, sizeof(int));
265dcf3266eSJoe Talbott 		break;
266a3894d77STomohiro Kusumi 	case USCHED_GET_CPUMASK:
267a3894d77STomohiro Kusumi 		/* USCHED_GET_CPUMASK doesn't require special privileges. */
268a3894d77STomohiro Kusumi 		if (uap->bytes != sizeof(cpumask_t)) {
269a3894d77STomohiro Kusumi 			error = EINVAL;
270a3894d77STomohiro Kusumi 			break;
271a3894d77STomohiro Kusumi 		}
2722dbb2134SSepherosa Ziehau 		mask = lp->lwp_cpumask;
2732dbb2134SSepherosa Ziehau 		CPUMASK_ANDMASK(mask, smp_active_mask);
2742dbb2134SSepherosa Ziehau 		error = copyout(&mask, uap->data, sizeof(cpumask_t));
275a3894d77STomohiro Kusumi 		break;
276a60ccb85SDavid Xu 	case USCHED_ADD_CPU:
2772b3f93eaSMatthew Dillon 		if ((error = caps_priv_check_self(SYSCAP_NOSCHED_CPUSET)) != 0)
2783919ced0SMatthew Dillon 			break;
2793919ced0SMatthew Dillon 		if (uap->bytes != sizeof(int)) {
2803919ced0SMatthew Dillon 			error = EINVAL;
2813919ced0SMatthew Dillon 			break;
2823919ced0SMatthew Dillon 		}
283a60ccb85SDavid Xu 		error = copyin(uap->data, &cpuid, sizeof(int));
284a60ccb85SDavid Xu 		if (error)
285a60ccb85SDavid Xu 			break;
286a5ae2446SMatthew Dillon 		if (cpuid < 0 || cpuid >= ncpus) {
287a5ae2446SMatthew Dillon 			error = EFBIG;
288a5ae2446SMatthew Dillon 			break;
289a5ae2446SMatthew Dillon 		}
290c07315c4SMatthew Dillon 		if (CPUMASK_TESTBIT(smp_active_mask, cpuid) == 0) {
291a60ccb85SDavid Xu 			error = EINVAL;
292a60ccb85SDavid Xu 			break;
293a60ccb85SDavid Xu 		}
294c07315c4SMatthew Dillon 		CPUMASK_ORBIT(lp->lwp_cpumask, cpuid);
295a60ccb85SDavid Xu 		break;
296a60ccb85SDavid Xu 	case USCHED_DEL_CPU:
297cc125f38SMichael Neumann 		/* USCHED_DEL_CPU doesn't require special privileges. */
2983919ced0SMatthew Dillon 		if (uap->bytes != sizeof(int)) {
2993919ced0SMatthew Dillon 			error = EINVAL;
3003919ced0SMatthew Dillon 			break;
3013919ced0SMatthew Dillon 		}
302a60ccb85SDavid Xu 		error = copyin(uap->data, &cpuid, sizeof(int));
303a60ccb85SDavid Xu 		if (error)
304a60ccb85SDavid Xu 			break;
305a5ae2446SMatthew Dillon 		if (cpuid < 0 || cpuid >= ncpus) {
306a5ae2446SMatthew Dillon 			error = EFBIG;
307a5ae2446SMatthew Dillon 			break;
308a5ae2446SMatthew Dillon 		}
309a60ccb85SDavid Xu 		lp = curthread->td_lwp;
310c07315c4SMatthew Dillon 		mask = lp->lwp_cpumask;
311c07315c4SMatthew Dillon 		CPUMASK_ANDMASK(mask, smp_active_mask);
312c07315c4SMatthew Dillon 		CPUMASK_NANDBIT(mask, cpuid);
313c07315c4SMatthew Dillon 		if (CPUMASK_TESTZERO(mask)) {
314a60ccb85SDavid Xu 			error = EPERM;
315c07315c4SMatthew Dillon 		} else {
316c07315c4SMatthew Dillon 			CPUMASK_NANDBIT(lp->lwp_cpumask, cpuid);
317c07315c4SMatthew Dillon 			if (CPUMASK_TESTMASK(lp->lwp_cpumask,
318c07315c4SMatthew Dillon 					    mycpu->gd_cpumask) == 0) {
319c07315c4SMatthew Dillon 				mask = lp->lwp_cpumask;
320c07315c4SMatthew Dillon 				CPUMASK_ANDMASK(mask, smp_active_mask);
321c07315c4SMatthew Dillon 				cpuid = BSFCPUMASK(mask);
322a60ccb85SDavid Xu 				lwkt_migratecpu(cpuid);
3239809f2dfSMatthew Dillon 				p->p_usched->changedcpu(lp);
324a60ccb85SDavid Xu 			}
325a60ccb85SDavid Xu 		}
326ba174a5dSMatthew Dillon 		break;
32791755bddSSepherosa Ziehau 	case USCHED_SET_CPUMASK:
3282b3f93eaSMatthew Dillon 		if ((error = caps_priv_check_self(SYSCAP_NOSCHED_CPUSET)) != 0)
32991755bddSSepherosa Ziehau 			break;
33091755bddSSepherosa Ziehau 		if (uap->bytes != sizeof(mask)) {
33191755bddSSepherosa Ziehau 			error = EINVAL;
33291755bddSSepherosa Ziehau 			break;
33391755bddSSepherosa Ziehau 		}
33491755bddSSepherosa Ziehau 		error = copyin(uap->data, &mask, sizeof(mask));
33591755bddSSepherosa Ziehau 		if (error)
33691755bddSSepherosa Ziehau 			break;
33791755bddSSepherosa Ziehau 
33891755bddSSepherosa Ziehau 		CPUMASK_ANDMASK(mask, smp_active_mask);
33991755bddSSepherosa Ziehau 		if (CPUMASK_TESTZERO(mask)) {
34091755bddSSepherosa Ziehau 			error = EPERM;
34191755bddSSepherosa Ziehau 			break;
34291755bddSSepherosa Ziehau 		}
34391755bddSSepherosa Ziehau 		/* Commit the new cpumask. */
34491755bddSSepherosa Ziehau 		lp->lwp_cpumask = mask;
34591755bddSSepherosa Ziehau 
34691755bddSSepherosa Ziehau 		/* Migrate if necessary. */
34791755bddSSepherosa Ziehau 		if (CPUMASK_TESTMASK(lp->lwp_cpumask, mycpu->gd_cpumask) == 0) {
34891755bddSSepherosa Ziehau 			cpuid = BSFCPUMASK(lp->lwp_cpumask);
34991755bddSSepherosa Ziehau 			lwkt_migratecpu(cpuid);
35091755bddSSepherosa Ziehau 			p->p_usched->changedcpu(lp);
35191755bddSSepherosa Ziehau 		}
35291755bddSSepherosa Ziehau 		break;
353a60ccb85SDavid Xu 	default:
354a60ccb85SDavid Xu 		error = EINVAL;
355a60ccb85SDavid Xu 		break;
356a60ccb85SDavid Xu 	}
357480ed3deSMatthew Dillon 	lwkt_reltoken(&lp->lwp_token);
358480ed3deSMatthew Dillon 
359cb7f4ab1SMatthew Dillon 	return (error);
360cb7f4ab1SMatthew Dillon }
361cb7f4ab1SMatthew Dillon 
3628f95cc34SSepherosa Ziehau int
sys_lwp_getaffinity(struct sysmsg * sysmsg,const struct lwp_getaffinity_args * uap)36380d831e1SMatthew Dillon sys_lwp_getaffinity(struct sysmsg *sysmsg,
36480d831e1SMatthew Dillon 		    const struct lwp_getaffinity_args *uap)
3658f95cc34SSepherosa Ziehau {
3668f95cc34SSepherosa Ziehau 	struct proc *p;
3678f95cc34SSepherosa Ziehau 	cpumask_t mask;
3688f95cc34SSepherosa Ziehau 	struct lwp *lp;
3698f95cc34SSepherosa Ziehau 	int error = 0;
3708f95cc34SSepherosa Ziehau 
371480ed3deSMatthew Dillon 	if (uap->pid < 0)
3728f95cc34SSepherosa Ziehau 		return (EINVAL);
373480ed3deSMatthew Dillon 
374480ed3deSMatthew Dillon 	if (uap->pid == 0) {
3758f95cc34SSepherosa Ziehau 		p = curproc;
3768f95cc34SSepherosa Ziehau 		PHOLD(p);
3778f95cc34SSepherosa Ziehau 	} else {
378480ed3deSMatthew Dillon 		p = pfind(uap->pid);	/* pfind() holds (p) */
3798f95cc34SSepherosa Ziehau 		if (p == NULL)
3808f95cc34SSepherosa Ziehau 			return (ESRCH);
3818f95cc34SSepherosa Ziehau 	}
3828f95cc34SSepherosa Ziehau 	lwkt_gettoken(&p->p_token);
3838f95cc34SSepherosa Ziehau 
384480ed3deSMatthew Dillon 	if (uap->tid < 0) {
385480ed3deSMatthew Dillon 		lp = RB_FIRST(lwp_rb_tree, &p->p_lwp_tree);
386480ed3deSMatthew Dillon 	} else {
3878f95cc34SSepherosa Ziehau 		lp = lwp_rb_tree_RB_LOOKUP(&p->p_lwp_tree, uap->tid);
388480ed3deSMatthew Dillon 	}
3898f95cc34SSepherosa Ziehau 	if (lp == NULL) {
3908f95cc34SSepherosa Ziehau 		error = ESRCH;
3918f95cc34SSepherosa Ziehau 	} else {
3928f95cc34SSepherosa Ziehau 		/* Take a snapshot for copyout, which may block. */
393480ed3deSMatthew Dillon 		LWPHOLD(lp);
394480ed3deSMatthew Dillon 		lwkt_gettoken(&lp->lwp_token);
3958f95cc34SSepherosa Ziehau 		mask = lp->lwp_cpumask;
3968f95cc34SSepherosa Ziehau 		CPUMASK_ANDMASK(mask, smp_active_mask);
397480ed3deSMatthew Dillon 		lwkt_reltoken(&lp->lwp_token);
398480ed3deSMatthew Dillon 		LWPRELE(lp);
3998f95cc34SSepherosa Ziehau 	}
4008f95cc34SSepherosa Ziehau 
4018f95cc34SSepherosa Ziehau 	lwkt_reltoken(&p->p_token);
4028f95cc34SSepherosa Ziehau 	PRELE(p);
4038f95cc34SSepherosa Ziehau 
404480ed3deSMatthew Dillon 	if (error == 0)
4058f95cc34SSepherosa Ziehau 		error = copyout(&mask, uap->mask, sizeof(cpumask_t));
406480ed3deSMatthew Dillon 
4078f95cc34SSepherosa Ziehau 	return (error);
4088f95cc34SSepherosa Ziehau }
4098f95cc34SSepherosa Ziehau 
4108f95cc34SSepherosa Ziehau int
sys_lwp_setaffinity(struct sysmsg * sysmsg,const struct lwp_setaffinity_args * uap)41180d831e1SMatthew Dillon sys_lwp_setaffinity(struct sysmsg *sysmsg,
41280d831e1SMatthew Dillon 		    const struct lwp_setaffinity_args *uap)
4138f95cc34SSepherosa Ziehau {
4148f95cc34SSepherosa Ziehau 	struct proc *p;
4158f95cc34SSepherosa Ziehau 	cpumask_t mask;
4168f95cc34SSepherosa Ziehau 	struct lwp *lp;
4178f95cc34SSepherosa Ziehau 	int error;
4188f95cc34SSepherosa Ziehau 
4190c774c17SSepherosa Ziehau 	/*
4200c774c17SSepherosa Ziehau 	 * NOTE:
4210c774c17SSepherosa Ziehau 	 * Always allow change self CPU affinity.
4220c774c17SSepherosa Ziehau 	 */
4232b3f93eaSMatthew Dillon 	if ((error = caps_priv_check_self(SYSCAP_NOSCHED_CPUSET)) != 0 &&
4240c774c17SSepherosa Ziehau 	    uap->pid != 0)
4252b3f93eaSMatthew Dillon 	{
4268f95cc34SSepherosa Ziehau 		return (error);
4272b3f93eaSMatthew Dillon 	}
4288f95cc34SSepherosa Ziehau 
4298f95cc34SSepherosa Ziehau 	error = copyin(uap->mask, &mask, sizeof(mask));
4308f95cc34SSepherosa Ziehau 	if (error)
4318f95cc34SSepherosa Ziehau 		return (error);
4328f95cc34SSepherosa Ziehau 
4338f95cc34SSepherosa Ziehau 	CPUMASK_ANDMASK(mask, smp_active_mask);
4348f95cc34SSepherosa Ziehau 	if (CPUMASK_TESTZERO(mask))
4358f95cc34SSepherosa Ziehau 		return (EPERM);
436480ed3deSMatthew Dillon 	if (uap->pid < 0)
4378f95cc34SSepherosa Ziehau 		return (EINVAL);
438480ed3deSMatthew Dillon 
439480ed3deSMatthew Dillon 	/*
440480ed3deSMatthew Dillon 	 * Locate the process
441480ed3deSMatthew Dillon 	 */
442480ed3deSMatthew Dillon 	if (uap->pid == 0) {
4438f95cc34SSepherosa Ziehau 		p = curproc;
4448f95cc34SSepherosa Ziehau 		PHOLD(p);
4458f95cc34SSepherosa Ziehau 	} else {
446480ed3deSMatthew Dillon 		p = pfind(uap->pid);	/* pfind() holds (p) */
4478f95cc34SSepherosa Ziehau 		if (p == NULL)
4488f95cc34SSepherosa Ziehau 			return (ESRCH);
4498f95cc34SSepherosa Ziehau 	}
4508f95cc34SSepherosa Ziehau 	lwkt_gettoken(&p->p_token);
4518f95cc34SSepherosa Ziehau 
452480ed3deSMatthew Dillon 	if (uap->tid < 0) {
453480ed3deSMatthew Dillon 		FOREACH_LWP_IN_PROC(lp, p) {
454480ed3deSMatthew Dillon 			error = setaffinity_lp(lp, &mask);
455480ed3deSMatthew Dillon 		}
456480ed3deSMatthew Dillon 		/* not an error if no LPs left in process */
4578f95cc34SSepherosa Ziehau 	} else {
458480ed3deSMatthew Dillon 		lp = lwp_rb_tree_RB_LOOKUP(&p->p_lwp_tree, uap->tid);
459480ed3deSMatthew Dillon 		error = setaffinity_lp(lp, &mask);
460480ed3deSMatthew Dillon 	}
461480ed3deSMatthew Dillon 	lwkt_reltoken(&p->p_token);
462480ed3deSMatthew Dillon 	PRELE(p);
4638f95cc34SSepherosa Ziehau 
464480ed3deSMatthew Dillon 	return (error);
465480ed3deSMatthew Dillon }
466480ed3deSMatthew Dillon 
467480ed3deSMatthew Dillon static int
setaffinity_lp(struct lwp * lp,cpumask_t * mask)468480ed3deSMatthew Dillon setaffinity_lp(struct lwp *lp, cpumask_t *mask)
469480ed3deSMatthew Dillon {
470480ed3deSMatthew Dillon 	if (lp == NULL)
471480ed3deSMatthew Dillon 		return ESRCH;
472480ed3deSMatthew Dillon 
473480ed3deSMatthew Dillon 	LWPHOLD(lp);
474480ed3deSMatthew Dillon 	lwkt_gettoken(&lp->lwp_token);
475480ed3deSMatthew Dillon 	lp->lwp_cpumask = *mask;
476480ed3deSMatthew Dillon 
477480ed3deSMatthew Dillon 	/*
478480ed3deSMatthew Dillon 	 * NOTE: When adjusting a thread that is not our own the migration
479480ed3deSMatthew Dillon 	 *	 will occur at the next reschedule.
480480ed3deSMatthew Dillon 	 */
4818f95cc34SSepherosa Ziehau 	if (lp == curthread->td_lwp) {
4828f95cc34SSepherosa Ziehau 		/*
4838f95cc34SSepherosa Ziehau 		 * Self migration can be done immediately,
4848f95cc34SSepherosa Ziehau 		 * if necessary.
4858f95cc34SSepherosa Ziehau 		 */
4868f95cc34SSepherosa Ziehau 		if (CPUMASK_TESTBIT(lp->lwp_cpumask,
4878f95cc34SSepherosa Ziehau 		    mycpu->gd_cpuid) == 0) {
4888f95cc34SSepherosa Ziehau 			lwkt_migratecpu(BSFCPUMASK(lp->lwp_cpumask));
489480ed3deSMatthew Dillon 			lp->lwp_proc->p_usched->changedcpu(lp);
4908f95cc34SSepherosa Ziehau 		}
4918f95cc34SSepherosa Ziehau 	}
492480ed3deSMatthew Dillon 	lwkt_reltoken(&lp->lwp_token);
493480ed3deSMatthew Dillon 	LWPRELE(lp);
4948f95cc34SSepherosa Ziehau 
495480ed3deSMatthew Dillon 	return 0;
4968f95cc34SSepherosa Ziehau }
497