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