|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: *
25: */
26:
27: /***
28: *** ??? The following lines were picked up when code was incorporated
29: *** into this file from `kern/syscall_subr.c.' These should be moved
30: *** with the code if it moves again. Otherwise, they should be trimmed,
31: *** based on the files included above.
32: ***/
33:
34: #include <mach/boolean.h>
35: #include <mach/thread_switch.h>
36: #include <ipc/ipc_port.h>
37: #include <ipc/ipc_space.h>
38: #include <kern/counters.h>
39: #include <kern/ipc_kobject.h>
40: #include <kern/processor.h>
41: #include <kern/sched.h>
42: #include <kern/sched_prim.h>
43: #include <kern/spl.h>
44: #include <kern/task.h>
45: #include <kern/thread.h>
46: #include <kern/ast.h>
47: #include <mach/policy.h>
48:
49: #include <kern/syscall_subr.h>
50: #include <mach/mach_host_server.h>
51: #include <mach/mach_syscalls.h>
52:
53: /***
54: *** ??? End of lines picked up when code was incorporated
55: *** into this file from `kern/syscall_subr.c.'
56: ***/
57:
58: #include <kern/sf.h>
59: #include <kern/mk_sp.h>
60: #include <kern/misc_protos.h>
61: #include <kern/spl.h>
62: #include <kern/sched.h>
63: #include <kern/sched_prim.h>
64: #include <kern/assert.h>
65: #include <kern/thread.h>
66: #include <mach/mach_host_server.h>
67:
68: /* Forwards */
69: void _mk_sp_thread_depress_priority(
70: sf_object_t policy,
71: mach_msg_timeout_t depress_time);
72:
73: /***
74: *** ??? The next two files supply the prototypes for `thread_set_policy()'
75: *** and `thread_policy.' These routines cannot stay here if they are
76: *** exported Mach system calls.
77: ***/
78: #include <mach/thread_act_server.h>
79: #include <mach/host_priv_server.h>
80:
81: /*
82: * Vector containing standard scheduling policy operations
83: */
84: sp_ops_t mk_sp_ops = {
85: _mk_sp_init,
86: _mk_sp_enable_processor_set,
87: _mk_sp_disable_processor_set,
88: _mk_sp_enable_processor,
89: _mk_sp_disable_processor,
90: _mk_sp_thread_update_mpri,
91: _mk_sp_thread_unblock,
92: _mk_sp_thread_done,
93: _mk_sp_thread_begin,
94: _mk_sp_thread_dispatch,
95: _mk_sp_thread_attach,
96: _mk_sp_thread_detach,
97: _mk_sp_thread_processor,
98: _mk_sp_thread_processor_set,
99: _mk_sp_thread_set,
100: _mk_sp_thread_get,
101: _mk_sp_db_print_sched_stats,
102: _mk_sp_swtch_pri,
103: _mk_sp_thread_switch,
104: _mk_sp_thread_depress_abort,
105: _mk_sp_thread_depress_timeout,
106: _mk_sp_task_attach,
107: _mk_sp_task_detach,
108: _mk_sp_task_policy,
109: _mk_sp_task_set_policy,
110: _mk_sp_task_set_sched,
111: _mk_sp_task_get_sched,
112: _mk_sp_thread_runnable,
113: _mk_sp_alarm_expired
114: };
115:
116: /* Forwards */
117: kern_return_t thread_policy_common(
118: thread_t thread,
119: int policy,
120: int data,
121: processor_set_t pset);
122:
123: void _mk_sp_thread_dump(
124: sched_thread_t thread);
125:
126: /*
127: * Local variables
128: */
129: #ifdef MACH_ASSERT
130: boolean_t mk_sp_first_thread = TRUE;
131: #endif /* MACH_ASSERT */
132:
133: /*
134: * Counters to monitor policy-related events
135: */
136: mach_counter_t c_mk_sp_init = 0,
137: c_mk_sp_enable_processor_set = 0,
138: c_mk_sp_disable_processor_set = 0,
139: c_mk_sp_enable_processor = 0,
140: c_mk_sp_disable_processor = 0,
141: c_mk_sp_thread_update_mpri = 0,
142: c_mk_sp_thread_unblock = 0,
143: c_mk_sp_thread_done = 0,
144: c_mk_sp_thread_begin = 0,
145: c_mk_sp_thread_dispatch = 0,
146: c_mk_sp_thread_attach = 0,
147: c_mk_sp_thread_detach = 0,
148: c_mk_sp_thread_processor = 0,
149: c_mk_sp_thread_processor_set = 0,
150: c_mk_sp_thread_set = 0,
151: c_mk_sp_thread_get = 0,
152: c_mk_sp_db_print_sched_stats = 0,
153: c_mk_sp_swtch_pri = 0,
154: c_mk_sp_thread_switch = 0,
155: c_mk_sp_thread_depress_abort = 0,
156: c_mk_sp_thread_depress_timeout = 0,
157: c_mk_sp_task_attach = 0,
158: c_mk_sp_task_detach = 0,
159: c_mk_sp_task_policy = 0,
160: c_mk_sp_task_set_policy = 0,
161: c_mk_sp_task_set_sched = 0,
162: c_mk_sp_task_get_sched = 0,
163: c_mk_sp_thread_runnable = 0,
164: c_mk_sp_alarm_expired = 0;
165:
166: /*
167: * Table to convert computed priorities into allocated priority range.
168: */
169: int convert_pri[NRQS];
170:
171: /*
172: * Lowest (normal -- i.e., not idle and not depressed) priority
173: */
174: int lpri = -1;
175:
176: natural_t min_quantum_ms;
177:
178: /*
179: * Standard operations for MK Scheduling Policy
180: */
181:
182: sf_return_t
183: _mk_sp_init(
184: sf_object_t policy,
185: int policy_id,
186: int priority_mask_length,
187: sf_priority_mask_t priority_mask)
188: {
189: int i;
190: int first_metapri;
191: int last_metapri;
192:
193: counter(c_mk_sp_init++);
194:
195: /*
196: * Initialize fields in the structure
197: */
198: policy->policy_id = policy_id;
199: policy->priority_mask_length = priority_mask_length;
200: policy->priority_mask = *priority_mask;
201: /*** ??? should something more dynamic be done here for mask? ***/
202: policy->sched_attributes_size = sizeof (mk_sp_attribute_struct_t);
203: policy->sched_info_size = sizeof (mk_sp_info_struct_t);
204:
205: /*
206: * Initialize table that maps computed priority values into
207: * allocated metapriority values.
208: */
209:
210: /* Find first metapriority value allocated to this policy */
211: first_metapri = MAXPRI - ffsbit(priority_mask->bitmap);
212: /*** ??? how to test for no set bits? ***/
213:
214: /* Map computed priorities higher than this to first metapriority */
215: for (i = MAXPRI; i > first_metapri; i--)
216: convert_pri[i] = first_metapri;
217:
218: /* For each remaining computed priority value... */
219: for (i = first_metapri; i >= 0; i--) {
220: /* ... is it a metapriority value assigned to this policy ?*/
221: if (testbit(MAXPRI - i, priority_mask->bitmap)) {
222: /* Yes; just use it */
223: convert_pri[i] = i;
224: last_metapri = i;
225: }
226: else {
227: /* No, bump it up to the last value assigned */
228: convert_pri[i] = last_metapri;
229: }
230: }
231:
232: /* Remember lowest "normal" priority available to this policy */
233: lpri = convert_pri[LPRI];
234:
235: min_quantum_ms = (1000 / hz) * min_quantum;
236:
237: #if 0
238: /* Initialize operation entries in "jump table" */
239: /***
240: *** ??? These must be done elsewhere. Otherwise, there is a
241: *** circularity: How does the framework find this init operation?
242: ***/
243: policy->sp_ops = mk_sp_ops;
244:
245: policy->sp_ops.sp_enable_processor_set = sp_mk_enable_processor_set;
246: policy->sp_ops.sp_disable_processor_set = sp_mk_disable_processor_set;
247: policy->sp_ops.sp_enable_processor = sp_mk_enable_processor;
248: policy->sp_ops.sp_disable_processor = sp_mk_disable_processor;
249: policy->sp_ops.sp_thread_unblock = sp_mk_thread_unblock;
250: policy->sp_ops.sp_thread_done = sp_mk_thread_done;
251: policy->sp_ops.sp_thread_begin = sp_mk_thread_begin;
252: policy->sp_ops.sp_thread_attach = sp_mk_thread_attach;
253: policy->sp_ops.sp_thread_detach = sp_mk_thread_detach;
254: policy->sp_ops.sp_thread_processor = sp_mk_thread_processor;
255: policy->sp_ops.sp_thread_processor_set = sp_mk_thread_processor_set;
256: policy->sp_ops.sp_thread_set = sp_mk_thread_set;
257: policy->sp_ops.sp_thread_get = sp_mk_thread_get;
258: policy->sp_ops.sp_db_print_sched_stats = sp_mk_db_print_sched_stats;
259: #endif
260:
261: return(SF_SUCCESS);
262: }
263:
264: sf_return_t
265: _mk_sp_enable_processor_set(
266: sf_object_t policy,
267: processor_set_t processor_set)
268: {
269: kern_return_t result;
270:
271: counter(c_mk_sp_enable_processor_set++);
272:
273: result = processor_set_policy_enable(processor_set, policy->policy_id);
274: assert(result == KERN_SUCCESS);
275:
276: return(SF_SUCCESS);
277: }
278:
279: sf_return_t
280: _mk_sp_disable_processor_set(
281: sf_object_t policy,
282: processor_set_t processor_set)
283: {
284: kern_return_t result;
285:
286: counter(c_mk_sp_disable_processor_set++);
287:
288: result = processor_set_policy_disable(
289: processor_set, policy->policy_id, TRUE);
290: assert(result == KERN_SUCCESS);
291:
292: return(SF_SUCCESS);
293: }
294:
295: sf_return_t
296: _mk_sp_enable_processor(
297: sf_object_t policy,
298: processor_t processor)
299: {
300: counter(c_mk_sp_enable_processor++);
301:
302: panic("not yet implemented???");
303:
304: return(SF_FAILURE);
305: }
306:
307: sf_return_t
308: _mk_sp_disable_processor(
309: sf_object_t policy,
310: processor_t processor)
311: {
312: counter(c_mk_sp_disable_processor++);
313:
314: panic("not yet implemented???");
315:
316: return(SF_FAILURE);
317: }
318:
319: sf_return_t
320: _mk_sp_thread_update_mpri(
321: sf_object_t policy,
322: sched_thread_t thread)
323: {
324: mk_sp_info_t sp_info;
325:
326: counter(c_mk_sp_thread_update_mpri++);
327:
328: /* get pointer to scheduling policy-specific data */
329: assert(thread->sp_info != SP_INFO_NULL);
330: sp_info = (mk_sp_info_t)thread->sp_info;
331:
332: if (sp_info->sched_stamp != sched_tick)
333: update_priority(thread);
334:
335: return(SF_SUCCESS);
336: }
337:
338: sf_return_t
339: _mk_sp_thread_unblock(
340: sf_object_t policy,
341: sched_thread_t thread)
342: {
343: mk_sp_info_t sp_info;
344:
345: counter(c_mk_sp_thread_unblock++);
346:
347: /* get pointer to scheduling policy-specific data */
348: assert(thread->sp_info != SP_INFO_NULL);
349: sp_info = (mk_sp_info_t)thread->sp_info;
350:
351: counter(sp_info->c_mk_sp_thread_unblock++);
352:
353: /*
354: * The following assert is removed because we're hacking the
355: * MK_SP_BLOCKED bit and removing it early to get SMP to work
356: * with this gosh darned scheduler. The whole danged thing is lousy and
357: * needs to be removed. Hopefully for now, no one tries to
358: * unblock a really runnable guy - HACKALERT!!!
359: */
360:
361: /* check for legal thread states */
362: #if 0
363: assert(sp_info->th_state == MK_SP_BLOCKED ||
364: sp_info->th_state == MK_SP_ATTACHED); /* ??? work to remove*/
365: #endif
366: /* indicate thread is now runnable */
367: sp_info->th_state = MK_SP_RUNNABLE;
368:
369: /* place thread at end of appropriate run queue */
370: thread_setrun(thread, TRUE, TAIL_Q);
371:
372: return(SF_SUCCESS);
373: }
374:
375: sf_return_t
376: _mk_sp_thread_done(
377: sf_object_t policy,
378: sched_thread_t old_thread)
379: {
380: processor_t myprocessor = cpu_to_processor(cpu_number());
381: mk_sp_info_t sp_info;
382:
383: counter(c_mk_sp_thread_done++);
384:
385: /*
386: * A running thread is being taken off a processor:
387: *
388: * - update the thread's `unconsumed_quantum' field
389: * - update the thread's state field
390: */
391:
392: /* get pointer to scheduling policy-specific data */
393: assert(old_thread->sp_info != SP_INFO_NULL);
394: sp_info = (mk_sp_info_t)old_thread->sp_info;
395:
396: counter(sp_info->c_mk_sp_thread_done++);
397: assert((sp_info->c_mk_sp_thread_done
398: == sp_info->c_mk_sp_thread_begin + 1) ||
399: (sp_info->c_mk_sp_thread_done
400: == sp_info->c_mk_sp_thread_begin));
401:
402: sp_info->unconsumed_quantum = myprocessor->quantum;
403:
404: /* check thread's current state */
405: assert(mk_sp_first_thread || (sp_info->th_state & MK_SP_RUNNABLE));
406: #ifdef MACH_ASSERT
407: mk_sp_first_thread = FALSE;
408: #endif /* MACH_ASSERT */
409:
410: /* update thread's state field based on reason for stopping now */
411: /*** ??? is this condition correct? should it be more selective? ***/
412: /*** ??? if ((old_thread->reason != AST_NONE) ||
413: (old_thread->wait_event != NO_EVENT)) { ***/
414: if (old_thread->state & TH_WAIT) {
415: sp_info->th_state = MK_SP_BLOCKED;
416: }
417:
418: return(SF_SUCCESS);
419: }
420:
421: sf_return_t
422: _mk_sp_thread_begin(
423: sf_object_t policy,
424: sched_thread_t thread)
425: {
426:
427: processor_t myprocessor = cpu_to_processor(cpu_number());
428: processor_set_t pset;
429: mk_sp_info_t sp_info;
430:
431: counter(c_mk_sp_thread_begin++);
432:
433: pset = myprocessor->processor_set;
434: /*
435: * The designated thread is about to begin execution:
436: *
437: * - update the processor's `quantum' field
438: */
439:
440: /* get pointer to scheduling policy-specific data */
441: assert(thread->sp_info != SP_INFO_NULL);
442: sp_info = (mk_sp_info_t)thread->sp_info;
443:
444: counter(sp_info->c_mk_sp_thread_begin++);
445: assert((sp_info->c_mk_sp_thread_done
446: == sp_info->c_mk_sp_thread_begin) ||
447: (sp_info->c_mk_sp_thread_done + 1
448: == sp_info->c_mk_sp_thread_begin));
449:
450: /* check for legal thread state */
451: assert(sp_info->th_state == MK_SP_RUNNABLE);
452:
453: if (thread->policy & (POLICY_RR|POLICY_FIFO))
454: myprocessor->quantum = sp_info->unconsumed_quantum;
455: else
456: myprocessor->quantum = (thread->bound_processor ?
457: min_quantum : pset->set_quantum);
458:
459: return(SF_SUCCESS);
460: }
461:
462: sf_return_t
463: _mk_sp_thread_dispatch(
464: sf_object_t policy,
465: sched_thread_t old_thread)
466: {
467: mk_sp_info_t sp_info;
468:
469: counter(c_mk_sp_thread_dispatch++);
470:
471: /* get pointer to scheduling policy-specific data */
472: assert(old_thread->sp_info != SP_INFO_NULL);
473: sp_info = (mk_sp_info_t)old_thread->sp_info;
474:
475: counter(sp_info->c_mk_sp_thread_dispatch++);
476:
477: if (sp_info->th_state & MK_SP_RUNNABLE) {
478: if (old_thread->reason & AST_QUANTUM) {
479: thread_setrun(old_thread, FALSE, TAIL_Q);
480: sp_info->unconsumed_quantum = sp_info->sched_data;
481: }
482: else
483: thread_setrun(old_thread, FALSE, HEAD_Q);
484: }
485:
486: if (sp_info->th_state & MK_SP_ATTACHED) {
487: /* indicate thread is now runnable */
488: sp_info->th_state = MK_SP_RUNNABLE;
489:
490: /* place thread at end of appropriate run queue */
491: thread_setrun(old_thread, FALSE, TAIL_Q);
492: }
493:
494: return(SF_SUCCESS);
495: }
496:
497: /*
498: * Thread must already be locked.
499: */
500: sf_return_t
501: _mk_sp_thread_attach(
502: sf_object_t policy,
503: sched_thread_t thread)
504: {
505: mk_sp_info_t sp_info;
506:
507: counter(c_mk_sp_thread_attach++);
508:
509: /* Make sure there is a place for policy-specific state */
510: assert(thread->sp_info != SP_INFO_NULL);
511:
512: sp_info = (mk_sp_info_t)thread->sp_info;
513: sp_info->th_state = MK_SP_ATTACHED;
514: /*** ??? Do these need to be done here? ***/
515: /*** ??? If so, could fill from template for speed -- maybe ***/
516: sp_info->priority = MINPRI; /*** ??? ***/
517: sp_info->max_priority = BASEPRI_USER;
518: /*** ??? sp_info->sched_pri =
519: (later - compute_priority); (for now, at least) ***/
520: sp_info->sched_data = 0;
521: sp_info->policy = policy->policy_id; /*** ??? ***/
522: sp_info->depress_priority = -1;
523: sp_info->cpu_usage = 0;
524: sp_info->sched_usage = 0;
525: sp_info->sched_stamp = 0; /*** ??? ***/
526: sp_info->unconsumed_quantum = 0; /*** ??? ***/
527:
528: #ifdef MACH_ASSERT
529: sp_info->c_mk_sp_thread_attach = 1;
530: sp_info->c_mk_sp_thread_detach = 0;
531: sp_info->c_mk_sp_thread_begin = 0;
532: sp_info->c_mk_sp_thread_done = 0;
533: sp_info->c_mk_sp_thread_dispatch = 0;
534: sp_info->c_mk_sp_thread_unblock = 0;
535: sp_info->c_mk_sp_thread_set = 0;
536: sp_info->c_mk_sp_thread_get = 0;
537: #endif /* MACH_ASSERT */
538:
539: /* Reflect this policy in thread data structure */
540: thread->policy = policy->policy_id;
541:
542: return(SF_SUCCESS);
543: }
544:
545: /*
546: * Check to make sure that thread is removed from run
547: * queues and active execution; and clean up the
548: * policy-specific data structure for thread.
549: *
550: * Thread must already be locked.
551: */
552: sf_return_t
553: _mk_sp_thread_detach(
554: sf_object_t policy,
555: sched_thread_t thread)
556: {
557: mk_sp_info_t sp_info;
558: struct run_queue *rq;
559:
560: assert(thread->policy == policy->policy_id);
561:
562: counter(c_mk_sp_thread_detach++);
563: /* get pointer to scheduling policy-specific data */
564: assert(thread->sp_info != SP_INFO_NULL);
565: sp_info = (mk_sp_info_t)thread->sp_info;
566:
567: counter(sp_info->c_mk_sp_thread_detach++);
568:
569: /* make sure that the thread has stopped executing */
570: /*** ??? look at machine's version of RUN bit, too? ***/
571: /***
572: *** Fix for SMP case.
573: ***/
574:
575: /* make sure that the thread is no longer on any run queue */
576: if (thread->runq != RUN_QUEUE_NULL) {
577: rq = rem_runq(thread);
578: if (rq == RUN_QUEUE_NULL) {
579: panic("mk_sp_thread_detach: missed thread");
580: }
581: }
582:
583: /* (optionally) clear policy-specific data structure for the thread */
584:
585: if (sp_info->depress_priority >= 0) {
586: sp_info->priority = sp_info->depress_priority;
587: sp_info->depress_priority = -1;
588: if (thread_call_cancel(&thread->depress_timer))
589: thread_call_enter(&thread->depress_timer);
590: }
591:
592: /* clear the thread's policy field */
593: thread->policy = POLICY_NULL;
594:
595: return(SF_SUCCESS);
596: }
597:
598: sf_return_t
599: _mk_sp_thread_processor(
600: sf_object_t policy,
601: sched_thread_t *thread,
602: processor_t processor)
603: {
604: counter(c_mk_sp_thread_processor++);
605:
606: panic("not yet implemented???");
607:
608: return(SF_FAILURE);
609: }
610:
611: sf_return_t
612: _mk_sp_thread_processor_set(
613: sf_object_t policy,
614: sched_thread_t thread,
615: processor_set_t processor_set)
616: {
617: counter(c_mk_sp_thread_processor_set++);
618:
619: pset_add_thread(processor_set, thread);
620:
621: return(SF_SUCCESS);
622: }
623:
624: sf_return_t
625: _mk_sp_thread_set(
626: sf_object_t policy,
627: sched_thread_t thread,
628: sp_attributes_t policy_attributes)
629: {
630: mk_sp_info_t sp_info;
631: mk_sp_attributes_t attributes;
632:
633: counter(c_mk_sp_thread_set++);
634:
635: /* check that attributes are for this policy */
636: assert(policy_attributes->policy_id == policy->policy_id);
637:
638: attributes = (mk_sp_attributes_t)policy_attributes;
639:
640: /* get pointer to scheduling policy-specific data */
641: assert(thread->sp_info != SP_INFO_NULL);
642: sp_info = (mk_sp_info_t)thread->sp_info;
643:
644: counter(sp_info->c_mk_sp_thread_set++);
645:
646: /* update scheduling parameters */
647: sp_info->priority = attributes->priority;
648: sp_info->max_priority = attributes->max_priority;
649: sp_info->sched_data = attributes->sched_data;
650: sp_info->unconsumed_quantum = attributes->unconsumed_quantum;
651:
652: /*
653: * No check is needed against the pset limit. If the task could raise
654: * its priority above the limit, then it must have had permisssion.
655: */
656:
657: /*
658: * Determine thread's state. (It may be an "older" thread
659: * that has just been associated with this policy.)
660: */
661: if (thread->state & TH_WAIT) {
662: sp_info->th_state = MK_SP_BLOCKED;
663: }
664:
665: /* recompute priority */
666: sp_info->sched_stamp = sched_tick;
667: compute_priority(thread, TRUE);
668:
669: return(SF_SUCCESS);
670: }
671:
672: sf_return_t
673: _mk_sp_thread_get(
674: sf_object_t policy,
675: sched_thread_t thread,
676: sp_attributes_t policy_attributes,
677: sp_attributes_size_t size)
678: /*
679: * Assumes that thread is locked.
680: */
681: /***
682: *** ??? Does it assume `splsched()'?
683: ***/
684: {
685: mk_sp_info_t sp_info;
686: mk_sp_attributes_t attributes;
687:
688: counter(c_mk_sp_thread_get++);
689:
690: /* check size of attribute structure provided by caller */
691: if (policy->sched_attributes_size > size)
692: return(SF_FAILURE);
693:
694: attributes = (mk_sp_attributes_t)policy_attributes;
695:
696:
697: /* get pointer to scheduling policy-specific data */
698: assert(thread->sp_info != SP_INFO_NULL);
699: sp_info = (mk_sp_info_t)thread->sp_info;
700:
701: counter(sp_info->c_mk_sp_thread_get++);
702:
703: /* copy scheduling attributes */
704: attributes->policy_id = policy->policy_id;
705: attributes->priority = sp_info->priority;
706: attributes->max_priority = sp_info->max_priority;
707: attributes->sched_data = sp_info->sched_data;
708: attributes->unconsumed_quantum = sp_info->unconsumed_quantum;
709:
710: return(SF_SUCCESS);
711: }
712:
713: int
714: _mk_sp_db_print_sched_stats(
715: sf_object_t policy,
716: sched_thread_t thread)
717: {
718: mk_sp_info_t sp_info;
719:
720: counter(c_mk_sp_db_print_sched_stats++);
721:
722: /* get pointer to scheduling policy-specific data */
723: assert(thread->sp_info != SP_INFO_NULL);
724: sp_info = (mk_sp_info_t)thread->sp_info;
725:
726: /* print one field -- `sched_pri' */
727: return (thread->sched_pri);
728: }
729:
730: /*
731: * thread_priority:
732: *
733: * Set priority (and possibly max priority) for thread.
734: */
735: kern_return_t
736: thread_priority(
737: thread_act_t thr_act,
738: int priority,
739: boolean_t set_max)
740: {
741: kern_return_t result;
742: thread_t thread;
743:
744: if (thr_act == THR_ACT_NULL)
745: return (KERN_INVALID_ARGUMENT);
746:
747: thread = act_lock_thread(thr_act);
748: if (thread == THREAD_NULL || invalid_pri(priority)) {
749: act_unlock_thread(thr_act);
750: return (KERN_INVALID_ARGUMENT);
751: }
752:
753: result = thread_priority_locked(thread, priority, set_max);
754: act_unlock_thread(thr_act);
755:
756: return (result);
757: }
758:
759: /*
760: * thread_priority_locked:
761: *
762: * Kernel-internal work function for thread_priority(). Called
763: * with thread "properly locked" to ensure synchrony with RPC
764: * (see act_lock_thread()).
765: */
766: kern_return_t
767: thread_priority_locked(
768: thread_t thread,
769: int priority,
770: boolean_t set_max)
771: {
772: kern_return_t result = KERN_SUCCESS;
773: mk_sp_info_t sched_info;
774: spl_t s;
775:
776: s = splsched();
777: thread_lock(thread);
778:
779: /* get pointer to scheduling policy-specific data */
780: assert(thread->sp_info != SP_INFO_NULL);
781: sched_info = (mk_sp_info_t)thread->sp_info;
782:
783: /*
784: * Check for violation of max priority
785: */
786: if (priority > sched_info->max_priority)
787: result = KERN_FAILURE;
788: else {
789: /*
790: * Set priorities. If a depression is in progress,
791: * change the priority to restore.
792: */
793: if (sched_info->depress_priority >= 0) {
794: sched_info->depress_priority = priority;
795: }
796: else {
797: sched_info->priority = priority;
798: compute_priority(thread, TRUE);
799:
800: /*
801: * If the current thread has changed its
802: * priority let the ast code decide whether
803: * a different thread should run.
804: */
805: if (thread == current_thread())
806: ast_on(AST_BLOCK);
807: }
808:
809: if (set_max)
810: sched_info->max_priority = priority;
811: }
812:
813: thread_unlock(thread);
814: splx(s);
815:
816: return(result);
817: }
818:
819: /*
820: * thread_set_own_priority:
821: *
822: * Internal use only; sets the priority of the calling thread.
823: * Will adjust max_priority if necessary.
824: */
825: void
826: thread_set_own_priority(
827: int priority)
828: {
829: thread_t thread = current_thread();
830: mk_sp_info_t sched_info;
831: spl_t s;
832:
833: s = splsched();
834: thread_lock(thread);
835:
836: /* get pointer to scheduling policy-specific data */
837: assert(thread->sp_info != SP_INFO_NULL);
838: sched_info = (mk_sp_info_t)thread->sp_info;
839:
840: if (priority > sched_info->max_priority)
841: sched_info->max_priority = priority;
842: sched_info->priority = priority;
843: compute_priority(thread, TRUE);
844:
845: thread_unlock(thread);
846: splx(s);
847: }
848:
849: /*
850: * thread_max_priority:
851: *
852: * Reset the max priority for a thread.
853: */
854: kern_return_t
855: thread_max_priority(
856: thread_act_t thr_act,
857: processor_set_t pset,
858: int max_priority)
859: {
860: thread_t thread;
861: kern_return_t result = KERN_SUCCESS;
862:
863: if (thr_act == THR_ACT_NULL)
864: return(KERN_INVALID_ARGUMENT);
865:
866: thread = act_lock_thread(thr_act);
867: if (thread == THREAD_NULL || pset == PROCESSOR_SET_NULL ||
868: invalid_pri(max_priority)) {
869: act_unlock_thread(thr_act);
870: return(KERN_INVALID_ARGUMENT);
871: }
872:
873: result = thread_max_priority_locked(thread, pset, max_priority);
874: act_unlock_thread(thr_act);
875:
876: return (result);
877: }
878:
879: /*
880: * thread_max_priority_locked:
881: *
882: * Work function for thread_max_priority.
883: *
884: * Called with all RPC-related locks held for thread (see
885: * act_lock_thread()).
886: */
887: kern_return_t
888: thread_max_priority_locked(
889: thread_t thread,
890: processor_set_t pset,
891: int max_priority)
892: {
893: kern_return_t result = KERN_SUCCESS;
894: mk_sp_info_t sched_info;
895: spl_t s;
896:
897: s = splsched();
898: thread_lock(thread);
899:
900: /* get pointer to scheduling policy-specific data */
901: assert(thread->sp_info != SP_INFO_NULL);
902: sched_info = (mk_sp_info_t)thread->sp_info;
903:
904: #if MACH_HOST
905: /*
906: * Check for wrong processor set.
907: */
908: if (pset != thread->processor_set)
909: result = KERN_FAILURE;
910: else {
911: #endif /* MACH_HOST */
912: sched_info->max_priority = max_priority;
913:
914: /*
915: * Reset priority if it violates new max priority
916: */
917: if (max_priority < sched_info->priority) {
918: sched_info->priority = max_priority;
919:
920: compute_priority(thread, TRUE);
921: }
922: else if (sched_info->depress_priority >= 0 &&
923: max_priority < sched_info->depress_priority)
924: sched_info->depress_priority = max_priority;
925: #if MACH_HOST
926: }
927: #endif /* MACH_HOST */
928:
929: thread_unlock(thread);
930: splx(s);
931:
932: return(result);
933: }
934:
935: /*
936: * thread_policy_common:
937: *
938: * Set scheduling policy for thread. If pset == PROCESSOR_SET_NULL,
939: * policy will be checked to make sure it is enabled.
940: */
941: kern_return_t
942: thread_policy_common(
943: thread_t thread,
944: int policy,
945: int data,
946: processor_set_t pset)
947: {
948: kern_return_t result = KERN_SUCCESS;
949: mk_sp_info_t sched_info;
950: register int temp;
951: spl_t s;
952:
953: if (thread == THREAD_NULL || invalid_policy(policy))
954: return(KERN_INVALID_ARGUMENT);
955:
956: s = splsched();
957: thread_lock(thread);
958:
959: /* get pointer to scheduling policy-specific data */
960: assert(thread->sp_info != SP_INFO_NULL);
961: sched_info = (mk_sp_info_t)thread->sp_info;
962:
963: /*
964: * Check if changing policy.
965: */
966: if (policy == thread->policy) {
967: /*
968: * Just changing data. This is meaningless for
969: * timeshareing, quantum for fixed priority (but
970: * has no effect until current quantum runs out).
971: */
972: if (policy == POLICY_FIFO || policy == POLICY_RR) {
973: temp = data * 1000;
974: if (temp % tick)
975: temp += tick;
976: sched_info->sched_data = temp/tick;
977: sched_info->unconsumed_quantum = temp/tick;
978: }
979: }
980: else {
981: /*
982: * Changing policy. Check if new policy is allowed.
983: */
984: if (pset == PROCESSOR_SET_NULL &&
985: (thread->processor_set->policies & policy) == 0) {
986: result = KERN_FAILURE;
987: }
988: else {
989: if (pset != thread->processor_set) {
990: result = KERN_FAILURE;
991: }
992: else {
993: /*
994: * Changing policy. Save data and calculate new
995: * priority.
996: */
997: thread->policy = policy;
998: sched_info->policy = policy;
999: if (policy == POLICY_FIFO || policy == POLICY_RR) {
1000: temp = data * 1000;
1001: if (temp % tick)
1002: temp += tick;
1003: sched_info->sched_data = temp/tick;
1004: sched_info->unconsumed_quantum = temp/tick;
1005: }
1006: compute_priority(thread, TRUE);
1007: }
1008: }
1009: }
1010:
1011: thread_unlock(thread);
1012: splx(s);
1013:
1014: return(result);
1015: }
1016:
1017: /*
1018: * thread_set_policy
1019: *
1020: * Set scheduling policy and parameters, both base and limit, for
1021: * the given thread. Policy can be any policy implemented by the
1022: * processor set, whether enabled or not.
1023: */
1024: kern_return_t
1025: thread_set_policy(
1026: thread_act_t thr_act,
1027: processor_set_t pset,
1028: policy_t policy,
1029: policy_base_t base,
1030: mach_msg_type_number_t base_count,
1031: policy_limit_t limit,
1032: mach_msg_type_number_t limit_count)
1033: {
1034: thread_t thread;
1035: int max, bas, dat;
1036: kern_return_t result = KERN_SUCCESS;
1037:
1038: if (thr_act == THR_ACT_NULL || pset == PROCESSOR_SET_NULL)
1039: return (KERN_INVALID_ARGUMENT);
1040:
1041: thread = act_lock_thread(thr_act);
1042: if (thread == THREAD_NULL) {
1043: act_unlock_thread(thr_act);
1044: return(KERN_INVALID_ARGUMENT);
1045: }
1046:
1047: if (pset != thread->processor_set) {
1048: act_unlock_thread(thr_act);
1049: return(KERN_FAILURE);
1050: }
1051:
1052: switch (policy) {
1053: case POLICY_RR:
1054: {
1055: policy_rr_base_t rr_base = (policy_rr_base_t) base;
1056: policy_rr_limit_t rr_limit = (policy_rr_limit_t) limit;
1057:
1058: if (base_count != POLICY_RR_BASE_COUNT ||
1059: limit_count != POLICY_RR_LIMIT_COUNT) {
1060: result = KERN_INVALID_ARGUMENT;
1061: break;
1062: }
1063: dat = rr_base->quantum;
1064: bas = rr_base->base_priority;
1065: max = rr_limit->max_priority;
1066: if (invalid_pri(bas) || invalid_pri(max)) {
1067: result = KERN_INVALID_ARGUMENT;
1068: break;
1069: }
1070: break;
1071: }
1072:
1073: case POLICY_FIFO:
1074: {
1075: policy_fifo_base_t fifo_base = (policy_fifo_base_t) base;
1076: policy_fifo_limit_t fifo_limit = (policy_fifo_limit_t) limit;
1077:
1078: if (base_count != POLICY_FIFO_BASE_COUNT ||
1079: limit_count != POLICY_FIFO_LIMIT_COUNT) {
1080: result = KERN_INVALID_ARGUMENT;
1081: break;
1082: }
1083: dat = 0;
1084: bas = fifo_base->base_priority;
1085: max = fifo_limit->max_priority;
1086: if (invalid_pri(bas) || invalid_pri(max)) {
1087: result = KERN_INVALID_ARGUMENT;
1088: break;
1089: }
1090: break;
1091: }
1092:
1093: case POLICY_TIMESHARE:
1094: {
1095: policy_timeshare_base_t ts_base =
1096: (policy_timeshare_base_t) base;
1097: policy_timeshare_limit_t ts_limit =
1098: (policy_timeshare_limit_t) limit;
1099:
1100: if (base_count != POLICY_TIMESHARE_BASE_COUNT ||
1101: limit_count != POLICY_TIMESHARE_LIMIT_COUNT) {
1102: result = KERN_INVALID_ARGUMENT;
1103: break;
1104: }
1105: dat = 0;
1106: bas = ts_base->base_priority;
1107: max = ts_limit->max_priority;
1108: if (invalid_pri(bas) || invalid_pri(max)) {
1109: result = KERN_INVALID_ARGUMENT;
1110: break;
1111: }
1112: break;
1113: }
1114:
1115: default:
1116: result = KERN_INVALID_POLICY;
1117: }
1118:
1119: if (result != KERN_SUCCESS) {
1120: act_unlock_thread(thr_act);
1121: return(result);
1122: }
1123:
1124: /*
1125: * We've already checked the inputs for thread_max_priority,
1126: * so it's safe to ignore the return value.
1127: */
1128: (void) thread_max_priority_locked(thread, pset, max);
1129: result = thread_priority_locked(thread, bas, FALSE);
1130: if (result == KERN_SUCCESS)
1131: result = thread_policy_common(thread, policy, dat, pset);
1132: act_unlock_thread(thr_act);
1133: return(result);
1134: }
1135:
1136:
1137: /*
1138: * thread_policy
1139: *
1140: * Set scheduling policy and parameters, both base and limit, for
1141: * the given thread. Policy must be a policy which is enabled for the
1142: * processor set. Change contained threads if requested.
1143: */
1144: kern_return_t
1145: thread_policy(
1146: thread_act_t thr_act,
1147: policy_t policy,
1148: policy_base_t base,
1149: mach_msg_type_number_t count,
1150: boolean_t set_limit)
1151: {
1152: thread_t thread;
1153: processor_set_t pset;
1154: mk_sp_info_t sched_info;
1155: kern_return_t result = KERN_SUCCESS;
1156: policy_limit_t limit;
1157: policy_rr_limit_data_t rr_limit;
1158: policy_fifo_limit_data_t fifo_limit;
1159: policy_timeshare_limit_data_t ts_limit;
1160: int limcount;
1161:
1162: if (thr_act == THR_ACT_NULL)
1163: return (KERN_INVALID_ARGUMENT);
1164:
1165: thread = act_lock_thread(thr_act);
1166: pset = thread->processor_set;
1167: if (thread == THREAD_NULL || pset == PROCESSOR_SET_NULL) {
1168: act_unlock_thread(thr_act);
1169: return(KERN_INVALID_ARGUMENT);
1170: }
1171:
1172: if (invalid_policy(policy) || (pset->policies & policy) == 0) {
1173: act_unlock_thread(thr_act);
1174: return(KERN_INVALID_POLICY);
1175: }
1176:
1177: /* get pointer to scheduling policy-specific data */
1178: assert(thread->sp_info != SP_INFO_NULL);
1179: sched_info = (mk_sp_info_t)thread->sp_info;
1180:
1181: if (set_limit) {
1182: /*
1183: * Set scheduling limits to base priority.
1184: */
1185: switch (policy) {
1186: case POLICY_RR:
1187: {
1188: policy_rr_base_t rr_base;
1189:
1190: if (count != POLICY_RR_BASE_COUNT) {
1191: result = KERN_INVALID_ARGUMENT;
1192: break;
1193: }
1194: limcount = POLICY_RR_LIMIT_COUNT;
1195: rr_base = (policy_rr_base_t) base;
1196: rr_limit.max_priority = rr_base->base_priority;
1197: limit = (policy_limit_t) &rr_limit;
1198: break;
1199: }
1200:
1201: case POLICY_FIFO:
1202: {
1203: policy_fifo_base_t fifo_base;
1204:
1205: if (count != POLICY_FIFO_BASE_COUNT) {
1206: result = KERN_INVALID_ARGUMENT;
1207: break;
1208: }
1209: limcount = POLICY_FIFO_LIMIT_COUNT;
1210: fifo_base = (policy_fifo_base_t) base;
1211: fifo_limit.max_priority = fifo_base->base_priority;
1212: limit = (policy_limit_t) &fifo_limit;
1213: break;
1214: }
1215:
1216: case POLICY_TIMESHARE:
1217: {
1218: policy_timeshare_base_t ts_base;
1219:
1220: if (count != POLICY_TIMESHARE_BASE_COUNT) {
1221: result = KERN_INVALID_ARGUMENT;
1222: break;
1223: }
1224: limcount = POLICY_TIMESHARE_LIMIT_COUNT;
1225: ts_base = (policy_timeshare_base_t) base;
1226: ts_limit.max_priority = ts_base->base_priority;
1227: limit = (policy_limit_t) &ts_limit;
1228: break;
1229: }
1230:
1231: default:
1232: result = KERN_INVALID_POLICY;
1233: break;
1234: }
1235:
1236: } else {
1237: /*
1238: * Use current scheduling limits. Ensure that the
1239: * new base priority will not exceed current limits.
1240: */
1241: switch (policy) {
1242: case POLICY_RR:
1243: {
1244: policy_rr_base_t rr_base;
1245:
1246: if (count != POLICY_RR_BASE_COUNT) {
1247: result = KERN_INVALID_ARGUMENT;
1248: break;
1249: }
1250: limcount = POLICY_RR_LIMIT_COUNT;
1251: rr_base = (policy_rr_base_t) base;
1252: if (rr_base->base_priority >
1253: sched_info->max_priority) {
1254: result = KERN_POLICY_LIMIT;
1255: break;
1256: }
1257: rr_limit.max_priority = sched_info->max_priority;
1258: limit = (policy_limit_t) &rr_limit;
1259: break;
1260: }
1261:
1262: case POLICY_FIFO:
1263: {
1264: policy_fifo_base_t fifo_base;
1265:
1266: if (count != POLICY_FIFO_BASE_COUNT) {
1267: result = KERN_INVALID_ARGUMENT;
1268: break;
1269: }
1270: limcount = POLICY_FIFO_LIMIT_COUNT;
1271: fifo_base = (policy_fifo_base_t) base;
1272: if (fifo_base->base_priority >
1273: sched_info->max_priority) {
1274: result = KERN_POLICY_LIMIT;
1275: break;
1276: }
1277: fifo_limit.max_priority = sched_info->max_priority;
1278: limit = (policy_limit_t) &fifo_limit;
1279: break;
1280: }
1281:
1282: case POLICY_TIMESHARE:
1283: {
1284: policy_timeshare_base_t ts_base;
1285:
1286: if (count != POLICY_TIMESHARE_BASE_COUNT) {
1287: result = KERN_INVALID_ARGUMENT;
1288: break;
1289: }
1290: limcount = POLICY_TIMESHARE_LIMIT_COUNT;
1291: ts_base = (policy_timeshare_base_t) base;
1292: if (ts_base->base_priority >
1293: sched_info->max_priority) {
1294: result = KERN_POLICY_LIMIT;
1295: break;
1296: }
1297: ts_limit.max_priority = sched_info->max_priority;
1298: limit = (policy_limit_t) &ts_limit;
1299: break;
1300: }
1301:
1302: default:
1303: result = KERN_INVALID_POLICY;
1304: break;
1305: }
1306:
1307: }
1308:
1309: act_unlock_thread(thr_act);
1310:
1311: if (result == KERN_SUCCESS)
1312: result = thread_set_policy(thr_act, pset,
1313: policy, base, count, limit, limcount);
1314:
1315: return(result);
1316: }
1317:
1318:
1319: /*
1320: * Define shifts for simulating (5/8)**n
1321: */
1322:
1323: shift_data_t wait_shift[32] = {
1324: {1,1},{1,3},{1,-3},{2,-7},{3,5},{3,-5},{4,-8},{5,7},
1325: {5,-7},{6,-10},{7,10},{7,-9},{8,-11},{9,12},{9,-11},{10,-13},
1326: {11,14},{11,-13},{12,-15},{13,17},{13,-15},{14,-17},{15,19},{16,18},
1327: {16,-19},{17,22},{18,20},{18,-20},{19,26},{20,22},{20,-22},{21,-27}};
1328:
1329: /*
1330: * do_priority_computation:
1331: *
1332: * Calculate new priority for thread based on its base priority plus
1333: * accumulated usage. PRI_SHIFT and PRI_SHIFT_2 convert from
1334: * usage to priorities. SCHED_SHIFT converts for the scaling
1335: * of the sched_usage field by SCHED_SCALE. This scaling comes
1336: * from the multiplication by sched_load (thread_timer_delta)
1337: * in sched.h. sched_load is calculated as a scaled overload
1338: * factor in compute_mach_factor (mach_factor.c).
1339: */
1340: #ifdef PRI_SHIFT_2
1341: #if PRI_SHIFT_2 > 0
1342: #define do_priority_computation(sp_info, pri) \
1343: MACRO_BEGIN \
1344: (pri) = (sp_info)->priority /* start with base priority */ \
1345: - ((sp_info)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT)) \
1346: - ((sp_info)->sched_usage >> (PRI_SHIFT_2 + SCHED_SHIFT)); \
1347: if ((pri) < lpri) (pri) = lpri; \
1348: (pri) = convert_pri[(pri)]; \
1349: MACRO_END
1350: #else /* PRI_SHIFT_2 */
1351: #define do_priority_computation(sp_info, pri) \
1352: MACRO_BEGIN \
1353: (pri) = (sp_info)->priority /* start with base priority */ \
1354: - ((sp_info)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT)) \
1355: + ((sp_info)->sched_usage >> (SCHED_SHIFT - PRI_SHIFT_2)); \
1356: if ((pri) < lpri) (pri) = lpri; \
1357: (pri) = convert_pri[(pri)]; \
1358: MACRO_END
1359: #endif /* PRI_SHIFT_2 */
1360: #else /* defined(PRI_SHIFT_2) */
1361: #define do_priority_computation(sp_info, pri) \
1362: MACRO_BEGIN \
1363: (pri) = (sp_info)->priority /* start with base priority */ \
1364: - ((sp_info)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT)); \
1365: if ((pri) < lpri) (pri) = lpri; \
1366: (pri) = convert_pri[(pri)]; \
1367: MACRO_END
1368: #endif /* defined(PRI_SHIFT_2) */
1369:
1370: /*
1371: * compute_priority:
1372: *
1373: * Compute the effective priority of the specified thread.
1374: * The effective priority computation is as follows:
1375: *
1376: * Take the base priority for this thread and add
1377: * to it an increment derived from its cpu_usage.
1378: *
1379: * The thread *must* be locked by the caller.
1380: */
1381:
1382: void
1383: compute_priority(
1384: register thread_t thread,
1385: boolean_t resched)
1386: {
1387: mk_sp_info_t sp_info = (mk_sp_info_t)thread->sp_info;
1388: register int pri;
1389:
1390: /* make sure policy-specific data are present */
1391: assert(sp_info != SP_INFO_NULL);
1392:
1393: if (thread->policy == POLICY_TIMESHARE) {
1394: do_priority_computation(sp_info, pri);
1395: if (sp_info->depress_priority < 0)
1396: set_pri(thread, pri, resched);
1397: else
1398: sp_info->depress_priority = pri;
1399: }
1400: else
1401: set_pri(thread, sp_info->priority, resched);
1402: }
1403:
1404: /*
1405: * compute_my_priority:
1406: *
1407: * Version of compute priority for current thread or thread
1408: * being manipulated by scheduler (going on or off a runq).
1409: * Only used for priority updates. Policy or priority changes
1410: * must call compute_priority above. Caller must have thread
1411: * locked and know it is timesharing and not depressed.
1412: */
1413:
1414: void
1415: compute_my_priority(
1416: register thread_t thread)
1417: {
1418: mk_sp_info_t sp_info = (mk_sp_info_t)thread->sp_info;
1419: register int temp_pri;
1420:
1421: /* make sure policy-specific data are present */
1422: assert(thread->sp_info != SP_INFO_NULL);
1423:
1424: do_priority_computation(sp_info,temp_pri);
1425: assert(thread->runq == RUN_QUEUE_NULL);
1426: thread->sched_pri = temp_pri;
1427: }
1428:
1429: struct mk_sp_usage {
1430: natural_t cpu_delta, sched_delta;
1431: natural_t sched_tick, ticks;
1432: natural_t cpu_usage, sched_usage,
1433: aged_cpu, aged_sched;
1434: thread_t thread;
1435: } idled_info, loaded_info;
1436:
1437: /*
1438: * update_priority
1439: *
1440: * Cause the priority computation of a thread that has been
1441: * sleeping or suspended to "catch up" with the system. Thread
1442: * *MUST* be locked by caller. If thread is running, then this
1443: * can only be called by the thread on itself.
1444: */
1445: void
1446: update_priority(
1447: register thread_t thread)
1448: {
1449: mk_sp_info_t sp_info = (mk_sp_info_t)thread->sp_info;
1450: register unsigned int ticks;
1451: register shift_t shiftp;
1452:
1453: /* make sure policy-specific data are present */
1454: assert(sp_info != SP_INFO_NULL);
1455:
1456: ticks = sched_tick - sp_info->sched_stamp;
1457: assert(ticks != 0);
1458:
1459: /*
1460: * If asleep for more than 30 seconds forget all
1461: * cpu_usage, else catch up on missed aging.
1462: * 5/8 ** n is approximated by the two shifts
1463: * in the wait_shift array.
1464: */
1465: sp_info->sched_stamp += ticks;
1466: thread_timer_delta(thread);
1467: if (ticks > 30) {
1468: sp_info->cpu_usage = 0;
1469: sp_info->sched_usage = 0;
1470: }
1471: else {
1472: struct mk_sp_usage *sp_usage;
1473:
1474: sp_info->cpu_usage += thread->cpu_delta;
1475: sp_info->sched_usage += thread->sched_delta;
1476:
1477: if (thread->state & TH_IDLE)
1478: sp_usage = &idled_info;
1479: else
1480: if (thread == loaded_info.thread)
1481: sp_usage = &loaded_info;
1482: else
1483: sp_usage = NULL;
1484:
1485: if (sp_usage != NULL) {
1486: sp_usage->cpu_delta = thread->cpu_delta;
1487: sp_usage->sched_delta = thread->sched_delta;
1488: sp_usage->sched_tick = sp_info->sched_stamp;
1489: sp_usage->ticks = ticks;
1490: sp_usage->cpu_usage = sp_info->cpu_usage;
1491: sp_usage->sched_usage = sp_info->sched_usage;
1492: sp_usage->thread = thread;
1493: }
1494:
1495: shiftp = &wait_shift[ticks];
1496: if (shiftp->shift2 > 0) {
1497: sp_info->cpu_usage =
1498: (sp_info->cpu_usage >> shiftp->shift1) +
1499: (sp_info->cpu_usage >> shiftp->shift2);
1500: sp_info->sched_usage =
1501: (sp_info->sched_usage >> shiftp->shift1) +
1502: (sp_info->sched_usage >> shiftp->shift2);
1503: }
1504: else {
1505: sp_info->cpu_usage =
1506: (sp_info->cpu_usage >> shiftp->shift1) -
1507: (sp_info->cpu_usage >> -(shiftp->shift2));
1508: sp_info->sched_usage =
1509: (sp_info->sched_usage >> shiftp->shift1) -
1510: (sp_info->sched_usage >> -(shiftp->shift2));
1511: }
1512:
1513: if (sp_usage != NULL) {
1514: sp_usage->aged_cpu = sp_info->cpu_usage;
1515: sp_usage->aged_sched = sp_info->sched_usage;
1516: }
1517: }
1518: thread->cpu_delta = 0;
1519: thread->sched_delta = 0;
1520:
1521: /*
1522: * Recompute priority if appropriate.
1523: */
1524: if ( thread->policy == POLICY_TIMESHARE &&
1525: sp_info->depress_priority < 0 ) {
1526: register int new_pri;
1527: run_queue_t runq;
1528:
1529: do_priority_computation(sp_info, new_pri);
1530: runq = rem_runq(thread);
1531: thread->sched_pri = new_pri;
1532: if (runq != RUN_QUEUE_NULL)
1533: thread_setrun(thread, TRUE, TAIL_Q);
1534: }
1535: }
1536:
1537: /*
1538: * `mk_sp_swtch_pri()' attempts to context switch (logic in
1539: * thread_block no-ops the context switch if nothing would happen).
1540: * A boolean is returned that indicates whether there is anything
1541: * else runnable.
1542: *
1543: * This boolean can be used by a thread waiting on a
1544: * lock or condition: If FALSE is returned, the thread is justified
1545: * in becoming a resource hog by continuing to spin because there's
1546: * nothing else useful that the processor could do. If TRUE is
1547: * returned, the thread should make one more check on the
1548: * lock and then be a good citizen and really suspend.
1549: */
1550:
1551: void
1552: _mk_sp_swtch_pri(
1553: sf_object_t policy,
1554: int pri)
1555: {
1556: register thread_t self = current_thread();
1557:
1558: #ifdef lint
1559: pri++;
1560: #endif /* lint */
1561:
1562: counter(c_mk_sp_swtch_pri++);
1563: /*
1564: * XXX need to think about depression duration.
1565: * XXX currently using min quantum.
1566: */
1567: _mk_sp_thread_depress_priority(policy, min_quantum_ms);
1568:
1569: counter(c_swtch_pri_block++);
1570: thread_block((void (*)(void)) 0);
1571:
1572: _mk_sp_thread_depress_abort(policy, self);
1573: }
1574:
1575: /*
1576: * thread_switch:
1577: *
1578: * Context switch. User may supply thread hint.
1579: *
1580: * Fixed priority threads that call this get what they asked for
1581: * even if that violates priority order.
1582: */
1583: kern_return_t
1584: _mk_sp_thread_switch(
1585: sf_object_t policy,
1586: thread_act_t hint_act,
1587: int option,
1588: mach_msg_timeout_t option_time)
1589: {
1590: register thread_t self = current_thread();
1591: register processor_t myprocessor;
1592: mk_sp_info_t sp_info;
1593: int s;
1594:
1595: counter(c_mk_sp_thread_switch++);
1596:
1597: /*
1598: * Process option.
1599: */
1600: switch (option) {
1601:
1602: case SWITCH_OPTION_NONE:
1603: /*
1604: * Nothing to do.
1605: */
1606: break;
1607:
1608: case SWITCH_OPTION_DEPRESS:
1609: /*
1610: * Depress priority for a given time.
1611: */
1612: _mk_sp_thread_depress_priority(policy, option_time);
1613: break;
1614:
1615: case SWITCH_OPTION_WAIT:
1616: assert_wait_timeout(option_time, THREAD_ABORTSAFE);
1617: break;
1618:
1619: default:
1620: return (KERN_INVALID_ARGUMENT);
1621: }
1622:
1623: /*
1624: * Check and use thr_act hint if appropriate. It is not
1625: * appropriate to give a hint that shares the current shuttle.
1626: *
1627: * JMM - Is it really appropriate to give a hint that isn't
1628: * the top activation for a thread?
1629: */
1630: if (hint_act->thread != self) {
1631: register thread_t thread = hint_act->thread;
1632:
1633: /*
1634: * Check if the thread is in the right pset. Then
1635: * pull it off its run queue. If it
1636: * doesn't come, then it's not eligible.
1637: */
1638: if (thread) {
1639: s = splsched();
1640: thread_lock(thread);
1641:
1642: if ( thread->processor_set == self->processor_set &&
1643: rem_runq(thread) != RUN_QUEUE_NULL ) {
1644: /*
1645: * Hah, got it!!
1646: */
1647: if (thread->policy & (POLICY_FIFO|POLICY_RR)) {
1648: myprocessor = current_processor();
1649:
1650: assert(thread->sp_info != SP_INFO_NULL);
1651: sp_info = (mk_sp_info_t)thread->sp_info;
1652:
1653: myprocessor->quantum = sp_info->unconsumed_quantum;
1654: myprocessor->first_quantum = TRUE;
1655: }
1656: thread_unlock(thread);
1657: splx(s);
1658: act_unlock_thread(hint_act);
1659:
1660: counter(c_thread_switch_handoff++);
1661: thread_run((void(*)(void)) 0, thread);
1662:
1663: goto out;
1664: }
1665:
1666: thread_unlock(thread);
1667: splx(s);
1668: }
1669:
1670: act_unlock_thread(hint_act);
1671: }
1672:
1673: /*
1674: * No handoff hint supplied, or hint was wrong. Call thread_block() in
1675: * hopes of running something else. If nothing else is runnable,
1676: * thread_block will detect this. WARNING: thread_switch with no
1677: * option will not do anything useful if the thread calling it is the
1678: * highest priority thread (can easily happen with a collection
1679: * of timesharing threads).
1680: */
1681: mp_disable_preemption();
1682: myprocessor = current_processor();
1683: if ( option != SWITCH_OPTION_NONE ||
1684: myprocessor->processor_set->runq.count > 0 ||
1685: myprocessor->runq.count > 0 ) {
1686: myprocessor->first_quantum = FALSE;
1687: mp_enable_preemption();
1688:
1689: counter(c_thread_switch_block++);
1690: thread_block((void (*)(void)) 0);
1691: }
1692: else
1693: mp_enable_preemption();
1694:
1695: out:
1696: if (option == SWITCH_OPTION_WAIT)
1697: thread_cancel_timer();
1698: else if (option == SWITCH_OPTION_DEPRESS)
1699: _mk_sp_thread_depress_abort(policy, self);
1700:
1701: return (KERN_SUCCESS);
1702: }
1703:
1704: /*
1705: * mk_sp_thread_depress_priority
1706: *
1707: * Depress thread's priority to lowest possible for specified period.
1708: * Intended for use when thread wants a lock but doesn't know which
1709: * other thread is holding it. As with thread_switch, fixed
1710: * priority threads get exactly what they asked for. Users access
1711: * this by the SWITCH_OPTION_DEPRESS option to thread_switch. A Time
1712: * of zero will result in no timeout being scheduled.
1713: */
1714: void
1715: _mk_sp_thread_depress_priority(
1716: sf_object_t policy,
1717: mach_msg_timeout_t interval)
1718: {
1719: register thread_t self = current_thread();
1720: mk_sp_info_t sp_info;
1721: AbsoluteTime deadline;
1722: boolean_t release = FALSE;
1723: spl_t s;
1724:
1725: s = splsched();
1726: thread_lock(self);
1727:
1728: if (self->policy == policy->policy_id) {
1729: /* get pointer to scheduling policy-specific data */
1730: assert(self->sp_info != SP_INFO_NULL);
1731: sp_info = (mk_sp_info_t)self->sp_info;
1732:
1733: /*
1734: * If we haven't already saved the priority to be restored
1735: * (depress_priority), then save it.
1736: */
1737: if (sp_info->depress_priority < 0)
1738: sp_info->depress_priority = sp_info->priority;
1739: else if (thread_call_cancel(&self->depress_timer))
1740: release = TRUE;
1741:
1742: self->sched_pri = sp_info->priority = DEPRESSPRI;
1743:
1744: if (interval != 0) {
1745: clock_interval_to_deadline(
1746: interval, 1000*NSEC_PER_USEC, &deadline);
1747: thread_call_enter_delayed(&self->depress_timer, deadline);
1748: if (!release)
1749: self->ref_count++;
1750: else
1751: release = FALSE;
1752: }
1753: }
1754:
1755: thread_unlock(self);
1756: splx(s);
1757:
1758: if (release)
1759: thread_deallocate(self);
1760: }
1761:
1762: /*
1763: * mk_sp_thread_depress_timeout:
1764: *
1765: * Timeout routine for priority depression.
1766: */
1767: void
1768: _mk_sp_thread_depress_timeout(
1769: sf_object_t policy,
1770: register thread_t thread)
1771: {
1772: mk_sp_info_t sp_info;
1773: spl_t s;
1774:
1775: counter(c_mk_sp_thread_depress_timeout++);
1776:
1777: s = splsched();
1778: thread_lock(thread);
1779: if (thread->policy == policy->policy_id) {
1780: /* get pointer to scheduling policy-specific data */
1781: assert(thread->sp_info != SP_INFO_NULL);
1782: sp_info = (mk_sp_info_t)thread->sp_info;
1783:
1784: /*
1785: * If we lose a race with mk_sp_thread_depress_abort,
1786: * then depress_priority might be -1.
1787: */
1788: if ( sp_info->depress_priority >= 0 &&
1789: !thread_call_is_delayed(&thread->depress_timer, NULL) ) {
1790: sp_info->priority = sp_info->depress_priority;
1791: sp_info->depress_priority = -1;
1792: compute_priority(thread, FALSE);
1793: }
1794: else
1795: if (sp_info->depress_priority == -2) {
1796: /*
1797: * Thread was temporarily undepressed by thread_suspend, to
1798: * be redepressed in special_handler as it blocks. We need to
1799: * prevent special_handler from redepressing it, since depression
1800: * has timed out:
1801: */
1802: sp_info->depress_priority = -1;
1803: }
1804: }
1805: thread_unlock(thread);
1806: splx(s);
1807: }
1808:
1809: /*
1810: * mk_sp_thread_depress_abort:
1811: *
1812: * Prematurely abort priority depression if there is one.
1813: */
1814: kern_return_t
1815: _mk_sp_thread_depress_abort(
1816: sf_object_t policy,
1817: register thread_t thread)
1818: {
1819: mk_sp_info_t sp_info;
1820: kern_return_t result = KERN_SUCCESS;
1821: boolean_t release = FALSE;
1822: spl_t s;
1823:
1824: s = splsched();
1825: thread_lock(thread);
1826:
1827: if (thread->policy == policy->policy_id) {
1828: /* get pointer to scheduling policy-specific data */
1829: assert(thread->sp_info != SP_INFO_NULL);
1830: sp_info = (mk_sp_info_t)thread->sp_info;
1831:
1832: if (sp_info->depress_priority >= 0) {
1833: if (thread_call_cancel(&thread->depress_timer))
1834: release = TRUE;
1835: sp_info->priority = sp_info->depress_priority;
1836: sp_info->depress_priority = -1;
1837: compute_priority(thread, FALSE);
1838: }
1839: else
1840: result = KERN_NOT_DEPRESSED;
1841: }
1842:
1843: thread_unlock(thread);
1844: splx(s);
1845:
1846: if (release)
1847: thread_deallocate(thread);
1848:
1849: return (result);
1850: }
1851:
1852: /*
1853: * mk_sp_thread_runnable:
1854: *
1855: * Return TRUE iff policy believes thread is runnable
1856: */
1857: boolean_t
1858: _mk_sp_thread_runnable(
1859: sf_object_t policy,
1860: sched_thread_t thread)
1861: {
1862: mk_sp_info_t sp_info;
1863:
1864: counter(c_mk_sp_thread_runnable++);
1865:
1866: /* get pointer to scheduling policy-specific data */
1867: assert(thread->sp_info != SP_INFO_NULL);
1868: sp_info = (mk_sp_info_t)thread->sp_info;
1869:
1870: counter(sp_info->c_mk_sp_thread_runnable++);
1871:
1872: return (sp_info->th_state == MK_SP_RUNNABLE);
1873: }
1874:
1875: sf_return_t
1876: _mk_sp_alarm_expired(
1877: sf_object_t policy,
1878: long alarm_seqno,
1879: kern_return_t result,
1880: int alarm_type,
1881: mach_timespec_t wakeup_time,
1882: void *alarm_data)
1883: {
1884: counter(c_mk_sp_alarm_expired++);
1885:
1886: /* this should NEVER happen */
1887: assert(0);
1888:
1889: return (SF_FAILURE);
1890: }
1891:
1892:
1893: void
1894: _mk_sp_thread_dump(
1895: sched_thread_t thread) /* thread */
1896: {
1897: mk_sp_info_t sp_info;
1898: int count;
1899:
1900: /* get pointer to scheduling policy-specific data */
1901: assert(thread->sp_info != SP_INFO_NULL);
1902: sp_info = (mk_sp_info_t)thread->sp_info;
1903:
1904: /* dump the data in a pretty format */
1905: printf("\nthread shuttle(0x%x):\n", thread);
1906:
1907: printf("\tpolicy: ");
1908: switch(thread->policy) {
1909: case POLICY_TIMESHARE:
1910: printf("POLICY_TIMESHARE\n");
1911: break;
1912:
1913: case POLICY_RR:
1914: printf("POLICY_RR\n");
1915: break;
1916:
1917: case POLICY_FIFO:
1918: printf("POLICY_FIFO\n");
1919: break;
1920:
1921: default:
1922: printf("NOT an MK Standard Policy\n");
1923: return;
1924: }
1925:
1926: printf("\tth_state: ");
1927: if (sp_info->th_state == 0) {
1928: printf("NULL");
1929: }
1930: else {
1931: count = 0;
1932: if (sp_info->th_state & MK_SP_ATTACHED) {
1933: printf("MK_SP_ATTACHED ");
1934: count++;
1935: }
1936: if (sp_info->th_state & MK_SP_RUNNABLE) {
1937: if (count > 0) printf(" | ");
1938: printf("MK_SP_RUNNABLE ");
1939: count++;
1940: }
1941: if (sp_info->th_state & MK_SP_BLOCKED) {
1942: if (count > 0) printf(" | ");
1943: printf("MK_SP_BLOCKED ");
1944: count++;
1945: }
1946: }
1947: printf("\n");
1948:
1949: printf("\tpriority: %d\n", sp_info->priority);
1950: printf("\tmax_priority: %d\n", sp_info->max_priority);
1951: printf("\tsched_data: %d\n", sp_info->sched_data);
1952: printf("\tdepress_priority: %d\n", sp_info->depress_priority);
1953: printf("\tcpu_usage: %d\n", sp_info->cpu_usage);
1954: printf("\tsched_usage: %d\n", sp_info->sched_usage);
1955: printf("\tsched_stamp: %d\n", sp_info->sched_stamp);
1956: printf("\tunconsumed_quantum: %d\n", sp_info->unconsumed_quantum);
1957: printf("\tsched_pri: %d\n", thread->sched_pri);
1958:
1959: #ifdef MACH_ASSERT
1960: printf("\tc_mk_sp_thread_attach: %d\n",
1961: sp_info->c_mk_sp_thread_attach);
1962: printf("\tc_mk_sp_thread_detach: %d\n",
1963: sp_info->c_mk_sp_thread_detach);
1964: printf("\tc_mk_sp_thread_begin: %d\n",
1965: sp_info->c_mk_sp_thread_begin);
1966: printf("\tc_mk_sp_thread_done: %d\n",
1967: sp_info->c_mk_sp_thread_done);
1968: printf("\tc_mk_sp_thread_dispatch: %d\n",
1969: sp_info->c_mk_sp_thread_dispatch);
1970: printf("\tc_mk_sp_thread_unblock: %d\n",
1971: sp_info->c_mk_sp_thread_unblock);
1972: printf("\tc_mk_sp_thread_set: %d\n",
1973: sp_info->c_mk_sp_thread_set);
1974: printf("\tc_mk_sp_thread_get: %d\n",
1975: sp_info->c_mk_sp_thread_get);
1976: #endif /* MACH_ASSERT */
1977:
1978: return;
1979: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.