xref: /titanic_41/usr/src/uts/common/disp/rt.c (revision 7c64d3750da7fda7e450b8f9b0b963905ded6379)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/sysmacros.h>
35 #include <sys/cred.h>
36 #include <sys/proc.h>
37 #include <sys/pcb.h>
38 #include <sys/signal.h>
39 #include <sys/user.h>
40 #include <sys/priocntl.h>
41 #include <sys/class.h>
42 #include <sys/disp.h>
43 #include <sys/procset.h>
44 #include <sys/cmn_err.h>
45 #include <sys/debug.h>
46 #include <sys/rt.h>
47 #include <sys/rtpriocntl.h>
48 #include <sys/kmem.h>
49 #include <sys/systm.h>
50 #include <sys/schedctl.h>
51 #include <sys/errno.h>
52 #include <sys/cpuvar.h>
53 #include <sys/vmsystm.h>
54 #include <sys/time.h>
55 #include <sys/policy.h>
56 #include <sys/sdt.h>
57 #include <sys/cpupart.h>
58 #include <sys/modctl.h>
59 
60 static pri_t	rt_init(id_t, int, classfuncs_t **);
61 
62 static struct sclass csw = {
63 	"RT",
64 	rt_init,
65 	0
66 };
67 
68 static struct modlsched modlsched = {
69 	&mod_schedops, "realtime scheduling class", &csw
70 };
71 
72 static struct modlinkage modlinkage = {
73 	MODREV_1, (void *)&modlsched, NULL
74 };
75 
76 int
77 _init()
78 {
79 	return (mod_install(&modlinkage));
80 }
81 
82 int
83 _fini()
84 {
85 	return (EBUSY);		/* don't remove RT for now */
86 }
87 
88 int
89 _info(struct modinfo *modinfop)
90 {
91 	return (mod_info(&modlinkage, modinfop));
92 }
93 
94 
95 /*
96  * Class specific code for the real-time class
97  */
98 
99 /*
100  * Extern declarations for variables defined in the rt master file
101  */
102 #define	RTMAXPRI 59
103 
104 pri_t rt_maxpri = RTMAXPRI;	/* maximum real-time priority */
105 rtdpent_t *rt_dptbl;	  /* real-time dispatcher parameter table */
106 
107 /*
108  * control flags (kparms->rt_cflags).
109  */
110 #define	RT_DOPRI	0x01	/* change priority */
111 #define	RT_DOTQ		0x02	/* change RT time quantum */
112 #define	RT_DOSIG	0x04	/* change RT time quantum signal */
113 
114 static int	rt_admin(caddr_t, cred_t *);
115 static int	rt_enterclass(kthread_t *, id_t, void *, cred_t *, void *);
116 static int	rt_fork(kthread_t *, kthread_t *, void *);
117 static int	rt_getclinfo(void *);
118 static int	rt_getclpri(pcpri_t *);
119 static int	rt_parmsin(void *);
120 static int	rt_parmsout(void *, pc_vaparms_t *);
121 static int	rt_vaparmsin(void *, pc_vaparms_t *);
122 static int	rt_vaparmsout(void *, pc_vaparms_t *);
123 static int	rt_parmsset(kthread_t *, void *, id_t, cred_t *);
124 static int	rt_donice(kthread_t *, cred_t *, int, int *);
125 static int	rt_doprio(kthread_t *, cred_t *, int, int *);
126 static void	rt_exitclass(void *);
127 static int	rt_canexit(kthread_t *, cred_t *);
128 static void	rt_forkret(kthread_t *, kthread_t *);
129 static void	rt_nullsys();
130 static void	rt_parmsget(kthread_t *, void *);
131 static void	rt_preempt(kthread_t *);
132 static void	rt_setrun(kthread_t *);
133 static void	rt_tick(kthread_t *);
134 static void	rt_wakeup(kthread_t *);
135 static pri_t	rt_swapin(kthread_t *, int);
136 static pri_t	rt_swapout(kthread_t *, int);
137 static pri_t	rt_globpri(kthread_t *);
138 static void	rt_yield(kthread_t *);
139 static int	rt_alloc(void **, int);
140 static void	rt_free(void *);
141 
142 static void	rt_change_priority(kthread_t *, rtproc_t *);
143 
144 static id_t	rt_cid;		/* real-time class ID */
145 static rtproc_t	rt_plisthead;	/* dummy rtproc at head of rtproc list */
146 static kmutex_t	rt_dptblock;	/* protects realtime dispatch table */
147 static kmutex_t	rt_list_lock;	/* protects RT thread list */
148 
149 extern rtdpent_t *rt_getdptbl(void);
150 
151 static struct classfuncs rt_classfuncs = {
152 	/* class ops */
153 	rt_admin,
154 	rt_getclinfo,
155 	rt_parmsin,
156 	rt_parmsout,
157 	rt_vaparmsin,
158 	rt_vaparmsout,
159 	rt_getclpri,
160 	rt_alloc,
161 	rt_free,
162 	/* thread ops */
163 	rt_enterclass,
164 	rt_exitclass,
165 	rt_canexit,
166 	rt_fork,
167 	rt_forkret,
168 	rt_parmsget,
169 	rt_parmsset,
170 	rt_nullsys,	/* stop */
171 	rt_nullsys,	/* exit */
172 	rt_nullsys,	/* active */
173 	rt_nullsys,	/* inactive */
174 	rt_swapin,
175 	rt_swapout,
176 	rt_nullsys,	/* trapret */
177 	rt_preempt,
178 	rt_setrun,
179 	rt_nullsys,	/* sleep */
180 	rt_tick,
181 	rt_wakeup,
182 	rt_donice,
183 	rt_globpri,
184 	rt_nullsys,	/* set_process_group */
185 	rt_yield,
186 	rt_doprio,
187 };
188 
189 /*
190  * Real-time class initialization. Called by dispinit() at boot time.
191  * We can ignore the clparmsz argument since we know that the smallest
192  * possible parameter buffer is big enough for us.
193  */
194 /* ARGSUSED */
195 pri_t
196 rt_init(id_t cid, int clparmsz, classfuncs_t **clfuncspp)
197 {
198 	rt_dptbl = rt_getdptbl();
199 	rt_cid = cid;	/* Record our class ID */
200 
201 	/*
202 	 * Initialize the rtproc list.
203 	 */
204 	rt_plisthead.rt_next = rt_plisthead.rt_prev = &rt_plisthead;
205 
206 	/*
207 	 * We're required to return a pointer to our classfuncs
208 	 * structure and the highest global priority value we use.
209 	 */
210 	*clfuncspp = &rt_classfuncs;
211 	mutex_init(&rt_dptblock, NULL, MUTEX_DEFAULT, NULL);
212 	mutex_init(&rt_list_lock, NULL, MUTEX_DEFAULT, NULL);
213 	return (rt_dptbl[rt_maxpri].rt_globpri);
214 }
215 
216 /*
217  * Get or reset the rt_dptbl values per the user's request.
218  */
219 /* ARGSUSED */
220 static int
221 rt_admin(caddr_t uaddr, cred_t *reqpcredp)
222 {
223 	rtadmin_t	rtadmin;
224 	rtdpent_t	*tmpdpp;
225 	size_t		userdpsz;
226 	size_t		rtdpsz;
227 	int		i;
228 
229 	if (get_udatamodel() == DATAMODEL_NATIVE) {
230 		if (copyin(uaddr, &rtadmin, sizeof (rtadmin_t)))
231 			return (EFAULT);
232 	}
233 #ifdef _SYSCALL32_IMPL
234 	else {
235 		/* rtadmin struct from ILP32 callers */
236 		rtadmin32_t rtadmin32;
237 		if (copyin(uaddr, &rtadmin32, sizeof (rtadmin32_t)))
238 			return (EFAULT);
239 		rtadmin.rt_dpents =
240 		    (struct rtdpent *)(uintptr_t)rtadmin32.rt_dpents;
241 		rtadmin.rt_ndpents = rtadmin32.rt_ndpents;
242 		rtadmin.rt_cmd = rtadmin32.rt_cmd;
243 	}
244 #endif /* _SYSCALL32_IMPL */
245 
246 	rtdpsz = (rt_maxpri + 1) * sizeof (rtdpent_t);
247 
248 	switch (rtadmin.rt_cmd) {
249 
250 	case RT_GETDPSIZE:
251 		rtadmin.rt_ndpents = rt_maxpri + 1;
252 
253 		if (get_udatamodel() == DATAMODEL_NATIVE) {
254 			if (copyout(&rtadmin, uaddr, sizeof (rtadmin_t)))
255 				return (EFAULT);
256 		}
257 #ifdef _SYSCALL32_IMPL
258 		else {
259 			/* return rtadmin struct to ILP32 callers */
260 			rtadmin32_t rtadmin32;
261 			rtadmin32.rt_dpents =
262 			    (caddr32_t)(uintptr_t)rtadmin.rt_dpents;
263 			rtadmin32.rt_ndpents = rtadmin.rt_ndpents;
264 			rtadmin32.rt_cmd = rtadmin.rt_cmd;
265 			if (copyout(&rtadmin32, uaddr, sizeof (rtadmin32_t)))
266 				return (EFAULT);
267 		}
268 #endif /* _SYSCALL32_IMPL */
269 
270 		break;
271 
272 	case RT_GETDPTBL:
273 		userdpsz = MIN(rtadmin.rt_ndpents * sizeof (rtdpent_t),
274 		    rtdpsz);
275 		if (copyout(rt_dptbl, rtadmin.rt_dpents, userdpsz))
276 			return (EFAULT);
277 		rtadmin.rt_ndpents = userdpsz / sizeof (rtdpent_t);
278 
279 		if (get_udatamodel() == DATAMODEL_NATIVE) {
280 			if (copyout(&rtadmin, uaddr, sizeof (rtadmin_t)))
281 				return (EFAULT);
282 		}
283 #ifdef _SYSCALL32_IMPL
284 		else {
285 			/* return rtadmin struct to ILP32 callers */
286 			rtadmin32_t rtadmin32;
287 			rtadmin32.rt_dpents =
288 			    (caddr32_t)(uintptr_t)rtadmin.rt_dpents;
289 			rtadmin32.rt_ndpents = rtadmin.rt_ndpents;
290 			rtadmin32.rt_cmd = rtadmin.rt_cmd;
291 			if (copyout(&rtadmin32, uaddr, sizeof (rtadmin32_t)))
292 				return (EFAULT);
293 		}
294 #endif /* _SYSCALL32_IMPL */
295 		break;
296 
297 	case RT_SETDPTBL:
298 		/*
299 		 * We require that the requesting process has sufficient
300 		 * priveleges.  We also require that the table supplied by
301 		 * the user exactly match the current rt_dptbl in size.
302 		 */
303 		if (secpolicy_dispadm(reqpcredp) != 0)
304 			return (EPERM);
305 		if (rtadmin.rt_ndpents * sizeof (rtdpent_t) != rtdpsz)
306 			return (EINVAL);
307 
308 		/*
309 		 * We read the user supplied table into a temporary buffer
310 		 * where the time quantum values are validated before
311 		 * being copied to the rt_dptbl.
312 		 */
313 		tmpdpp = kmem_alloc(rtdpsz, KM_SLEEP);
314 		if (copyin(rtadmin.rt_dpents, tmpdpp, rtdpsz)) {
315 			kmem_free(tmpdpp, rtdpsz);
316 			return (EFAULT);
317 		}
318 		for (i = 0; i < rtadmin.rt_ndpents; i++) {
319 
320 			/*
321 			 * Validate the user supplied time quantum values.
322 			 */
323 			if (tmpdpp[i].rt_quantum <= 0 &&
324 			    tmpdpp[i].rt_quantum != RT_TQINF) {
325 				kmem_free(tmpdpp, rtdpsz);
326 				return (EINVAL);
327 			}
328 		}
329 
330 		/*
331 		 * Copy the user supplied values over the current rt_dptbl
332 		 * values.  The rt_globpri member is read-only so we don't
333 		 * overwrite it.
334 		 */
335 		mutex_enter(&rt_dptblock);
336 		for (i = 0; i < rtadmin.rt_ndpents; i++)
337 			rt_dptbl[i].rt_quantum = tmpdpp[i].rt_quantum;
338 		mutex_exit(&rt_dptblock);
339 		kmem_free(tmpdpp, rtdpsz);
340 		break;
341 
342 	default:
343 		return (EINVAL);
344 	}
345 	return (0);
346 }
347 
348 
349 /*
350  * Allocate a real-time class specific proc structure and
351  * initialize it with the parameters supplied. Also move thread
352  * to specified real-time priority.
353  */
354 /* ARGSUSED */
355 static int
356 rt_enterclass(kthread_t *t, id_t cid, void *parmsp, cred_t *reqpcredp,
357     void *bufp)
358 {
359 	rtkparms_t *rtkparmsp = (rtkparms_t *)parmsp;
360 	rtproc_t *rtpp;
361 
362 	/*
363 	 * For a thread to enter the real-time class the thread
364 	 * which initiates the request must be privileged.
365 	 * This may have been checked previously but if our
366 	 * caller passed us a credential structure we assume it
367 	 * hasn't and we check it here.
368 	 */
369 	if (reqpcredp != NULL && secpolicy_setpriority(reqpcredp) != 0)
370 		return (EPERM);
371 
372 	rtpp = (rtproc_t *)bufp;
373 	ASSERT(rtpp != NULL);
374 
375 	/*
376 	 * If this thread's lwp is swapped out, it will be brought in
377 	 * when it is put onto the runqueue.
378 	 *
379 	 * Now, Initialize the rtproc structure.
380 	 */
381 	if (rtkparmsp == NULL) {
382 		/*
383 		 * Use default values
384 		 */
385 		rtpp->rt_pri = 0;
386 		rtpp->rt_pquantum = rt_dptbl[0].rt_quantum;
387 		rtpp->rt_tqsignal = 0;
388 	} else {
389 		/*
390 		 * Use supplied values
391 		 */
392 		if ((rtkparmsp->rt_cflags & RT_DOPRI) == 0)
393 			rtpp->rt_pri = 0;
394 		else
395 			rtpp->rt_pri = rtkparmsp->rt_pri;
396 
397 		if (rtkparmsp->rt_tqntm == RT_TQINF)
398 			rtpp->rt_pquantum = RT_TQINF;
399 		else if (rtkparmsp->rt_tqntm == RT_TQDEF ||
400 		    (rtkparmsp->rt_cflags & RT_DOTQ) == 0)
401 			rtpp->rt_pquantum = rt_dptbl[rtpp->rt_pri].rt_quantum;
402 		else
403 			rtpp->rt_pquantum = rtkparmsp->rt_tqntm;
404 
405 		if ((rtkparmsp->rt_cflags & RT_DOSIG) == 0)
406 			rtpp->rt_tqsignal = 0;
407 		else
408 			rtpp->rt_tqsignal = rtkparmsp->rt_tqsig;
409 	}
410 	rtpp->rt_flags = 0;
411 	rtpp->rt_tp = t;
412 	/*
413 	 * Reset thread priority
414 	 */
415 	thread_lock(t);
416 	t->t_clfuncs = &(sclass[cid].cl_funcs->thread);
417 	t->t_cid = cid;
418 	t->t_cldata = (void *)rtpp;
419 	t->t_schedflag &= ~TS_RUNQMATCH;
420 	rt_change_priority(t, rtpp);
421 	thread_unlock(t);
422 	/*
423 	 * Link new structure into rtproc list
424 	 */
425 	mutex_enter(&rt_list_lock);
426 	rtpp->rt_next = rt_plisthead.rt_next;
427 	rtpp->rt_prev = &rt_plisthead;
428 	rt_plisthead.rt_next->rt_prev = rtpp;
429 	rt_plisthead.rt_next = rtpp;
430 	mutex_exit(&rt_list_lock);
431 	return (0);
432 }
433 
434 
435 /*
436  * Free rtproc structure of thread.
437  */
438 static void
439 rt_exitclass(void *procp)
440 {
441 	rtproc_t *rtprocp = (rtproc_t *)procp;
442 
443 	mutex_enter(&rt_list_lock);
444 	rtprocp->rt_prev->rt_next = rtprocp->rt_next;
445 	rtprocp->rt_next->rt_prev = rtprocp->rt_prev;
446 	mutex_exit(&rt_list_lock);
447 	kmem_free(rtprocp, sizeof (rtproc_t));
448 }
449 
450 
451 /*
452  * Allocate and initialize real-time class specific
453  * proc structure for child.
454  */
455 /* ARGSUSED */
456 static int
457 rt_fork(kthread_t *t, kthread_t *ct, void *bufp)
458 {
459 	rtproc_t *prtpp;
460 	rtproc_t *crtpp;
461 
462 	ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
463 
464 	/*
465 	 * Initialize child's rtproc structure
466 	 */
467 	crtpp = (rtproc_t *)bufp;
468 	ASSERT(crtpp != NULL);
469 	prtpp = (rtproc_t *)t->t_cldata;
470 	thread_lock(t);
471 	crtpp->rt_timeleft = crtpp->rt_pquantum = prtpp->rt_pquantum;
472 	crtpp->rt_pri = prtpp->rt_pri;
473 	crtpp->rt_flags = prtpp->rt_flags & ~RTBACKQ;
474 	crtpp->rt_tqsignal = prtpp->rt_tqsignal;
475 
476 	crtpp->rt_tp = ct;
477 	thread_unlock(t);
478 
479 	/*
480 	 * Link new structure into rtproc list
481 	 */
482 	ct->t_cldata = (void *)crtpp;
483 	mutex_enter(&rt_list_lock);
484 	crtpp->rt_next = rt_plisthead.rt_next;
485 	crtpp->rt_prev = &rt_plisthead;
486 	rt_plisthead.rt_next->rt_prev = crtpp;
487 	rt_plisthead.rt_next = crtpp;
488 	mutex_exit(&rt_list_lock);
489 	return (0);
490 }
491 
492 
493 /*
494  * The child goes to the back of its dispatcher queue while the
495  * parent continues to run after a real time thread forks.
496  */
497 /* ARGSUSED */
498 static void
499 rt_forkret(kthread_t *t, kthread_t *ct)
500 {
501 	proc_t *pp = ttoproc(t);
502 	proc_t *cp = ttoproc(ct);
503 
504 	ASSERT(t == curthread);
505 	ASSERT(MUTEX_HELD(&pidlock));
506 
507 	/*
508 	 * Grab the child's p_lock before dropping pidlock to ensure
509 	 * the process does not disappear before we set it running.
510 	 */
511 	mutex_enter(&cp->p_lock);
512 	mutex_exit(&pidlock);
513 	continuelwps(cp);
514 	mutex_exit(&cp->p_lock);
515 
516 	mutex_enter(&pp->p_lock);
517 	continuelwps(pp);
518 	mutex_exit(&pp->p_lock);
519 }
520 
521 
522 /*
523  * Get information about the real-time class into the buffer
524  * pointed to by rtinfop.  The maximum configured real-time
525  * priority is the only information we supply.  We ignore the
526  * class and credential arguments because anyone can have this
527  * information.
528  */
529 /* ARGSUSED */
530 static int
531 rt_getclinfo(void *infop)
532 {
533 	rtinfo_t *rtinfop = (rtinfo_t *)infop;
534 	rtinfop->rt_maxpri = rt_maxpri;
535 	return (0);
536 }
537 
538 /*
539  * Return the user mode scheduling priority range.
540  */
541 static int
542 rt_getclpri(pcpri_t *pcprip)
543 {
544 	pcprip->pc_clpmax = rt_maxpri;
545 	pcprip->pc_clpmin = 0;
546 	return (0);
547 }
548 
549 static void
550 rt_nullsys()
551 {
552 }
553 
554 /* ARGSUSED */
555 static int
556 rt_canexit(kthread_t *t, cred_t *cred)
557 {
558 	/*
559 	 * Thread can always leave RT class
560 	 */
561 	return (0);
562 }
563 
564 /*
565  * Get the real-time scheduling parameters of the thread pointed to by
566  * rtprocp into the buffer pointed to by rtkparmsp.
567  */
568 static void
569 rt_parmsget(kthread_t *t, void *parmsp)
570 {
571 	rtproc_t	*rtprocp = (rtproc_t *)t->t_cldata;
572 	rtkparms_t	*rtkparmsp = (rtkparms_t *)parmsp;
573 
574 	rtkparmsp->rt_pri = rtprocp->rt_pri;
575 	rtkparmsp->rt_tqntm = rtprocp->rt_pquantum;
576 	rtkparmsp->rt_tqsig = rtprocp->rt_tqsignal;
577 }
578 
579 
580 
581 /*
582  * Check the validity of the real-time parameters in the buffer
583  * pointed to by rtprmsp.
584  * We convert the rtparms buffer from the user supplied format to
585  * our internal format (i.e. time quantum expressed in ticks).
586  */
587 static int
588 rt_parmsin(void *prmsp)
589 {
590 	rtparms_t *rtprmsp = (rtparms_t *)prmsp;
591 	longlong_t	ticks;
592 	uint_t		cflags;
593 
594 	/*
595 	 * First check the validity of parameters and convert
596 	 * the buffer to kernel format.
597 	 */
598 	if ((rtprmsp->rt_pri < 0 || rtprmsp->rt_pri > rt_maxpri) &&
599 	    rtprmsp->rt_pri != RT_NOCHANGE)
600 		return (EINVAL);
601 
602 	cflags = (rtprmsp->rt_pri != RT_NOCHANGE ? RT_DOPRI : 0);
603 
604 	if ((rtprmsp->rt_tqsecs == 0 && rtprmsp->rt_tqnsecs == 0) ||
605 	    rtprmsp->rt_tqnsecs >= NANOSEC)
606 		return (EINVAL);
607 
608 	if (rtprmsp->rt_tqnsecs != RT_NOCHANGE)
609 		cflags |= RT_DOTQ;
610 
611 	if (rtprmsp->rt_tqnsecs >= 0) {
612 		if ((ticks = SEC_TO_TICK((longlong_t)rtprmsp->rt_tqsecs) +
613 		    NSEC_TO_TICK_ROUNDUP(rtprmsp->rt_tqnsecs)) > INT_MAX)
614 			return (ERANGE);
615 
616 		((rtkparms_t *)rtprmsp)->rt_tqntm = (int)ticks;
617 	} else {
618 		if (rtprmsp->rt_tqnsecs != RT_NOCHANGE &&
619 		    rtprmsp->rt_tqnsecs != RT_TQINF &&
620 		    rtprmsp->rt_tqnsecs != RT_TQDEF)
621 			return (EINVAL);
622 
623 		((rtkparms_t *)rtprmsp)->rt_tqntm = rtprmsp->rt_tqnsecs;
624 	}
625 	((rtkparms_t *)rtprmsp)->rt_cflags = cflags;
626 
627 	return (0);
628 }
629 
630 
631 /*
632  * Check the validity of the real-time parameters in the pc_vaparms_t
633  * structure vaparmsp and put them in the buffer pointed to by rtprmsp.
634  * pc_vaparms_t contains (key, value) pairs of parameter.
635  * rt_vaparmsin() is the variable parameter version of rt_parmsin().
636  */
637 static int
638 rt_vaparmsin(void *prmsp, pc_vaparms_t *vaparmsp)
639 {
640 	uint_t		secs = 0;
641 	uint_t		cnt;
642 	int		nsecs = 0;
643 	int		priflag, secflag, nsecflag, sigflag;
644 	longlong_t	ticks;
645 	rtkparms_t	*rtprmsp = (rtkparms_t *)prmsp;
646 	pc_vaparm_t	*vpp = &vaparmsp->pc_parms[0];
647 
648 
649 	/*
650 	 * First check the validity of parameters and convert them
651 	 * from the user supplied format to the internal format.
652 	 */
653 	priflag = secflag = nsecflag = sigflag = 0;
654 	rtprmsp->rt_cflags = 0;
655 
656 	if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT)
657 		return (EINVAL);
658 
659 	for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) {
660 
661 		switch (vpp->pc_key) {
662 		case RT_KY_PRI:
663 			if (priflag++)
664 				return (EINVAL);
665 			rtprmsp->rt_cflags |= RT_DOPRI;
666 			rtprmsp->rt_pri = (pri_t)vpp->pc_parm;
667 			if (rtprmsp->rt_pri < 0 || rtprmsp->rt_pri > rt_maxpri)
668 				return (EINVAL);
669 			break;
670 
671 		case RT_KY_TQSECS:
672 			if (secflag++)
673 				return (EINVAL);
674 			rtprmsp->rt_cflags |= RT_DOTQ;
675 			secs = (uint_t)vpp->pc_parm;
676 			break;
677 
678 		case RT_KY_TQNSECS:
679 			if (nsecflag++)
680 				return (EINVAL);
681 			rtprmsp->rt_cflags |= RT_DOTQ;
682 			nsecs = (int)vpp->pc_parm;
683 			break;
684 
685 		case RT_KY_TQSIG:
686 			if (sigflag++)
687 				return (EINVAL);
688 			rtprmsp->rt_cflags |= RT_DOSIG;
689 			rtprmsp->rt_tqsig = (int)vpp->pc_parm;
690 			if (rtprmsp->rt_tqsig < 0 || rtprmsp->rt_tqsig >= NSIG)
691 				return (EINVAL);
692 			break;
693 
694 		default:
695 			return (EINVAL);
696 		}
697 	}
698 
699 	if (vaparmsp->pc_vaparmscnt == 0) {
700 		/*
701 		 * Use default parameters.
702 		 */
703 		rtprmsp->rt_pri = 0;
704 		rtprmsp->rt_tqntm = RT_TQDEF;
705 		rtprmsp->rt_tqsig = 0;
706 		rtprmsp->rt_cflags = RT_DOPRI | RT_DOTQ | RT_DOSIG;
707 	} else if ((rtprmsp->rt_cflags & RT_DOTQ) != 0) {
708 		if ((secs == 0 && nsecs == 0) || nsecs >= NANOSEC)
709 			return (EINVAL);
710 
711 		if (nsecs >= 0) {
712 			if ((ticks = SEC_TO_TICK((longlong_t)secs) +
713 			    NSEC_TO_TICK_ROUNDUP(nsecs)) > INT_MAX)
714 				return (ERANGE);
715 
716 			rtprmsp->rt_tqntm = (int)ticks;
717 		} else {
718 			if (nsecs != RT_TQINF && nsecs != RT_TQDEF)
719 				return (EINVAL);
720 			rtprmsp->rt_tqntm = nsecs;
721 		}
722 	}
723 
724 	return (0);
725 }
726 
727 /*
728  * Do required processing on the real-time parameter buffer
729  * before it is copied out to the user.
730  * All we have to do is convert the buffer from kernel to user format
731  * (i.e. convert time quantum from ticks to seconds-nanoseconds).
732  */
733 /* ARGSUSED */
734 static int
735 rt_parmsout(void *prmsp, pc_vaparms_t *vaparmsp)
736 {
737 	rtkparms_t	*rtkprmsp = (rtkparms_t *)prmsp;
738 
739 	if (vaparmsp != NULL)
740 		return (0);
741 
742 	if (rtkprmsp->rt_tqntm < 0) {
743 		/*
744 		 * Quantum field set to special value (e.g. RT_TQINF)
745 		 */
746 		((rtparms_t *)rtkprmsp)->rt_tqnsecs = rtkprmsp->rt_tqntm;
747 		((rtparms_t *)rtkprmsp)->rt_tqsecs = 0;
748 	} else {
749 		/* Convert quantum from ticks to seconds-nanoseconds */
750 
751 		timestruc_t ts;
752 		TICK_TO_TIMESTRUC(rtkprmsp->rt_tqntm, &ts);
753 		((rtparms_t *)rtkprmsp)->rt_tqsecs = ts.tv_sec;
754 		((rtparms_t *)rtkprmsp)->rt_tqnsecs = ts.tv_nsec;
755 	}
756 
757 	return (0);
758 }
759 
760 
761 /*
762  * Copy all selected real-time class parameters to the user.
763  * The parameters are specified by a key.
764  */
765 static int
766 rt_vaparmsout(void *prmsp, pc_vaparms_t *vaparmsp)
767 {
768 	rtkparms_t	*rtkprmsp = (rtkparms_t *)prmsp;
769 	timestruc_t	ts;
770 	uint_t		cnt;
771 	uint_t		secs;
772 	int		nsecs;
773 	int		priflag, secflag, nsecflag, sigflag;
774 	pc_vaparm_t	*vpp = &vaparmsp->pc_parms[0];
775 
776 	ASSERT(MUTEX_NOT_HELD(&curproc->p_lock));
777 
778 	priflag = secflag = nsecflag = sigflag = 0;
779 
780 	if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT)
781 		return (EINVAL);
782 
783 	if (rtkprmsp->rt_tqntm < 0) {
784 		/*
785 		 * Quantum field set to special value (e.g. RT_TQINF).
786 		 */
787 		secs = 0;
788 		nsecs = rtkprmsp->rt_tqntm;
789 	} else {
790 		/*
791 		 * Convert quantum from ticks to seconds-nanoseconds.
792 		 */
793 		TICK_TO_TIMESTRUC(rtkprmsp->rt_tqntm, &ts);
794 		secs = ts.tv_sec;
795 		nsecs = ts.tv_nsec;
796 	}
797 
798 
799 	for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) {
800 
801 		switch (vpp->pc_key) {
802 		case RT_KY_PRI:
803 			if (priflag++)
804 				return (EINVAL);
805 			if (copyout(&rtkprmsp->rt_pri,
806 			    (caddr_t)(uintptr_t)vpp->pc_parm, sizeof (pri_t)))
807 				return (EFAULT);
808 			break;
809 
810 		case RT_KY_TQSECS:
811 			if (secflag++)
812 				return (EINVAL);
813 			if (copyout(&secs, (caddr_t)(uintptr_t)vpp->pc_parm,
814 			    sizeof (uint_t)))
815 				return (EFAULT);
816 			break;
817 
818 		case RT_KY_TQNSECS:
819 			if (nsecflag++)
820 				return (EINVAL);
821 			if (copyout(&nsecs, (caddr_t)(uintptr_t)vpp->pc_parm,
822 			    sizeof (int)))
823 				return (EFAULT);
824 			break;
825 
826 		case RT_KY_TQSIG:
827 			if (sigflag++)
828 				return (EINVAL);
829 			if (copyout(&rtkprmsp->rt_tqsig,
830 			    (caddr_t)(uintptr_t)vpp->pc_parm, sizeof (int)))
831 				return (EFAULT);
832 			break;
833 
834 		default:
835 			return (EINVAL);
836 		}
837 	}
838 
839 	return (0);
840 }
841 
842 
843 /*
844  * Set the scheduling parameters of the thread pointed to by rtprocp
845  * to those specified in the buffer pointed to by rtkprmsp.
846  * Note that the parameters are expected to be in kernel format
847  * (i.e. time quantm expressed in ticks).  Real time parameters copied
848  * in from the user should be processed by rt_parmsin() before they are
849  * passed to this function.
850  */
851 static int
852 rt_parmsset(kthread_t *tx, void *prmsp, id_t reqpcid, cred_t *reqpcredp)
853 {
854 	rtkparms_t *rtkprmsp = (rtkparms_t *)prmsp;
855 	rtproc_t *rtpp = (rtproc_t *)tx->t_cldata;
856 
857 	ASSERT(MUTEX_HELD(&(ttoproc(tx))->p_lock));
858 
859 	/*
860 	 * Basic permissions enforced by generic kernel code
861 	 * for all classes require that a thread attempting
862 	 * to change the scheduling parameters of a target thread
863 	 * be privileged or have a real or effective UID
864 	 * matching that of the target thread. We are not
865 	 * called unless these basic permission checks have
866 	 * already passed. The real-time class requires in addition
867 	 * that the requesting thread be real-time unless it is privileged.
868 	 * This may also have been checked previously but if our caller
869 	 * passes us a credential structure we assume it hasn't and
870 	 * we check it here.
871 	 */
872 	if (reqpcredp != NULL && reqpcid != rt_cid &&
873 	    secpolicy_setpriority(reqpcredp) != 0)
874 		return (EPERM);
875 
876 	thread_lock(tx);
877 	if ((rtkprmsp->rt_cflags & RT_DOPRI) != 0) {
878 		rtpp->rt_pri = rtkprmsp->rt_pri;
879 		rt_change_priority(tx, rtpp);
880 	}
881 	if (rtkprmsp->rt_tqntm == RT_TQINF)
882 		rtpp->rt_pquantum = RT_TQINF;
883 	else if (rtkprmsp->rt_tqntm == RT_TQDEF)
884 		rtpp->rt_timeleft = rtpp->rt_pquantum =
885 		    rt_dptbl[rtpp->rt_pri].rt_quantum;
886 	else if ((rtkprmsp->rt_cflags & RT_DOTQ) != 0)
887 		rtpp->rt_timeleft = rtpp->rt_pquantum = rtkprmsp->rt_tqntm;
888 
889 	if ((rtkprmsp->rt_cflags & RT_DOSIG) != 0)
890 		rtpp->rt_tqsignal = rtkprmsp->rt_tqsig;
891 
892 	thread_unlock(tx);
893 	return (0);
894 }
895 
896 
897 /*
898  * Arrange for thread to be placed in appropriate location
899  * on dispatcher queue.  Runs at splhi() since the clock
900  * interrupt can cause RTBACKQ to be set.
901  */
902 static void
903 rt_preempt(kthread_t *t)
904 {
905 	rtproc_t *rtpp = (rtproc_t *)(t->t_cldata);
906 	klwp_t *lwp;
907 
908 	ASSERT(THREAD_LOCK_HELD(t));
909 
910 	/*
911 	 * If the state is user I allow swapping because I know I won't
912 	 * be holding any locks.
913 	 */
914 	if ((lwp = curthread->t_lwp) != NULL && lwp->lwp_state == LWP_USER)
915 		t->t_schedflag &= ~TS_DONT_SWAP;
916 	if ((rtpp->rt_flags & RTBACKQ) != 0) {
917 		rtpp->rt_timeleft = rtpp->rt_pquantum;
918 		rtpp->rt_flags &= ~RTBACKQ;
919 		setbackdq(t);
920 	} else
921 		setfrontdq(t);
922 
923 }
924 
925 /*
926  * Return the global priority associated with this rt_pri.
927  */
928 static pri_t
929 rt_globpri(kthread_t *t)
930 {
931 	rtproc_t *rtprocp = (rtproc_t *)t->t_cldata;
932 	return (rt_dptbl[rtprocp->rt_pri].rt_globpri);
933 }
934 
935 static void
936 rt_setrun(kthread_t *t)
937 {
938 	rtproc_t *rtpp = (rtproc_t *)(t->t_cldata);
939 
940 	ASSERT(THREAD_LOCK_HELD(t));
941 
942 	rtpp->rt_timeleft = rtpp->rt_pquantum;
943 	rtpp->rt_flags &= ~RTBACKQ;
944 	setbackdq(t);
945 }
946 
947 /*
948  * Returns the priority of the thread, -1 if the thread is loaded or ineligible
949  * for swapin.
950  *
951  * FX and RT threads are designed so that they don't swapout; however, it
952  * is possible that while the thread is swapped out and in another class, it
953  * can be changed to FX or RT.  Since these threads should be swapped in as
954  * soon as they're runnable, rt_swapin returns SHRT_MAX, and fx_swapin
955  * returns SHRT_MAX - 1, so that it gives deference to any swapped out RT
956  * threads.
957  */
958 /* ARGSUSED */
959 static pri_t
960 rt_swapin(kthread_t *t, int flags)
961 {
962 	pri_t	tpri = -1;
963 
964 	ASSERT(THREAD_LOCK_HELD(t));
965 
966 	if (t->t_state == TS_RUN && (t->t_schedflag & TS_LOAD) == 0) {
967 		tpri = (pri_t)SHRT_MAX;
968 	}
969 
970 	return (tpri);
971 }
972 
973 /*
974  * Return an effective priority for swapout.
975  */
976 /* ARGSUSED */
977 static pri_t
978 rt_swapout(kthread_t *t, int flags)
979 {
980 	ASSERT(THREAD_LOCK_HELD(t));
981 
982 	return (-1);
983 }
984 
985 /*
986  * Check for time slice expiration (unless thread has infinite time
987  * slice).  If time slice has expired arrange for thread to be preempted
988  * and placed on back of queue.
989  */
990 static void
991 rt_tick(kthread_t *t)
992 {
993 	rtproc_t *rtpp = (rtproc_t *)(t->t_cldata);
994 
995 	ASSERT(MUTEX_HELD(&(ttoproc(t))->p_lock));
996 
997 	thread_lock(t);
998 	if ((rtpp->rt_pquantum != RT_TQINF && --rtpp->rt_timeleft == 0) ||
999 	    (t->t_state == TS_ONPROC && DISP_MUST_SURRENDER(t))) {
1000 		if (rtpp->rt_timeleft == 0 && rtpp->rt_tqsignal) {
1001 			thread_unlock(t);
1002 			sigtoproc(ttoproc(t), t, rtpp->rt_tqsignal);
1003 			thread_lock(t);
1004 		}
1005 		rtpp->rt_flags |= RTBACKQ;
1006 		cpu_surrender(t);
1007 	}
1008 	thread_unlock(t);
1009 }
1010 
1011 
1012 /*
1013  * Place the thread waking up on the dispatcher queue.
1014  */
1015 static void
1016 rt_wakeup(kthread_t *t)
1017 {
1018 	rtproc_t *rtpp = (rtproc_t *)(t->t_cldata);
1019 
1020 	ASSERT(THREAD_LOCK_HELD(t));
1021 
1022 	rtpp->rt_timeleft = rtpp->rt_pquantum;
1023 	rtpp->rt_flags &= ~RTBACKQ;
1024 	setbackdq(t);
1025 }
1026 
1027 static void
1028 rt_yield(kthread_t *t)
1029 {
1030 	rtproc_t *rtpp = (rtproc_t *)(t->t_cldata);
1031 
1032 	ASSERT(t == curthread);
1033 	ASSERT(THREAD_LOCK_HELD(t));
1034 
1035 	rtpp->rt_flags &= ~RTBACKQ;
1036 	setbackdq(t);
1037 }
1038 
1039 /* ARGSUSED */
1040 static int
1041 rt_donice(kthread_t *t, cred_t *cr, int incr, int *retvalp)
1042 {
1043 	return (EINVAL);
1044 }
1045 
1046 /*
1047  * Increment the priority of the specified thread by incr and
1048  * return the new value in *retvalp.
1049  */
1050 static int
1051 rt_doprio(kthread_t *t, cred_t *cr, int incr, int *retvalp)
1052 {
1053 	int newpri;
1054 	rtproc_t *rtpp = (rtproc_t *)(t->t_cldata);
1055 	rtkparms_t rtkparms;
1056 
1057 	/* If there's no change to the priority, just return current setting */
1058 	if (incr == 0) {
1059 		*retvalp = rtpp->rt_pri;
1060 		return (0);
1061 	}
1062 
1063 	newpri = rtpp->rt_pri + incr;
1064 	if (newpri > rt_maxpri || newpri < 0)
1065 		return (EINVAL);
1066 
1067 	*retvalp = newpri;
1068 	rtkparms.rt_pri = newpri;
1069 	rtkparms.rt_tqntm = RT_NOCHANGE;
1070 	rtkparms.rt_tqsig = 0;
1071 	rtkparms.rt_cflags = RT_DOPRI;
1072 	return (rt_parmsset(t, &rtkparms, rt_cid, cr));
1073 }
1074 
1075 static int
1076 rt_alloc(void **p, int flag)
1077 {
1078 	void *bufp;
1079 	bufp = kmem_alloc(sizeof (rtproc_t), flag);
1080 	if (bufp == NULL) {
1081 		return (ENOMEM);
1082 	} else {
1083 		*p = bufp;
1084 		return (0);
1085 	}
1086 }
1087 
1088 static void
1089 rt_free(void *bufp)
1090 {
1091 	if (bufp)
1092 		kmem_free(bufp, sizeof (rtproc_t));
1093 }
1094 
1095 static void
1096 rt_change_priority(kthread_t *t, rtproc_t *rtpp)
1097 {
1098 	pri_t new_pri;
1099 
1100 	ASSERT(THREAD_LOCK_HELD(t));
1101 
1102 	new_pri = rt_dptbl[rtpp->rt_pri].rt_globpri;
1103 
1104 	t->t_cpri = rtpp->rt_pri;
1105 	if (t == curthread || t->t_state == TS_ONPROC) {
1106 		cpu_t	*cp = t->t_disp_queue->disp_cpu;
1107 		THREAD_CHANGE_PRI(t, new_pri);
1108 		if (t == cp->cpu_dispthread)
1109 			cp->cpu_dispatch_pri = DISP_PRIO(t);
1110 		if (DISP_MUST_SURRENDER(t)) {
1111 			rtpp->rt_flags |= RTBACKQ;
1112 			cpu_surrender(t);
1113 		} else {
1114 			rtpp->rt_timeleft = rtpp->rt_pquantum;
1115 		}
1116 	} else {
1117 		/*
1118 		 * When the priority of a thread is changed,
1119 		 * it may be necessary to adjust its position
1120 		 * on a sleep queue or dispatch queue.  The
1121 		 * function thread_change_pri() accomplishes this.
1122 		 */
1123 		if (thread_change_pri(t, new_pri, 0)) {
1124 			/*
1125 			 * The thread was on a run queue.
1126 			 * Reset its CPU timeleft.
1127 			 */
1128 			rtpp->rt_timeleft = rtpp->rt_pquantum;
1129 		} else {
1130 			rtpp->rt_flags |= RTBACKQ;
1131 		}
1132 	}
1133 }
1134