+/*
+ * This helper canonicalizes the resource/resource_type given the current qos_override_mode
+ * in effect. Note that wildcards (THREAD_QOS_OVERRIDE_RESOURCE_WILDCARD) may need
+ * to be handled specially in the future, but for now it's fine to slam
+ * *resource to USER_ADDR_NULL even if it was previously a wildcard.
+ */
+static void _canonicalize_resource_and_type(user_addr_t *resource, int *resource_type) {
+ if (qos_override_mode == QOS_OVERRIDE_MODE_OVERHANG_PEAK || qos_override_mode == QOS_OVERRIDE_MODE_IGNORE_OVERRIDE) {
+ /* Map all input resource/type to a single one */
+ *resource = USER_ADDR_NULL;
+ *resource_type = THREAD_QOS_OVERRIDE_TYPE_UNKNOWN;
+ } else if (qos_override_mode == QOS_OVERRIDE_MODE_FINE_GRAINED_OVERRIDE) {
+ /* no transform */
+ } else if (qos_override_mode == QOS_OVERRIDE_MODE_FINE_GRAINED_OVERRIDE_BUT_IGNORE_DISPATCH) {
+ /* Map all dispatch overrides to a single one, to avoid memory overhead */
+ if (*resource_type == THREAD_QOS_OVERRIDE_TYPE_DISPATCH_ASYNCHRONOUS_OVERRIDE) {
+ *resource = USER_ADDR_NULL;
+ }
+ } else if (qos_override_mode == QOS_OVERRIDE_MODE_FINE_GRAINED_OVERRIDE_BUT_SINGLE_MUTEX_OVERRIDE) {
+ /* Map all mutex overrides to a single one, to avoid memory overhead */
+ if (*resource_type == THREAD_QOS_OVERRIDE_TYPE_PTHREAD_MUTEX) {
+ *resource = USER_ADDR_NULL;
+ }
+ }
+}
+
+/* This helper routine finds an existing override if known. Locking should be done by caller */
+static struct thread_qos_override *_find_qos_override(thread_t thread, user_addr_t resource, int resource_type) {
+ struct thread_qos_override *override;
+
+ override = thread->overrides;
+ while (override) {
+ if (override->override_resource == resource &&
+ override->override_resource_type == resource_type) {
+ return override;
+ }
+
+ override = override->override_next;
+ }
+
+ return NULL;
+}
+
+static void _find_and_decrement_qos_override(thread_t thread, user_addr_t resource, int resource_type, boolean_t reset, struct thread_qos_override **free_override_list) {
+ struct thread_qos_override *override, *override_prev;
+
+ override_prev = NULL;
+ override = thread->overrides;
+ while (override) {
+ struct thread_qos_override *override_next = override->override_next;
+
+ if ((THREAD_QOS_OVERRIDE_RESOURCE_WILDCARD == resource || override->override_resource == resource) &&
+ override->override_resource_type == resource_type) {
+ if (reset) {
+ override->override_contended_resource_count = 0;
+ } else {
+ override->override_contended_resource_count--;
+ }
+
+ if (override->override_contended_resource_count == 0) {
+ if (override_prev == NULL) {
+ thread->overrides = override_next;
+ } else {
+ override_prev->override_next = override_next;
+ }
+
+ /* Add to out-param for later zfree */
+ override->override_next = *free_override_list;
+ *free_override_list = override;
+ } else {
+ override_prev = override;
+ }
+
+ if (THREAD_QOS_OVERRIDE_RESOURCE_WILDCARD != resource) {
+ return;
+ }
+ } else {
+ override_prev = override;
+ }
+
+ override = override_next;
+ }
+}
+
+/* This helper recalculates the current requested override using the policy selected at boot */
+static int _calculate_requested_qos_override(thread_t thread)
+{
+ if (qos_override_mode == QOS_OVERRIDE_MODE_IGNORE_OVERRIDE) {
+ return THREAD_QOS_UNSPECIFIED;
+ }
+
+ /* iterate over all overrides and calculate MAX */
+ struct thread_qos_override *override;
+ int qos_override = THREAD_QOS_UNSPECIFIED;
+
+ override = thread->overrides;
+ while (override) {
+ if (qos_override_mode != QOS_OVERRIDE_MODE_FINE_GRAINED_OVERRIDE_BUT_IGNORE_DISPATCH ||
+ override->override_resource_type != THREAD_QOS_OVERRIDE_TYPE_DISPATCH_ASYNCHRONOUS_OVERRIDE) {
+ qos_override = MAX(qos_override, override->override_qos);
+ }
+
+ override = override->override_next;
+ }
+
+ return qos_override;
+}
+
+boolean_t proc_thread_qos_add_override(task_t task, thread_t thread, uint64_t tid, int override_qos, boolean_t first_override_for_resource, user_addr_t resource, int resource_type)