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 133 134 135 136 | #include <stdio.h> #include <stdlib.h> #include <darwintest.h> #include <darwintest_utils.h> #include <dispatch/dispatch.h> #include <kern/debug.h> #include <libproc.h> #include <mach-o/dyld.h> #include <sys/syscall.h> #include <sys/stackshot.h> #include <spawn.h> T_GLOBAL_META( T_META_NAMESPACE("xnu.stackshot"), T_META_RADAR_COMPONENT_NAME("xnu"), T_META_RADAR_COMPONENT_VERSION("stackshot"), T_META_OWNER("jonathan_w_adams"), T_META_CHECK_LEAKS(false), T_META_ASROOT(true) ); #define TEST_DURATION_NS (60 * NSEC_PER_SEC) #define REAP_INTERVAL 10 static void* loop(__attribute__ ((unused)) void *arg) { exit(0); } T_HELPER_DECL(spawn_children_helper, "spawn_children helper") { pthread_t pthread; T_QUIET; T_ASSERT_POSIX_ZERO(pthread_create(&pthread, NULL, loop, NULL), "pthread_create"); while (1) { ; } } static void take_stackshot(void) { uint64_t stackshot_flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_GET_GLOBAL_MEM_STATS | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_KCDATA_FORMAT); void *config = stackshot_config_create(); T_QUIET; T_ASSERT_NOTNULL(config, "created stackshot config"); int ret = stackshot_config_set_flags(config, stackshot_flags); T_QUIET; T_ASSERT_POSIX_ZERO(ret, "set flags on stackshot config"); int retries_remaining = 5; retry: ret = stackshot_capture_with_config(config); if (ret == EBUSY || ret == ETIMEDOUT) { if (retries_remaining > 0) { retries_remaining--; goto retry; } else { T_QUIET; T_ASSERT_POSIX_ZERO(ret, "called stackshot_capture_with_config (no retries remaining)"); } } else { T_QUIET; T_ASSERT_POSIX_ZERO(ret, "called stackshot_capture_with_config"); } ret = stackshot_config_dealloc(config); T_QUIET; T_EXPECT_POSIX_ZERO(ret, "deallocated stackshot config"); } T_DECL(stackshot_spawn_exit, "tests taking many stackshots while children processes are spawning+exiting", T_META_TIMEOUT(120)) { char path[PATH_MAX]; uint32_t path_size = sizeof(path); T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path, &path_size), "_NSGetExecutablePath"); char *args[] = { path, "-n", "spawn_children_helper", NULL }; uint64_t stop_time = clock_gettime_nsec_np(CLOCK_UPTIME_RAW) + TEST_DURATION_NS; dispatch_queue_t stackshot_queue = dispatch_queue_create("stackshot_queue", NULL); dispatch_async(stackshot_queue, ^(void) { int num_stackshots = 0; while (1) { take_stackshot(); num_stackshots++; if ((num_stackshots % 100) == 0) { T_LOG("completed %d stackshots", num_stackshots); } // Sleep between each stackshot usleep(100); } }); // <rdar://problem/39739547> META option for T_HELPER_DECL to not output test begin on start posix_spawn_file_actions_t actions; T_QUIET; T_ASSERT_POSIX_SUCCESS(posix_spawn_file_actions_init(&actions), "create spawn actions"); T_QUIET; T_ASSERT_POSIX_SUCCESS(posix_spawn_file_actions_addopen(&actions, STDOUT_FILENO, "/dev/null", O_WRONLY, 0), "set stdout of child to NULL"); int children_unreaped = 0, status; uint64_t iterations_completed = 0; while (clock_gettime_nsec_np(CLOCK_UPTIME_RAW) < stop_time) { pid_t pid; int sp_ret = posix_spawn(&pid, args[0], &actions, NULL, args, NULL); T_QUIET; T_ASSERT_POSIX_ZERO(sp_ret, "spawned process '%s' with PID %d", args[0], pid); children_unreaped++; if (children_unreaped >= REAP_INTERVAL) { while (children_unreaped) { T_QUIET; T_ASSERT_POSIX_SUCCESS(waitpid(-1, &status, 0), "waitpid returned child pid"); children_unreaped--; } } if ((iterations_completed % 100) == 0) { T_LOG("spawned %llu children thus far", iterations_completed); } iterations_completed++; } while (children_unreaped) { T_QUIET; T_ASSERT_POSIX_SUCCESS(waitpid(-1, &status, 0), "waitpid returned child pid"); children_unreaped--; } } |