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