]>
Commit | Line | Data |
---|---|---|
d9a64523 A |
1 | #include <stdio.h> |
2 | #include <stdlib.h> | |
3 | ||
4 | #include <darwintest.h> | |
5 | #include <darwintest_utils.h> | |
6 | ||
7 | #include <dispatch/dispatch.h> | |
8 | #include <kern/debug.h> | |
9 | #include <libproc.h> | |
10 | #include <mach-o/dyld.h> | |
11 | #include <sys/syscall.h> | |
12 | #include <sys/stackshot.h> | |
13 | #include <spawn.h> | |
14 | ||
15 | T_GLOBAL_META( | |
16 | T_META_NAMESPACE("xnu.stackshot"), | |
17 | T_META_CHECK_LEAKS(false), | |
18 | T_META_ASROOT(true) | |
19 | ); | |
20 | ||
21 | #if TARGET_OS_WATCH | |
22 | #define SPAWN_ITERATIONS 1999 | |
23 | #elif TARGET_OS_IPHONE | |
24 | #define SPAWN_ITERATIONS 4999 | |
25 | #else | |
26 | #define SPAWN_ITERATIONS 9999 | |
27 | #endif | |
28 | ||
29 | #define REAP_INTERVAL 10 | |
30 | ||
31 | static void* loop(__attribute__ ((unused)) void *arg) { | |
32 | exit(0); | |
33 | } | |
34 | ||
35 | T_HELPER_DECL(spawn_children_helper, "spawn_children helper") | |
36 | { | |
37 | pthread_t pthread; | |
38 | ||
39 | T_QUIET; T_ASSERT_POSIX_ZERO(pthread_create(&pthread, NULL, loop, NULL), "pthread_create"); | |
40 | ||
41 | while (1) { ; } | |
42 | } | |
43 | ||
44 | static void | |
45 | take_stackshot(void) | |
46 | { | |
47 | uint32_t stackshot_flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_GET_GLOBAL_MEM_STATS | | |
48 | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_KCDATA_FORMAT); | |
49 | ||
50 | void *config = stackshot_config_create(); | |
51 | T_QUIET; T_ASSERT_NOTNULL(config, "created stackshot config"); | |
52 | ||
53 | int ret = stackshot_config_set_flags(config, stackshot_flags); | |
54 | T_QUIET; T_ASSERT_POSIX_ZERO(ret, "set flags on stackshot config"); | |
55 | ||
56 | int retries_remaining = 5; | |
57 | ||
58 | retry: | |
59 | ret = stackshot_capture_with_config(config); | |
60 | ||
61 | if (ret == EBUSY || ret == ETIMEDOUT) { | |
62 | if (retries_remaining > 0) { | |
63 | retries_remaining--; | |
64 | goto retry; | |
65 | } else { | |
66 | T_QUIET; T_ASSERT_POSIX_ZERO(ret, | |
67 | "called stackshot_capture_with_config (no retries remaining)"); | |
68 | } | |
69 | } else { | |
70 | T_QUIET; T_ASSERT_POSIX_ZERO(ret, "called stackshot_capture_with_config"); | |
71 | } | |
72 | ||
73 | ret = stackshot_config_dealloc(config); | |
74 | T_QUIET; T_EXPECT_POSIX_ZERO(ret, "deallocated stackshot config"); | |
75 | } | |
76 | ||
77 | T_DECL(stackshot_spawn_exit, "tests taking many stackshots while children processes are spawning+exiting") | |
78 | { | |
79 | char path[PATH_MAX]; | |
80 | uint32_t path_size = sizeof(path); | |
81 | T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path, &path_size), "_NSGetExecutablePath"); | |
82 | char *args[] = { path, "-n", "spawn_children_helper", NULL }; | |
83 | ||
84 | dispatch_queue_t stackshot_queue = dispatch_queue_create("stackshot_queue", NULL); | |
85 | dispatch_async(stackshot_queue, ^(void) { | |
86 | int num_stackshots = 0; | |
87 | ||
88 | while (1) { | |
89 | take_stackshot(); | |
90 | num_stackshots++; | |
91 | if ((num_stackshots % 100) == 0) { | |
92 | T_LOG("completed %d stackshots", num_stackshots); | |
93 | } | |
94 | ||
95 | // Sleep between each stackshot | |
96 | usleep(100); | |
97 | } | |
98 | }); | |
99 | ||
100 | // <rdar://problem/39739547> META option for T_HELPER_DECL to not output test begin on start | |
101 | posix_spawn_file_actions_t actions; | |
102 | T_QUIET; T_ASSERT_POSIX_SUCCESS(posix_spawn_file_actions_init(&actions), "create spawn actions"); | |
103 | T_QUIET; T_ASSERT_POSIX_SUCCESS(posix_spawn_file_actions_addopen (&actions, STDOUT_FILENO, "/dev/null", O_WRONLY, 0), | |
104 | "set stdout of child to NULL"); | |
105 | ||
106 | int children_unreaped = 0, status; | |
107 | for (int iterations_remaining = SPAWN_ITERATIONS; iterations_remaining > 0; iterations_remaining--) { | |
108 | pid_t pid; | |
109 | ||
110 | int sp_ret = posix_spawn(&pid, args[0], &actions, NULL, args, NULL); | |
111 | T_QUIET; T_ASSERT_POSIX_ZERO(sp_ret, "spawned process '%s' with PID %d", args[0], pid); | |
112 | ||
113 | children_unreaped++; | |
114 | ||
115 | if (children_unreaped >= REAP_INTERVAL) { | |
116 | while (children_unreaped) { | |
117 | T_QUIET; T_ASSERT_POSIX_SUCCESS(waitpid(-1, &status, 0), "waitpid returned child pid"); | |
118 | children_unreaped--; | |
119 | } | |
120 | } | |
121 | ||
122 | if ((iterations_remaining % 100) == 0) { | |
123 | T_LOG("spawned %d children thus far", (SPAWN_ITERATIONS - iterations_remaining)); | |
124 | } | |
125 | } | |
126 | ||
127 | while (children_unreaped) { | |
128 | T_QUIET; T_ASSERT_POSIX_SUCCESS(waitpid(-1, &status, 0), "waitpid returned child pid"); | |
129 | children_unreaped--; | |
130 | } | |
131 | } |