+ }
+
+ return;
+}
+
+#endif /* CONFIG_SCHED_TIMESHARE_CORE */
+
+#if MACH_ASSERT
+/* sched_mode == TH_MODE_TIMESHARE controls whether a thread has a timeshare count when it has a run count */
+
+void sched_share_incr(thread_t thread) {
+ assert((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN);
+ assert(thread->sched_mode == TH_MODE_TIMESHARE);
+ assert(thread->SHARE_COUNT == 0);
+ thread->SHARE_COUNT++;
+ (void)hw_atomic_add(&sched_share_count, 1);
+}
+
+void sched_share_decr(thread_t thread) {
+ assert((thread->state & (TH_RUN|TH_IDLE)) != TH_RUN || thread->sched_mode != TH_MODE_TIMESHARE);
+ assert(thread->SHARE_COUNT == 1);
+ (void)hw_atomic_sub(&sched_share_count, 1);
+ thread->SHARE_COUNT--;
+}
+
+/* TH_SFLAG_THROTTLED controls whether a thread has a background count when it has a run count and a share count */
+
+void sched_background_incr(thread_t thread) {
+ assert((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN);
+ assert(thread->sched_mode == TH_MODE_TIMESHARE);
+ assert((thread->sched_flags & TH_SFLAG_THROTTLED) == TH_SFLAG_THROTTLED);
+
+ assert(thread->BG_COUNT == 0);
+ thread->BG_COUNT++;
+ int val = hw_atomic_add(&sched_background_count, 1);
+ assert(val >= 0);
+
+ /* Always do the background change while holding a share count */
+ assert(thread->SHARE_COUNT == 1);
+}
+
+void sched_background_decr(thread_t thread) {
+ if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN && thread->sched_mode == TH_MODE_TIMESHARE)
+ assert((thread->sched_flags & TH_SFLAG_THROTTLED) != TH_SFLAG_THROTTLED);
+ assert(thread->BG_COUNT == 1);
+ int val = hw_atomic_sub(&sched_background_count, 1);
+ thread->BG_COUNT--;
+ assert(val >= 0);
+ assert(thread->BG_COUNT == 0);
+
+ /* Always do the background change while holding a share count */
+ assert(thread->SHARE_COUNT == 1);
+}
+
+
+void
+assert_thread_sched_count(thread_t thread) {
+ /* Only 0 or 1 are acceptable values */
+ assert(thread->BG_COUNT == 0 || thread->BG_COUNT == 1);
+ assert(thread->SHARE_COUNT == 0 || thread->SHARE_COUNT == 1);
+
+ /* BG is only allowed when you already have a share count */
+ if (thread->BG_COUNT == 1)
+ assert(thread->SHARE_COUNT == 1);
+ if (thread->SHARE_COUNT == 0)
+ assert(thread->BG_COUNT == 0);
+
+ if ((thread->state & (TH_RUN|TH_IDLE)) != TH_RUN ||
+ (thread->sched_mode != TH_MODE_TIMESHARE))
+ assert(thread->SHARE_COUNT == 0);
+
+ if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN &&
+ (thread->sched_mode == TH_MODE_TIMESHARE))
+ assert(thread->SHARE_COUNT == 1);
+
+ if ((thread->state & (TH_RUN|TH_IDLE)) != TH_RUN ||
+ (thread->sched_mode != TH_MODE_TIMESHARE) ||
+ !(thread->sched_flags & TH_SFLAG_THROTTLED))
+ assert(thread->BG_COUNT == 0);
+
+ if ((thread->state & (TH_RUN|TH_IDLE)) == TH_RUN &&
+ (thread->sched_mode == TH_MODE_TIMESHARE) &&
+ (thread->sched_flags & TH_SFLAG_THROTTLED))
+ assert(thread->BG_COUNT == 1);
+}
+
+#endif /* MACH_ASSERT */
+
+/*
+ * Set the thread's true scheduling mode
+ * Called with thread mutex and thread locked
+ * The thread has already been removed from the runqueue.
+ *
+ * (saved_mode is handled before this point)
+ */
+void
+sched_set_thread_mode(thread_t thread, sched_mode_t new_mode)
+{
+ assert_thread_sched_count(thread);
+ assert(thread->runq == PROCESSOR_NULL);
+
+ sched_mode_t old_mode = thread->sched_mode;