Print this page
remove whole-process swapping
Long before Unix supported paging, it used process swapping to reclaim
memory. The code is there and in theory it runs when we get *extremely* low
on memory. In practice, it never runs since the definition of low-on-memory
is antiquated. (XXX: define what antiquated means)
You can check the number of swapout/swapin events with kstats:
$ kstat -p ::vm:swapin ::vm:swapout
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/disp/fx.c
+++ new/usr/src/uts/common/disp/fx.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2013, Joyent, Inc. All rights reserved.
25 25 */
26 26
27 27 #include <sys/types.h>
28 28 #include <sys/param.h>
29 29 #include <sys/sysmacros.h>
30 30 #include <sys/cred.h>
31 31 #include <sys/proc.h>
32 32 #include <sys/session.h>
33 33 #include <sys/strsubr.h>
34 34 #include <sys/user.h>
35 35 #include <sys/priocntl.h>
36 36 #include <sys/class.h>
37 37 #include <sys/disp.h>
38 38 #include <sys/procset.h>
39 39 #include <sys/debug.h>
40 40 #include <sys/kmem.h>
41 41 #include <sys/errno.h>
42 42 #include <sys/fx.h>
43 43 #include <sys/fxpriocntl.h>
44 44 #include <sys/cpuvar.h>
45 45 #include <sys/systm.h>
46 46 #include <sys/vtrace.h>
47 47 #include <sys/schedctl.h>
48 48 #include <sys/tnf_probe.h>
49 49 #include <sys/sunddi.h>
50 50 #include <sys/spl.h>
51 51 #include <sys/modctl.h>
52 52 #include <sys/policy.h>
53 53 #include <sys/sdt.h>
54 54 #include <sys/cpupart.h>
55 55 #include <sys/cpucaps.h>
56 56
57 57 static pri_t fx_init(id_t, int, classfuncs_t **);
58 58
59 59 static struct sclass csw = {
60 60 "FX",
61 61 fx_init,
62 62 0
63 63 };
64 64
65 65 static struct modlsched modlsched = {
66 66 &mod_schedops, "Fixed priority sched class", &csw
67 67 };
68 68
69 69 static struct modlinkage modlinkage = {
70 70 MODREV_1, (void *)&modlsched, NULL
71 71 };
72 72
73 73
74 74 /*
75 75 * control flags (kparms->fx_cflags).
76 76 */
77 77 #define FX_DOUPRILIM 0x01 /* change user priority limit */
78 78 #define FX_DOUPRI 0x02 /* change user priority */
79 79 #define FX_DOTQ 0x04 /* change FX time quantum */
80 80
81 81
82 82 #define FXMAXUPRI 60 /* maximum user priority setting */
83 83
84 84 #define FX_MAX_UNPRIV_PRI 0 /* maximum unpriviledge priority */
85 85
86 86 /*
87 87 * The fxproc_t structures that have a registered callback vector,
88 88 * are also kept in an array of circular doubly linked lists. A hash on
89 89 * the thread id (from ddi_get_kt_did()) is used to determine which list
90 90 * each of such fxproc structures should be placed. Each list has a dummy
91 91 * "head" which is never removed, so the list is never empty.
92 92 */
93 93
94 94 #define FX_CB_LISTS 16 /* number of lists, must be power of 2 */
95 95 #define FX_CB_LIST_HASH(ktid) ((uint_t)ktid & (FX_CB_LISTS - 1))
96 96
97 97 /* Insert fxproc into callback list */
98 98 #define FX_CB_LIST_INSERT(fxpp) \
99 99 { \
100 100 int index = FX_CB_LIST_HASH(fxpp->fx_ktid); \
101 101 kmutex_t *lockp = &fx_cb_list_lock[index]; \
102 102 fxproc_t *headp = &fx_cb_plisthead[index]; \
103 103 mutex_enter(lockp); \
104 104 fxpp->fx_cb_next = headp->fx_cb_next; \
105 105 fxpp->fx_cb_prev = headp; \
106 106 headp->fx_cb_next->fx_cb_prev = fxpp; \
107 107 headp->fx_cb_next = fxpp; \
108 108 mutex_exit(lockp); \
109 109 }
110 110
111 111 /*
112 112 * Remove thread from callback list.
113 113 */
114 114 #define FX_CB_LIST_DELETE(fxpp) \
115 115 { \
116 116 int index = FX_CB_LIST_HASH(fxpp->fx_ktid); \
117 117 kmutex_t *lockp = &fx_cb_list_lock[index]; \
118 118 mutex_enter(lockp); \
119 119 fxpp->fx_cb_prev->fx_cb_next = fxpp->fx_cb_next; \
120 120 fxpp->fx_cb_next->fx_cb_prev = fxpp->fx_cb_prev; \
121 121 mutex_exit(lockp); \
122 122 }
123 123
124 124 #define FX_HAS_CB(fxpp) (fxpp->fx_callback != NULL)
125 125
126 126 /* adjust x to be between 0 and fx_maxumdpri */
127 127
128 128 #define FX_ADJUST_PRI(pri) \
129 129 { \
130 130 if (pri < 0) \
131 131 pri = 0; \
132 132 else if (pri > fx_maxumdpri) \
133 133 pri = fx_maxumdpri; \
134 134 }
135 135
136 136 #define FX_ADJUST_QUANTUM(q) \
137 137 { \
138 138 if (q > INT_MAX) \
139 139 q = INT_MAX; \
140 140 else if (q <= 0) \
141 141 q = FX_TQINF; \
142 142 }
143 143
144 144 #define FX_ISVALID(pri, quantum) \
145 145 (((pri >= 0) || (pri == FX_CB_NOCHANGE)) && \
146 146 ((quantum >= 0) || (quantum == FX_NOCHANGE) || \
147 147 (quantum == FX_TQDEF) || (quantum == FX_TQINF)))
148 148
149 149
150 150 static id_t fx_cid; /* fixed priority class ID */
151 151 static fxdpent_t *fx_dptbl; /* fixed priority disp parameter table */
152 152
153 153 static pri_t fx_maxupri = FXMAXUPRI;
154 154 static pri_t fx_maxumdpri; /* max user mode fixed priority */
155 155
156 156 static pri_t fx_maxglobpri; /* maximum global priority used by fx class */
157 157 static kmutex_t fx_dptblock; /* protects fixed priority dispatch table */
158 158
159 159
160 160 static kmutex_t fx_cb_list_lock[FX_CB_LISTS]; /* protects list of fxprocs */
161 161 /* that have callbacks */
162 162 static fxproc_t fx_cb_plisthead[FX_CB_LISTS]; /* dummy fxproc at head of */
163 163 /* list of fxprocs with */
164 164 /* callbacks */
165 165
166 166 static int fx_admin(caddr_t, cred_t *);
167 167 static int fx_getclinfo(void *);
168 168 static int fx_parmsin(void *);
169 169 static int fx_parmsout(void *, pc_vaparms_t *);
170 170 static int fx_vaparmsin(void *, pc_vaparms_t *);
171 171 static int fx_vaparmsout(void *, pc_vaparms_t *);
172 172 static int fx_getclpri(pcpri_t *);
173 173 static int fx_alloc(void **, int);
↓ open down ↓ |
173 lines elided |
↑ open up ↑ |
174 174 static void fx_free(void *);
175 175 static int fx_enterclass(kthread_t *, id_t, void *, cred_t *, void *);
176 176 static void fx_exitclass(void *);
177 177 static int fx_canexit(kthread_t *, cred_t *);
178 178 static int fx_fork(kthread_t *, kthread_t *, void *);
179 179 static void fx_forkret(kthread_t *, kthread_t *);
180 180 static void fx_parmsget(kthread_t *, void *);
181 181 static int fx_parmsset(kthread_t *, void *, id_t, cred_t *);
182 182 static void fx_stop(kthread_t *, int, int);
183 183 static void fx_exit(kthread_t *);
184 -static pri_t fx_swapin(kthread_t *, int);
185 -static pri_t fx_swapout(kthread_t *, int);
186 184 static void fx_trapret(kthread_t *);
187 185 static void fx_preempt(kthread_t *);
188 186 static void fx_setrun(kthread_t *);
189 187 static void fx_sleep(kthread_t *);
190 188 static void fx_tick(kthread_t *);
191 189 static void fx_wakeup(kthread_t *);
192 190 static int fx_donice(kthread_t *, cred_t *, int, int *);
193 191 static int fx_doprio(kthread_t *, cred_t *, int, int *);
194 192 static pri_t fx_globpri(kthread_t *);
195 193 static void fx_yield(kthread_t *);
196 194 static void fx_nullsys();
197 195
198 196 extern fxdpent_t *fx_getdptbl(void);
199 197
200 198 static void fx_change_priority(kthread_t *, fxproc_t *);
201 199 static fxproc_t *fx_list_lookup(kt_did_t);
202 200 static void fx_list_release(fxproc_t *);
203 201
204 202
205 203 static struct classfuncs fx_classfuncs = {
206 204 /* class functions */
207 205 fx_admin,
208 206 fx_getclinfo,
209 207 fx_parmsin,
210 208 fx_parmsout,
211 209 fx_vaparmsin,
212 210 fx_vaparmsout,
213 211 fx_getclpri,
214 212 fx_alloc,
215 213 fx_free,
216 214
217 215 /* thread functions */
218 216 fx_enterclass,
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
219 217 fx_exitclass,
220 218 fx_canexit,
221 219 fx_fork,
222 220 fx_forkret,
223 221 fx_parmsget,
224 222 fx_parmsset,
225 223 fx_stop,
226 224 fx_exit,
227 225 fx_nullsys, /* active */
228 226 fx_nullsys, /* inactive */
229 - fx_swapin,
230 - fx_swapout,
231 227 fx_trapret,
232 228 fx_preempt,
233 229 fx_setrun,
234 230 fx_sleep,
235 231 fx_tick,
236 232 fx_wakeup,
237 233 fx_donice,
238 234 fx_globpri,
239 235 fx_nullsys, /* set_process_group */
240 236 fx_yield,
241 237 fx_doprio,
242 238 };
243 239
244 240
245 241 int
246 242 _init()
247 243 {
248 244 return (mod_install(&modlinkage));
249 245 }
250 246
251 247 int
252 248 _fini()
253 249 {
254 250 return (EBUSY);
255 251 }
256 252
257 253 int
258 254 _info(struct modinfo *modinfop)
259 255 {
260 256 return (mod_info(&modlinkage, modinfop));
261 257 }
262 258
263 259 /*
264 260 * Fixed priority class initialization. Called by dispinit() at boot time.
265 261 * We can ignore the clparmsz argument since we know that the smallest
266 262 * possible parameter buffer is big enough for us.
267 263 */
268 264 /* ARGSUSED */
269 265 static pri_t
270 266 fx_init(id_t cid, int clparmsz, classfuncs_t **clfuncspp)
271 267 {
272 268 int i;
273 269 extern pri_t fx_getmaxumdpri(void);
274 270
275 271 fx_dptbl = fx_getdptbl();
276 272 fx_maxumdpri = fx_getmaxumdpri();
277 273 fx_maxglobpri = fx_dptbl[fx_maxumdpri].fx_globpri;
278 274
279 275 fx_cid = cid; /* Record our class ID */
280 276
281 277 /*
282 278 * Initialize the hash table for fxprocs with callbacks
283 279 */
284 280 for (i = 0; i < FX_CB_LISTS; i++) {
285 281 fx_cb_plisthead[i].fx_cb_next = fx_cb_plisthead[i].fx_cb_prev =
286 282 &fx_cb_plisthead[i];
287 283 }
288 284
289 285 /*
290 286 * We're required to return a pointer to our classfuncs
291 287 * structure and the highest global priority value we use.
292 288 */
293 289 *clfuncspp = &fx_classfuncs;
294 290 return (fx_maxglobpri);
295 291 }
296 292
297 293 /*
298 294 * Get or reset the fx_dptbl values per the user's request.
299 295 */
300 296 static int
301 297 fx_admin(caddr_t uaddr, cred_t *reqpcredp)
302 298 {
303 299 fxadmin_t fxadmin;
304 300 fxdpent_t *tmpdpp;
305 301 int userdpsz;
306 302 int i;
307 303 size_t fxdpsz;
308 304
309 305 if (get_udatamodel() == DATAMODEL_NATIVE) {
310 306 if (copyin(uaddr, &fxadmin, sizeof (fxadmin_t)))
311 307 return (EFAULT);
312 308 }
313 309 #ifdef _SYSCALL32_IMPL
314 310 else {
315 311 /* get fxadmin struct from ILP32 caller */
316 312 fxadmin32_t fxadmin32;
317 313 if (copyin(uaddr, &fxadmin32, sizeof (fxadmin32_t)))
318 314 return (EFAULT);
319 315 fxadmin.fx_dpents =
320 316 (struct fxdpent *)(uintptr_t)fxadmin32.fx_dpents;
321 317 fxadmin.fx_ndpents = fxadmin32.fx_ndpents;
322 318 fxadmin.fx_cmd = fxadmin32.fx_cmd;
323 319 }
324 320 #endif /* _SYSCALL32_IMPL */
325 321
326 322 fxdpsz = (fx_maxumdpri + 1) * sizeof (fxdpent_t);
327 323
328 324 switch (fxadmin.fx_cmd) {
329 325 case FX_GETDPSIZE:
330 326 fxadmin.fx_ndpents = fx_maxumdpri + 1;
331 327
332 328 if (get_udatamodel() == DATAMODEL_NATIVE) {
333 329 if (copyout(&fxadmin, uaddr, sizeof (fxadmin_t)))
334 330 return (EFAULT);
335 331 }
336 332 #ifdef _SYSCALL32_IMPL
337 333 else {
338 334 /* return fxadmin struct to ILP32 caller */
339 335 fxadmin32_t fxadmin32;
340 336 fxadmin32.fx_dpents =
341 337 (caddr32_t)(uintptr_t)fxadmin.fx_dpents;
342 338 fxadmin32.fx_ndpents = fxadmin.fx_ndpents;
343 339 fxadmin32.fx_cmd = fxadmin.fx_cmd;
344 340 if (copyout(&fxadmin32, uaddr, sizeof (fxadmin32_t)))
345 341 return (EFAULT);
346 342 }
347 343 #endif /* _SYSCALL32_IMPL */
348 344 break;
349 345
350 346 case FX_GETDPTBL:
351 347 userdpsz = MIN(fxadmin.fx_ndpents * sizeof (fxdpent_t),
352 348 fxdpsz);
353 349 if (copyout(fx_dptbl, fxadmin.fx_dpents, userdpsz))
354 350 return (EFAULT);
355 351
356 352 fxadmin.fx_ndpents = userdpsz / sizeof (fxdpent_t);
357 353
358 354 if (get_udatamodel() == DATAMODEL_NATIVE) {
359 355 if (copyout(&fxadmin, uaddr, sizeof (fxadmin_t)))
360 356 return (EFAULT);
361 357 }
362 358 #ifdef _SYSCALL32_IMPL
363 359 else {
364 360 /* return fxadmin struct to ILP32 callers */
365 361 fxadmin32_t fxadmin32;
366 362 fxadmin32.fx_dpents =
367 363 (caddr32_t)(uintptr_t)fxadmin.fx_dpents;
368 364 fxadmin32.fx_ndpents = fxadmin.fx_ndpents;
369 365 fxadmin32.fx_cmd = fxadmin.fx_cmd;
370 366 if (copyout(&fxadmin32, uaddr, sizeof (fxadmin32_t)))
371 367 return (EFAULT);
372 368 }
373 369 #endif /* _SYSCALL32_IMPL */
374 370 break;
375 371
376 372 case FX_SETDPTBL:
377 373 /*
378 374 * We require that the requesting process has sufficient
379 375 * privileges. We also require that the table supplied by
380 376 * the user exactly match the current fx_dptbl in size.
381 377 */
382 378 if (secpolicy_dispadm(reqpcredp) != 0) {
383 379 return (EPERM);
384 380 }
385 381 if (fxadmin.fx_ndpents * sizeof (fxdpent_t) != fxdpsz) {
386 382 return (EINVAL);
387 383 }
388 384
389 385 /*
390 386 * We read the user supplied table into a temporary buffer
391 387 * where it is validated before being copied over the
392 388 * fx_dptbl.
393 389 */
394 390 tmpdpp = kmem_alloc(fxdpsz, KM_SLEEP);
395 391 if (copyin(fxadmin.fx_dpents, tmpdpp, fxdpsz)) {
396 392 kmem_free(tmpdpp, fxdpsz);
397 393 return (EFAULT);
398 394 }
399 395 for (i = 0; i < fxadmin.fx_ndpents; i++) {
400 396
401 397 /*
402 398 * Validate the user supplied values. All we are doing
403 399 * here is verifying that the values are within their
404 400 * allowable ranges and will not panic the system. We
405 401 * make no attempt to ensure that the resulting
406 402 * configuration makes sense or results in reasonable
407 403 * performance.
408 404 */
409 405 if (tmpdpp[i].fx_quantum <= 0 &&
410 406 tmpdpp[i].fx_quantum != FX_TQINF) {
411 407 kmem_free(tmpdpp, fxdpsz);
412 408 return (EINVAL);
413 409 }
414 410 }
415 411
416 412 /*
417 413 * Copy the user supplied values over the current fx_dptbl
418 414 * values. The fx_globpri member is read-only so we don't
419 415 * overwrite it.
420 416 */
421 417 mutex_enter(&fx_dptblock);
422 418 for (i = 0; i < fxadmin.fx_ndpents; i++) {
423 419 fx_dptbl[i].fx_quantum = tmpdpp[i].fx_quantum;
424 420 }
425 421 mutex_exit(&fx_dptblock);
426 422 kmem_free(tmpdpp, fxdpsz);
427 423 break;
428 424
429 425 default:
430 426 return (EINVAL);
431 427 }
432 428 return (0);
433 429 }
434 430
435 431 /*
436 432 * Allocate a fixed priority class specific thread structure and
437 433 * initialize it with the parameters supplied. Also move the thread
438 434 * to specified priority.
439 435 */
440 436 static int
441 437 fx_enterclass(kthread_t *t, id_t cid, void *parmsp, cred_t *reqpcredp,
442 438 void *bufp)
443 439 {
444 440 fxkparms_t *fxkparmsp = (fxkparms_t *)parmsp;
445 441 fxproc_t *fxpp;
446 442 pri_t reqfxupri;
447 443 pri_t reqfxuprilim;
448 444
449 445 fxpp = (fxproc_t *)bufp;
450 446 ASSERT(fxpp != NULL);
451 447
452 448 /*
453 449 * Initialize the fxproc structure.
454 450 */
455 451 fxpp->fx_flags = 0;
456 452 fxpp->fx_callback = NULL;
457 453 fxpp->fx_cookie = NULL;
458 454
459 455 if (fxkparmsp == NULL) {
460 456 /*
461 457 * Use default values.
462 458 */
463 459 fxpp->fx_pri = fxpp->fx_uprilim = 0;
464 460 fxpp->fx_pquantum = fx_dptbl[fxpp->fx_pri].fx_quantum;
465 461 fxpp->fx_nice = NZERO;
466 462 } else {
467 463 /*
468 464 * Use supplied values.
469 465 */
470 466
471 467 if ((fxkparmsp->fx_cflags & FX_DOUPRILIM) == 0) {
472 468 reqfxuprilim = 0;
473 469 } else {
474 470 if (fxkparmsp->fx_uprilim > FX_MAX_UNPRIV_PRI &&
475 471 secpolicy_setpriority(reqpcredp) != 0)
476 472 return (EPERM);
477 473 reqfxuprilim = fxkparmsp->fx_uprilim;
478 474 FX_ADJUST_PRI(reqfxuprilim);
479 475 }
480 476
481 477 if ((fxkparmsp->fx_cflags & FX_DOUPRI) == 0) {
482 478 reqfxupri = reqfxuprilim;
483 479 } else {
484 480 if (fxkparmsp->fx_upri > FX_MAX_UNPRIV_PRI &&
485 481 secpolicy_setpriority(reqpcredp) != 0)
486 482 return (EPERM);
487 483 /*
488 484 * Set the user priority to the requested value
489 485 * or the upri limit, whichever is lower.
490 486 */
491 487 reqfxupri = fxkparmsp->fx_upri;
492 488 FX_ADJUST_PRI(reqfxupri);
493 489
494 490 if (reqfxupri > reqfxuprilim)
495 491 reqfxupri = reqfxuprilim;
496 492 }
497 493
498 494
499 495 fxpp->fx_uprilim = reqfxuprilim;
500 496 fxpp->fx_pri = reqfxupri;
501 497
502 498 fxpp->fx_nice = NZERO - (NZERO * reqfxupri) / fx_maxupri;
503 499
504 500 if (((fxkparmsp->fx_cflags & FX_DOTQ) == 0) ||
505 501 (fxkparmsp->fx_tqntm == FX_TQDEF)) {
506 502 fxpp->fx_pquantum = fx_dptbl[fxpp->fx_pri].fx_quantum;
507 503 } else {
508 504 if (secpolicy_setpriority(reqpcredp) != 0)
509 505 return (EPERM);
510 506
511 507 if (fxkparmsp->fx_tqntm == FX_TQINF)
512 508 fxpp->fx_pquantum = FX_TQINF;
513 509 else {
514 510 fxpp->fx_pquantum = fxkparmsp->fx_tqntm;
515 511 }
516 512 }
517 513
518 514 }
519 515
520 516 fxpp->fx_timeleft = fxpp->fx_pquantum;
521 517 cpucaps_sc_init(&fxpp->fx_caps);
522 518 fxpp->fx_tp = t;
523 519
524 520 thread_lock(t); /* get dispatcher lock on thread */
525 521 t->t_clfuncs = &(sclass[cid].cl_funcs->thread);
526 522 t->t_cid = cid;
527 523 t->t_cldata = (void *)fxpp;
528 524 t->t_schedflag &= ~TS_RUNQMATCH;
529 525 fx_change_priority(t, fxpp);
530 526 thread_unlock(t);
531 527
532 528 return (0);
533 529 }
534 530
535 531 /*
536 532 * The thread is exiting.
537 533 */
538 534 static void
539 535 fx_exit(kthread_t *t)
540 536 {
541 537 fxproc_t *fxpp;
542 538
543 539 thread_lock(t);
544 540 fxpp = (fxproc_t *)(t->t_cldata);
545 541
546 542 /*
547 543 * A thread could be exiting in between clock ticks, so we need to
548 544 * calculate how much CPU time it used since it was charged last time.
549 545 *
550 546 * CPU caps are not enforced on exiting processes - it is usually
551 547 * desirable to exit as soon as possible to free resources.
552 548 */
553 549 (void) CPUCAPS_CHARGE(t, &fxpp->fx_caps, CPUCAPS_CHARGE_ONLY);
554 550
555 551 if (FX_HAS_CB(fxpp)) {
556 552 FX_CB_EXIT(FX_CALLB(fxpp), fxpp->fx_cookie);
557 553 fxpp->fx_callback = NULL;
558 554 fxpp->fx_cookie = NULL;
559 555 thread_unlock(t);
560 556 FX_CB_LIST_DELETE(fxpp);
561 557 return;
562 558 }
563 559
564 560 thread_unlock(t);
565 561 }
566 562
567 563 /*
568 564 * Exiting the class. Free fxproc structure of thread.
569 565 */
570 566 static void
571 567 fx_exitclass(void *procp)
572 568 {
573 569 fxproc_t *fxpp = (fxproc_t *)procp;
574 570
575 571 thread_lock(fxpp->fx_tp);
576 572 if (FX_HAS_CB(fxpp)) {
577 573
578 574 FX_CB_EXIT(FX_CALLB(fxpp), fxpp->fx_cookie);
579 575
580 576 fxpp->fx_callback = NULL;
581 577 fxpp->fx_cookie = NULL;
582 578 thread_unlock(fxpp->fx_tp);
583 579 FX_CB_LIST_DELETE(fxpp);
584 580 } else
585 581 thread_unlock(fxpp->fx_tp);
586 582
587 583 kmem_free(fxpp, sizeof (fxproc_t));
588 584 }
589 585
590 586 /* ARGSUSED */
591 587 static int
592 588 fx_canexit(kthread_t *t, cred_t *cred)
593 589 {
594 590 /*
595 591 * A thread can always leave the FX class
596 592 */
597 593 return (0);
598 594 }
599 595
600 596 /*
601 597 * Initialize fixed-priority class specific proc structure for a child.
602 598 * callbacks are not inherited upon fork.
603 599 */
604 600 static int
605 601 fx_fork(kthread_t *t, kthread_t *ct, void *bufp)
606 602 {
607 603 fxproc_t *pfxpp; /* ptr to parent's fxproc structure */
608 604 fxproc_t *cfxpp; /* ptr to child's fxproc structure */
609 605
610 606 ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
611 607
612 608 cfxpp = (fxproc_t *)bufp;
613 609 ASSERT(cfxpp != NULL);
614 610 thread_lock(t);
615 611 pfxpp = (fxproc_t *)t->t_cldata;
616 612 /*
617 613 * Initialize child's fxproc structure.
618 614 */
619 615 cfxpp->fx_timeleft = cfxpp->fx_pquantum = pfxpp->fx_pquantum;
620 616 cfxpp->fx_pri = pfxpp->fx_pri;
621 617 cfxpp->fx_uprilim = pfxpp->fx_uprilim;
622 618 cfxpp->fx_nice = pfxpp->fx_nice;
623 619 cfxpp->fx_callback = NULL;
624 620 cfxpp->fx_cookie = NULL;
625 621 cfxpp->fx_flags = pfxpp->fx_flags & ~(FXBACKQ);
626 622 cpucaps_sc_init(&cfxpp->fx_caps);
627 623
628 624 cfxpp->fx_tp = ct;
629 625 ct->t_cldata = (void *)cfxpp;
630 626 thread_unlock(t);
631 627
632 628 /*
633 629 * Link new structure into fxproc list.
634 630 */
635 631 return (0);
636 632 }
637 633
638 634
639 635 /*
640 636 * Child is placed at back of dispatcher queue and parent gives
641 637 * up processor so that the child runs first after the fork.
642 638 * This allows the child immediately execing to break the multiple
643 639 * use of copy on write pages with no disk home. The parent will
644 640 * get to steal them back rather than uselessly copying them.
645 641 */
646 642 static void
647 643 fx_forkret(kthread_t *t, kthread_t *ct)
648 644 {
649 645 proc_t *pp = ttoproc(t);
650 646 proc_t *cp = ttoproc(ct);
651 647 fxproc_t *fxpp;
652 648
653 649 ASSERT(t == curthread);
654 650 ASSERT(MUTEX_HELD(&pidlock));
655 651
656 652 /*
657 653 * Grab the child's p_lock before dropping pidlock to ensure
658 654 * the process does not disappear before we set it running.
659 655 */
660 656 mutex_enter(&cp->p_lock);
661 657 continuelwps(cp);
662 658 mutex_exit(&cp->p_lock);
663 659
664 660 mutex_enter(&pp->p_lock);
665 661 mutex_exit(&pidlock);
666 662 continuelwps(pp);
667 663
668 664 thread_lock(t);
669 665 fxpp = (fxproc_t *)(t->t_cldata);
670 666 t->t_pri = fx_dptbl[fxpp->fx_pri].fx_globpri;
671 667 ASSERT(t->t_pri >= 0 && t->t_pri <= fx_maxglobpri);
672 668 THREAD_TRANSITION(t);
673 669 fx_setrun(t);
674 670 thread_unlock(t);
675 671 /*
676 672 * Safe to drop p_lock now since it is safe to change
677 673 * the scheduling class after this point.
678 674 */
679 675 mutex_exit(&pp->p_lock);
680 676
681 677 swtch();
682 678 }
683 679
684 680
685 681 /*
686 682 * Get information about the fixed-priority class into the buffer
687 683 * pointed to by fxinfop. The maximum configured user priority
688 684 * is the only information we supply.
689 685 */
690 686 static int
691 687 fx_getclinfo(void *infop)
692 688 {
693 689 fxinfo_t *fxinfop = (fxinfo_t *)infop;
694 690 fxinfop->fx_maxupri = fx_maxupri;
695 691 return (0);
696 692 }
697 693
698 694
699 695
700 696 /*
701 697 * Return the user mode scheduling priority range.
702 698 */
703 699 static int
704 700 fx_getclpri(pcpri_t *pcprip)
705 701 {
706 702 pcprip->pc_clpmax = fx_maxupri;
707 703 pcprip->pc_clpmin = 0;
708 704 return (0);
709 705 }
710 706
711 707
712 708 static void
713 709 fx_nullsys()
714 710 {}
715 711
716 712
717 713 /*
718 714 * Get the fixed-priority parameters of the thread pointed to by
719 715 * fxprocp into the buffer pointed to by fxparmsp.
720 716 */
721 717 static void
722 718 fx_parmsget(kthread_t *t, void *parmsp)
723 719 {
724 720 fxproc_t *fxpp = (fxproc_t *)t->t_cldata;
725 721 fxkparms_t *fxkparmsp = (fxkparms_t *)parmsp;
726 722
727 723 fxkparmsp->fx_upri = fxpp->fx_pri;
728 724 fxkparmsp->fx_uprilim = fxpp->fx_uprilim;
729 725 fxkparmsp->fx_tqntm = fxpp->fx_pquantum;
730 726 }
731 727
732 728
733 729
734 730 /*
735 731 * Check the validity of the fixed-priority parameters in the buffer
736 732 * pointed to by fxparmsp.
737 733 */
738 734 static int
739 735 fx_parmsin(void *parmsp)
740 736 {
741 737 fxparms_t *fxparmsp = (fxparms_t *)parmsp;
742 738 uint_t cflags;
743 739 longlong_t ticks;
744 740 /*
745 741 * Check validity of parameters.
746 742 */
747 743
748 744 if ((fxparmsp->fx_uprilim > fx_maxupri ||
749 745 fxparmsp->fx_uprilim < 0) &&
750 746 fxparmsp->fx_uprilim != FX_NOCHANGE)
751 747 return (EINVAL);
752 748
753 749 if ((fxparmsp->fx_upri > fx_maxupri ||
754 750 fxparmsp->fx_upri < 0) &&
755 751 fxparmsp->fx_upri != FX_NOCHANGE)
756 752 return (EINVAL);
757 753
758 754 if ((fxparmsp->fx_tqsecs == 0 && fxparmsp->fx_tqnsecs == 0) ||
759 755 fxparmsp->fx_tqnsecs >= NANOSEC)
760 756 return (EINVAL);
761 757
762 758 cflags = (fxparmsp->fx_upri != FX_NOCHANGE ? FX_DOUPRI : 0);
763 759
764 760 if (fxparmsp->fx_uprilim != FX_NOCHANGE) {
765 761 cflags |= FX_DOUPRILIM;
766 762 }
767 763
768 764 if (fxparmsp->fx_tqnsecs != FX_NOCHANGE)
769 765 cflags |= FX_DOTQ;
770 766
771 767 /*
772 768 * convert the buffer to kernel format.
773 769 */
774 770
775 771 if (fxparmsp->fx_tqnsecs >= 0) {
776 772 if ((ticks = SEC_TO_TICK((longlong_t)fxparmsp->fx_tqsecs) +
777 773 NSEC_TO_TICK_ROUNDUP(fxparmsp->fx_tqnsecs)) > INT_MAX)
778 774 return (ERANGE);
779 775
780 776 ((fxkparms_t *)fxparmsp)->fx_tqntm = (int)ticks;
781 777 } else {
782 778 if ((fxparmsp->fx_tqnsecs != FX_NOCHANGE) &&
783 779 (fxparmsp->fx_tqnsecs != FX_TQINF) &&
784 780 (fxparmsp->fx_tqnsecs != FX_TQDEF))
785 781 return (EINVAL);
786 782 ((fxkparms_t *)fxparmsp)->fx_tqntm = fxparmsp->fx_tqnsecs;
787 783 }
788 784
789 785 ((fxkparms_t *)fxparmsp)->fx_cflags = cflags;
790 786
791 787 return (0);
792 788 }
793 789
794 790
795 791 /*
796 792 * Check the validity of the fixed-priority parameters in the pc_vaparms_t
797 793 * structure vaparmsp and put them in the buffer pointed to by fxprmsp.
798 794 * pc_vaparms_t contains (key, value) pairs of parameter.
799 795 */
800 796 static int
801 797 fx_vaparmsin(void *prmsp, pc_vaparms_t *vaparmsp)
802 798 {
803 799 uint_t secs = 0;
804 800 uint_t cnt;
805 801 int nsecs = 0;
806 802 int priflag, secflag, nsecflag, limflag;
807 803 longlong_t ticks;
808 804 fxkparms_t *fxprmsp = (fxkparms_t *)prmsp;
809 805 pc_vaparm_t *vpp = &vaparmsp->pc_parms[0];
810 806
811 807
812 808 /*
813 809 * First check the validity of parameters and convert them
814 810 * from the user supplied format to the internal format.
815 811 */
816 812 priflag = secflag = nsecflag = limflag = 0;
817 813
818 814 fxprmsp->fx_cflags = 0;
819 815
820 816 if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT)
821 817 return (EINVAL);
822 818
823 819 for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) {
824 820
825 821 switch (vpp->pc_key) {
826 822 case FX_KY_UPRILIM:
827 823 if (limflag++)
828 824 return (EINVAL);
829 825 fxprmsp->fx_cflags |= FX_DOUPRILIM;
830 826 fxprmsp->fx_uprilim = (pri_t)vpp->pc_parm;
831 827 if (fxprmsp->fx_uprilim > fx_maxupri ||
832 828 fxprmsp->fx_uprilim < 0)
833 829 return (EINVAL);
834 830 break;
835 831
836 832 case FX_KY_UPRI:
837 833 if (priflag++)
838 834 return (EINVAL);
839 835 fxprmsp->fx_cflags |= FX_DOUPRI;
840 836 fxprmsp->fx_upri = (pri_t)vpp->pc_parm;
841 837 if (fxprmsp->fx_upri > fx_maxupri ||
842 838 fxprmsp->fx_upri < 0)
843 839 return (EINVAL);
844 840 break;
845 841
846 842 case FX_KY_TQSECS:
847 843 if (secflag++)
848 844 return (EINVAL);
849 845 fxprmsp->fx_cflags |= FX_DOTQ;
850 846 secs = (uint_t)vpp->pc_parm;
851 847 break;
852 848
853 849 case FX_KY_TQNSECS:
854 850 if (nsecflag++)
855 851 return (EINVAL);
856 852 fxprmsp->fx_cflags |= FX_DOTQ;
857 853 nsecs = (int)vpp->pc_parm;
858 854 break;
859 855
860 856 default:
861 857 return (EINVAL);
862 858 }
863 859 }
864 860
865 861 if (vaparmsp->pc_vaparmscnt == 0) {
866 862 /*
867 863 * Use default parameters.
868 864 */
869 865 fxprmsp->fx_upri = 0;
870 866 fxprmsp->fx_uprilim = 0;
871 867 fxprmsp->fx_tqntm = FX_TQDEF;
872 868 fxprmsp->fx_cflags = FX_DOUPRI | FX_DOUPRILIM | FX_DOTQ;
873 869 } else if ((fxprmsp->fx_cflags & FX_DOTQ) != 0) {
874 870 if ((secs == 0 && nsecs == 0) || nsecs >= NANOSEC)
875 871 return (EINVAL);
876 872
877 873 if (nsecs >= 0) {
878 874 if ((ticks = SEC_TO_TICK((longlong_t)secs) +
879 875 NSEC_TO_TICK_ROUNDUP(nsecs)) > INT_MAX)
880 876 return (ERANGE);
881 877
882 878 fxprmsp->fx_tqntm = (int)ticks;
883 879 } else {
884 880 if (nsecs != FX_TQINF && nsecs != FX_TQDEF)
885 881 return (EINVAL);
886 882 fxprmsp->fx_tqntm = nsecs;
887 883 }
888 884 }
889 885
890 886 return (0);
891 887 }
892 888
893 889
894 890 /*
895 891 * Nothing to do here but return success.
896 892 */
897 893 /* ARGSUSED */
898 894 static int
899 895 fx_parmsout(void *parmsp, pc_vaparms_t *vaparmsp)
900 896 {
901 897 register fxkparms_t *fxkprmsp = (fxkparms_t *)parmsp;
902 898
903 899 if (vaparmsp != NULL)
904 900 return (0);
905 901
906 902 if (fxkprmsp->fx_tqntm < 0) {
907 903 /*
908 904 * Quantum field set to special value (e.g. FX_TQINF)
909 905 */
910 906 ((fxparms_t *)fxkprmsp)->fx_tqnsecs = fxkprmsp->fx_tqntm;
911 907 ((fxparms_t *)fxkprmsp)->fx_tqsecs = 0;
912 908
913 909 } else {
914 910 /* Convert quantum from ticks to seconds-nanoseconds */
915 911
916 912 timestruc_t ts;
917 913 TICK_TO_TIMESTRUC(fxkprmsp->fx_tqntm, &ts);
918 914 ((fxparms_t *)fxkprmsp)->fx_tqsecs = ts.tv_sec;
919 915 ((fxparms_t *)fxkprmsp)->fx_tqnsecs = ts.tv_nsec;
920 916 }
921 917
922 918 return (0);
923 919 }
924 920
925 921
926 922 /*
927 923 * Copy all selected fixed-priority class parameters to the user.
928 924 * The parameters are specified by a key.
929 925 */
930 926 static int
931 927 fx_vaparmsout(void *prmsp, pc_vaparms_t *vaparmsp)
932 928 {
933 929 fxkparms_t *fxkprmsp = (fxkparms_t *)prmsp;
934 930 timestruc_t ts;
935 931 uint_t cnt;
936 932 uint_t secs;
937 933 int nsecs;
938 934 int priflag, secflag, nsecflag, limflag;
939 935 pc_vaparm_t *vpp = &vaparmsp->pc_parms[0];
940 936
941 937 ASSERT(MUTEX_NOT_HELD(&curproc->p_lock));
942 938
943 939 priflag = secflag = nsecflag = limflag = 0;
944 940
945 941 if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT)
946 942 return (EINVAL);
947 943
948 944 if (fxkprmsp->fx_tqntm < 0) {
949 945 /*
950 946 * Quantum field set to special value (e.g. FX_TQINF).
951 947 */
952 948 secs = 0;
953 949 nsecs = fxkprmsp->fx_tqntm;
954 950 } else {
955 951 /*
956 952 * Convert quantum from ticks to seconds-nanoseconds.
957 953 */
958 954 TICK_TO_TIMESTRUC(fxkprmsp->fx_tqntm, &ts);
959 955 secs = ts.tv_sec;
960 956 nsecs = ts.tv_nsec;
961 957 }
962 958
963 959
964 960 for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) {
965 961
966 962 switch (vpp->pc_key) {
967 963 case FX_KY_UPRILIM:
968 964 if (limflag++)
969 965 return (EINVAL);
970 966 if (copyout(&fxkprmsp->fx_uprilim,
971 967 (void *)(uintptr_t)vpp->pc_parm, sizeof (pri_t)))
972 968 return (EFAULT);
973 969 break;
974 970
975 971 case FX_KY_UPRI:
976 972 if (priflag++)
977 973 return (EINVAL);
978 974 if (copyout(&fxkprmsp->fx_upri,
979 975 (void *)(uintptr_t)vpp->pc_parm, sizeof (pri_t)))
980 976 return (EFAULT);
981 977 break;
982 978
983 979 case FX_KY_TQSECS:
984 980 if (secflag++)
985 981 return (EINVAL);
986 982 if (copyout(&secs,
987 983 (void *)(uintptr_t)vpp->pc_parm, sizeof (uint_t)))
988 984 return (EFAULT);
989 985 break;
990 986
991 987 case FX_KY_TQNSECS:
992 988 if (nsecflag++)
993 989 return (EINVAL);
994 990 if (copyout(&nsecs,
995 991 (void *)(uintptr_t)vpp->pc_parm, sizeof (int)))
996 992 return (EFAULT);
997 993 break;
998 994
999 995 default:
1000 996 return (EINVAL);
1001 997 }
1002 998 }
1003 999
1004 1000 return (0);
1005 1001 }
1006 1002
1007 1003 /*
1008 1004 * Set the scheduling parameters of the thread pointed to by fxprocp
1009 1005 * to those specified in the buffer pointed to by fxparmsp.
1010 1006 */
1011 1007 /* ARGSUSED */
1012 1008 static int
1013 1009 fx_parmsset(kthread_t *tx, void *parmsp, id_t reqpcid, cred_t *reqpcredp)
1014 1010 {
1015 1011 char nice;
1016 1012 pri_t reqfxuprilim;
1017 1013 pri_t reqfxupri;
1018 1014 fxkparms_t *fxkparmsp = (fxkparms_t *)parmsp;
1019 1015 fxproc_t *fxpp;
1020 1016
1021 1017
1022 1018 ASSERT(MUTEX_HELD(&(ttoproc(tx))->p_lock));
1023 1019
1024 1020 thread_lock(tx);
1025 1021 fxpp = (fxproc_t *)tx->t_cldata;
1026 1022
1027 1023 if ((fxkparmsp->fx_cflags & FX_DOUPRILIM) == 0)
1028 1024 reqfxuprilim = fxpp->fx_uprilim;
1029 1025 else
1030 1026 reqfxuprilim = fxkparmsp->fx_uprilim;
1031 1027
1032 1028 /*
1033 1029 * Basic permissions enforced by generic kernel code
1034 1030 * for all classes require that a thread attempting
1035 1031 * to change the scheduling parameters of a target
1036 1032 * thread be privileged or have a real or effective
1037 1033 * UID matching that of the target thread. We are not
1038 1034 * called unless these basic permission checks have
1039 1035 * already passed. The fixed priority class requires in
1040 1036 * addition that the calling thread be privileged if it
1041 1037 * is attempting to raise the pri above its current
1042 1038 * value This may have been checked previously but if our
1043 1039 * caller passed us a non-NULL credential pointer we assume
1044 1040 * it hasn't and we check it here.
1045 1041 */
1046 1042
1047 1043 if ((reqpcredp != NULL) &&
1048 1044 (reqfxuprilim > fxpp->fx_uprilim ||
1049 1045 ((fxkparmsp->fx_cflags & FX_DOTQ) != 0)) &&
1050 1046 secpolicy_raisepriority(reqpcredp) != 0) {
1051 1047 thread_unlock(tx);
1052 1048 return (EPERM);
1053 1049 }
1054 1050
1055 1051 FX_ADJUST_PRI(reqfxuprilim);
1056 1052
1057 1053 if ((fxkparmsp->fx_cflags & FX_DOUPRI) == 0)
1058 1054 reqfxupri = fxpp->fx_pri;
1059 1055 else
1060 1056 reqfxupri = fxkparmsp->fx_upri;
1061 1057
1062 1058
1063 1059 /*
1064 1060 * Make sure the user priority doesn't exceed the upri limit.
1065 1061 */
1066 1062 if (reqfxupri > reqfxuprilim)
1067 1063 reqfxupri = reqfxuprilim;
1068 1064
1069 1065 /*
1070 1066 * Set fx_nice to the nice value corresponding to the user
1071 1067 * priority we are setting. Note that setting the nice field
1072 1068 * of the parameter struct won't affect upri or nice.
1073 1069 */
1074 1070
1075 1071 nice = NZERO - (reqfxupri * NZERO) / fx_maxupri;
1076 1072
1077 1073 if (nice > NZERO)
1078 1074 nice = NZERO;
1079 1075
1080 1076 fxpp->fx_uprilim = reqfxuprilim;
1081 1077 fxpp->fx_pri = reqfxupri;
1082 1078
1083 1079 if (fxkparmsp->fx_tqntm == FX_TQINF)
1084 1080 fxpp->fx_pquantum = FX_TQINF;
1085 1081 else if (fxkparmsp->fx_tqntm == FX_TQDEF)
1086 1082 fxpp->fx_pquantum = fx_dptbl[fxpp->fx_pri].fx_quantum;
1087 1083 else if ((fxkparmsp->fx_cflags & FX_DOTQ) != 0)
1088 1084 fxpp->fx_pquantum = fxkparmsp->fx_tqntm;
1089 1085
1090 1086 fxpp->fx_nice = nice;
1091 1087
1092 1088 fx_change_priority(tx, fxpp);
1093 1089 thread_unlock(tx);
1094 1090 return (0);
1095 1091 }
1096 1092
1097 1093
1098 1094 /*
1099 1095 * Return the global scheduling priority that would be assigned
1100 1096 * to a thread entering the fixed-priority class with the fx_upri.
1101 1097 */
1102 1098 static pri_t
1103 1099 fx_globpri(kthread_t *t)
1104 1100 {
1105 1101 fxproc_t *fxpp;
1106 1102
1107 1103 ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
1108 1104
1109 1105 fxpp = (fxproc_t *)t->t_cldata;
1110 1106 return (fx_dptbl[fxpp->fx_pri].fx_globpri);
1111 1107
1112 1108 }
1113 1109
1114 1110 /*
1115 1111 * Arrange for thread to be placed in appropriate location
1116 1112 * on dispatcher queue.
1117 1113 *
1118 1114 * This is called with the current thread in TS_ONPROC and locked.
1119 1115 */
1120 1116 static void
1121 1117 fx_preempt(kthread_t *t)
1122 1118 {
1123 1119 fxproc_t *fxpp = (fxproc_t *)(t->t_cldata);
1124 1120
1125 1121 ASSERT(t == curthread);
1126 1122 ASSERT(THREAD_LOCK_HELD(curthread));
1127 1123
1128 1124 (void) CPUCAPS_CHARGE(t, &fxpp->fx_caps, CPUCAPS_CHARGE_ENFORCE);
1129 1125
1130 1126 /*
1131 1127 * Check to see if we're doing "preemption control" here. If
1132 1128 * we are, and if the user has requested that this thread not
1133 1129 * be preempted, and if preemptions haven't been put off for
1134 1130 * too long, let the preemption happen here but try to make
1135 1131 * sure the thread is rescheduled as soon as possible. We do
1136 1132 * this by putting it on the front of the highest priority run
1137 1133 * queue in the FX class. If the preemption has been put off
1138 1134 * for too long, clear the "nopreempt" bit and let the thread
1139 1135 * be preempted.
1140 1136 */
1141 1137 if (t->t_schedctl && schedctl_get_nopreempt(t)) {
1142 1138 if (fxpp->fx_pquantum == FX_TQINF ||
1143 1139 fxpp->fx_timeleft > -SC_MAX_TICKS) {
1144 1140 DTRACE_SCHED1(schedctl__nopreempt, kthread_t *, t);
1145 1141 schedctl_set_yield(t, 1);
1146 1142 setfrontdq(t);
1147 1143 return;
1148 1144 } else {
1149 1145 schedctl_set_nopreempt(t, 0);
1150 1146 DTRACE_SCHED1(schedctl__preempt, kthread_t *, t);
1151 1147 TNF_PROBE_2(schedctl_preempt, "schedctl FX fx_preempt",
1152 1148 /* CSTYLED */, tnf_pid, pid, ttoproc(t)->p_pid,
1153 1149 tnf_lwpid, lwpid, t->t_tid);
1154 1150 /*
1155 1151 * Fall through and be preempted below.
1156 1152 */
1157 1153 }
1158 1154 }
1159 1155
1160 1156 if (FX_HAS_CB(fxpp)) {
1161 1157 clock_t new_quantum = (clock_t)fxpp->fx_pquantum;
1162 1158 pri_t newpri = fxpp->fx_pri;
1163 1159 FX_CB_PREEMPT(FX_CALLB(fxpp), fxpp->fx_cookie,
1164 1160 &new_quantum, &newpri);
1165 1161 FX_ADJUST_QUANTUM(new_quantum);
1166 1162 if ((int)new_quantum != fxpp->fx_pquantum) {
1167 1163 fxpp->fx_pquantum = (int)new_quantum;
1168 1164 fxpp->fx_timeleft = fxpp->fx_pquantum;
1169 1165 }
1170 1166 FX_ADJUST_PRI(newpri);
1171 1167 fxpp->fx_pri = newpri;
1172 1168 THREAD_CHANGE_PRI(t, fx_dptbl[fxpp->fx_pri].fx_globpri);
1173 1169 }
1174 1170
1175 1171 /*
1176 1172 * This thread may be placed on wait queue by CPU Caps. In this case we
1177 1173 * do not need to do anything until it is removed from the wait queue.
1178 1174 */
1179 1175 if (CPUCAPS_ENFORCE(t)) {
1180 1176 return;
1181 1177 }
1182 1178
1183 1179 if ((fxpp->fx_flags & (FXBACKQ)) == FXBACKQ) {
1184 1180 fxpp->fx_timeleft = fxpp->fx_pquantum;
1185 1181 fxpp->fx_flags &= ~FXBACKQ;
1186 1182 setbackdq(t);
1187 1183 } else {
1188 1184 setfrontdq(t);
1189 1185 }
1190 1186 }
1191 1187
1192 1188 static void
1193 1189 fx_setrun(kthread_t *t)
1194 1190 {
1195 1191 fxproc_t *fxpp = (fxproc_t *)(t->t_cldata);
1196 1192
1197 1193 ASSERT(THREAD_LOCK_HELD(t)); /* t should be in transition */
1198 1194 fxpp->fx_flags &= ~FXBACKQ;
1199 1195
1200 1196 if (t->t_disp_time != ddi_get_lbolt())
1201 1197 setbackdq(t);
1202 1198 else
1203 1199 setfrontdq(t);
1204 1200 }
1205 1201
1206 1202
1207 1203 /*
1208 1204 * Prepare thread for sleep. We reset the thread priority so it will
1209 1205 * run at the kernel priority level when it wakes up.
1210 1206 */
1211 1207 static void
1212 1208 fx_sleep(kthread_t *t)
1213 1209 {
1214 1210 fxproc_t *fxpp = (fxproc_t *)(t->t_cldata);
1215 1211
1216 1212 ASSERT(t == curthread);
↓ open down ↓ |
976 lines elided |
↑ open up ↑ |
1217 1213 ASSERT(THREAD_LOCK_HELD(t));
1218 1214
1219 1215 /*
1220 1216 * Account for time spent on CPU before going to sleep.
1221 1217 */
1222 1218 (void) CPUCAPS_CHARGE(t, &fxpp->fx_caps, CPUCAPS_CHARGE_ENFORCE);
1223 1219
1224 1220 if (FX_HAS_CB(fxpp)) {
1225 1221 FX_CB_SLEEP(FX_CALLB(fxpp), fxpp->fx_cookie);
1226 1222 }
1227 - t->t_stime = ddi_get_lbolt(); /* time stamp for the swapper */
1228 -}
1229 -
1230 -
1231 -/*
1232 - * Return Values:
1233 - *
1234 - * -1 if the thread is loaded or is not eligible to be swapped in.
1235 - *
1236 - * FX and RT threads are designed so that they don't swapout; however,
1237 - * it is possible that while the thread is swapped out and in another class, it
1238 - * can be changed to FX or RT. Since these threads should be swapped in
1239 - * as soon as they're runnable, rt_swapin returns SHRT_MAX, and fx_swapin
1240 - * returns SHRT_MAX - 1, so that it gives deference to any swapped out
1241 - * RT threads.
1242 - */
1243 -/* ARGSUSED */
1244 -static pri_t
1245 -fx_swapin(kthread_t *t, int flags)
1246 -{
1247 - pri_t tpri = -1;
1248 -
1249 - ASSERT(THREAD_LOCK_HELD(t));
1250 -
1251 - if (t->t_state == TS_RUN && (t->t_schedflag & TS_LOAD) == 0) {
1252 - tpri = (pri_t)SHRT_MAX - 1;
1253 - }
1254 -
1255 - return (tpri);
1256 -}
1257 -
1258 -/*
1259 - * Return Values
1260 - * -1 if the thread isn't loaded or is not eligible to be swapped out.
1261 - */
1262 -/* ARGSUSED */
1263 -static pri_t
1264 -fx_swapout(kthread_t *t, int flags)
1265 -{
1266 - ASSERT(THREAD_LOCK_HELD(t));
1267 -
1268 - return (-1);
1269 -
1270 1223 }
1271 1224
1272 1225 /* ARGSUSED */
1273 1226 static void
1274 1227 fx_stop(kthread_t *t, int why, int what)
1275 1228 {
1276 1229 fxproc_t *fxpp = (fxproc_t *)(t->t_cldata);
1277 1230
1278 1231 ASSERT(THREAD_LOCK_HELD(t));
1279 1232
1280 1233 if (FX_HAS_CB(fxpp)) {
1281 1234 FX_CB_STOP(FX_CALLB(fxpp), fxpp->fx_cookie);
1282 1235 }
1283 1236 }
1284 1237
1285 1238 /*
1286 1239 * Check for time slice expiration. If time slice has expired
1287 1240 * set runrun to cause preemption.
1288 1241 */
1289 1242 static void
1290 1243 fx_tick(kthread_t *t)
1291 1244 {
1292 1245 boolean_t call_cpu_surrender = B_FALSE;
1293 1246 fxproc_t *fxpp;
1294 1247
1295 1248 ASSERT(MUTEX_HELD(&(ttoproc(t))->p_lock));
1296 1249
1297 1250 thread_lock(t);
1298 1251
1299 1252 fxpp = (fxproc_t *)(t->t_cldata);
1300 1253
1301 1254 if (FX_HAS_CB(fxpp)) {
1302 1255 clock_t new_quantum = (clock_t)fxpp->fx_pquantum;
1303 1256 pri_t newpri = fxpp->fx_pri;
1304 1257 FX_CB_TICK(FX_CALLB(fxpp), fxpp->fx_cookie,
1305 1258 &new_quantum, &newpri);
1306 1259 FX_ADJUST_QUANTUM(new_quantum);
1307 1260 if ((int)new_quantum != fxpp->fx_pquantum) {
1308 1261 fxpp->fx_pquantum = (int)new_quantum;
1309 1262 fxpp->fx_timeleft = fxpp->fx_pquantum;
1310 1263 }
1311 1264 FX_ADJUST_PRI(newpri);
1312 1265 if (newpri != fxpp->fx_pri) {
1313 1266 fxpp->fx_pri = newpri;
1314 1267 fx_change_priority(t, fxpp);
1315 1268 }
1316 1269 }
1317 1270
1318 1271 /*
1319 1272 * Keep track of thread's project CPU usage. Note that projects
1320 1273 * get charged even when threads are running in the kernel.
1321 1274 */
1322 1275 call_cpu_surrender = CPUCAPS_CHARGE(t, &fxpp->fx_caps,
1323 1276 CPUCAPS_CHARGE_ENFORCE);
1324 1277
1325 1278 if ((fxpp->fx_pquantum != FX_TQINF) &&
1326 1279 (--fxpp->fx_timeleft <= 0)) {
1327 1280 pri_t new_pri;
1328 1281
1329 1282 /*
1330 1283 * If we're doing preemption control and trying to
1331 1284 * avoid preempting this thread, just note that
1332 1285 * the thread should yield soon and let it keep
1333 1286 * running (unless it's been a while).
1334 1287 */
1335 1288 if (t->t_schedctl && schedctl_get_nopreempt(t)) {
1336 1289 if (fxpp->fx_timeleft > -SC_MAX_TICKS) {
1337 1290 DTRACE_SCHED1(schedctl__nopreempt,
1338 1291 kthread_t *, t);
1339 1292 schedctl_set_yield(t, 1);
1340 1293 thread_unlock_nopreempt(t);
1341 1294 return;
1342 1295 }
1343 1296 TNF_PROBE_2(schedctl_failsafe,
1344 1297 "schedctl FX fx_tick", /* CSTYLED */,
1345 1298 tnf_pid, pid, ttoproc(t)->p_pid,
1346 1299 tnf_lwpid, lwpid, t->t_tid);
1347 1300 }
1348 1301 new_pri = fx_dptbl[fxpp->fx_pri].fx_globpri;
1349 1302 ASSERT(new_pri >= 0 && new_pri <= fx_maxglobpri);
1350 1303 /*
1351 1304 * When the priority of a thread is changed,
1352 1305 * it may be necessary to adjust its position
1353 1306 * on a sleep queue or dispatch queue. Even
1354 1307 * when the priority is not changed, we need
1355 1308 * to preserve round robin on dispatch queue.
1356 1309 * The function thread_change_pri accomplishes
1357 1310 * this.
1358 1311 */
1359 1312 if (thread_change_pri(t, new_pri, 0)) {
1360 1313 fxpp->fx_timeleft = fxpp->fx_pquantum;
1361 1314 } else {
1362 1315 call_cpu_surrender = B_TRUE;
1363 1316 }
1364 1317 } else if (t->t_state == TS_ONPROC &&
1365 1318 t->t_pri < t->t_disp_queue->disp_maxrunpri) {
1366 1319 call_cpu_surrender = B_TRUE;
1367 1320 }
1368 1321
1369 1322 if (call_cpu_surrender) {
1370 1323 fxpp->fx_flags |= FXBACKQ;
1371 1324 cpu_surrender(t);
1372 1325 }
1373 1326 thread_unlock_nopreempt(t); /* clock thread can't be preempted */
1374 1327 }
1375 1328
1376 1329
1377 1330 static void
1378 1331 fx_trapret(kthread_t *t)
1379 1332 {
1380 1333 cpu_t *cp = CPU;
1381 1334
1382 1335 ASSERT(THREAD_LOCK_HELD(t));
1383 1336 ASSERT(t == curthread);
1384 1337 ASSERT(cp->cpu_dispthread == t);
1385 1338 ASSERT(t->t_state == TS_ONPROC);
1386 1339 }
1387 1340
1388 1341
↓ open down ↓ |
109 lines elided |
↑ open up ↑ |
1389 1342 /*
1390 1343 * Processes waking up go to the back of their queue.
1391 1344 */
1392 1345 static void
1393 1346 fx_wakeup(kthread_t *t)
1394 1347 {
1395 1348 fxproc_t *fxpp = (fxproc_t *)(t->t_cldata);
1396 1349
1397 1350 ASSERT(THREAD_LOCK_HELD(t));
1398 1351
1399 - t->t_stime = ddi_get_lbolt(); /* time stamp for the swapper */
1400 1352 if (FX_HAS_CB(fxpp)) {
1401 1353 clock_t new_quantum = (clock_t)fxpp->fx_pquantum;
1402 1354 pri_t newpri = fxpp->fx_pri;
1403 1355 FX_CB_WAKEUP(FX_CALLB(fxpp), fxpp->fx_cookie,
1404 1356 &new_quantum, &newpri);
1405 1357 FX_ADJUST_QUANTUM(new_quantum);
1406 1358 if ((int)new_quantum != fxpp->fx_pquantum) {
1407 1359 fxpp->fx_pquantum = (int)new_quantum;
1408 1360 fxpp->fx_timeleft = fxpp->fx_pquantum;
1409 1361 }
1410 1362
1411 1363 FX_ADJUST_PRI(newpri);
1412 1364 if (newpri != fxpp->fx_pri) {
1413 1365 fxpp->fx_pri = newpri;
1414 1366 THREAD_CHANGE_PRI(t, fx_dptbl[fxpp->fx_pri].fx_globpri);
1415 1367 }
1416 1368 }
1417 1369
1418 1370 fxpp->fx_flags &= ~FXBACKQ;
1419 1371
1420 1372 if (t->t_disp_time != ddi_get_lbolt())
1421 1373 setbackdq(t);
1422 1374 else
1423 1375 setfrontdq(t);
1424 1376 }
1425 1377
1426 1378
1427 1379 /*
1428 1380 * When a thread yields, put it on the back of the run queue.
1429 1381 */
1430 1382 static void
1431 1383 fx_yield(kthread_t *t)
1432 1384 {
1433 1385 fxproc_t *fxpp = (fxproc_t *)(t->t_cldata);
1434 1386
1435 1387 ASSERT(t == curthread);
1436 1388 ASSERT(THREAD_LOCK_HELD(t));
1437 1389
1438 1390 /*
1439 1391 * Collect CPU usage spent before yielding CPU.
1440 1392 */
1441 1393 (void) CPUCAPS_CHARGE(t, &fxpp->fx_caps, CPUCAPS_CHARGE_ENFORCE);
1442 1394
1443 1395 if (FX_HAS_CB(fxpp)) {
1444 1396 clock_t new_quantum = (clock_t)fxpp->fx_pquantum;
1445 1397 pri_t newpri = fxpp->fx_pri;
1446 1398 FX_CB_PREEMPT(FX_CALLB(fxpp), fxpp->fx_cookie,
1447 1399 &new_quantum, &newpri);
1448 1400 FX_ADJUST_QUANTUM(new_quantum);
1449 1401 if ((int)new_quantum != fxpp->fx_pquantum) {
1450 1402 fxpp->fx_pquantum = (int)new_quantum;
1451 1403 fxpp->fx_timeleft = fxpp->fx_pquantum;
1452 1404 }
1453 1405 FX_ADJUST_PRI(newpri);
1454 1406 fxpp->fx_pri = newpri;
1455 1407 THREAD_CHANGE_PRI(t, fx_dptbl[fxpp->fx_pri].fx_globpri);
1456 1408 }
1457 1409
1458 1410 /*
1459 1411 * Clear the preemption control "yield" bit since the user is
1460 1412 * doing a yield.
1461 1413 */
1462 1414 if (t->t_schedctl)
1463 1415 schedctl_set_yield(t, 0);
1464 1416
1465 1417 if (fxpp->fx_timeleft <= 0) {
1466 1418 /*
1467 1419 * Time slice was artificially extended to avoid
1468 1420 * preemption, so pretend we're preempting it now.
1469 1421 */
1470 1422 DTRACE_SCHED1(schedctl__yield, int, -fxpp->fx_timeleft);
1471 1423 fxpp->fx_timeleft = fxpp->fx_pquantum;
1472 1424 THREAD_CHANGE_PRI(t, fx_dptbl[fxpp->fx_pri].fx_globpri);
1473 1425 ASSERT(t->t_pri >= 0 && t->t_pri <= fx_maxglobpri);
1474 1426 }
1475 1427
1476 1428 fxpp->fx_flags &= ~FXBACKQ;
1477 1429 setbackdq(t);
1478 1430 }
1479 1431
1480 1432 /*
1481 1433 * Increment the nice value of the specified thread by incr and
1482 1434 * return the new value in *retvalp.
1483 1435 */
1484 1436 static int
1485 1437 fx_donice(kthread_t *t, cred_t *cr, int incr, int *retvalp)
1486 1438 {
1487 1439 int newnice;
1488 1440 fxproc_t *fxpp = (fxproc_t *)(t->t_cldata);
1489 1441 fxkparms_t fxkparms;
1490 1442
1491 1443 ASSERT(MUTEX_HELD(&(ttoproc(t))->p_lock));
1492 1444
1493 1445 /* If there's no change to priority, just return current setting */
1494 1446 if (incr == 0) {
1495 1447 if (retvalp) {
1496 1448 *retvalp = fxpp->fx_nice - NZERO;
1497 1449 }
1498 1450 return (0);
1499 1451 }
1500 1452
1501 1453 if ((incr < 0 || incr > 2 * NZERO) &&
1502 1454 secpolicy_raisepriority(cr) != 0)
1503 1455 return (EPERM);
1504 1456
1505 1457 /*
1506 1458 * Specifying a nice increment greater than the upper limit of
1507 1459 * 2 * NZERO - 1 will result in the thread's nice value being
1508 1460 * set to the upper limit. We check for this before computing
1509 1461 * the new value because otherwise we could get overflow
1510 1462 * if a privileged user specified some ridiculous increment.
1511 1463 */
1512 1464 if (incr > 2 * NZERO - 1)
1513 1465 incr = 2 * NZERO - 1;
1514 1466
1515 1467 newnice = fxpp->fx_nice + incr;
1516 1468 if (newnice > NZERO)
1517 1469 newnice = NZERO;
1518 1470 else if (newnice < 0)
1519 1471 newnice = 0;
1520 1472
1521 1473 fxkparms.fx_uprilim = fxkparms.fx_upri =
1522 1474 -((newnice - NZERO) * fx_maxupri) / NZERO;
1523 1475
1524 1476 fxkparms.fx_cflags = FX_DOUPRILIM | FX_DOUPRI;
1525 1477
1526 1478 fxkparms.fx_tqntm = FX_TQDEF;
1527 1479
1528 1480 /*
1529 1481 * Reset the uprilim and upri values of the thread. Adjust
1530 1482 * time quantum accordingly.
1531 1483 */
1532 1484
1533 1485 (void) fx_parmsset(t, (void *)&fxkparms, (id_t)0, (cred_t *)NULL);
1534 1486
1535 1487 /*
1536 1488 * Although fx_parmsset already reset fx_nice it may
1537 1489 * not have been set to precisely the value calculated above
1538 1490 * because fx_parmsset determines the nice value from the
1539 1491 * user priority and we may have truncated during the integer
1540 1492 * conversion from nice value to user priority and back.
1541 1493 * We reset fx_nice to the value we calculated above.
1542 1494 */
1543 1495 fxpp->fx_nice = (char)newnice;
1544 1496
1545 1497 if (retvalp)
1546 1498 *retvalp = newnice - NZERO;
1547 1499
1548 1500 return (0);
1549 1501 }
1550 1502
1551 1503 /*
1552 1504 * Increment the priority of the specified thread by incr and
1553 1505 * return the new value in *retvalp.
1554 1506 */
1555 1507 static int
1556 1508 fx_doprio(kthread_t *t, cred_t *cr, int incr, int *retvalp)
1557 1509 {
1558 1510 int newpri;
1559 1511 fxproc_t *fxpp = (fxproc_t *)(t->t_cldata);
1560 1512 fxkparms_t fxkparms;
1561 1513
1562 1514 ASSERT(MUTEX_HELD(&(ttoproc(t))->p_lock));
1563 1515
1564 1516 /* If there's no change to priority, just return current setting */
1565 1517 if (incr == 0) {
1566 1518 *retvalp = fxpp->fx_pri;
1567 1519 return (0);
1568 1520 }
1569 1521
1570 1522 newpri = fxpp->fx_pri + incr;
1571 1523 if (newpri > fx_maxupri || newpri < 0)
1572 1524 return (EINVAL);
1573 1525
1574 1526 *retvalp = newpri;
1575 1527 fxkparms.fx_uprilim = fxkparms.fx_upri = newpri;
1576 1528 fxkparms.fx_tqntm = FX_NOCHANGE;
1577 1529 fxkparms.fx_cflags = FX_DOUPRILIM | FX_DOUPRI;
1578 1530
1579 1531 /*
1580 1532 * Reset the uprilim and upri values of the thread.
1581 1533 */
1582 1534 return (fx_parmsset(t, (void *)&fxkparms, (id_t)0, cr));
1583 1535 }
1584 1536
1585 1537 static void
1586 1538 fx_change_priority(kthread_t *t, fxproc_t *fxpp)
1587 1539 {
1588 1540 pri_t new_pri;
1589 1541
1590 1542 ASSERT(THREAD_LOCK_HELD(t));
1591 1543 new_pri = fx_dptbl[fxpp->fx_pri].fx_globpri;
1592 1544 ASSERT(new_pri >= 0 && new_pri <= fx_maxglobpri);
1593 1545 t->t_cpri = fxpp->fx_pri;
1594 1546 if (t == curthread || t->t_state == TS_ONPROC) {
1595 1547 /* curthread is always onproc */
1596 1548 cpu_t *cp = t->t_disp_queue->disp_cpu;
1597 1549 THREAD_CHANGE_PRI(t, new_pri);
1598 1550 if (t == cp->cpu_dispthread)
1599 1551 cp->cpu_dispatch_pri = DISP_PRIO(t);
1600 1552 if (DISP_MUST_SURRENDER(t)) {
1601 1553 fxpp->fx_flags |= FXBACKQ;
1602 1554 cpu_surrender(t);
1603 1555 } else {
1604 1556 fxpp->fx_timeleft = fxpp->fx_pquantum;
1605 1557 }
1606 1558 } else {
1607 1559 /*
1608 1560 * When the priority of a thread is changed,
1609 1561 * it may be necessary to adjust its position
1610 1562 * on a sleep queue or dispatch queue.
1611 1563 * The function thread_change_pri accomplishes
1612 1564 * this.
1613 1565 */
1614 1566 if (thread_change_pri(t, new_pri, 0)) {
1615 1567 /*
1616 1568 * The thread was on a run queue. Reset
1617 1569 * its CPU timeleft from the quantum
1618 1570 * associated with the new priority.
1619 1571 */
1620 1572 fxpp->fx_timeleft = fxpp->fx_pquantum;
1621 1573 } else {
1622 1574 fxpp->fx_flags |= FXBACKQ;
1623 1575 }
1624 1576 }
1625 1577 }
1626 1578
1627 1579 static int
1628 1580 fx_alloc(void **p, int flag)
1629 1581 {
1630 1582 void *bufp;
1631 1583
1632 1584 bufp = kmem_alloc(sizeof (fxproc_t), flag);
1633 1585 if (bufp == NULL) {
1634 1586 return (ENOMEM);
1635 1587 } else {
1636 1588 *p = bufp;
1637 1589 return (0);
1638 1590 }
1639 1591 }
1640 1592
1641 1593 static void
1642 1594 fx_free(void *bufp)
1643 1595 {
1644 1596 if (bufp)
1645 1597 kmem_free(bufp, sizeof (fxproc_t));
1646 1598 }
1647 1599
1648 1600 /*
1649 1601 * Release the callback list mutex after successful lookup
1650 1602 */
1651 1603 void
1652 1604 fx_list_release(fxproc_t *fxpp)
1653 1605 {
1654 1606 int index = FX_CB_LIST_HASH(fxpp->fx_ktid);
1655 1607 kmutex_t *lockp = &fx_cb_list_lock[index];
1656 1608 mutex_exit(lockp);
1657 1609 }
1658 1610
1659 1611 fxproc_t *
1660 1612 fx_list_lookup(kt_did_t ktid)
1661 1613 {
1662 1614 int index = FX_CB_LIST_HASH(ktid);
1663 1615 kmutex_t *lockp = &fx_cb_list_lock[index];
1664 1616 fxproc_t *fxpp;
1665 1617
1666 1618 mutex_enter(lockp);
1667 1619
1668 1620 for (fxpp = fx_cb_plisthead[index].fx_cb_next;
1669 1621 fxpp != &fx_cb_plisthead[index]; fxpp = fxpp->fx_cb_next) {
1670 1622 if (fxpp->fx_tp->t_cid == fx_cid && fxpp->fx_ktid == ktid &&
1671 1623 fxpp->fx_callback != NULL) {
1672 1624 /*
1673 1625 * The caller is responsible for calling
1674 1626 * fx_list_release to drop the lock upon
1675 1627 * successful lookup
1676 1628 */
1677 1629 return (fxpp);
1678 1630 }
1679 1631 }
1680 1632 mutex_exit(lockp);
1681 1633 return ((fxproc_t *)NULL);
1682 1634 }
1683 1635
1684 1636
1685 1637 /*
1686 1638 * register a callback set of routines for current thread
1687 1639 * thread should already be in FX class
1688 1640 */
1689 1641 int
1690 1642 fx_register_callbacks(fx_callbacks_t *fx_callback, fx_cookie_t cookie,
1691 1643 pri_t pri, clock_t quantum)
1692 1644 {
1693 1645
1694 1646 fxproc_t *fxpp;
1695 1647
1696 1648 if (fx_callback == NULL)
1697 1649 return (EINVAL);
1698 1650
1699 1651 if (secpolicy_dispadm(CRED()) != 0)
1700 1652 return (EPERM);
1701 1653
1702 1654 if (FX_CB_VERSION(fx_callback) != FX_CALLB_REV)
1703 1655 return (EINVAL);
1704 1656
1705 1657 if (!FX_ISVALID(pri, quantum))
1706 1658 return (EINVAL);
1707 1659
1708 1660 thread_lock(curthread); /* get dispatcher lock on thread */
1709 1661
1710 1662 if (curthread->t_cid != fx_cid) {
1711 1663 thread_unlock(curthread);
1712 1664 return (EINVAL);
1713 1665 }
1714 1666
1715 1667 fxpp = (fxproc_t *)(curthread->t_cldata);
1716 1668 ASSERT(fxpp != NULL);
1717 1669 if (FX_HAS_CB(fxpp)) {
1718 1670 thread_unlock(curthread);
1719 1671 return (EINVAL);
1720 1672 }
1721 1673
1722 1674 fxpp->fx_callback = fx_callback;
1723 1675 fxpp->fx_cookie = cookie;
1724 1676
1725 1677 if (pri != FX_CB_NOCHANGE) {
1726 1678 fxpp->fx_pri = pri;
1727 1679 FX_ADJUST_PRI(fxpp->fx_pri);
1728 1680 if (quantum == FX_TQDEF) {
1729 1681 fxpp->fx_pquantum = fx_dptbl[fxpp->fx_pri].fx_quantum;
1730 1682 } else if (quantum == FX_TQINF) {
1731 1683 fxpp->fx_pquantum = FX_TQINF;
1732 1684 } else if (quantum != FX_NOCHANGE) {
1733 1685 FX_ADJUST_QUANTUM(quantum);
1734 1686 fxpp->fx_pquantum = quantum;
1735 1687 }
1736 1688 } else if (quantum != FX_NOCHANGE && quantum != FX_TQDEF) {
1737 1689 if (quantum == FX_TQINF)
1738 1690 fxpp->fx_pquantum = FX_TQINF;
1739 1691 else {
1740 1692 FX_ADJUST_QUANTUM(quantum);
1741 1693 fxpp->fx_pquantum = quantum;
1742 1694 }
1743 1695 }
1744 1696
1745 1697 fxpp->fx_ktid = ddi_get_kt_did();
1746 1698
1747 1699 fx_change_priority(curthread, fxpp);
1748 1700
1749 1701 thread_unlock(curthread);
1750 1702
1751 1703 /*
1752 1704 * Link new structure into fxproc list.
1753 1705 */
1754 1706 FX_CB_LIST_INSERT(fxpp);
1755 1707 return (0);
1756 1708 }
1757 1709
1758 1710 /* unregister a callback set of routines for current thread */
1759 1711 int
1760 1712 fx_unregister_callbacks()
1761 1713 {
1762 1714 fxproc_t *fxpp;
1763 1715
1764 1716 if ((fxpp = fx_list_lookup(ddi_get_kt_did())) == NULL) {
1765 1717 /*
1766 1718 * did not have a registered callback;
1767 1719 */
1768 1720 return (EINVAL);
1769 1721 }
1770 1722
1771 1723 thread_lock(fxpp->fx_tp);
1772 1724 fxpp->fx_callback = NULL;
1773 1725 fxpp->fx_cookie = NULL;
1774 1726 thread_unlock(fxpp->fx_tp);
1775 1727 fx_list_release(fxpp);
1776 1728
1777 1729 FX_CB_LIST_DELETE(fxpp);
1778 1730 return (0);
1779 1731 }
1780 1732
1781 1733 /*
1782 1734 * modify priority and/or quantum value of a thread with callback
1783 1735 */
1784 1736 int
1785 1737 fx_modify_priority(kt_did_t ktid, clock_t quantum, pri_t pri)
1786 1738 {
1787 1739 fxproc_t *fxpp;
1788 1740
1789 1741 if (!FX_ISVALID(pri, quantum))
1790 1742 return (EINVAL);
1791 1743
1792 1744 if ((fxpp = fx_list_lookup(ktid)) == NULL) {
1793 1745 /*
1794 1746 * either thread had exited or did not have a registered
1795 1747 * callback;
1796 1748 */
1797 1749 return (ESRCH);
1798 1750 }
1799 1751
1800 1752 thread_lock(fxpp->fx_tp);
1801 1753
1802 1754 if (pri != FX_CB_NOCHANGE) {
1803 1755 fxpp->fx_pri = pri;
1804 1756 FX_ADJUST_PRI(fxpp->fx_pri);
1805 1757 if (quantum == FX_TQDEF) {
1806 1758 fxpp->fx_pquantum = fx_dptbl[fxpp->fx_pri].fx_quantum;
1807 1759 } else if (quantum == FX_TQINF) {
1808 1760 fxpp->fx_pquantum = FX_TQINF;
1809 1761 } else if (quantum != FX_NOCHANGE) {
1810 1762 FX_ADJUST_QUANTUM(quantum);
1811 1763 fxpp->fx_pquantum = quantum;
1812 1764 }
1813 1765 } else if (quantum != FX_NOCHANGE && quantum != FX_TQDEF) {
1814 1766 if (quantum == FX_TQINF) {
1815 1767 fxpp->fx_pquantum = FX_TQINF;
1816 1768 } else {
1817 1769 FX_ADJUST_QUANTUM(quantum);
1818 1770 fxpp->fx_pquantum = quantum;
1819 1771 }
1820 1772 }
1821 1773
1822 1774 fx_change_priority(fxpp->fx_tp, fxpp);
1823 1775
1824 1776 thread_unlock(fxpp->fx_tp);
1825 1777 fx_list_release(fxpp);
1826 1778 return (0);
1827 1779 }
1828 1780
1829 1781
1830 1782 /*
1831 1783 * return an iblock cookie for mutex initialization to be used in callbacks
1832 1784 */
1833 1785 void *
1834 1786 fx_get_mutex_cookie()
1835 1787 {
1836 1788 return ((void *)(uintptr_t)__ipltospl(DISP_LEVEL));
1837 1789 }
1838 1790
1839 1791 /*
1840 1792 * return maximum relative priority
1841 1793 */
1842 1794 pri_t
1843 1795 fx_get_maxpri()
1844 1796 {
1845 1797 return (fx_maxumdpri);
1846 1798 }
↓ open down ↓ |
437 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX