/* * thread_call_wake: * * Wake a call thread to service * pending call entries. May wake * the daemon thread in order to * create additional call threads. * * Called with thread_call_lock held. */ static __inline__ void thread_call_wake( thread_call_group_t group) { if (group->idle_count > 0 && wait_queue_wakeup_one(&group->idle_wqueue, NO_EVENT, THREAD_AWAKENED, -1) == KERN_SUCCESS) { group->idle_count--; group->active_count++; } else if (!thread_call_daemon_awake) { thread_call_daemon_awake = TRUE; wait_queue_wakeup_one(&group->daemon_wqueue, NO_EVENT, THREAD_AWAKENED, -1); } }
/* * thread_call_wake: * * Wake a call thread to service * pending call entries. May wake * the daemon thread in order to * create additional call threads. * * Called with thread_call_lock held. * * For high-priority group, only does wakeup/creation if there are no threads * running. */ static __inline__ void thread_call_wake( thread_call_group_t group) { /* * New behavior: use threads if you've got 'em. * Traditional behavior: wake only if no threads running. */ if (group_isparallel(group) || group->active_count == 0) { if (wait_queue_wakeup_one(&group->idle_wqueue, NO_EVENT, THREAD_AWAKENED, -1) == KERN_SUCCESS) { group->idle_count--; group->active_count++; if (group->idle_count == 0) { timer_call_cancel(&group->dealloc_timer); group->flags &= TCG_DEALLOC_ACTIVE; } } else { if (!thread_call_daemon_awake && thread_call_group_should_add_thread(group)) { thread_call_daemon_awake = TRUE; wait_queue_wakeup_one(&daemon_wqueue, NO_EVENT, THREAD_AWAKENED, -1); } } } }
/* * Timer callback to tell a thread to terminate if * we have an excess of threads and at least one has been * idle for a long time. */ static void thread_call_dealloc_timer( timer_call_param_t p0, __unused timer_call_param_t p1) { thread_call_group_t group = (thread_call_group_t)p0; uint64_t now; kern_return_t res; boolean_t terminated = FALSE; thread_call_lock_spin(); now = mach_absolute_time(); if (group->idle_count > 0) { if (now > group->idle_timestamp + thread_call_dealloc_interval_abs) { terminated = TRUE; group->idle_count--; res = wait_queue_wakeup_one(&group->idle_wqueue, NO_EVENT, THREAD_INTERRUPTED, -1); if (res != KERN_SUCCESS) { panic("Unable to wake up idle thread for termination?"); } } } /* * If we still have an excess of threads, schedule another * invocation of this function. */ if (group->idle_count > 0 && (group->idle_count + group->active_count > group->target_thread_count)) { /* * If we killed someone just now, push out the * next deadline. */ if (terminated) { group->idle_timestamp = now; } thread_call_start_deallocate_timer(group); } else { group->flags &= ~TCG_DEALLOC_ACTIVE; } thread_call_unlock(); }