Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | #include <pthread.h> #include <stdbool.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/time.h> #include <mach/mach_time.h> #include <mach/thread_policy.h> #include <pthread.h> #include <pthread/tsd_private.h> #include <pthread/qos_private.h> #include <dispatch/dispatch.h> #include <dispatch/private.h> #include <darwintest.h> #include <pthread/workqueue_private.h> T_GLOBAL_META( T_META_NAMESPACE("xnu.workq"), T_META_RADAR_COMPONENT_NAME("xnu"), T_META_RADAR_COMPONENT_VERSION("workq"), T_META_RUN_CONCURRENTLY(true)); static mach_timebase_info_data_t timebase_info; static uint64_t nanos_to_abs(uint64_t nanos) { return nanos * timebase_info.denom / timebase_info.numer; } static void spin_for_duration(uint32_t seconds) { kern_return_t kr = mach_timebase_info(&timebase_info); assert(kr == KERN_SUCCESS); uint64_t duration = nanos_to_abs((uint64_t)seconds * NSEC_PER_SEC); uint64_t current_time = mach_absolute_time(); uint64_t timeout = duration + current_time; uint64_t spin_count = 0; while (mach_absolute_time() < timeout) { spin_count++; } return; } T_DECL(cooperative_workqueue_and_vfork, "rdar://74489806") { dispatch_queue_t dq = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0); T_ASSERT_NE(dq, NULL, "global_queue"); dispatch_async(dq, ^{ /* We are a workqueue non-overcommit thread, we should be getting a * quantum */ spin_for_duration(1); pid_t child; if ((child = vfork()) == 0) { usleep(100); spin_for_duration(1); _exit(0); } int status; waitpid(child, &status, 0); T_ASSERT_EQ(status, 0, "child status"); T_END; }); dispatch_main(); } T_DECL(adjust_quantum_nonovercommit_to_overcommit_switch, "rdar://75084197") { dispatch_queue_t dq = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0); T_ASSERT_NE(dq, NULL, "global_queue"); dispatch_async(dq, ^{ /* We are a workqueue non-overcommit thread, we should be getting a * quantum that we expire here */ spin_for_duration(1); /* Should not panic when we switch to overcommit */ pthread_priority_t overcommit = (pthread_priority_t)_pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS) | _PTHREAD_PRIORITY_OVERCOMMIT_FLAG; T_ASSERT_POSIX_ZERO(_pthread_set_properties_self(_PTHREAD_SET_SELF_QOS_FLAG, overcommit, 0), NULL); T_END; }); dispatch_main(); } T_DECL(cooperative_to_overcommit_switch, "Switching from cooperative queue to another type should not panic") { dispatch_queue_t cooperative_dq = dispatch_get_global_queue(QOS_CLASS_UTILITY, DISPATCH_QUEUE_COOPERATIVE); T_ASSERT_NE(cooperative_dq, NULL, "global_queue"); dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL, QOS_CLASS_USER_INITIATED, 0); dispatch_queue_t dq = dispatch_queue_create("serial IN overcommit queue", attr); dispatch_async(cooperative_dq, ^{ spin_for_duration(1); dispatch_async_and_wait(dq, ^{ spin_for_duration(1); }); dispatch_release(dq); T_END; }); dispatch_main(); } T_DECL(maintenance_bg_coalesced, "BG and MT coalescing should work") { dispatch_queue_t dq = dispatch_get_global_queue(QOS_CLASS_MAINTENANCE, DISPATCH_QUEUE_COOPERATIVE); T_ASSERT_NE(dq, NULL, "global_queue"); dispatch_group_t dg = dispatch_group_create(); dispatch_group_async(dg, dq, ^{ spin_for_duration(1); }); dispatch_group_wait(dg, DISPATCH_TIME_FOREVER); dispatch_release(dg); } |