+#if CONFIG_SCHED_AUTO_JOIN
+
+/*
+ * work_interval_perform_deferred_finish()
+ *
+ * Perform a deferred finish for a work interval. The routine accepts the deferred_finish_state as an
+ * argument rather than looking at the work_interval since the deferred finish can race with another
+ * start-finish cycle. To address that, the caller ensures that it gets a consistent snapshot of the
+ * deferred state before calling this routine. This allows the racing start-finish cycle to overwrite
+ * the deferred state without issues.
+ */
+static inline void
+work_interval_perform_deferred_finish(__unused struct work_interval_deferred_finish_state *deferred_finish_state,
+ __unused struct work_interval *work_interval, __unused thread_t thread)
+{
+
+ KDBG(MACHDBG_CODE(DBG_MACH_SCHED, MACH_SCHED_WI_DEFERRED_FINISH),
+ thread_tid(thread), thread_group_get_id(work_interval->wi_group));
+}
+
+/*
+ * work_interval_auto_join_increment()
+ *
+ * Routine to increment auto-join counter when a new thread is auto-joined to
+ * the work interval.
+ */
+static void
+work_interval_auto_join_increment(struct work_interval *work_interval)
+{
+ struct work_interval_auto_join_info *join_info = &work_interval->wi_auto_join_info;
+ __assert_only work_interval_auto_join_status_t old_status = os_atomic_add_orig(&join_info->status, 1, relaxed);
+ assert(work_interval_status_auto_join_count(old_status) < WORK_INTERVAL_STATUS_AUTO_JOIN_COUNT_MAX);
+}
+
+/*
+ * work_interval_auto_join_decrement()
+ *
+ * Routine to decrement the auto-join counter when a thread unjoins the work interval (due to
+ * blocking or termination). If this was the last auto-joined thread in the work interval and
+ * there was a deferred finish, performs the finish operation for the work interval.
+ */
+static void
+work_interval_auto_join_decrement(struct work_interval *work_interval, thread_t thread)
+{
+ struct work_interval_auto_join_info *join_info = &work_interval->wi_auto_join_info;
+ work_interval_auto_join_status_t old_status, new_status;
+ struct work_interval_deferred_finish_state deferred_finish_state;
+ bool perform_finish;
+
+ /* Update the auto-join count for the work interval atomically */
+ os_atomic_rmw_loop(&join_info->status, old_status, new_status, acquire, {
+ perform_finish = false;
+ new_status = old_status;
+ assert(work_interval_status_auto_join_count(old_status) > 0);
+ new_status -= 1;
+ if (new_status == WORK_INTERVAL_STATUS_DEFERRED_FINISH_MASK) {
+ /* No auto-joined threads remaining and finish is deferred */
+ new_status = 0;
+ perform_finish = true;
+ /*
+ * Its important to copy the deferred finish state here so that this works
+ * when racing with another start-finish cycle.
+ */
+ deferred_finish_state = join_info->deferred_finish_state;
+ }
+ });
+
+ if (perform_finish == true) {
+ /*
+ * Since work_interval_perform_deferred_finish() calls down to
+ * the machine layer callout for finish which gets the thread
+ * group from the thread passed in here, it is important to
+ * make sure that the thread still has the work interval thread
+ * group here.
+ */
+ assert(thread->thread_group == work_interval->wi_group);
+ work_interval_perform_deferred_finish(&deferred_finish_state, work_interval, thread);
+ }
+}
+
+/*
+ * work_interval_auto_join_enabled()
+ *
+ * Helper routine to check if work interval has auto-join enabled.
+ */
+static inline bool
+work_interval_auto_join_enabled(struct work_interval *work_interval)
+{
+ return (work_interval->wi_create_flags & WORK_INTERVAL_FLAG_ENABLE_AUTO_JOIN) != 0;
+}
+
+/*
+ * work_interval_deferred_finish_enabled()
+ *
+ * Helper routine to check if work interval has deferred finish enabled.
+ */
+static inline bool __unused
+work_interval_deferred_finish_enabled(struct work_interval *work_interval)
+{
+ return (work_interval->wi_create_flags & WORK_INTERVAL_FLAG_ENABLE_DEFERRED_FINISH) != 0;
+}
+
+#endif /* CONFIG_SCHED_AUTO_JOIN */
+