4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/types.h>
28 #include <sys/systm.h>
29 #include <sys/cmn_err.h>
30 #include <sys/class.h>
34 #include <sys/procset.h>
35 #include <sys/modctl.h>
37 #include <sys/sysmacros.h>
38 #include <sys/schedctl.h>
40 static int getcidbyname_locked(char *, id_t
*);
43 * Allocate a cid given a class name if one is not already allocated.
44 * Returns 0 if the cid was already exists or if the allocation of a new
45 * cid was successful. Nonzero return indicates error.
48 alloc_cid(char *clname
, id_t
*cidp
)
52 ASSERT(MUTEX_HELD(&class_lock
));
55 * If the clname doesn't already have a cid, allocate one.
57 if (getcidbyname_locked(clname
, cidp
) != 0) {
59 * Allocate a class entry and a lock for it.
61 for (clp
= sclass
; clp
< &sclass
[nclass
]; clp
++)
62 if (clp
->cl_name
[0] == '\0' && clp
->cl_lock
== NULL
)
65 if (clp
== &sclass
[nclass
]) {
68 *cidp
= clp
- &sclass
[0];
69 clp
->cl_lock
= kmem_alloc(sizeof (krwlock_t
), KM_SLEEP
);
70 clp
->cl_name
= kmem_alloc(strlen(clname
) + 1, KM_SLEEP
);
71 (void) strcpy(clp
->cl_name
, clname
);
72 rw_init(clp
->cl_lock
, NULL
, RW_DEFAULT
, NULL
);
76 * At this point, *cidp will contain the index into the class
77 * array for the given class name.
83 scheduler_load(char *clname
, sclass_t
*clp
)
86 char *tmp
= clname
+ 1;
88 /* Check if class name is "", ".", ".." or "`" */
89 if (*clname
== '\0' || *clname
== '`' || (*clname
== '.' &&
91 (*clname
== '.' && *tmp
== '.' && *(++tmp
) == '\0'))
94 if (LOADABLE_SCHED(clp
)) {
95 rw_enter(clp
->cl_lock
, RW_READER
);
96 if (!SCHED_INSTALLED(clp
)) {
97 rw_exit(clp
->cl_lock
);
98 if (modload("sched", clname
) == -1)
100 rw_enter(clp
->cl_lock
, RW_READER
);
101 /* did we really load a scheduling class? */
102 if (!SCHED_INSTALLED(clp
))
105 rw_exit(clp
->cl_lock
);
111 * Get class ID given class name.
114 getcid(char *clname
, id_t
*cidp
)
119 mutex_enter(&class_lock
);
120 if ((retval
= alloc_cid(clname
, cidp
)) == 0) {
121 clp
= &sclass
[*cidp
];
125 * If it returns zero, it's loaded & locked
126 * or we found a statically installed scheduler
128 * If it returns EINVAL, modload() failed when
129 * it tried to load the module.
131 mutex_exit(&class_lock
);
132 retval
= scheduler_load(clname
, clp
);
133 mutex_enter(&class_lock
);
136 if (retval
!= 0 && clp
->cl_count
== 0) {
137 /* last guy out of scheduler_load frees the storage */
138 kmem_free(clp
->cl_name
, strlen(clname
) + 1);
139 kmem_free(clp
->cl_lock
, sizeof (krwlock_t
));
144 mutex_exit(&class_lock
);
150 getcidbyname_locked(char *clname
, id_t
*cidp
)
154 ASSERT(MUTEX_HELD(&class_lock
));
159 for (clp
= &sclass
[0]; clp
< &sclass
[nclass
]; clp
++) {
160 if (strcmp(clp
->cl_name
, clname
) == 0) {
161 *cidp
= clp
- &sclass
[0];
169 * Lookup a module by name.
172 getcidbyname(char *clname
, id_t
*cidp
)
176 mutex_enter(&class_lock
);
177 retval
= getcidbyname_locked(clname
, cidp
);
178 mutex_exit(&class_lock
);
184 * Get the scheduling parameters of the thread pointed to by
185 * tp into the buffer pointed to by parmsp.
188 parmsget(kthread_t
*tp
, pcparms_t
*parmsp
)
190 parmsp
->pc_cid
= tp
->t_cid
;
191 CL_PARMSGET(tp
, parmsp
->pc_clparms
);
196 * Check the validity of the scheduling parameters in the buffer
197 * pointed to by parmsp.
198 * Note that the format of the parameters may be changed by class
199 * specific code which we call.
202 parmsin(pcparms_t
*parmsp
, pc_vaparms_t
*vaparmsp
)
204 if (parmsp
->pc_cid
>= loaded_classes
|| parmsp
->pc_cid
< 1)
208 * Call the class specific routine to validate class
209 * specific parameters.
210 * The input parameters are either in a pcparms structure (PC_SETPARMS)
211 * or in a variable parameter structure (PC_SETXPARMS). In the
212 * 'PC_SETPARMS' case vaparmsp is a NULL pointer and a CL_PARMSIN()
213 * routine gets the parameter. Otherwise vaparmsp points to a variable
214 * parameter structure and a CL_VAPARMSIN() routine gets the parameter.
216 if (vaparmsp
!= NULL
)
217 return (CL_VAPARMSIN(&sclass
[parmsp
->pc_cid
],
218 parmsp
->pc_clparms
, vaparmsp
));
220 return (CL_PARMSIN(&sclass
[parmsp
->pc_cid
],
221 parmsp
->pc_clparms
));
226 * Call the class specific code to do the required processing
227 * before the scheduling parameters are copied out to the user.
228 * Note that the format of the parameters may be changed by the
229 * class specific code.
232 parmsout(pcparms_t
*parmsp
, pc_vaparms_t
*vaparmsp
)
234 return (CL_PARMSOUT(&sclass
[parmsp
->pc_cid
], parmsp
->pc_clparms
,
240 * Set the scheduling parameters of the thread pointed to by
241 * targtp to those specified in the pcparms structure pointed
242 * to by parmsp. If reqtp is non-NULL it points to the thread
243 * that initiated the request for the parameter change and indicates
244 * that our caller wants us to verify that the requesting thread
245 * has the appropriate permissions.
248 parmsset(pcparms_t
*parmsp
, kthread_t
*targtp
)
253 proc_t
*reqpp
= ttoproc(curthread
);
254 proc_t
*targpp
= ttoproc(targtp
);
257 ASSERT(MUTEX_HELD(&pidlock
));
258 ASSERT(MUTEX_HELD(&targpp
->p_lock
));
260 mutex_enter(&reqpp
->p_crlock
);
261 crhold(reqpcredp
= reqpp
->p_cred
);
262 mutex_exit(&reqpp
->p_crlock
);
265 * Check basic permissions.
267 if (!prochasprocperm(targpp
, reqpp
, reqpcredp
)) {
275 if (parmsp
->pc_cid
!= targtp
->t_cid
) {
278 * Target thread must change to new class.
280 clprocp
= (caddr_t
)targtp
->t_cldata
;
281 oldcid
= targtp
->t_cid
;
284 * Purpose: allow scheduling class to veto moves
285 * to other classes. All the classes, except FSS,
286 * do nothing except returning 0.
288 error
= CL_CANEXIT(targtp
, reqpcredp
);
291 * Not allowed to leave the class, so return error.
297 * Pre-allocate scheduling class data.
299 if (CL_ALLOC(&bufp
, parmsp
->pc_cid
, KM_NOSLEEP
) != 0) {
300 error
= ENOMEM
; /* no memory available */
304 error
= CL_ENTERCLASS(targtp
, parmsp
->pc_cid
,
305 parmsp
->pc_clparms
, reqpcredp
, bufp
);
308 CL_FREE(parmsp
->pc_cid
, bufp
);
313 CL_EXITCLASS(oldcid
, clprocp
);
319 error
= CL_PARMSSET(targtp
, parmsp
->pc_clparms
,
320 curthread
->t_cid
, reqpcredp
);
325 schedctl_set_cidpri(targtp
);
331 * Copy all selected class parameters to the user.
332 * The parameters are specified by a key.
335 vaparmsout(char *classp
, pcparms_t
*prmsp
, pc_vaparms_t
*vaparmsp
,
340 ASSERT(MUTEX_NOT_HELD(&curproc
->p_lock
));
343 return (CL_VAPARMSOUT(&sclass
[prmsp
->pc_cid
],
344 prmsp
->pc_clparms
, vaparmsp
));
346 switch (vaparmsp
->pc_vaparmscnt
) {
355 if (vaparmsp
->pc_parms
[0].pc_key
!= PC_KY_CLNAME
)
358 clname
= sclass
[prmsp
->pc_cid
].cl_name
;
359 if ((seg
== UIO_USERSPACE
? copyout
: kcopy
)(clname
,
360 (void *)(uintptr_t)vaparmsp
->pc_parms
[0].pc_parm
,
361 MIN(strlen(clname
) + 1, PC_CLNMSZ
)))